pax_global_header00006660000000000000000000000064152523402500014510gustar00rootroot0000000000000052 comment=26cdc9d69a5698ea6786821f2e0376597d3ad6ca matthewwithanm-django-imagekit-26cdc9d/000077500000000000000000000000001525234025000203015ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/.coveragerc000066400000000000000000000002111525234025000224140ustar00rootroot00000000000000[run] branch = true parallel = true [report] show_missing = true skip_empty = true skip_covered = true precision = 2 omit = tests/* matthewwithanm-django-imagekit-26cdc9d/.github/000077500000000000000000000000001525234025000216415ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/.github/workflows/000077500000000000000000000000001525234025000236765ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/.github/workflows/python.yml000066400000000000000000000012011525234025000257340ustar00rootroot00000000000000name: Python CI on: push: branches: [ develop ] pull_request: branches: [ develop ] jobs: build: runs-on: ubuntu-latest strategy: max-parallel: 4 matrix: python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] steps: - uses: actions/checkout@v6 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip python -m pip install tox tox-gh-actions - name: Run tests run: tox matthewwithanm-django-imagekit-26cdc9d/.gitignore000066400000000000000000000002521525234025000222700ustar00rootroot00000000000000*.db *.egg* *.orig *.pyc .DS_Store .tox .idea .vscode .coverage .coverage.* .venv MANIFEST build dist /tests/media/* !/tests/media/reference.png /venv /venv3 /.env /tags matthewwithanm-django-imagekit-26cdc9d/.readthedocs.yaml000066400000000000000000000015731525234025000235360ustar00rootroot00000000000000version: 2 # Set the OS, Python version and other tools you might need build: os: ubuntu-22.04 tools: python: "3.12" # You can also specify other tool versions: # nodejs: "20" # rust: "1.70" # golang: "1.20" # Build documentation in the "docs/" directory with Sphinx sphinx: configuration: docs/conf.py # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs # builder: "dirhtml" # Fail on all warnings to avoid broken references # fail_on_warning: true # Optionally build your docs in additional formats such as PDF and ePub # formats: # - pdf # - epub # Optional but recommended, declare the Python requirements required # to build your documentation # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html # python: # install: # - requirements: docs/requirements.txt matthewwithanm-django-imagekit-26cdc9d/AUTHORS000066400000000000000000000031431525234025000213520ustar00rootroot00000000000000ImageKit was originally written by `Justin Driscoll`_. The field-based API and other post-1.0 stuff was written by the bright people at HZDG_. Maintainers ----------- * `Venelin Stoykov`_ * `Matthew Tretter`_ * `Bryan Veloso`_ * `Chris Drackett`_ * `Greg Newman`_ Contributors ------------ * `Josh Ourisman`_ * `Jonathan Slenders`_ * `Eric Eldredge`_ * `Chris McKenzie`_ * `Markus Kaiserswerth`_ * `Ryan Bagwell`_ * `Alexander Bohn`_ * `Timothée Peignier`_ * `Madis Väin`_ * `Jan Sagemüller`_ * `Clay McClure`_ * `Jannis Leidel`_ * `Sean Bell`_ * `Saul Shanabrook`_ * `Jaap Roes`_ .. _Justin Driscoll: http://github.com/jdriscoll .. _HZDG: http://hzdg.com .. _Bryan Veloso: http://github.com/bryanveloso .. _Chris Drackett: http://github.com/chrisdrackett .. _Greg Newman: http://github.com/gregnewman .. _Josh Ourisman: http://github.com/joshourisman .. _Jonathan Slenders: http://github.com/jonathanslenders .. _Matthew Tretter: http://github.com/matthewwithanm .. _Eric Eldredge: http://github.com/lettertwo .. _Chris McKenzie: http://github.com/kenzic .. _Ryan Bagwell: http://github.com/ryanbagwell .. _Markus Kaiserswerth: http://github.com/mkai .. _Alexander Bohn: http://github.com/fish2000 .. _Timothée Peignier: http://github.com/cyberdelia .. _Madis Väin: http://github.com/madisvain .. _Jan Sagemüller: https://github.com/version2 .. _Clay McClure: https://github.com/claymation .. _Jannis Leidel: https://github.com/jezdez .. _Sean Bell: https://github.com/seanbell .. _Saul Shanabrook: https://github.com/saulshanabrook .. _Venelin Stoykov: https://github.com/vstoykov .. _Jaap Roes: https://github.com/jaap3 matthewwithanm-django-imagekit-26cdc9d/CONTRIBUTING.rst000066400000000000000000000022571525234025000227500ustar00rootroot00000000000000Contributing ------------ We love contributions! These guidelines will help make sure we can get your contributions merged as quickly as possible: 1. Write `good commit messages`__! 2. If you want to add a new feature, talk to us on the `mailing list`__ or `IRC`__ first. We might already have plans, or be able to offer some advice. 3. Make sure your code passes the tests that ImageKit already has. To run the tests, first install tox, ``pip install tox``, then use ``tox``. This will let you know about any errors or style issues. 4. While we're talking about tests, creating new ones for your code makes it much easier for us to merge your code quickly. ImageKit uses pytest_, so writing tests is painless. Check out `ours`__ for examples. 5. It's a good idea to do your work in a branch; that way, you can work on more than one contribution at a time without making them interdependent. __ http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html __ https://groups.google.com/forum/#!forum/django-imagekit __ irc://irc.freenode.net/imagekit .. _pytest: https://docs.pytest.org/en/latest/ __ https://github.com/matthewwithanm/django-imagekit/tree/develop/tests matthewwithanm-django-imagekit-26cdc9d/LICENSE000066400000000000000000000030761525234025000213140ustar00rootroot00000000000000Copyright (c) 2007-2008, Justin C. Driscoll Copyright (c) 2011, Justin C. Driscoll and Primary Maintainers All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of django-imagekit nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. matthewwithanm-django-imagekit-26cdc9d/MANIFEST.in000066400000000000000000000007771525234025000220520ustar00rootroot00000000000000include AUTHORS include LICENSE include README.rst include pyproject.toml include testrunner.py include tests/*.py include tests/assets/Lenna.png include tests/assets/lenna-*.jpg include tests/media/lenna.png prune tests/media/CACHE prune tests/media/b prune tests/media/photos include docs/Makefile include docs/conf.py include docs/make.bat include docs/*.rst recursive-include docs/_themes LICENSE README.rst flask_theme_support.py theme.conf *.css_t *.css *.html recursive-include imagekit/templates *.html matthewwithanm-django-imagekit-26cdc9d/README.rst000066400000000000000000000410171525234025000217730ustar00rootroot00000000000000|Build Status|_ .. |Build Status| image:: https://github.com/matthewwithanm/django-imagekit/actions/workflows/python.yml/badge.svg?branch=develop .. _Build Status: https://github.com/matthewwithanm/django-imagekit/actions/workflows/python.yml ImageKit is a Django app for processing images. Need a thumbnail? A black-and-white version of a user-uploaded image? ImageKit will make them for you. If you need to programmatically generate one image from another, you need ImageKit. ImageKit comes with a bunch of image processors for common tasks like resizing and cropping, but you can also create your own. For an idea of what's possible, check out the `Instakit`__ project. **For the complete documentation on the latest stable version of ImageKit, see** `ImageKit on RTD`_. .. _`ImageKit on RTD`: http://django-imagekit.readthedocs.org __ https://github.com/fish2000/instakit Installation ============ 1. Install `Pillow`_. (If you're using an ``ImageField`` in Django, you should have already done this.) 2. ``pip install django-imagekit`` 3. Add ``'imagekit'`` to your ``INSTALLED_APPS`` list in your project's ``settings.py`` .. _`Pillow`: http://pypi.python.org/pypi/Pillow Usage Overview ============== .. _specs: Specs ----- You have one image and you want to do something to it to create another image. But how do you tell ImageKit what to do? By defining an image spec. An **image spec** is a type of **image generator** that generates a new image from a source image. Defining Specs In Models ^^^^^^^^^^^^^^^^^^^^^^^^ The easiest way to use define an image spec is by using an ImageSpecField on your model class: .. code-block:: python from django.db import models from imagekit.models import ImageSpecField from imagekit.processors import ResizeToFill class Profile(models.Model): avatar = models.ImageField(upload_to='avatars') avatar_thumbnail = ImageSpecField(source='avatar', processors=[ResizeToFill(100, 50)], format='JPEG', options={'quality': 60}) profile = Profile.objects.all()[0] print(profile.avatar_thumbnail.url) # > /media/CACHE/images/982d5af84cddddfd0fbf70892b4431e4.jpg print(profile.avatar_thumbnail.width) # > 100 As you can probably tell, ImageSpecFields work a lot like Django's ImageFields. The difference is that they're automatically generated by ImageKit based on the instructions you give. In the example above, the avatar thumbnail is a resized version of the avatar image, saved as a JPEG with a quality of 60. Sometimes, however, you don't need to keep the original image (the avatar in the above example); when the user uploads an image, you just want to process it and save the result. In those cases, you can use the ``ProcessedImageField`` class: .. code-block:: python from django.db import models from imagekit.models import ProcessedImageField from imagekit.processors import ResizeToFill class Profile(models.Model): avatar_thumbnail = ProcessedImageField(upload_to='avatars', processors=[ResizeToFill(100, 50)], format='JPEG', options={'quality': 60}) profile = Profile.objects.all()[0] print(profile.avatar_thumbnail.url) # > /media/avatars/MY-avatar.jpg print(profile.avatar_thumbnail.width) # > 100 This is pretty similar to our previous example. We don't need to specify a "source" any more since we're not processing another image field, but we do need to pass an "upload_to" argument. This behaves exactly as it does for Django ImageFields. .. note:: You might be wondering why we didn't need an "upload_to" argument for our ImageSpecField. The reason is that ProcessedImageFields really are just like ImageFields—they save the file path in the database and you need to run syncdb (or create a migration) when you add one to your model. ImageSpecFields, on the other hand, are virtual—they add no fields to your database and don't require a database. This is handy for a lot of reasons, but it means that the path to the image file needs to be programmatically constructed based on the source image and the spec. Defining Specs Outside of Models ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Defining specs as models fields is one very convenient way to process images, but it isn't the only way. Sometimes you can't (or don't want to) add fields to your models, and that's okay. You can define image spec classes and use them directly. This can be especially useful for doing image processing in views— particularly when the processing being done depends on user input. .. code-block:: python from imagekit import ImageSpec from imagekit.processors import ResizeToFill class Thumbnail(ImageSpec): processors = [ResizeToFill(100, 50)] format = 'JPEG' options = {'quality': 60} It's probably not surprising that this class is capable of processing an image in the exact same way as our ImageSpecField above. However, unlike with the image spec model field, this class doesn't define what source the spec is acting on, or what should be done with the result; that's up to you: .. code-block:: python source_file = open('/path/to/myimage.jpg', 'rb') image_generator = Thumbnail(source=source_file) result = image_generator.generate() .. note:: You don't have to use ``open``! You can use whatever File-like object you want—including a model's ``ImageField``. The result of calling ``generate()`` on an image spec is a file-like object containing our resized image, with which you can do whatever you want. For example, if you wanted to save it to disk: .. code-block:: python dest = open('/path/to/dest.jpg', 'wb') dest.write(result.read()) dest.close() Using Specs In Templates ^^^^^^^^^^^^^^^^^^^^^^^^ If you have a model with an ImageSpecField or ProcessedImageField, you can easily use those processed image just as you would a normal image field: .. code-block:: html (This is assuming you have a view that's setting a context variable named "profile" to an instance of our Profile model.) But you can also generate processed image files directly in your template—from any image—without adding anything to your model. In order to do this, you'll first have to define an image generator class (remember, specs are a type of generator) in your app somewhere, just as we did in the last section. You'll also need a way of referring to the generator in your template, so you'll need to register it. .. code-block:: python from imagekit import ImageSpec, register from imagekit.processors import ResizeToFill class Thumbnail(ImageSpec): processors = [ResizeToFill(100, 50)] format = 'JPEG' options = {'quality': 60} register.generator('myapp:thumbnail', Thumbnail) .. note:: You can register your generator with any id you want, but choose wisely! If you pick something too generic, you could have a conflict with another third-party app you're using. For this reason, it's a good idea to prefix your generator ids with the name of your app. Also, ImageKit recognizes colons as separators when doing pattern matching (e.g. in the generateimages management command), so it's a good idea to use those too! .. warning:: This code can go in any file you want—but you need to make sure it's loaded! In order to keep things simple, ImageKit will automatically try to load an module named "imagegenerators" in each of your installed apps. So why don't you just save yourself the headache and put your image specs in there? Now that we've created an image generator class and registered it with ImageKit, we can use it in our templates! generateimage """"""""""""" The most generic template tag that ImageKit gives you is called "generateimage". It requires at least one argument: the id of a registered image generator. Additional keyword-style arguments are passed to the registered generator class. As we saw above, image spec constructors expect a source keyword argument, so that's what we need to pass to use our thumbnail spec: .. code-block:: html {% load imagekit %} {% generateimage 'myapp:thumbnail' source=source_file %} This will output the following HTML: .. code-block:: html You can also add additional HTML attributes; just separate them from your keyword args using two dashes: .. code-block:: html {% load imagekit %} {% generateimage 'myapp:thumbnail' source=source_file -- alt="A picture of Me" id="mypicture" %} Not generating HTML image tags? No problem. The tag also functions as an assignment tag, providing access to the underlying file object: .. code-block:: html {% load imagekit %} {% generateimage 'myapp:thumbnail' source=source_file as th %} Click to download a cool {{ th.width }} x {{ th.height }} image! thumbnail """"""""" Because it's such a common use case, ImageKit also provides a "thumbnail" template tag: .. code-block:: html {% load imagekit %} {% thumbnail '100x50' source_file %} Like the generateimage tag, the thumbnail tag outputs an tag: .. code-block:: html Comparing this syntax to the generateimage tag above, you'll notice a few differences. First, we didn't have to specify an image generator id; unless we tell it otherwise, thumbnail tag uses the generator registered with the id "imagekit:thumbnail". **It's important to note that this tag is *not* using the Thumbnail spec class we defined earlier**; it's using the generator registered with the id "imagekit:thumbnail" which, by default, is ``imagekit.generatorlibrary.Thumbnail``. Second, we're passing two positional arguments (the dimensions and the source image) as opposed to the keyword arguments we used with the generateimage tag. Like with the generateimage tag, you can also specify additional HTML attributes for the thumbnail tag, or use it as an assignment tag: .. code-block:: html {% load imagekit %} {% thumbnail '100x50' source_file -- alt="A picture of Me" id="mypicture" %} {% thumbnail '100x50' source_file as th %} Using Specs in Forms ^^^^^^^^^^^^^^^^^^^^ In addition to the model field above, there's also a form field version of the ``ProcessedImageField`` class. The functionality is basically the same (it processes an image once and saves the result), but it's used in a form class: .. code-block:: python from django import forms from imagekit.forms import ProcessedImageField from imagekit.processors import ResizeToFill class ProfileForm(forms.Form): avatar_thumbnail = ProcessedImageField(spec_id='myapp:profile:avatar_thumbnail', processors=[ResizeToFill(100, 50)], format='JPEG', options={'quality': 60}) The benefit of using ``imagekit.forms.ProcessedImageField`` (as opposed to ``imagekit.models.ProcessedImageField`` above) is that it keeps the logic for creating the image outside of your model (in which you would use a normal Django ImageField). You can even create multiple forms, each with their own ProcessedImageField, that all store their results in the same image field. Processors ---------- So far, we've only seen one processor: ``imagekit.processors.ResizeToFill``. But ImageKit is capable of far more than just resizing images, and that power comes from its processors. Processors take a PIL image object, do something to it, and return a new one. A spec can make use of as many processors as you'd like, which will all be run in order. .. code-block:: python from imagekit import ImageSpec from imagekit.processors import TrimBorderColor, Adjust class MySpec(ImageSpec): processors = [ TrimBorderColor(), Adjust(contrast=1.2, sharpness=1.1), ] format = 'JPEG' options = {'quality': 60} The ``imagekit.processors`` module contains processors for many common image manipulations, like resizing, rotating, and color adjustments. However, if they aren't up to the task, you can create your own. All you have to do is define a class that implements a ``process()`` method: .. code-block:: python class Watermark(object): def process(self, image): # Code for adding the watermark goes here. return image That's all there is to it! To use your fancy new custom processor, just include it in your spec's ``processors`` list: .. code-block:: python from imagekit import ImageSpec from imagekit.processors import TrimBorderColor, Adjust from myapp.processors import Watermark class MySpec(ImageSpec): processors = [ TrimBorderColor(), Adjust(contrast=1.2, sharpness=1.1), Watermark(), ] format = 'JPEG' options = {'quality': 60} Note that when you import a processor from ``imagekit.processors``, imagekit in turn imports the processor from `PILKit`_. So if you are looking for available processors, look at PILKit. .. _`PILKit`: https://github.com/matthewwithanm/pilkit Admin ----- ImageKit also contains a class named ``imagekit.admin.AdminThumbnail`` for displaying specs (or even regular ImageFields) in the `Django admin change list`_. AdminThumbnail is used as a property on Django admin classes: .. code-block:: python from django.contrib import admin from imagekit.admin import AdminThumbnail from .models import Photo class PhotoAdmin(admin.ModelAdmin): list_display = ('__str__', 'admin_thumbnail') admin_thumbnail = AdminThumbnail(image_field='thumbnail') admin.site.register(Photo, PhotoAdmin) To use specs defined outside of models: .. code-block:: python from django.contrib import admin from imagekit.admin import AdminThumbnail from imagekit import ImageSpec from imagekit.processors import ResizeToFill from imagekit.cachefiles import ImageCacheFile from .models import Photo class AdminThumbnailSpec(ImageSpec): processors = [ResizeToFill(100, 30)] format = 'JPEG' options = {'quality': 60 } def cached_admin_thumb(instance): # `image` is the name of the image field on the model cached = ImageCacheFile(AdminThumbnailSpec(instance.image)) # only generates the first time, subsequent calls use cache cached.generate() return cached class PhotoAdmin(admin.ModelAdmin): list_display = ('__str__', 'admin_thumbnail') admin_thumbnail = AdminThumbnail(image_field=cached_admin_thumb) admin.site.register(Photo, PhotoAdmin) AdminThumbnail can even use a custom template. For more information, see ``imagekit.admin.AdminThumbnail``. .. _`Django admin change list`: https://docs.djangoproject.com/en/dev/intro/tutorial02/#customize-the-admin-change-list Management Commands ------------------- ImageKit has one management command—``generateimages``—which will generate cache files for all of your registered image generators. You can also pass it a list of generator ids in order to generate images selectively. Community ========= Please use `the GitHub issue tracker `_ to report bugs with django-imagekit. `A mailing list `_ also exists to discuss the project and ask questions, as well as the official `#imagekit `_ channel on Freenode. Contributing ============ We love contributions! And you don't have to be an expert with the library—or even Django—to contribute either: ImageKit's processors are standalone classes that are completely separate from the more intimidating internals of Django's ORM. If you've written a processor that you think might be useful to other people, open a pull request so we can take a look! You can also check out our list of `open, contributor-friendly issues`__ for ideas. Check out our `contributing guidelines`_ for more information about pitching in with ImageKit. __ https://github.com/matthewwithanm/django-imagekit/issues?labels=contributor-friendly&state=open .. _`contributing guidelines`: https://github.com/matthewwithanm/django-imagekit/blob/develop/CONTRIBUTING.rst matthewwithanm-django-imagekit-26cdc9d/docs/000077500000000000000000000000001525234025000212315ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/docs/Makefile000066400000000000000000000127311525234025000226750ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = python $(shell which sphinx-build) PAPER = BUILDDIR = build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ImageKit.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ImageKit.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/ImageKit" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ImageKit" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." matthewwithanm-django-imagekit-26cdc9d/docs/_themes/000077500000000000000000000000001525234025000226555ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/docs/_themes/LICENSE000077500000000000000000000035071525234025000236720ustar00rootroot00000000000000Modifications: Copyright (c) 2010 Kenneth Reitz. Original Project: Copyright (c) 2010 by Armin Ronacher. Some rights reserved. Redistribution and use in source and binary forms of the theme, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission. We kindly ask you to only use these themes in an unmodified manner just for Flask and Flask-related products, not for unrelated projects. If you like the visual style and want to use it for your own projects, please consider making some larger changes to the themes (such as changing font faces, sizes, colors or margins). THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. matthewwithanm-django-imagekit-26cdc9d/docs/_themes/README.rst000077500000000000000000000013251525234025000243500ustar00rootroot00000000000000krTheme Sphinx Style ==================== This repository contains sphinx styles Kenneth Reitz uses in most of his projects. It is a derivative of Mitsuhiko's themes for Flask and Flask related projects. To use this style in your Sphinx documentation, follow this guide: 1. put this folder as _themes into your docs folder. Alternatively you can also use git submodules to check out the contents there. 2. add this to your conf.py: :: sys.path.append(os.path.abspath('_themes')) html_theme_path = ['_themes'] html_theme = 'kr' The following themes exist: **kr** the standard flask documentation theme for large projects **kr_small** small one-page theme. Intended to be used by very small addon libraries. matthewwithanm-django-imagekit-26cdc9d/docs/_themes/flask_theme_support.py000077500000000000000000000114761525234025000273210ustar00rootroot00000000000000# flasky extensions. flasky pygments style based on tango style from pygments.style import Style from pygments.token import (Comment, Error, Generic, Keyword, Literal, Name, Number, Operator, Other, Punctuation, String, Whitespace) class FlaskyStyle(Style): background_color = "#f8f8f8" default_style = "" styles = { # No corresponding class for the following: #Text: "", # class: '' Whitespace: "underline #f8f8f8", # class: 'w' Error: "#a40000 border:#ef2929", # class: 'err' Other: "#000000", # class 'x' Comment: "italic #8f5902", # class: 'c' Comment.Preproc: "noitalic", # class: 'cp' Keyword: "bold #004461", # class: 'k' Keyword.Constant: "bold #004461", # class: 'kc' Keyword.Declaration: "bold #004461", # class: 'kd' Keyword.Namespace: "bold #004461", # class: 'kn' Keyword.Pseudo: "bold #004461", # class: 'kp' Keyword.Reserved: "bold #004461", # class: 'kr' Keyword.Type: "bold #004461", # class: 'kt' Operator: "#582800", # class: 'o' Operator.Word: "bold #004461", # class: 'ow' - like keywords Punctuation: "bold #000000", # class: 'p' # because special names such as Name.Class, Name.Function, etc. # are not recognized as such later in the parsing, we choose them # to look the same as ordinary variables. Name: "#000000", # class: 'n' Name.Attribute: "#c4a000", # class: 'na' - to be revised Name.Builtin: "#004461", # class: 'nb' Name.Builtin.Pseudo: "#3465a4", # class: 'bp' Name.Class: "#000000", # class: 'nc' - to be revised Name.Constant: "#000000", # class: 'no' - to be revised Name.Decorator: "#888", # class: 'nd' - to be revised Name.Entity: "#ce5c00", # class: 'ni' Name.Exception: "bold #cc0000", # class: 'ne' Name.Function: "#000000", # class: 'nf' Name.Property: "#000000", # class: 'py' Name.Label: "#f57900", # class: 'nl' Name.Namespace: "#000000", # class: 'nn' - to be revised Name.Other: "#000000", # class: 'nx' Name.Tag: "bold #004461", # class: 'nt' - like a keyword Name.Variable: "#000000", # class: 'nv' - to be revised Name.Variable.Class: "#000000", # class: 'vc' - to be revised Name.Variable.Global: "#000000", # class: 'vg' - to be revised Name.Variable.Instance: "#000000", # class: 'vi' - to be revised Number: "#990000", # class: 'm' Literal: "#000000", # class: 'l' Literal.Date: "#000000", # class: 'ld' String: "#4e9a06", # class: 's' String.Backtick: "#4e9a06", # class: 'sb' String.Char: "#4e9a06", # class: 'sc' String.Doc: "italic #8f5902", # class: 'sd' - like a comment String.Double: "#4e9a06", # class: 's2' String.Escape: "#4e9a06", # class: 'se' String.Heredoc: "#4e9a06", # class: 'sh' String.Interpol: "#4e9a06", # class: 'si' String.Other: "#4e9a06", # class: 'sx' String.Regex: "#4e9a06", # class: 'sr' String.Single: "#4e9a06", # class: 's1' String.Symbol: "#4e9a06", # class: 'ss' Generic: "#000000", # class: 'g' Generic.Deleted: "#a40000", # class: 'gd' Generic.Emph: "italic #000000", # class: 'ge' Generic.Error: "#ef2929", # class: 'gr' Generic.Heading: "bold #000080", # class: 'gh' Generic.Inserted: "#00A000", # class: 'gi' Generic.Output: "#888", # class: 'go' Generic.Prompt: "#745334", # class: 'gp' Generic.Strong: "bold #000000", # class: 'gs' Generic.Subheading: "bold #800080", # class: 'gu' Generic.Traceback: "bold #a40000", # class: 'gt' } matthewwithanm-django-imagekit-26cdc9d/docs/_themes/kr/000077500000000000000000000000001525234025000232715ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/docs/_themes/kr/layout.html000077500000000000000000000011411525234025000254740ustar00rootroot00000000000000{%- extends "basic/layout.html" %} {%- block extrahead %} {{ super() }} {% if theme_touch_icon %} {% endif %} {% endblock %} {%- block relbar2 %}{% endblock %} {%- block footer %} {%- endblock %} matthewwithanm-django-imagekit-26cdc9d/docs/_themes/kr/relations.html000077500000000000000000000011161525234025000261610ustar00rootroot00000000000000

Related Topics

matthewwithanm-django-imagekit-26cdc9d/docs/_themes/kr/static/000077500000000000000000000000001525234025000245605ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/docs/_themes/kr/static/flasky.css_t000077500000000000000000000166601525234025000271220ustar00rootroot00000000000000/* * flasky.css_t * ~~~~~~~~~~~~ * * :copyright: Copyright 2010 by Armin Ronacher. Modifications by Kenneth Reitz. * :license: Flask Design License, see LICENSE for details. */ {% set page_width = '940px' %} {% set sidebar_width = '220px' %} @import url("basic.css"); /* -- page layout ----------------------------------------------------------- */ body { font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro'; font-size: 17px; background-color: white; color: #000; margin: 0; padding: 0; } div.document { width: {{ page_width }}; margin: 30px auto 0 auto; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 0 0 0 {{ sidebar_width }}; } div.sphinxsidebar { width: {{ sidebar_width }}; } hr { border: 1px solid #B1B4B6; } div.body { background-color: #ffffff; color: #3E4349; padding: 0 30px 0 30px; } img.floatingflask { padding: 0 0 10px 10px; float: right; } div.footer { width: {{ page_width }}; margin: 20px auto 30px auto; font-size: 14px; color: #888; text-align: right; } div.footer a { color: #888; } div.related { display: none; } div.sphinxsidebar a { color: #444; text-decoration: none; border-bottom: 1px dotted #999; } div.sphinxsidebar a:hover { border-bottom: 1px solid #999; } div.sphinxsidebar { font-size: 14px; line-height: 1.5; } div.sphinxsidebarwrapper { padding: 18px 10px; } div.sphinxsidebarwrapper p.logo { padding: 0; margin: -10px 0 0 -20px; text-align: center; } div.sphinxsidebar h3, div.sphinxsidebar h4 { font-family: 'Garamond', 'Georgia', serif; color: #444; font-size: 24px; font-weight: normal; margin: 0 0 5px 0; padding: 0; } div.sphinxsidebar h4 { font-size: 20px; } div.sphinxsidebar h3 a { color: #444; } div.sphinxsidebar p.logo a, div.sphinxsidebar h3 a, div.sphinxsidebar p.logo a:hover, div.sphinxsidebar h3 a:hover { border: none; } div.sphinxsidebar p { color: #555; margin: 10px 0; } div.sphinxsidebar ul { margin: 10px 0; padding: 0; color: #000; } div.sphinxsidebar input { border: 1px solid #ccc; font-family: 'Georgia', serif; font-size: 1em; } /* -- body styles ----------------------------------------------------------- */ a { color: #004B6B; text-decoration: underline; } a:hover { color: #6D4100; text-decoration: underline; } div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; margin: 30px 0px 10px 0px; padding: 0; } div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } div.body h2 { font-size: 180%; } div.body h3 { font-size: 150%; } div.body h4 { font-size: 130%; } div.body h5 { font-size: 100%; } div.body h6 { font-size: 100%; } a.headerlink { color: #ddd; padding: 0 4px; text-decoration: none; } a.headerlink:hover { color: #444; background: #eaeaea; } div.body p, div.body dd, div.body li { line-height: 1.4em; } div.admonition { background: #fafafa; margin: 20px -30px; padding: 10px 30px; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; } div.admonition tt.xref, div.admonition a tt { border-bottom: 1px solid #fafafa; } dd div.admonition { margin-left: -60px; padding-left: 60px; } div.admonition p.admonition-title { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; font-size: 24px; margin: 0 0 10px 0; padding: 0; line-height: 1; } div.admonition p.last { margin-bottom: 0; } div.highlight { background-color: white; } dt:target, .highlight { background: #FAF3E8; } div.note { background-color: #eee; border: 1px solid #ccc; } div.seealso { background-color: #ffc; border: 1px solid #ff6; } div.topic { background-color: #eee; } p.admonition-title { display: inline; } p.admonition-title:after { content: ":"; } pre, tt { font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.9em; } img.screenshot { } tt.descname, tt.descclassname { font-size: 0.95em; } tt.descname { padding-right: 0.08em; } img.screenshot { -moz-box-shadow: 2px 2px 4px #eee; -webkit-box-shadow: 2px 2px 4px #eee; box-shadow: 2px 2px 4px #eee; } table.docutils { border: 1px solid #888; -moz-box-shadow: 2px 2px 4px #eee; -webkit-box-shadow: 2px 2px 4px #eee; box-shadow: 2px 2px 4px #eee; } table.docutils td, table.docutils th { border: 1px solid #888; padding: 0.25em 0.7em; } table.field-list, table.footnote { border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } table.footnote { margin: 15px 0; width: 100%; border: 1px solid #eee; background: #fdfdfd; font-size: 0.9em; } table.footnote + table.footnote { margin-top: -15px; border-top: none; } table.field-list th { padding: 0 0.8em 0 0; } table.field-list td { padding: 0; } table.footnote td.label { width: 0px; padding: 0.3em 0 0.3em 0.5em; } table.footnote td { padding: 0.3em 0.5em; } dl { margin: 0; padding: 0; } dl dd { margin-left: 30px; } blockquote { margin: 0 0 0 30px; padding: 0; } ul, ol { margin: 10px 0 10px 30px; padding: 0; } pre { background: #eee; padding: 7px 30px; margin: 15px -30px; line-height: 1.3em; } dl pre, blockquote pre, li pre { margin-left: -60px; padding-left: 60px; } dl dl pre { margin-left: -90px; padding-left: 90px; } tt { background-color: #ecf0f3; color: #222; /* padding: 1px 2px; */ } tt.xref, a tt { background-color: #FBFBFB; border-bottom: 1px solid white; } a.reference { text-decoration: none; border-bottom: 1px dotted #004B6B; } a.reference:hover { border-bottom: 1px solid #6D4100; } a.footnote-reference { text-decoration: none; font-size: 0.7em; vertical-align: top; border-bottom: 1px dotted #004B6B; } a.footnote-reference:hover { border-bottom: 1px solid #6D4100; } a:hover tt { background: #EEE; } @media screen and (max-width: 600px) { div.sphinxsidebar { display: none; } div.document { width: 100%; } div.documentwrapper { margin-left: 0; margin-top: 0; margin-right: 0; margin-bottom: 0; } div.bodywrapper { margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0; } ul { margin-left: 0; } .document { width: auto; } .footer { width: auto; } .bodywrapper { margin: 0; } .footer { width: auto; } .github { display: none; } } /* scrollbars */ ::-webkit-scrollbar { width: 6px; height: 6px; } ::-webkit-scrollbar-button:start:decrement, ::-webkit-scrollbar-button:end:increment { display: block; height: 10px; } ::-webkit-scrollbar-button:vertical:increment { background-color: #fff; } ::-webkit-scrollbar-track-piece { background-color: #eee; -webkit-border-radius: 3px; } ::-webkit-scrollbar-thumb:vertical { height: 50px; background-color: #ccc; -webkit-border-radius: 3px; } ::-webkit-scrollbar-thumb:horizontal { width: 50px; background-color: #ccc; -webkit-border-radius: 3px; } /* misc. */ .revsys-inline { display: none!important; }matthewwithanm-django-imagekit-26cdc9d/docs/_themes/kr/static/small_flask.css000077500000000000000000000021551525234025000275700ustar00rootroot00000000000000/* * small_flask.css_t * ~~~~~~~~~~~~~~~~~ * * :copyright: Copyright 2010 by Armin Ronacher. * :license: Flask Design License, see LICENSE for details. */ body { margin: 0; padding: 20px 30px; } div.documentwrapper { float: none; background: white; } div.sphinxsidebar { display: block; float: none; width: 102.5%; margin: 50px -30px -20px -30px; padding: 10px 20px; background: #333; color: white; } div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, div.sphinxsidebar h3 a { color: white; } div.sphinxsidebar a { color: #aaa; } div.sphinxsidebar p.logo { display: none; } div.document { width: 100%; margin: 0; } div.related { display: block; margin: 0; padding: 10px 0 20px 0; } div.related ul, div.related ul li { margin: 0; padding: 0; } div.footer { display: none; } div.bodywrapper { margin: 0; } div.body { min-height: 0; padding: 0; } .rtd_doc_footer { display: none; } .document { width: auto; } .footer { width: auto; } .footer { width: auto; } .github { display: none; }matthewwithanm-django-imagekit-26cdc9d/docs/_themes/kr/theme.conf000077500000000000000000000001721525234025000252450ustar00rootroot00000000000000[theme] inherit = basic stylesheet = flasky.css pygments_style = flask_theme_support.FlaskyStyle [options] touch_icon = matthewwithanm-django-imagekit-26cdc9d/docs/_themes/kr_small/000077500000000000000000000000001525234025000244615ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/docs/_themes/kr_small/layout.html000077500000000000000000000012531525234025000266700ustar00rootroot00000000000000{% extends "basic/layout.html" %} {% block header %} {{ super() }} {% if pagename == 'index' %}
{% endif %} {% endblock %} {% block footer %} {% if pagename == 'index' %}
{% endif %} {% endblock %} {# do not display relbars #} {% block relbar1 %}{% endblock %} {% block relbar2 %} {% if theme_github_fork %} Fork me on GitHub {% endif %} {% endblock %} {% block sidebar1 %}{% endblock %} {% block sidebar2 %}{% endblock %} matthewwithanm-django-imagekit-26cdc9d/docs/_themes/kr_small/static/000077500000000000000000000000001525234025000257505ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/docs/_themes/kr_small/static/flasky.css_t000077500000000000000000000110011525234025000302720ustar00rootroot00000000000000/* * flasky.css_t * ~~~~~~~~~~~~ * * Sphinx stylesheet -- flasky theme based on nature theme. * * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @import url("basic.css"); /* -- page layout ----------------------------------------------------------- */ body { font-family: 'Georgia', serif; font-size: 17px; color: #000; background: white; margin: 0; padding: 0; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 40px auto 0 auto; width: 700px; } hr { border: 1px solid #B1B4B6; } div.body { background-color: #ffffff; color: #3E4349; padding: 0 30px 30px 30px; } img.floatingflask { padding: 0 0 10px 10px; float: right; } div.footer { text-align: right; color: #888; padding: 10px; font-size: 14px; width: 650px; margin: 0 auto 40px auto; } div.footer a { color: #888; text-decoration: underline; } div.related { line-height: 32px; color: #888; } div.related ul { padding: 0 0 0 10px; } div.related a { color: #444; } /* -- body styles ----------------------------------------------------------- */ a { color: #004B6B; text-decoration: underline; } a:hover { color: #6D4100; text-decoration: underline; } div.body { padding-bottom: 40px; /* saved for footer */ } div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; margin: 30px 0px 10px 0px; padding: 0; } {% if theme_index_logo %} div.indexwrapper h1 { text-indent: -999999px; background: url({{ theme_index_logo }}) no-repeat center center; height: {{ theme_index_logo_height }}; } {% endif %} div.body h2 { font-size: 180%; } div.body h3 { font-size: 150%; } div.body h4 { font-size: 130%; } div.body h5 { font-size: 100%; } div.body h6 { font-size: 100%; } a.headerlink { color: white; padding: 0 4px; text-decoration: none; } a.headerlink:hover { color: #444; background: #eaeaea; } div.body p, div.body dd, div.body li { line-height: 1.4em; } div.admonition { background: #fafafa; margin: 20px -30px; padding: 10px 30px; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; } div.admonition p.admonition-title { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; font-size: 24px; margin: 0 0 10px 0; padding: 0; line-height: 1; } div.admonition p.last { margin-bottom: 0; } div.highlight{ background-color: white; } dt:target, .highlight { background: #FAF3E8; } div.note { background-color: #eee; border: 1px solid #ccc; } div.seealso { background-color: #ffc; border: 1px solid #ff6; } div.topic { background-color: #eee; } div.warning { background-color: #ffe4e4; border: 1px solid #f66; } p.admonition-title { display: inline; } p.admonition-title:after { content: ":"; } pre, tt { font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.85em; } img.screenshot { } tt.descname, tt.descclassname { font-size: 0.95em; } tt.descname { padding-right: 0.08em; } img.screenshot { -moz-box-shadow: 2px 2px 4px #eee; -webkit-box-shadow: 2px 2px 4px #eee; box-shadow: 2px 2px 4px #eee; } table.docutils { border: 1px solid #888; -moz-box-shadow: 2px 2px 4px #eee; -webkit-box-shadow: 2px 2px 4px #eee; box-shadow: 2px 2px 4px #eee; } table.docutils td, table.docutils th { border: 1px solid #888; padding: 0.25em 0.7em; } table.field-list, table.footnote { border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } table.footnote { margin: 15px 0; width: 100%; border: 1px solid #eee; } table.field-list th { padding: 0 0.8em 0 0; } table.field-list td { padding: 0; } table.footnote td { padding: 0.5em; } dl { margin: 0; padding: 0; } dl dd { margin-left: 30px; } pre { padding: 0; margin: 15px -30px; padding: 8px; line-height: 1.3em; padding: 7px 30px; background: #eee; border-radius: 2px; -moz-border-radius: 2px; -webkit-border-radius: 2px; } dl pre { margin-left: -60px; padding-left: 60px; } tt { background-color: #ecf0f3; color: #222; /* padding: 1px 2px; */ } tt.xref, a tt { background-color: #FBFBFB; } a:hover tt { background: #EEE; } matthewwithanm-django-imagekit-26cdc9d/docs/_themes/kr_small/theme.conf000077500000000000000000000002701525234025000264340ustar00rootroot00000000000000[theme] inherit = basic stylesheet = flasky.css nosidebar = true pygments_style = flask_theme_support.FlaskyStyle [options] index_logo = '' index_logo_height = 120px github_fork = '' matthewwithanm-django-imagekit-26cdc9d/docs/advanced_usage.rst000066400000000000000000000160041525234025000247150ustar00rootroot00000000000000Advanced Usage ************** Models ====== The ``ImageSpecField`` Shorthand Syntax --------------------------------------- If you've read the README, you already know what an ``ImageSpecField`` is and the basics of defining one: .. code-block:: python from django.db import models from imagekit.models import ImageSpecField from imagekit.processors import ResizeToFill class Profile(models.Model): avatar = models.ImageField(upload_to='avatars') avatar_thumbnail = ImageSpecField(source='avatar', processors=[ResizeToFill(100, 50)], format='JPEG', options={'quality': 60}) This will create an ``avatar_thumbnail`` field which is a resized version of the image stored in the ``avatar`` image field. But this is actually just shorthand for creating an ``ImageSpec``, registering it, and associating it with an ``ImageSpecField``: .. code-block:: python from django.db import models from imagekit import ImageSpec, register from imagekit.models import ImageSpecField from imagekit.processors import ResizeToFill class AvatarThumbnail(ImageSpec): processors = [ResizeToFill(100, 50)] format = 'JPEG' options = {'quality': 60} register.generator('myapp:profile:avatar_thumbnail', AvatarThumbnail) class Profile(models.Model): avatar = models.ImageField(upload_to='avatars') avatar_thumbnail = ImageSpecField(source='avatar', id='myapp:profile:avatar_thumbnail') Obviously, the shorthand version is a lot, well…shorter. So why would you ever want to go through the trouble of using the long form? The answer is that the long form—creating an image spec class and registering it—gives you a lot more power over the generated image. .. _dynamic-specs: Specs That Change ----------------- As you'll remember from the README, an image spec is just a type of image generator that generates a new image from a source image. How does the image spec get access to the source image? Simple! It's passed to the constructor as a keyword argument and stored as an attribute of the spec. Normally, we don't have to concern ourselves with this; the ``ImageSpec`` knows what to do with the source image and we're happy to let it do its thing. However, having access to the source image in our spec class can be very useful… Often, when using an ``ImageSpecField``, you may want the spec to vary based on properties of a model. (For example, you might want to store image dimensions on the model and then use them to generate your thumbnail.) Now that we know how to access the source image from our spec, it's a simple matter to extract its model and use it to create our processors list. In fact, ImageKit includes a utility for getting this information. .. code-block:: python :emphasize-lines: 11-14 from django.db import models from imagekit import ImageSpec, register from imagekit.models import ImageSpecField from imagekit.processors import ResizeToFill from imagekit.utils import get_field_info class AvatarThumbnail(ImageSpec): format = 'JPEG' options = {'quality': 60} @property def processors(self): model, field_name = get_field_info(self.source) return [ResizeToFill(model.thumbnail_width, model.thumbnail_height)] register.generator('myapp:profile:avatar_thumbnail', AvatarThumbnail) class Profile(models.Model): avatar = models.ImageField(upload_to='avatars') avatar_thumbnail = ImageSpecField(source='avatar', id='myapp:profile:avatar_thumbnail') thumbnail_width = models.PositiveIntegerField() thumbnail_height = models.PositiveIntegerField() Now each avatar thumbnail will be resized according to the dimensions stored on the model! Of course, processors aren't the only thing that can vary based on the model of the source image; spec behavior can change in any way you want. .. _source-groups: Source Groups ============= When you run the ``generateimages`` management command, how does ImageKit know which source images to use with which specs? Obviously, when you define an ImageSpecField, the source image is being connected to a spec, but what's going on underneath the hood? The answer is that, when you define an ImageSpecField, ImageKit automatically creates and registers an object called a *source group*. Source groups are responsible for two things: 1. They dispatch signals when a source is saved, and 2. They expose a generator method that enumerates source files. When these objects are registered (using ``imagekit.register.source_group()``), their signals will trigger callbacks on the cache file strategies associated with image specs that use the source. (So, for example, you can chose to generate a file every time the source image changes.) In addition, the generator method is used (indirectly) to create the list of files to generate with the ``generateimages`` management command. Currently, there is only one source group class bundled with ImageKit—the one used by ImageSpecFields. This source group (``imagekit.specs.sourcegroups.ImageFieldSourceGroup``) represents an ImageField on every instance of a particular model. In terms of the above description, the instance ``ImageFieldSourceGroup(Profile, 'avatar')`` 1) dispatches a signal every time the image in Profile's avatar ImageField changes, and 2) exposes a generator method that iterates over every Profile's "avatar" image. Chances are, this is the only source group you will ever need to use, however, ImageKit lets you define and register custom source groups easily. This may be useful, for example, if you're using the template tags "generateimage" and "thumbnail" and the optimistic cache file strategy. Again, the purpose is to tell ImageKit which specs are used with which sources (so the "generateimages" management command can generate those files) and when the source image has been created or changed (so that the strategy has the opportunity to act on it). A simple example of a custom source group class is as follows: .. code-block:: python import glob import os class JpegsInADirectory(object): def __init__(self, dir): self.dir = dir def files(self): os.chdir(self.dir) for name in glob.glob('*.jpg'): yield open(name, 'rb') Instances of this class could then be registered with one or more spec id: .. code-block:: python from imagekit import register register.source_group('myapp:profile:avatar_thumbnail', JpegsInADirectory('/path/to/some/pics')) Running the "generateimages" management command would now cause thumbnails to be generated (using the "myapp:profile:avatar_thumbnail" spec) for each of the JPEGs in `/path/to/some/pics`. Note that, since this source group doesnt send the `source_saved` signal, the corresponding cache file strategy callbacks would not be called for them. matthewwithanm-django-imagekit-26cdc9d/docs/caching.rst000066400000000000000000000271111525234025000233610ustar00rootroot00000000000000Caching ******* Default Backend Workflow ======================== ``ImageSpec`` ------------- At the heart of ImageKit are image generators. These are classes with a ``generate()`` method which returns an image file. An image spec is a type of image generator. The thing that makes specs special is that they accept a source image. So an image spec is just an image generator that makes an image from some other image. ``ImageCacheFile`` ------------------ However, an image spec by itself would be vastly inefficient. Every time an an image was accessed in some way, it would have be regenerated and saved. Most of the time, you want to re-use a previously generated image, based on the input image and spec, instead of generating a new one. That's where ``ImageCacheFile`` comes in. ``ImageCacheFile`` is a File-like object that wraps an image generator. They look and feel just like regular file objects, but they've got a little trick up their sleeve: they represent files that may not actually exist! .. _cache-file-strategy: Cache File Strategy ------------------- Each ``ImageCacheFile`` has a cache file strategy, which abstracts away when image is actually generated. It can implement the following three methods: * ``on_content_required`` - called by ``ImageCacheFile`` when it requires the contents of the generated image. For example, when you call ``read()`` or try to access information contained in the file. * ``on_existence_required`` - called by ``ImageCacheFile`` when it requires the generated image to exist but may not be concerned with its contents. For example, when you access its ``url`` or ``path`` attribute. * ``on_source_saved`` - called when the source of a spec is saved The default strategy only defines the first two of these, as follows: .. code-block:: python class JustInTime(object): def on_content_required(self, file): file.generate() def on_existence_required(self, file): file.generate() .. _cache-file-backend: Cache File Backend ------------------ The ``generate`` method on the ``ImageCacheFile`` is further delegated to the cache file backend, which abstracts away how an image is generated. The cache file backend defaults to the setting ``IMAGEKIT_DEFAULT_CACHEFILE_BACKEND`` and can be set explicitly on a spec with the ``cachefile_backend`` attribute. The default works like this: * Checks the file storage to see if a file exists * If not, caches that information for 5 seconds * If it does, caches that information in the ``IMAGEKIT_CACHE_BACKEND`` If file doesn't exist, generates it immediately and synchronously That pretty much covers the architecture of the caching layer, and its default behavior. I like the default behavior. When will an image be regenerated? Whenever it needs to be! When will your storage backend get hit? Depending on your ``IMAGEKIT_CACHE_BACKEND`` settings, as little as twice per file (once for the existence check and once to save the generated file). What if you want to change a spec? The generated file name (which is used as part of the cache keys) vary with the source file name and spec attributes, so if you change any of those, a new file will be generated. The default behavior is easy! .. note:: Like regular Django ImageFields, IK doesn't currently cache width and height values, so accessing those will always result in a read. That will probably change soon though. Optimizing ========== There are several ways to improve the performance (reduce I/O operations) of ImageKit. Each has its own pros and cons. Caching Data About Generated Files ---------------------------------- Generally, once a file is generated, you will never be removing it, so by default ImageKit will use default cache to cache the state of generated files "forever" (or only 5 minutes when ``DEBUG = True``). The time for which ImageKit will cache state is configured with ``IMAGEKIT_CACHE_TIMEOUT``. If set to ``None`` this means "never expire" (default when ``DEBUG = False``). You can reduce this timeout if you want or set it to some numeric value in seconds if your cache backend behaves differently and for example do not cache values if timeout is ``None``. If you clear your cache durring deployment or some other reason probably you do not want to lose the cache for generated images especcialy if you are using some slow remote storage (like Amazon S3). Then you can configure separate cache (for example redis) in your ``CACHES`` config and tell ImageKit to use it instead of the default cache by setting ``IMAGEKIT_CACHE_BACKEND``. Pre-Generating Images --------------------- The default cache file backend generates images immediately and synchronously. If you don't do anything special, that will be when they are first requested—as part of request-response cycle. This means that the first visitor to your page will have to wait for the file to be created before they see any HTML. This can be mitigated, though, by simply generating the images ahead of time, by running the ``generateimages`` management command. .. note:: If using with template tags, be sure to read :ref:`source-groups`. Reducing Cache Backend Round Trips ---------------------------------- When rendering pages with many images, ImageKit performs one cache lookup per image to check the cachefile state (so a page with 50 images can cause 50 cache round trips). This can become a major request latency problem, and is highly sensitive to the network latency to the cache. To reduce this overhead, ImageKit provides a set of APIs that can be used to prefetch cache states into a request-local state cache using a single ``cache.get_many()`` call: .. code-block:: python from imagekit.cachefiles.state import use_cachefile_state_cache, prefetch_cachefile_states def gallery(request): images = list(Image.objects.filter(...)[:50]) # Construct ImageCacheFile objects. (No cache request yet) thumbs = [img.thumbnail for img in images] # Create a request-local mapping and prefetch states state_cache = {} with use_cachefile_state_cache(state_cache): prefetch_cachefile_states(thumbs, state_cache=state_cache) return render(request, "gallery.html", {"images": images}) How it works: 1. ``use_cachefile_state_cache()`` activates a request-local in-memory cache for the duration of the context (a plain dict is typically used). 2. ``prefetch_cachefile_states()`` fetches all cache file states in a single ``cache.get_many()`` call and stores them in the state cache. 3. During template rendering, ``ImageCacheFile.url`` accesses check the state cache first before calling ``cache.get()``, so prefetched keys incur no additional cache round trips. Deferring Image Generation -------------------------- As mentioned above, image generation is normally done synchronously. through the default cache file backend. However, you can also take advantage of deferred generation. In order to do this, you'll need to do two things: 1) install `celery`__ (or `django-celery`__ if you are bound to Celery<3.1) 2) tell ImageKit to use the async cachefile backend. To do this for all specs, set the ``IMAGEKIT_DEFAULT_CACHEFILE_BACKEND`` in your settings .. code-block:: python IMAGEKIT_DEFAULT_CACHEFILE_BACKEND = 'imagekit.cachefiles.backends.Async' Images will now be generated asynchronously. But watch out! Asynchrounous generation means you'll have to account for images that haven't been generated yet. You can do this by checking the truthiness of your files; if an image hasn't been generated, it will be falsy: .. code-block:: html {% if not profile.avatar_thumbnail %} {% else %} {% endif %} Or, in Python: .. code-block:: python profile = Profile.objects.all()[0] if profile.avatar_thumbnail: url = profile.avatar_thumbnail.url else: url = '/path/to/placeholder.jpg' .. note:: If you are using an "async" backend in combination with the "optimistic" cache file strategy (see `Removing Safeguards`_ below), checking for truthiness as described above will not work. The "optimistic" backend is very optimistic so to say, and removes the check. Create and use the following strategy to a) have images only created on save, and b) retain the ability to check whether the images have already been created:: class ImagekitOnSaveStrategy(object): def on_source_saved(self, file): file.generate() .. note:: If you use custom storage backend for some specs, (storage passed to the field different than configured one) it's required the storage to be pickleable __ https://pypi.python.org/pypi/django-celery __ http://www.celeryproject.org Removing Safeguards ------------------- Even with pre-generating images, ImageKit will still try to ensure that your image exists when you access it by default. This is for your benefit: if you forget to generate your images, ImageKit will see that and generate it for you. If the state of the file is cached (see above), this is a pretty cheap operation. However, if the state isn't cached, ImageKit will need to query the storage backend. For those who aren't willing to accept that cost (and who never want ImageKit to generate images in the request-response cycle), there's the "optimistic" cache file strategy. This strategy only generates a new image when a spec's source image is created or changed. Unlike with the "just in time" strategy, accessing the file won't cause it to be generated, ImageKit will just assume that it already exists. To use this cache file strategy for all specs, set the ``IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY`` in your settings: .. code-block:: python IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY = 'imagekit.cachefiles.strategies.Optimistic' If you have specs that :ref:`change based on attributes of the source `, that's not going to cut it, though; the file will also need to be generated when those attributes change. Likewise, image generators that don't have sources (i.e. generators that aren't specs) won't cause files to be generated automatically when using the optimistic strategy. (ImageKit can't know when those need to be generated, if not on access.) In both cases, you'll have to trigger the file generation yourself—either by generating the file in code when necessary, or by periodically running the ``generateimages`` management command. Luckily, ImageKit makes this pretty easy: .. code-block:: python from imagekit.cachefiles import LazyImageCacheFile file = LazyImageCacheFile('myapp:profile:avatar_thumbnail', source=source_file) file.generate() One final situation in which images won't be generated automatically when using the optimistic strategy is when you use a spec with a source that hasn't been registered with it. Unlike the previous two examples, this situation cannot be rectified by running the ``generateimages`` management command, for the simple reason that the command has no way of knowing it needs to generate a file for that spec from that source. Typically, this situation would arise when using the template tags. Unlike ImageSpecFields, which automatically register all the possible source images with the spec you define, the template tags ("generateimage" and "thumbnail") let you use any spec with any source. Therefore, in order to generate the appropriate files using the ``generateimages`` management command, you'll need to first register a source group that represents all of the sources you wish to use with the corresponding specs. See :ref:`source-groups` for more information. matthewwithanm-django-imagekit-26cdc9d/docs/conf.py000066400000000000000000000202701525234025000225310ustar00rootroot00000000000000# # ImageKit documentation build configuration file, created by # sphinx-quickstart on Sun Sep 25 17:05:55 2011. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import os import re import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('..')) sys.path.append(os.path.abspath('_themes')) os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings' # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = 'ImageKit' copyright = '2011, Justin Driscoll, Bryan Veloso, Greg Newman, Chris Drackett, Matthew Tretter, Venelin Stoykov & contributors' pkgmeta = {} pkgmeta_file = os.path.join(os.path.dirname(__file__), '..', 'imagekit', 'pkgmeta.py') with open(pkgmeta_file, 'r') as f: exec(f.read(), pkgmeta) # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = re.match(r'\d+\.\d+', pkgmeta['__version__']).group() # The full version, including alpha/beta/rc tags. release = pkgmeta['__version__'] # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'kr' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. html_theme_path = ['_themes'] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". # html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. html_show_copyright = False # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'ImageKitdoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'ImageKit.tex', 'ImageKit Documentation', 'Justin Driscoll, Bryan Veloso, Greg Newman, Chris Drackett \\& Matthew Tretter', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'imagekit', 'ImageKit Documentation', ['Justin Driscoll, Bryan Veloso, Greg Newman, Chris Drackett & Matthew Tretter'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'ImageKit', 'ImageKit Documentation', 'Justin Driscoll, Bryan Veloso, Greg Newman, Chris Drackett & Matthew Tretter', 'ImageKit', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' autoclass_content = 'both' matthewwithanm-django-imagekit-26cdc9d/docs/configuration.rst000066400000000000000000000065111525234025000246350ustar00rootroot00000000000000.. _settings: Configuration ============= Settings -------- .. currentmodule:: django.conf.settings .. attribute:: IMAGEKIT_DEFAULT_THUMBNAIL_FORMAT :default: ``None`` The output format of the images generated by the ``thumbnail`` template tag. .. attribute:: IMAGEKIT_CACHEFILE_DIR :default: ``'CACHE/images'`` The directory to which image files will be cached. .. attribute:: IMAGEKIT_DEFAULT_THUMBNAIL_SRCSET_SCALES :default: ``None`` A list of scale factors, for example ``[2, 3]``. If specified, every ```` generated by the ``thumbnail`` template tag will have a ``srcset`` attribute with the given scales. To prevent this, set ``srcset=None``. .. attribute:: IMAGEKIT_DEFAULT_FILE_STORAGE :default: ``None`` Starting with Django 4.2, if you defined ``settings.STORAGES``: the Django storage backend alias to retrieve the storage instance defined in your settings, as described in the `Django file storage documentation`_. If no value is provided for ``IMAGEKIT_DEFAULT_FILE_STORAGE``, and none is specified by the spec definition, the ``default`` file storage will be used. Before Django 4.2, or if ``settings.STORAGES`` is not defined: The qualified class name of a Django storage backend to use to save the cached images. If no value is provided for ``IMAGEKIT_DEFAULT_FILE_STORAGE``, and none is specified by the spec definition, `your default file storage`__ will be used. .. _`Django file storage documentation`: https://docs.djangoproject.com/en/dev/ref/files/storage/ .. attribute:: IMAGEKIT_DEFAULT_CACHEFILE_BACKEND :default: ``'imagekit.cachefiles.backends.Simple'`` Specifies the class that will be used to validate cached image files. .. attribute:: IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY :default: ``'imagekit.cachefiles.strategies.JustInTime'`` The class responsible for specifying how and when cache files are generated. .. attribute:: IMAGEKIT_CACHE_BACKEND :default: ``'default'`` The Django cache backend alias to retrieve the shared cache instance defined in your settings, as described in the `Django cache section`_. The cache is then used to store information like the state of cached images (i.e. validated or not). .. _`Django cache section`: https://docs.djangoproject.com/en/dev/topics/cache/#accessing-the-cache .. attribute:: IMAGEKIT_CACHE_TIMEOUT :default: ``None`` Use when you need to override the timeout used to cache file state. By default it is "cache forever". It's highly recommended that you use a very high timeout. .. attribute:: IMAGEKIT_CACHE_PREFIX :default: ``'imagekit:'`` A cache prefix to be used when values are stored in ``IMAGEKIT_CACHE_BACKEND`` .. attribute:: IMAGEKIT_CACHEFILE_NAMER :default: ``'imagekit.cachefiles.namers.hash'`` A function responsible for generating file names for non-spec cache files. .. attribute:: IMAGEKIT_SPEC_CACHEFILE_NAMER :default: ``'imagekit.cachefiles.namers.source_name_as_path'`` A function responsible for generating file names for cache files that correspond to image specs. Since you will likely want to base the name of your cache files on the name of the source, this extra setting is provided. __ https://docs.djangoproject.com/en/dev/ref/settings/#default-file-storage matthewwithanm-django-imagekit-26cdc9d/docs/index.rst000066400000000000000000000004151525234025000230720ustar00rootroot00000000000000.. include:: ../README.rst Authors ======= .. include:: ../AUTHORS Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` .. toctree:: :glob: :maxdepth: 2 configuration advanced_usage caching upgrading matthewwithanm-django-imagekit-26cdc9d/docs/make.bat000066400000000000000000000117531525234025000226450ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\ImageKit.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\ImageKit.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end matthewwithanm-django-imagekit-26cdc9d/docs/upgrading.rst000066400000000000000000000104601525234025000237440ustar00rootroot00000000000000Upgrading from 2.x ================== ImageKit 3.0 introduces new APIs and tools that augment, improve, and in some cases entirely replace old IK workflows. Below, you'll find some useful guides for migrating your ImageKit 2.0 apps over to the shiny new IK3. Model Specs ----------- IK3 is chock full of new features and better tools for even the most sophisticated use cases. Despite this, not too much has changed when it comes to the most common of use cases: processing an ``ImageField`` on a model. In IK2, you may have used an ``ImageSpecField`` on a model to process an existing ``ImageField``: .. code-block:: python class Profile(models.Model): avatar = models.ImageField(upload_to='avatars') avatar_thumbnail = ImageSpecField(image_field='avatar', processors=[ResizeToFill(100, 50)], format='JPEG', options={'quality': 60}) In IK3, things look much the same: .. code-block:: python class Profile(models.Model): avatar = models.ImageField(upload_to='avatars') avatar_thumbnail = ImageSpecField(source='avatar', processors=[ResizeToFill(100, 50)], format='JPEG', options={'quality': 60}) The major difference is that ``ImageSpecField`` no longer takes an ``image_field`` kwarg. Instead, you define a ``source``. Image Cache Backends -------------------- In IK2, you could gain some control over how your cached images were generated by providing an ``image_cache_backend``: .. code-block:: python class Photo(models.Model): ... thumbnail = ImageSpecField(..., image_cache_backend=MyImageCacheBackend()) This gave you great control over *how* your images are generated and stored, but it could be difficult to control *when* they were generated and stored. IK3 retains the image cache backend concept (now called cache file backends), but separates the 'when' control out to cache file strategies: .. code-block:: python class Photo(models.Model): ... thumbnail = ImageSpecField(..., cachefile_backend=MyCacheFileBackend(), cachefile_strategy=MyCacheFileStrategy()) If you are using the IK2 default image cache backend setting: .. code-block:: python IMAGEKIT_DEFAULT_IMAGE_CACHE_BACKEND = 'path.to.MyImageCacheBackend' IK3 provides analogous settings for cache file backends and strategies: .. code-block:: python IMAGEKIT_DEFAULT_CACHEFILE_BACKEND = 'path.to.MyCacheFileBackend' IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY = 'path.to.MyCacheFileStrategy' See the documentation on :ref:`cache file backends ` and :ref:`cache file strategies ` for more details. Conditional model ``processors`` -------------------------------- In IK2, an ``ImageSpecField`` could take a ``processors`` callable instead of an iterable, which allowed processing decisions to made based on other properties of the model. IK3 does away with this feature for consistency's sake (if one kwarg could be callable, why not all?), but provides a much more robust solution: the custom ``spec``. See the :doc:`advanced usage ` documentation for more. Conditonal ``cache_to`` file names ---------------------------------- IK2 provided a means of specifying custom cache file names for your image specs by passing a ``cache_to`` callable to an ``ImageSpecField``. IK3 does away with this feature, again, for consistency. There is a way to achieve custom file names by overriding your spec's ``cachefile_name``, but it is not recommended, as the spec's default behavior is to hash the combination of ``source``, ``processors``, ``format``, and other spec options to ensure that changes to the spec always result in unique file names. See the documentation on :ref:`specs` for more. Processors have moved to PILKit ------------------------------- Processors have moved to a separate project: `PILKit`_. You should not have to make any changes to an IK2 project to use PILKit--it should be installed with IK3, and importing from ``imagekit.processors`` will still work. .. _`PILKit`: https://github.com/matthewwithanm/pilkit matthewwithanm-django-imagekit-26cdc9d/imagekit/000077500000000000000000000000001525234025000220735ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/__init__.py000066400000000000000000000004261525234025000242060ustar00rootroot00000000000000from . import conf, generatorlibrary from .pkgmeta import * from .registry import register, unregister from .specs import ImageSpec __all__ = [ 'ImageSpec', 'conf', 'generatorlibrary', 'register', 'unregister', '__title__', '__author__', '__version__', '__license__' ] matthewwithanm-django-imagekit-26cdc9d/imagekit/admin.py000066400000000000000000000024531525234025000235410ustar00rootroot00000000000000from django.template.loader import render_to_string from django.utils.translation import gettext_lazy as _ class AdminThumbnail: """ A convenience utility for adding thumbnails to Django's admin change list. """ short_description = _('Thumbnail') allow_tags = True def __init__(self, image_field, template=None): """ :param image_field: The name of the ImageField or ImageSpecField on the model to use for the thumbnail. :param template: The template with which to render the thumbnail """ self.image_field = image_field self.template = template def __call__(self, obj): if callable(self.image_field): thumbnail = self.image_field(obj) else: try: thumbnail = getattr(obj, self.image_field) except AttributeError: raise Exception('The property %s is not defined on %s.' % (self.image_field, obj.__class__.__name__)) original_image = getattr(thumbnail, 'source', None) or thumbnail template = self.template or 'imagekit/admin/thumbnail.html' return render_to_string(template, { 'model': obj, 'thumbnail': thumbnail, 'original_image': original_image, }) matthewwithanm-django-imagekit-26cdc9d/imagekit/cachefiles/000077500000000000000000000000001525234025000241615ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/cachefiles/__init__.py000066400000000000000000000162531525234025000263010ustar00rootroot00000000000000import os.path from copy import copy from django.conf import settings from django.core.files import File from django.core.files.images import ImageFile from django.utils.encoding import smart_str from django.utils.functional import SimpleLazyObject from ..files import BaseIKFile from ..registry import generator_registry from ..signals import content_required, existence_required from ..utils import ( generate, get_by_qname, get_logger, get_singleton, get_storage ) class ImageCacheFile(BaseIKFile, ImageFile): """ A file that represents the result of a generator. Creating an instance of this class is not enough to trigger the generation of the file. In fact, one of the main points of this class is to allow the creation of the file to be deferred until the time that the cache file strategy requires it. """ def __init__(self, generator, name=None, storage=None, cachefile_backend=None, cachefile_strategy=None): """ :param generator: The object responsible for generating a new image. :param name: The filename :param storage: A Django storage object, or a callable which returns a storage object that will be used to save the file. :param cachefile_backend: The object responsible for managing the state of the file. :param cachefile_strategy: The object responsible for handling events for this file. """ self.generator = generator if not name: try: name = generator.cachefile_name except AttributeError: fn = get_by_qname(settings.IMAGEKIT_CACHEFILE_NAMER, 'namer') name = fn(generator) self.name = name storage = (callable(storage) and storage()) or storage or \ getattr(generator, 'cachefile_storage', None) or get_storage() self.cachefile_backend = ( cachefile_backend or getattr(generator, 'cachefile_backend', None) or get_singleton(settings.IMAGEKIT_DEFAULT_CACHEFILE_BACKEND, 'cache file backend')) self.cachefile_strategy = ( cachefile_strategy or getattr(generator, 'cachefile_strategy', None) or get_singleton(settings.IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY, 'cache file strategy') ) super().__init__(storage=storage) def _require_file(self): if getattr(self, '_file', None) is None: content_required.send(sender=self, file=self) self._file = self.storage.open(self.name, 'rb') # The ``path`` and ``url`` properties are overridden so as to not call # ``_require_file``, which is only meant to be called when the file object # will be directly interacted with (e.g. when using ``read()``). These only # require the file to exist; they do not need its contents to work. This # distinction gives the user the flexibility to create a cache file # strategy that assumes the existence of a file, but can still make the file # available when its contents are required. def _storage_attr(self, attr): if getattr(self, '_file', None) is None: existence_required.send(sender=self, file=self) fn = getattr(self.storage, attr) return fn(self.name) @property def path(self): return self._storage_attr('path') @property def url(self): return self._storage_attr('url') def generate(self, force=False): """ Generate the file. If ``force`` is ``True``, the file will be generated whether the file already exists or not. """ if force or getattr(self, '_file', None) is None: self.cachefile_backend.generate(self, force) def _generate(self): # Generate the file content = generate(self.generator) actual_name = self.storage.save(self.name, content) # We're going to reuse the generated file, so we need to reset the pointer. if not hasattr(content, "seekable") or content.seekable(): content.seek(0) # Store the generated file. If we don't do this, the next time the # "file" attribute is accessed, it will result in a call to the storage # backend (in ``BaseIKFile._get_file``). Since we already have the # contents of the file, what would the point of that be? self.file = File(content) # ``actual_name`` holds the output of ``self.storage.save()`` that # by default returns filenames with forward slashes, even on windows. # On the other hand, ``self.name`` holds OS-specific paths results # from applying path normalizers like ``os.path.normpath()`` in the # ``namer``. So, the filenames should be normalized before their # equality checking. if os.path.normpath(actual_name) != os.path.normpath(self.name): get_logger().warning( 'The storage backend %s did not save the file with the' ' requested name ("%s") and instead used "%s". This may be' ' because a file already existed with the requested name. If' ' so, you may have meant to call generate() instead of' ' generate(force=True), or there may be a race condition in the' ' file backend %s. The saved file will not be used.', self.storage, self.name, actual_name, self.cachefile_backend ) def __bool__(self): if not self.name: return False # Dispatch the existence_required signal before checking to see if the # file exists. This gives the strategy a chance to create the file. existence_required.send(sender=self, file=self) try: check = self.cachefile_strategy.should_verify_existence(self) except AttributeError: # All synchronous backends should have created the file as part of # `existence_required` if they wanted to. check = getattr(self.cachefile_backend, 'is_async', False) return self.cachefile_backend.exists(self) if check else True def __getstate__(self): state = copy(self.__dict__) # file is hidden link to "file" attribute state.pop('_file', None) # remove storage from state as some non-FileSystemStorage can't be # pickled settings_storage = get_storage() if state['storage'] == settings_storage: state.pop('storage') return state def __setstate__(self, state): if 'storage' not in state: state['storage'] = get_storage() self.__dict__.update(state) def __repr__(self): return smart_str("<%s: %s>" % ( self.__class__.__name__, self if self.name else "None") ) class LazyImageCacheFile(SimpleLazyObject): def __init__(self, generator_id, *args, **kwargs): def setup(): generator = generator_registry.get(generator_id, *args, **kwargs) return ImageCacheFile(generator) super().__init__(setup) def __repr__(self): return '<%s: %s>' % (self.__class__.__name__, str(self) or 'None') matthewwithanm-django-imagekit-26cdc9d/imagekit/cachefiles/backends.py000066400000000000000000000164561525234025000263210ustar00rootroot00000000000000import warnings from copy import copy from django.conf import settings from django.core.exceptions import ImproperlyConfigured from .state import get_active_state_cache from ..utils import get_cache, get_singleton, sanitize_cache_key class CacheFileState: EXISTS = 'exists' GENERATING = 'generating' DOES_NOT_EXIST = 'does_not_exist' def get_default_cachefile_backend(): """ Get the default file backend. """ from django.conf import settings return get_singleton(settings.IMAGEKIT_DEFAULT_CACHEFILE_BACKEND, 'file backend') class InvalidFileBackendError(ImproperlyConfigured): pass class AbstractCacheFileBackend: """ An abstract cache file backend. This isn't used by any internal classes and is included simply to illustrate the minimum interface of a cache file backend for users who wish to implement their own. """ def generate(self, file, force=False): raise NotImplementedError def exists(self, file): raise NotImplementedError class CachedFileBackend: existence_check_timeout = 5 """ The number of seconds to wait before rechecking to see if the file exists. If the image is found to exist, that information will be cached using the timeout specified in your CACHES setting (which should be very high). However, when the file does not exist, you probably want to check again in a relatively short amount of time. This attribute allows you to do that. """ @property def cache(self): if not getattr(self, '_cache', None): self._cache = get_cache() return self._cache def get_key(self, file): from django.conf import settings return sanitize_cache_key('%s%s-state' % (settings.IMAGEKIT_CACHE_PREFIX, file.name)) def get_state(self, file, check_if_unknown=True): key = self.get_key(file) # Check request-local state cache first state_cache = get_active_state_cache() if state_cache is not None and key in state_cache: state = state_cache[key] else: state = self.cache.get(key) # Write-through to request-local cache if active if state_cache is not None: state_cache[key] = state if state is None and check_if_unknown: exists = self._exists(file) state = CacheFileState.EXISTS if exists else CacheFileState.DOES_NOT_EXIST self.set_state(file, state) return state def set_state(self, file, state): key = self.get_key(file) if state == CacheFileState.DOES_NOT_EXIST: self.cache.set(key, state, self.existence_check_timeout) else: self.cache.set(key, state, settings.IMAGEKIT_CACHE_TIMEOUT) # Write-through to request-local state cache if active state_cache = get_active_state_cache() if state_cache is not None: state_cache[key] = state def __getstate__(self): state = copy(self.__dict__) # Don't include the cache when pickling. It'll be reconstituted based # on the settings. state.pop('_cache', None) return state def exists(self, file): return self.get_state(file) == CacheFileState.EXISTS def generate(self, file, force=False): raise NotImplementedError def generate_now(self, file, force=False): if force or self.get_state(file) not in (CacheFileState.GENERATING, CacheFileState.EXISTS): self.set_state(file, CacheFileState.GENERATING) file._generate() self.set_state(file, CacheFileState.EXISTS) file.close() class Simple(CachedFileBackend): """ The most basic file backend. The storage is consulted to see if the file exists. Files are generated synchronously. """ def generate(self, file, force=False): self.generate_now(file, force=force) def _exists(self, file): return bool(getattr(file, '_file', None) or (file.name and file.storage.exists(file.name))) def _generate_file(backend, file, force=False): backend.generate_now(file, force=force) class BaseAsync(Simple): """ Base class for cache file backends that generate files asynchronously. """ is_async = True def generate(self, file, force=False): # Schedule the file for generation, unless we know for sure we don't # need to. If an already-generated file sneaks through, that's okay; # ``generate_now`` will catch it. We just want to make sure we don't # schedule anything we know is unnecessary--but we also don't want to # force a costly existence check. state = self.get_state(file, check_if_unknown=False) if state not in (CacheFileState.GENERATING, CacheFileState.EXISTS): self.schedule_generation(file, force=force) def schedule_generation(self, file, force=False): # overwrite this to have the file generated in the background, # e. g. in a worker queue. raise NotImplementedError try: from celery import shared_task as task except ImportError: pass else: _celery_task = task(ignore_result=True, serializer='pickle')(_generate_file) class Celery(BaseAsync): """ A backend that uses Celery to generate the images. """ def __init__(self, *args, **kwargs): try: import celery # noqa except ImportError: raise ImproperlyConfigured('You must install celery to use' ' imagekit.cachefiles.backends.Celery.') super().__init__(*args, **kwargs) def schedule_generation(self, file, force=False): _celery_task.delay(self, file, force=force) # Stub class to preserve backwards compatibility and issue a warning class Async(Celery): def __init__(self, *args, **kwargs): message = '{path}.Async is deprecated. Use {path}.Celery instead.' warnings.warn(message.format(path=__name__), DeprecationWarning) super().__init__(*args, **kwargs) try: from django_rq import job except ImportError: pass else: _rq_job = job('default', result_ttl=0)(_generate_file) class RQ(BaseAsync): """ A backend that uses RQ to generate the images. """ def __init__(self, *args, **kwargs): try: import django_rq # noqa except ImportError: raise ImproperlyConfigured('You must install django-rq to use' ' imagekit.cachefiles.backends.RQ.') super().__init__(*args, **kwargs) def schedule_generation(self, file, force=False): _rq_job.delay(self, file, force=force) try: from dramatiq import actor except ImportError: pass else: _dramatiq_actor = actor()(_generate_file) class Dramatiq(BaseAsync): """ A backend that uses Dramatiq to generate the images. """ def __init__(self, *args, **kwargs): try: import dramatiq # noqa except ImportError: raise ImproperlyConfigured('You must install django-dramatiq to use' ' imagekit.cachefiles.backends.Dramatiq.') super().__init__(*args, **kwargs) def schedule_generation(self, file, force=False): _dramatiq_actor.send(self, file, force=force) matthewwithanm-django-imagekit-26cdc9d/imagekit/cachefiles/namers.py000066400000000000000000000061151525234025000260230ustar00rootroot00000000000000""" Functions responsible for returning filenames for the given image generator. Users are free to define their own functions; these are just some some sensible choices. """ import os from django.conf import settings from ..utils import format_to_extension, suggest_extension def source_name_as_path(generator): """ A namer that, given the following source file name:: photos/thumbnails/bulldog.jpg will generate a name like this:: /path/to/generated/images/photos/thumbnails/bulldog/5ff3233527c5ac3e4b596343b440ff67.jpg where "/path/to/generated/images/" is the value specified by the ``IMAGEKIT_CACHEFILE_DIR`` setting. """ source_filename = getattr(generator.source, 'name', None) if source_filename is None or os.path.isabs(source_filename): # Generally, we put the file right in the cache file directory. dir = settings.IMAGEKIT_CACHEFILE_DIR else: # For source files with relative names (like Django media files), # use the source's name to create the new filename. dir = os.path.join(settings.IMAGEKIT_CACHEFILE_DIR, os.path.splitext(source_filename)[0]) ext = suggest_extension(source_filename or '', generator.format) return os.path.normpath(os.path.join(dir, '%s%s' % (generator.get_hash(), ext))) def source_name_dot_hash(generator): """ A namer that, given the following source file name:: photos/thumbnails/bulldog.jpg will generate a name like this:: /path/to/generated/images/photos/thumbnails/bulldog.5ff3233527c5.jpg where "/path/to/generated/images/" is the value specified by the ``IMAGEKIT_CACHEFILE_DIR`` setting. """ source_filename = getattr(generator.source, 'name', None) if source_filename is None or os.path.isabs(source_filename): # Generally, we put the file right in the cache file directory. dir = settings.IMAGEKIT_CACHEFILE_DIR else: # For source files with relative names (like Django media files), # use the source's name to create the new filename. dir = os.path.join(settings.IMAGEKIT_CACHEFILE_DIR, os.path.dirname(source_filename)) ext = suggest_extension(source_filename or '', generator.format) basename = os.path.basename(source_filename) return os.path.normpath(os.path.join(dir, '%s.%s%s' % ( os.path.splitext(basename)[0], generator.get_hash()[:12], ext))) def hash(generator): """ A namer that, given the following source file name:: photos/thumbnails/bulldog.jpg will generate a name like this:: /path/to/generated/images/5ff3233527c5ac3e4b596343b440ff67.jpg where "/path/to/generated/images/" is the value specified by the ``IMAGEKIT_CACHEFILE_DIR`` setting. """ format = getattr(generator, 'format', None) ext = format_to_extension(format) if format else '' return os.path.normpath(os.path.join(settings.IMAGEKIT_CACHEFILE_DIR, '%s%s' % (generator.get_hash(), ext))) matthewwithanm-django-imagekit-26cdc9d/imagekit/cachefiles/state.py000066400000000000000000000073421525234025000256610ustar00rootroot00000000000000""" Request-local state cache for ImageKit cachefiles to reduce cache lookups. This module provides an optional request-local in-memory state cache that can be used to batch prefetch cache file states, reducing round trips to the Django cache backend. """ from contextlib import contextmanager from contextvars import ContextVar # ContextVar for storing the active state cache (a dict-like mapping) for the # current execution context. _active_state_cache: ContextVar = ContextVar('_active_state_cache', default=None) @contextmanager def use_cachefile_state_cache(state_cache=None): """ Context manager to activate a request-local state cache. Usage:: from imagekit.cachefiles.state import use_cachefile_state_cache, prefetch_cachefile_states state_cache = {} with use_cachefile_state_cache(state_cache): prefetch_cachefile_states(thumbs, state_cache=state_cache) # ... render template with thumbs ... :param state_cache: A dict-like mapping to use as the cache. If None, a new empty dict will be created. """ if state_cache is None: state_cache = {} token = _active_state_cache.set(state_cache) try: yield state_cache finally: _active_state_cache.reset(token) def get_active_state_cache(): """ Get the active state cache for the current context, if any. :return: The active dict-like mapping, or None if no cache is active. """ return _active_state_cache.get(None) def prefetch_cachefile_states(files, *, state_cache=None, cache=None): """ Prefetch cache file states using cache.get_many(). This function computes cache keys for the given files and fetches their states in as few cache.get_many() calls as possible. The results are stored in the provided state_cache (or the active request-local cache if not provided). Example usage in a view:: from imagekit.cachefiles.state import use_cachefile_state_cache, prefetch_cachefile_states def gallery(request): images = list(Image.objects.filter(...)) thumbs = [img.thumbnail for img in images] state_cache = {} with use_cachefile_state_cache(state_cache): prefetch_cachefile_states(thumbs, state_cache=state_cache) return render(request, "gallery.html", {"images": images}) :param files: Iterable of ImageCacheFile objects to prefetch states for. :param state_cache: Optional dict-like mapping to populate. If None, the active request-local cache will be used (if any). :param cache: Optional Django cache instance. If provided, all lookups will use this cache. If None, each file's cachefile backend will determine which cache to read from. """ from .backends import CachedFileBackend if state_cache is None: state_cache = get_active_state_cache() if state_cache is None: return # Group keys by the Django cache object used for the lookup. keys_by_cache = {} for f in files: backend = getattr(f, 'cachefile_backend', None) if not isinstance(backend, CachedFileBackend): continue key = backend.get_key(f) backend_cache = cache or backend.cache keys_by_cache.setdefault(backend_cache, set()).add(key) if not keys_by_cache: return for backend_cache, keys in keys_by_cache.items(): states = backend_cache.get_many(keys) # Store hits in state_cache for key, state in states.items(): state_cache[key] = state # Also record misses so later checks don't fall back to cache.get() for key in keys: if key not in states: state_cache[key] = None matthewwithanm-django-imagekit-26cdc9d/imagekit/cachefiles/strategies.py000066400000000000000000000020341525234025000267040ustar00rootroot00000000000000from ..utils import get_singleton class JustInTime: """ A strategy that ensures the file exists right before it's needed. """ def on_existence_required(self, file): file.generate() def on_content_required(self, file): file.generate() class Optimistic: """ A strategy that acts immediately when the source file changes and assumes that the cache files will not be removed (i.e. it doesn't ensure the cache file exists when it's accessed). """ def on_source_saved(self, file): file.generate() def should_verify_existence(self, file): return False class DictStrategy: def __init__(self, callbacks): for k, v in callbacks.items(): setattr(self, k, v) def load_strategy(strategy): if isinstance(strategy, str): strategy = get_singleton(strategy, 'cache file strategy') elif isinstance(strategy, dict): strategy = DictStrategy(strategy) elif callable(strategy): strategy = strategy() return strategy matthewwithanm-django-imagekit-26cdc9d/imagekit/conf.py000066400000000000000000000030571525234025000233770ustar00rootroot00000000000000from appconf import AppConf from django.conf import settings from django.core.exceptions import ImproperlyConfigured class ImageKitConf(AppConf): CACHEFILE_NAMER = 'imagekit.cachefiles.namers.hash' SPEC_CACHEFILE_NAMER = 'imagekit.cachefiles.namers.source_name_as_path' CACHEFILE_DIR = 'CACHE/images' DEFAULT_CACHEFILE_BACKEND = 'imagekit.cachefiles.backends.Simple' DEFAULT_CACHEFILE_STRATEGY = 'imagekit.cachefiles.strategies.JustInTime' DEFAULT_FILE_STORAGE = None CACHE_BACKEND = None CACHE_PREFIX = 'imagekit:' CACHE_TIMEOUT = None USE_MEMCACHED_SAFE_CACHE_KEY = True def configure_cache_backend(self, value): if value is None: from django.core.cache import DEFAULT_CACHE_ALIAS return DEFAULT_CACHE_ALIAS if value not in settings.CACHES: raise ImproperlyConfigured("{0} is not present in settings.CACHES".format(value)) return value def configure_cache_timeout(self, value): if value is None and settings.DEBUG: # If value is not configured and is DEBUG set it to 5 minutes return 300 # Otherwise leave it as is. If it is None then valies will never expire return value def configure_default_file_storage(self, value): if value is None: try: from django.conf import DEFAULT_STORAGE_ALIAS except ImportError: # Django < 4.2 return settings.DEFAULT_FILE_STORAGE else: return DEFAULT_STORAGE_ALIAS return value matthewwithanm-django-imagekit-26cdc9d/imagekit/exceptions.py000066400000000000000000000006021525234025000246240ustar00rootroot00000000000000from pilkit.exceptions import UnknownExtension, UnknownFormat class AlreadyRegistered(Exception): pass class NotRegistered(Exception): pass class MissingGeneratorId(Exception): pass class MissingSource(ValueError): silent_variable_failure = True # Aliases for backwards compatibility UnknownExtensionError = UnknownExtension UnknownFormatError = UnknownFormat matthewwithanm-django-imagekit-26cdc9d/imagekit/files.py000066400000000000000000000056321525234025000235550ustar00rootroot00000000000000import os from django.core.files.base import ContentFile, File from .utils import extension_to_mimetype, format_to_mimetype class BaseIKFile(File): """ This class contains all of the methods we need from django.db.models.fields.files.FieldFile, but with the model stuff ripped out. It's only extended by one class, but we keep it separate for organizational reasons. """ def __init__(self, storage): self.storage = storage def _require_file(self): if not self: raise ValueError() def _get_file(self): self._require_file() if not hasattr(self, '_file') or self._file is None: self._file = self.storage.open(self.name, 'rb') return self._file def _set_file(self, file): self._file = file def _del_file(self): del self._file file = property(_get_file, _set_file, _del_file) def _get_path(self): self._require_file() return self.storage.path(self.name) path = property(_get_path) def _get_url(self): self._require_file() return self.storage.url(self.name) url = property(_get_url) def _get_size(self): self._require_file() if not getattr(self, '_committed', False): return self.file.size return self.storage.size(self.name) size = property(_get_size) def open(self, mode='rb'): self._require_file() try: self.file.open(mode) except ValueError: # if the underlying file can't be reopened # then we will use the storage to try to open it again if self.file.closed: # clear cached file instance del self.file # Because file is a property we can acces it after # we deleted it return self.file.open(mode) raise def _get_closed(self): file = getattr(self, '_file', None) return file is None or file.closed closed = property(_get_closed) def close(self): file = getattr(self, '_file', None) if file is not None: file.close() class IKContentFile(ContentFile): """ Wraps a ContentFile in a file-like object with a filename and a content_type. A PIL image format can be optionally be provided as a content type hint. """ def __init__(self, filename, content, format=None): self.file = ContentFile(content) self.file.name = filename mimetype = getattr(self.file, 'content_type', None) if format and not mimetype: mimetype = format_to_mimetype(format) if not mimetype: ext = os.path.splitext(filename or '')[1] mimetype = extension_to_mimetype(ext) self.file.content_type = mimetype @property def name(self): return self.file.name def __str__(self): return str(self.file.name or '') matthewwithanm-django-imagekit-26cdc9d/imagekit/forms/000077500000000000000000000000001525234025000232215ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/forms/__init__.py000066400000000000000000000000701525234025000253270ustar00rootroot00000000000000# flake8: noqa from .fields import ProcessedImageField matthewwithanm-django-imagekit-26cdc9d/imagekit/forms/fields.py000066400000000000000000000023621525234025000250440ustar00rootroot00000000000000from django.forms import ImageField from ..specs import SpecHost from ..utils import generate class ProcessedImageField(ImageField, SpecHost): def __init__(self, processors=None, format=None, options=None, autoconvert=True, spec_id=None, spec=None, *args, **kwargs): if spec_id is None: # Unlike model fields, form fields are never told their field name. # (Model fields are done so via `contribute_to_class()`.) Therefore # we can't really generate a good spec id automatically. raise TypeError('You must provide a spec_id') SpecHost.__init__(self, processors=processors, format=format, options=options, autoconvert=autoconvert, spec=spec, spec_id=spec_id) super().__init__(*args, **kwargs) def clean(self, data, initial=None): data = super().clean(data, initial) if data and data != initial: spec = self.get_spec(source=data) f = generate(spec) # Name is required in Django 1.4. When we drop support for it # then we can directly return the result from `generate(spec)` f.name = data.name return f return data matthewwithanm-django-imagekit-26cdc9d/imagekit/generatorlibrary.py000066400000000000000000000012321525234025000260160ustar00rootroot00000000000000from .processors import Thumbnail as ThumbnailProcessor from .registry import register from .specs import ImageSpec from django.conf import settings default_thumbnail_format = getattr(settings, 'IMAGEKIT_DEFAULT_THUMBNAIL_FORMAT', None) class Thumbnail(ImageSpec): def __init__(self, width=None, height=None, anchor=None, crop=None, upscale=None, format=default_thumbnail_format, **kwargs): self.processors = [ThumbnailProcessor(width, height, anchor=anchor, crop=crop, upscale=upscale)] super().__init__(**kwargs) self.format = format register.generator('imagekit:thumbnail', Thumbnail) matthewwithanm-django-imagekit-26cdc9d/imagekit/hashers.py000066400000000000000000000017011525234025000241010ustar00rootroot00000000000000import sys from copy import copy from hashlib import md5 from io import BytesIO from pickle import DICT, MARK, _Pickler class CanonicalizingPickler(_Pickler): dispatch = copy(_Pickler.dispatch) def save_set(self, obj): rv = obj.__reduce_ex__(0) rv = (rv[0], (sorted(rv[1][0]),), rv[2]) self.save_reduce(obj=obj, *rv) dispatch[set] = save_set if sys.version_info[:2] >= (3, 14): def save_dict(self, obj): write = self.write write(MARK + DICT) self.memoize(obj) self._batch_setitems(sorted(obj.items()), obj) else: def save_dict(self, obj): write = self.write write(MARK + DICT) self.memoize(obj) self._batch_setitems(sorted(obj.items())) dispatch[dict] = save_dict def pickle(obj): file = BytesIO() CanonicalizingPickler(file, 0).dump(obj) return md5(file.getvalue()).hexdigest() matthewwithanm-django-imagekit-26cdc9d/imagekit/management/000077500000000000000000000000001525234025000242075ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/management/__init__.py000066400000000000000000000000001525234025000263060ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/management/commands/000077500000000000000000000000001525234025000260105ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/management/commands/__init__.py000066400000000000000000000000001525234025000301070ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/management/commands/generateimages.py000066400000000000000000000043331525234025000313450ustar00rootroot00000000000000import re from django.core.management.base import BaseCommand from ...exceptions import MissingSource from ...registry import cachefile_registry, generator_registry class Command(BaseCommand): help = ("""Generate files for the specified image generators (or all of them if none was provided). Simple, glob-like wildcards are allowed, with * matching all characters within a segment, and ** matching across segments. (Segments are separated with colons.) So, for example, "a:*:c" will match "a:b:c", but not "a:b:x:c", whereas "a:**:c" will match both. Subsegments are always matched, so "a" will match "a" as well as "a:b" and "a:b:c".""") args = '[generator_ids]' def add_arguments(self, parser): parser.add_argument('generator_id', nargs='*', help=':: for model specs') def handle(self, *args, **options): generators = generator_registry.get_ids() generator_ids = options['generator_id'] if 'generator_id' in options else args if generator_ids: patterns = self.compile_patterns(generator_ids) generators = (id for id in generators if any(p.match(id) for p in patterns)) for generator_id in generators: self.stdout.write('Validating generator: %s\n' % generator_id) for image_file in cachefile_registry.get(generator_id): if image_file.name: self.stdout.write(' %s\n' % image_file.name) try: image_file.generate() except MissingSource as err: self.stdout.write('\t No source associated with\n') except Exception as err: self.stdout.write('\tFailed %s\n' % (err)) def compile_patterns(self, generator_ids): return [self.compile_pattern(id) for id in generator_ids] def compile_pattern(self, generator_id): parts = re.split(r'(\*{1,2})', generator_id) pattern = '' for part in parts: if part == '*': pattern += '[^:]*' elif part == '**': pattern += '.*' else: pattern += re.escape(part) return re.compile('^%s(:.*)?$' % pattern) matthewwithanm-django-imagekit-26cdc9d/imagekit/models/000077500000000000000000000000001525234025000233565ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/models/__init__.py000066400000000000000000000001341525234025000254650ustar00rootroot00000000000000# flake8: noqa from .. import conf from .fields import ImageSpecField, ProcessedImageField matthewwithanm-django-imagekit-26cdc9d/imagekit/models/fields/000077500000000000000000000000001525234025000246245ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/models/fields/__init__.py000066400000000000000000000113151525234025000267360ustar00rootroot00000000000000from django.db import models from django.db.models.signals import class_prepared from ...registry import register from ...specs import SpecHost from ...specs.sourcegroups import ImageFieldSourceGroup from .files import ProcessedImageFieldFile from .utils import ImageSpecFileDescriptor class SpecHostField(SpecHost): def _set_spec_id(self, cls, name): spec_id = getattr(self, 'spec_id', None) # Generate a spec_id to register the spec with. The default spec id is # ":_" if not spec_id: spec_id = ('%s:%s:%s' % (cls._meta.app_label, cls._meta.object_name, name)).lower() # Register the spec with the id. This allows specs to be overridden # later, from outside of the model definition. super().set_spec_id(spec_id) class ImageSpecField(SpecHostField): """ The heart and soul of the ImageKit library, ImageSpecField allows you to add variants of uploaded images to your models. """ def __init__(self, processors=None, format=None, options=None, source=None, cachefile_storage=None, autoconvert=None, cachefile_backend=None, cachefile_strategy=None, spec=None, id=None): SpecHost.__init__(self, processors=processors, format=format, options=options, cachefile_storage=cachefile_storage, autoconvert=autoconvert, cachefile_backend=cachefile_backend, cachefile_strategy=cachefile_strategy, spec=spec, spec_id=id) # TODO: Allow callable for source. See https://github.com/matthewwithanm/django-imagekit/issues/158#issuecomment-10921664 self.source = source def contribute_to_class(self, cls, name): # If the source field name isn't defined, figure it out. def register_source_group(source): setattr(cls, name, ImageSpecFileDescriptor(self, name, source)) self._set_spec_id(cls, name) # Add the model and field as a source for this spec id register.source_group(self.spec_id, ImageFieldSourceGroup(cls, source)) if self.source: register_source_group(self.source) else: # The source argument is not defined # Then we need to see if there is only one ImageField in that model # But we need to do that after full model initialization def handle_model_preparation(sender, **kwargs): image_fields = [f.attname for f in cls._meta.fields if isinstance(f, models.ImageField)] if len(image_fields) == 0: raise Exception( '%s does not define any ImageFields, so your %s' ' ImageSpecField has no image to act on.' % (cls.__name__, name)) elif len(image_fields) > 1: raise Exception( '%s defines multiple ImageFields, but you have not' ' specified a source for your %s ImageSpecField.' % (cls.__name__, name)) register_source_group(image_fields[0]) class_prepared.connect(handle_model_preparation, sender=cls, weak=False) class ProcessedImageField(models.ImageField, SpecHostField): """ ProcessedImageField is an ImageField that runs processors on the uploaded image *before* saving it to storage. This is in contrast to specs, which maintain the original. Useful for coercing fileformats or keeping images within a reasonable size. """ attr_class = ProcessedImageFieldFile def __init__(self, processors=None, format=None, options=None, verbose_name=None, name=None, width_field=None, height_field=None, autoconvert=None, spec=None, spec_id=None, **kwargs): """ The ProcessedImageField constructor accepts all of the arguments that the :class:`django.db.models.ImageField` constructor accepts, as well as the ``processors``, ``format``, and ``options`` arguments of :class:`imagekit.models.ImageSpecField`. """ # if spec is not provided then autoconvert will be True by default if spec is None and autoconvert is None: autoconvert = True SpecHost.__init__(self, processors=processors, format=format, options=options, autoconvert=autoconvert, spec=spec, spec_id=spec_id) models.ImageField.__init__(self, verbose_name, name, width_field, height_field, **kwargs) def contribute_to_class(self, cls, name): self._set_spec_id(cls, name) return super().contribute_to_class(cls, name) matthewwithanm-django-imagekit-26cdc9d/imagekit/models/fields/files.py000066400000000000000000000007541525234025000263060ustar00rootroot00000000000000import os from django.db.models.fields.files import ImageFieldFile from ...utils import generate, suggest_extension class ProcessedImageFieldFile(ImageFieldFile): def save(self, name, content, save=True): filename, ext = os.path.splitext(name) spec = self.field.get_spec(source=content) ext = suggest_extension(name, spec.format) new_name = '%s%s' % (filename, ext) content = generate(spec) return super().save(new_name, content, save) matthewwithanm-django-imagekit-26cdc9d/imagekit/models/fields/utils.py000066400000000000000000000012451525234025000263400ustar00rootroot00000000000000from ...cachefiles import ImageCacheFile class ImageSpecFileDescriptor: def __init__(self, field, attname, source_field_name): self.attname = attname self.field = field self.source_field_name = source_field_name def __get__(self, instance, owner): if instance is None: return self.field else: source = getattr(instance, self.source_field_name) spec = self.field.get_spec(source=source) file = ImageCacheFile(spec) instance.__dict__[self.attname] = file return file def __set__(self, instance, value): instance.__dict__[self.attname] = value matthewwithanm-django-imagekit-26cdc9d/imagekit/pkgmeta.py000066400000000000000000000004071525234025000240760ustar00rootroot00000000000000__title__ = 'django-imagekit' __author__ = 'Matthew Tretter, Venelin Stoykov, Eric Eldredge, Bryan Veloso, Greg Newman, Chris Drackett, Justin Driscoll' __version__ = '6.1.1' __license__ = 'BSD' __all__ = ['__title__', '__author__', '__version__', '__license__'] matthewwithanm-django-imagekit-26cdc9d/imagekit/processors/000077500000000000000000000000001525234025000242755ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/processors/__init__.py000066400000000000000000000005221525234025000264050ustar00rootroot00000000000000from pilkit.processors import * __all__ = [ # Base 'ProcessorPipeline', 'Adjust', 'Reflection', 'Transpose', 'Anchor', 'MakeOpaque', # Crop 'TrimBorderColor', 'Crop', 'SmartCrop', # Resize 'Resize', 'ResizeToCover', 'ResizeToFill', 'SmartResize', 'ResizeCanvas', 'AddBorder', 'ResizeToFit', 'Thumbnail' ] matthewwithanm-django-imagekit-26cdc9d/imagekit/processors/base.py000066400000000000000000000004011525234025000255540ustar00rootroot00000000000000import warnings from pilkit.processors.base import * warnings.warn('imagekit.processors.base is deprecated use imagekit.processors instead', DeprecationWarning) __all__ = ['ProcessorPipeline', 'Adjust', 'Reflection', 'Transpose', 'Anchor', 'MakeOpaque'] matthewwithanm-django-imagekit-26cdc9d/imagekit/processors/crop.py000066400000000000000000000003271525234025000256140ustar00rootroot00000000000000import warnings from pilkit.processors.crop import * warnings.warn('imagekit.processors.crop is deprecated use imagekit.processors instead', DeprecationWarning) __all__ = ['TrimBorderColor', 'Crop', 'SmartCrop'] matthewwithanm-django-imagekit-26cdc9d/imagekit/processors/resize.py000066400000000000000000000004461525234025000261540ustar00rootroot00000000000000import warnings from pilkit.processors.resize import * warnings.warn('imagekit.processors.resize is deprecated use imagekit.processors instead', DeprecationWarning) __all__ = ['Resize', 'ResizeToCover', 'ResizeToFill', 'SmartResize', 'ResizeCanvas', 'AddBorder', 'ResizeToFit', 'Thumbnail'] matthewwithanm-django-imagekit-26cdc9d/imagekit/processors/utils.py000066400000000000000000000002511525234025000260050ustar00rootroot00000000000000import warnings from pilkit.processors.utils import * warnings.warn('imagekit.processors.utils is deprecated use pilkit.processors.utils instead', DeprecationWarning) matthewwithanm-django-imagekit-26cdc9d/imagekit/registry.py000066400000000000000000000150321525234025000243160ustar00rootroot00000000000000from .exceptions import AlreadyRegistered, NotRegistered from .signals import content_required, existence_required, source_saved from .utils import autodiscover, call_strategy_method class GeneratorRegistry: """ An object for registering generators. This registry provides a convenient way for a distributable app to define default generators without locking the users of the app into it. """ def __init__(self): self._generators = {} content_required.connect(self.content_required_receiver) existence_required.connect(self.existence_required_receiver) def register(self, id, generator): registered_generator = self._generators.get(id) if registered_generator and generator != self._generators[id]: raise AlreadyRegistered('The generator with id %s is' ' already registered' % id) self._generators[id] = generator def unregister(self, id): try: del self._generators[id] except KeyError: raise NotRegistered('The generator with id %s is not' ' registered' % id) def get(self, id, **kwargs): autodiscover() try: generator = self._generators[id] except KeyError: raise NotRegistered('The generator with id %s is not' ' registered' % id) if callable(generator): return generator(**kwargs) else: return generator def get_ids(self): autodiscover() return self._generators.keys() def content_required_receiver(self, sender, file, **kwargs): self._receive(file, 'on_content_required') def existence_required_receiver(self, sender, file, **kwargs): self._receive(file, 'on_existence_required') def _receive(self, file, callback): generator = file.generator # FIXME: I guess this means you can't register functions? if generator.__class__ in self._generators.values(): # Only invoke the strategy method for registered generators. call_strategy_method(file, callback) class SourceGroupRegistry: """ The source group registry is responsible for listening to source_* signals on source groups, and relaying them to the image generated file strategies of the appropriate generators. In addition, registering a new source group also registers its generated files with that registry. """ _signals = { source_saved: 'on_source_saved', } def __init__(self): self._source_groups = {} for signal in self._signals.keys(): signal.connect(self.source_group_receiver) def register(self, generator_id, source_group): from .specs.sourcegroups import SourceGroupFilesGenerator generator_ids = self._source_groups.setdefault(source_group, set()) generator_ids.add(generator_id) cachefile_registry.register(generator_id, SourceGroupFilesGenerator(source_group, generator_id)) def unregister(self, generator_id, source_group): from .specs.sourcegroups import SourceGroupFilesGenerator generator_ids = self._source_groups.setdefault(source_group, set()) if generator_id in generator_ids: generator_ids.remove(generator_id) cachefile_registry.unregister(generator_id, SourceGroupFilesGenerator(source_group, generator_id)) def source_group_receiver(self, sender, source, signal, **kwargs): """ Relay source group signals to the appropriate spec strategy. """ from .cachefiles import ImageCacheFile source_group = sender # Ignore signals from unregistered groups. if source_group not in self._source_groups: return specs = [generator_registry.get(id, source=source) for id in self._source_groups[source_group]] callback_name = self._signals[signal] for spec in specs: file = ImageCacheFile(spec) call_strategy_method(file, callback_name) class CacheFileRegistry: """ An object for registering generated files with image generators. The two are associated with each other via a string id. We do this (as opposed to associating them directly by, for example, putting a ``cachefiles`` attribute on image generators) so that image generators can be overridden without losing the associated files. That way, a distributable app can define its own generators without locking the users of the app into it. """ def __init__(self): self._cachefiles = {} def register(self, generator_id, cachefiles): """ Associates generated files with a generator id """ if cachefiles not in self._cachefiles: self._cachefiles[cachefiles] = set() self._cachefiles[cachefiles].add(generator_id) def unregister(self, generator_id, cachefiles): """ Disassociates generated files with a generator id """ try: self._cachefiles[cachefiles].remove(generator_id) except KeyError: pass def get(self, generator_id): for k, v in self._cachefiles.items(): if generator_id in v: yield from k() class Register: """ Register generators and generated files. """ def generator(self, id, generator=None): if generator is None: # Return a decorator def decorator(cls): self.generator(id, cls) return cls return decorator generator_registry.register(id, generator) # iterable that returns kwargs or callable that returns iterable of kwargs def cachefiles(self, generator_id, cachefiles): cachefile_registry.register(generator_id, cachefiles) def source_group(self, generator_id, source_group): source_group_registry.register(generator_id, source_group) class Unregister: """ Unregister generators and generated files. """ def generator(self, id): generator_registry.unregister(id) def cachefiles(self, generator_id, cachefiles): cachefile_registry.unregister(generator_id, cachefiles) def source_group(self, generator_id, source_group): source_group_registry.unregister(generator_id, source_group) generator_registry = GeneratorRegistry() cachefile_registry = CacheFileRegistry() source_group_registry = SourceGroupRegistry() register = Register() unregister = Unregister() matthewwithanm-django-imagekit-26cdc9d/imagekit/signals.py000066400000000000000000000002471525234025000241100ustar00rootroot00000000000000from django.dispatch import Signal # Generated file signals content_required = Signal() existence_required = Signal() # Source group signals source_saved = Signal() matthewwithanm-django-imagekit-26cdc9d/imagekit/specs/000077500000000000000000000000001525234025000232105ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/specs/__init__.py000066400000000000000000000203621525234025000253240ustar00rootroot00000000000000from copy import copy from django.conf import settings from django.db.models.fields.files import ImageFieldFile from .. import hashers from ..cachefiles.backends import get_default_cachefile_backend from ..cachefiles.strategies import load_strategy from ..exceptions import AlreadyRegistered, MissingSource from ..registry import generator_registry, register from ..utils import get_by_qname, open_image, process_image class BaseImageSpec: """ An object that defines how an new image should be generated from a source image. """ cachefile_storage = None """A Django storage system to use to save a cache file.""" cachefile_backend = None """ An object responsible for managing the state of cache files. Defaults to an instance of ``IMAGEKIT_DEFAULT_CACHEFILE_BACKEND`` """ cachefile_strategy = settings.IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY """ A dictionary containing callbacks that allow you to customize how and when the image file is created. Defaults to ``IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY``. """ def __init__(self): self.cachefile_backend = self.cachefile_backend or get_default_cachefile_backend() self.cachefile_strategy = load_strategy(self.cachefile_strategy) def generate(self): raise NotImplementedError MissingSource = MissingSource """ Raised when an operation requiring a source is attempted on a spec that has no source. """ class ImageSpec(BaseImageSpec): """ An object that defines how to generate a new image from a source file using PIL-based processors. (See :mod:`imagekit.processors`) """ processors = [] """A list of processors to run on the original image.""" format = None """ The format of the output file. If not provided, ImageSpecField will try to guess the appropriate format based on the extension of the filename and the format of the input image. """ options = None """ A dictionary that will be passed to PIL's ``Image.save()`` method as keyword arguments. Valid options vary between formats, but some examples include ``quality``, ``optimize``, and ``progressive`` for JPEGs. See the PIL documentation for others. """ autoconvert = True """ Specifies whether automatic conversion using ``prepare_image()`` should be performed prior to saving. """ def __init__(self, source): self.source = source super().__init__() @property def cachefile_name(self): if not self.source: return None fn = get_by_qname(settings.IMAGEKIT_SPEC_CACHEFILE_NAMER, 'namer') return fn(self) @property def source(self): src = getattr(self, '_source', None) if not src: field_data = getattr(self, '_field_data', None) if field_data: src = self._source = getattr(field_data['instance'], field_data['attname']) del self._field_data return src @source.setter def source(self, value): self._source = value def __getstate__(self): state = copy(self.__dict__) # Unpickled ImageFieldFiles won't work (they're missing a storage # object). Since they're such a common use case, we special case them. # Unfortunately, this also requires us to add the source getter to # lazily retrieve the source on the reconstructed object; simply trying # to look up the source in ``__setstate__`` would require us to get the # model instance but, if ``__setstate__`` was called as part of # deserializing that model, the model wouldn't be fully reconstructed # yet, preventing us from accessing the source field. # (This is issue #234.) if isinstance(self.source, ImageFieldFile): field = self.source.field state['_field_data'] = { 'instance': getattr(self.source, 'instance', None), 'attname': getattr(field, 'name', None), } state.pop('_source', None) return state def get_hash(self): return hashers.pickle([ self.source.name, self.processors, self.format, self.options, self.autoconvert, ]) def generate(self): if not self.source: raise MissingSource("The spec '%s' has no source file associated" " with it." % self) # TODO: Move into a generator base class # TODO: Factor out a generate_image function so you can create a generator and only override the PIL.Image creating part. # (The tricky part is how to deal with original_format since generator base class won't have one.) closed = self.source.closed if closed: # Django file object should know how to reopen itself if it was closed # https://code.djangoproject.com/ticket/13750 self.source.open() try: img = open_image(self.source) new_image = process_image(img, processors=self.processors, format=self.format, autoconvert=self.autoconvert, options=self.options) finally: if closed: # We need to close the file if it was opened by us self.source.close() return new_image def create_spec_class(class_attrs): class DynamicSpecBase(ImageSpec): def __reduce__(self): try: getstate = self.__getstate__ except AttributeError: state = self.__dict__ else: state = getstate() return (create_spec, (class_attrs, state)) return type('DynamicSpec', (DynamicSpecBase,), class_attrs) def create_spec(class_attrs, state): cls = create_spec_class(class_attrs) instance = cls.__new__(cls) # Create an instance without calling the __init__ (which may have required args). try: setstate = instance.__setstate__ except AttributeError: instance.__dict__ = state else: setstate(state) return instance class SpecHost: """ An object that ostensibly has a spec attribute but really delegates to the spec registry. """ def __init__(self, spec=None, spec_id=None, **kwargs): spec_attrs = {k: v for k, v in kwargs.items() if v is not None} if spec_attrs: if spec: raise TypeError('You can provide either an image spec or' ' arguments for the ImageSpec constructor, but not both.') else: spec = create_spec_class(spec_attrs) self._original_spec = spec if spec_id: self.set_spec_id(spec_id) def set_spec_id(self, id): """ Sets the spec id for this object. Useful for when the id isn't known when the instance is constructed (e.g. for ImageSpecFields whose generated `spec_id`s are only known when they are contributed to a class). If the object was initialized with a spec, it will be registered under the provided id. """ self.spec_id = id if self._original_spec: try: register.generator(id, self._original_spec) except AlreadyRegistered: # Fields should not cause AlreadyRegistered exceptions. If a # spec is already registered, that should be used. It is # especially important that an error is not thrown here because # of South, which will create duplicate models as part of its # "fake orm," therefore re-registering specs. pass def get_spec(self, source): """ Look up the spec by the spec id. We do this (instead of storing the spec as an attribute) so that users can override apps' specs--without having to edit model definitions--simply by registering another spec with the same id. """ if not getattr(self, 'spec_id', None): raise Exception('Object %s has no spec id.' % self) return generator_registry.get(self.spec_id, source=source) matthewwithanm-django-imagekit-26cdc9d/imagekit/specs/sourcegroups.py000066400000000000000000000142561525234025000263320ustar00rootroot00000000000000""" Source groups are the means by which image spec sources are identified. They have two responsibilities: 1. To dispatch ``source_saved`` signals. (These will be relayed to the corresponding specs' cache file strategies.) 2. To provide the source files that they represent, via a generator method named ``files()``. (This is used by the generateimages management command for "pre-caching" image files.) """ import inspect from django.db.models.signals import post_init, post_save from django.utils.functional import wraps from ..cachefiles import LazyImageCacheFile from ..signals import source_saved from ..utils import get_nonabstract_descendants def ik_model_receiver(fn): """ A method decorator that filters out signals coming from models that don't have fields that function as ImageFieldSourceGroup sources. """ @wraps(fn) def receiver(self, sender, **kwargs): if not inspect.isclass(sender): return for src in self._source_groups: if issubclass(sender, src.model_class): fn(self, sender=sender, **kwargs) # If we find a match, return. We don't want to handle the signal # more than once. return return receiver class ModelSignalRouter: """ Normally, ``ImageFieldSourceGroup`` would be directly responsible for watching for changes on the model field it represents. However, Django does not dispatch events for abstract base classes. Therefore, we must listen for the signals on all models and filter out those that aren't represented by ``ImageFieldSourceGroup``s. This class encapsulates that functionality. Related: https://github.com/matthewwithanm/django-imagekit/issues/126 https://code.djangoproject.com/ticket/9318 """ def __init__(self): self._source_groups = [] uid = 'ik_spec_field_receivers' post_init.connect(self.post_init_receiver, dispatch_uid=uid) post_save.connect(self.post_save_receiver, dispatch_uid=uid) def add(self, source_group): self._source_groups.append(source_group) def init_instance(self, instance): instance._ik = getattr(instance, '_ik', {}) def update_source_hashes(self, instance): """ Stores hashes of the source image files so that they can be compared later to see whether the source image has changed (and therefore whether the spec file needs to be regenerated). """ self.init_instance(instance) instance._ik['source_hashes'] = { attname: hash(getattr(instance, attname)) for attname in self.get_source_fields(instance)} return instance._ik['source_hashes'] def get_source_fields(self, instance): """ Returns a list of the source fields for the given instance. """ return { src.image_field for src in self._source_groups if isinstance(instance, src.model_class)} @ik_model_receiver def post_save_receiver(self, sender, instance=None, created=False, update_fields=None, raw=False, **kwargs): if not raw: self.init_instance(instance) old_hashes = instance._ik.get('source_hashes', {}).copy() new_hashes = self.update_source_hashes(instance) for attname in self.get_source_fields(instance): if update_fields and attname not in update_fields: continue file = getattr(instance, attname) if file and old_hashes.get(attname) != new_hashes[attname]: self.dispatch_signal(source_saved, file, sender, instance, attname) @ik_model_receiver def post_init_receiver(self, sender, instance=None, **kwargs): self.init_instance(instance) source_fields = self.get_source_fields(instance) local_fields = { field.name: field for field in instance._meta.local_fields if field.name in source_fields} instance._ik['source_hashes'] = { attname: hash(file_field) for attname, file_field in local_fields.items()} def dispatch_signal(self, signal, file, model_class, instance, attname): """ Dispatch the signal for each of the matching source groups. Note that more than one source can have the same model and image_field; it's important that we dispatch the signal for each. """ for source_group in self._source_groups: if issubclass(model_class, source_group.model_class) and source_group.image_field == attname: signal.send(sender=source_group, source=file) class ImageFieldSourceGroup: """ A source group that represents a particular field across all instances of a model and its subclasses. """ def __init__(self, model_class, image_field): self.model_class = model_class self.image_field = image_field signal_router.add(self) def files(self): """ A generator that returns the source files that this source group represents; in this case, a particular field of every instance of a particular model and its subclasses. """ for model in get_nonabstract_descendants(self.model_class): for instance in model.objects.all().iterator(): yield getattr(instance, self.image_field) class SourceGroupFilesGenerator: """ A Python generator that yields cache file objects for source groups. """ def __init__(self, source_group, generator_id): self.source_group = source_group self.generator_id = generator_id def __eq__(self, other): return (isinstance(other, self.__class__) and self.__dict__ == other.__dict__) def __ne__(self, other): return not self.__eq__(other) def __hash__(self): return hash((self.source_group, self.generator_id)) def __call__(self): for source_file in self.source_group.files(): yield LazyImageCacheFile(self.generator_id, source=source_file) signal_router = ModelSignalRouter() matthewwithanm-django-imagekit-26cdc9d/imagekit/templates/000077500000000000000000000000001525234025000240715ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/templates/imagekit/000077500000000000000000000000001525234025000256635ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/templates/imagekit/admin/000077500000000000000000000000001525234025000267535ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/templates/imagekit/admin/thumbnail.html000066400000000000000000000002121525234025000316170ustar00rootroot00000000000000{% if thumbnail %} {% endif %}matthewwithanm-django-imagekit-26cdc9d/imagekit/templatetags/000077500000000000000000000000001525234025000245655ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/templatetags/__init__.py000066400000000000000000000000001525234025000266640ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/imagekit/templatetags/imagekit.py000066400000000000000000000275021525234025000267370ustar00rootroot00000000000000from inspect import signature from django import template from django.template.library import parse_bits from django.utils.encoding import force_str from django.utils.html import escape from django.utils.safestring import mark_safe from django.conf import settings from ..cachefiles import ImageCacheFile from ..registry import generator_registry register = template.Library() ASSIGNMENT_DELIMETER = 'as' HTML_ATTRS_DELIMITER = '--' DEFAULT_THUMBNAIL_GENERATOR = 'imagekit:thumbnail' default_thumbnail_srcset_scales = getattr(settings, 'IMAGEKIT_DEFAULT_THUMBNAIL_SRCSET_SCALES', None) # Django 6.1 removed the takes_context parameter from the undocumented parse_bits if 'takes_context' in signature(parse_bits).parameters: def _parse_args_kwargs(parser, bits, params, tag_name): return parse_bits(parser, bits, params, 'args', 'kwargs', None, [], None, False, tag_name) else: def _parse_args_kwargs(parser, bits, params, tag_name): return parse_bits(parser, bits, params, 'args', 'kwargs', None, [], None, tag_name) def get_cachefile(context, generator_id, generator_kwargs, source=None): generator_id = generator_id.resolve(context) kwargs = {k: v.resolve(context) for k, v in generator_kwargs.items()} generator = generator_registry.get(generator_id, **kwargs) return ImageCacheFile(generator) def parse_dimensions(dimensions): """ Parse the width and height values from a dimension string. Valid values are '1x1', '1x', and 'x1'. If one of the dimensions is omitted, the parse result will be None for that value. """ width, height = [d.strip() and int(d) or None for d in dimensions.split('x')] return {'width': width, 'height': height} class GenerateImageAssignmentNode(template.Node): def __init__(self, variable_name, generator_id, generator_kwargs): self._generator_id = generator_id self._generator_kwargs = generator_kwargs self._variable_name = variable_name def get_variable_name(self, context): return force_str(self._variable_name) def render(self, context): variable_name = self.get_variable_name(context) context[variable_name] = get_cachefile(context, self._generator_id, self._generator_kwargs) return '' class GenerateImageTagNode(template.Node): def __init__(self, generator_id, generator_kwargs, html_attrs): self._generator_id = generator_id self._generator_kwargs = generator_kwargs self._html_attrs = html_attrs def render(self, context): file = get_cachefile(context, self._generator_id, self._generator_kwargs) attrs = {k: v.resolve(context) for k, v in self._html_attrs.items()} # Only add width and height if neither is specified (to allow for # proportional in-browser scaling). if 'width' not in attrs and 'height' not in attrs: attrs.update(width=file.width, height=file.height) attrs['src'] = file.url attr_str = ' '.join('%s="%s"' % (escape(k), escape(v)) for k, v in attrs.items()) return mark_safe('' % attr_str) class ThumbnailAssignmentNode(template.Node): def __init__(self, variable_name, generator_id, dimensions, source, generator_kwargs): self._variable_name = variable_name self._generator_id = generator_id self._dimensions = dimensions self._source = source self._generator_kwargs = generator_kwargs def get_variable_name(self, context): return force_str(self._variable_name) def render(self, context): variable_name = self.get_variable_name(context) generator_id = self._generator_id.resolve(context) if self._generator_id else DEFAULT_THUMBNAIL_GENERATOR kwargs = {k: v.resolve(context) for k, v in self._generator_kwargs.items()} kwargs['source'] = self._source.resolve(context) kwargs.update(parse_dimensions(self._dimensions.resolve(context))) if kwargs.get('anchor'): # ImageKit uses pickle at protocol 0, which throws infinite # recursion errors when anchor is set to a SafeString instance. # This converts the SafeString into a str instance. kwargs['anchor'] = kwargs['anchor'][:] if kwargs.get('format'): kwargs['format'] = kwargs['format'][:] generator = generator_registry.get(generator_id, **kwargs) context[variable_name] = ImageCacheFile(generator) return '' class ThumbnailImageTagNode(template.Node): def __init__(self, generator_id, dimensions, source, generator_kwargs, html_attrs): self._generator_id = generator_id self._dimensions = dimensions self._source = source self._generator_kwargs = generator_kwargs self._html_attrs = html_attrs def render(self, context): generator_id = self._generator_id.resolve(context) if self._generator_id else DEFAULT_THUMBNAIL_GENERATOR dimensions = parse_dimensions(self._dimensions.resolve(context)) kwargs = {k: v.resolve(context) for k, v in self._generator_kwargs.items()} kwargs['source'] = self._source.resolve(context) kwargs.update(dimensions) if kwargs.get('anchor'): # ImageKit uses pickle at protocol 0, which throws infinite # recursion errors when anchor is set to a SafeString instance. # This converts the SafeString into a str instance. kwargs['anchor'] = kwargs['anchor'][:] srcset_scales = default_thumbnail_srcset_scales if "srcset" in kwargs: if kwargs['srcset'] is not None: srcset_scales = list(map(float, kwargs['srcset'].split())) else: srcset_scales = None kwargs.pop("srcset") if kwargs.get('format'): kwargs['format'] = kwargs['format'][:] generator = generator_registry.get(generator_id, **kwargs) file = ImageCacheFile(generator) srcset = [] if srcset_scales: for scale in srcset_scales: scaled_kwargs = dict(kwargs) if scaled_kwargs.get("height"): scaled_kwargs["height"] = int(scaled_kwargs["height"] * scale) if scaled_kwargs.get("width"): scaled_kwargs["width"] = int(scaled_kwargs["width"] * scale) srcset.append(ImageCacheFile(generator_registry.get(generator_id, **scaled_kwargs))) attrs = {k: v.resolve(context) for k, v in self._html_attrs.items()} # Only add width and height if neither is specified (to allow for # proportional in-browser scaling). if 'width' not in attrs and 'height' not in attrs: attrs.update(width=file.width, height=file.height) attrs['src'] = file.url if len(srcset) > 0: attrs['srcset'] = f'{file.url} 1x , ' + ' , '.join( f'{entry[0].url} {entry[1]}x' for entry in zip(srcset, srcset_scales)) attr_str = ' '.join('%s="%s"' % (escape(k), escape(v)) for k, v in attrs.items()) return mark_safe('' % attr_str) def parse_ik_tag_bits(parser, bits): """ Parses the tag name, html attributes and variable name (for assignment tags) from the provided bits. The preceding bits may vary and are left to be parsed by specific tags. """ varname = None html_attrs = {} tag_name = bits.pop(0) if len(bits) >= 2 and bits[-2] == ASSIGNMENT_DELIMETER: varname = bits[-1] bits = bits[:-2] if HTML_ATTRS_DELIMITER in bits: if varname: raise template.TemplateSyntaxError('Do not specify html attributes' ' (using "%s") when using the "%s" tag as an assignment' ' tag.' % (HTML_ATTRS_DELIMITER, tag_name)) index = bits.index(HTML_ATTRS_DELIMITER) html_bits = bits[index + 1:] bits = bits[:index] if not html_bits: raise template.TemplateSyntaxError('Don\'t use "%s" unless you\'re' ' setting html attributes.' % HTML_ATTRS_DELIMITER) args, html_attrs = _parse_args_kwargs(parser, html_bits, [], tag_name) if len(args): raise template.TemplateSyntaxError('All "%s" tag arguments after' ' the "%s" token must be named.' % (tag_name, HTML_ATTRS_DELIMITER)) return (tag_name, bits, html_attrs, varname) @register.tag def generateimage(parser, token): """ Creates an image based on the provided arguments. By default:: {% generateimage 'myapp:thumbnail' source=mymodel.profile_image %} generates an ```` tag:: You can add additional attributes to the tag using "--". For example, this:: {% generateimage 'myapp:thumbnail' source=mymodel.profile_image -- alt="Hello!" %} will result in the following markup:: Hello! For more flexibility, ``generateimage`` also works as an assignment tag:: {% generateimage 'myapp:thumbnail' source=mymodel.profile_image as th %} """ bits = token.split_contents() tag_name, bits, html_attrs, varname = parse_ik_tag_bits(parser, bits) args, kwargs = _parse_args_kwargs(parser, bits, ['generator_id'], tag_name) if len(args) != 1: raise template.TemplateSyntaxError('The "%s" tag requires exactly one' ' unnamed argument (the generator id).' % tag_name) generator_id = args[0] if varname: return GenerateImageAssignmentNode(varname, generator_id, kwargs) else: return GenerateImageTagNode(generator_id, kwargs, html_attrs) @register.tag def thumbnail(parser, token): """ A convenient shortcut syntax for generating a thumbnail. The following:: {% thumbnail '100x100' mymodel.profile_image %} is equivalent to:: {% generateimage 'imagekit:thumbnail' source=mymodel.profile_image width=100 height=100 %} The thumbnail tag supports the "--" and "as" bits for adding html attributes and assigning to a variable, respectively. It also accepts the kwargs "format", "srcset", "anchor", and "crop". To use "srcset" (generating multiple thumbnails for different pixel densities) list the scale factors:: {% thumbnail '100x100' mymodel.profile_image srcset='2 3' %} To use "smart cropping" (the ``SmartResize`` processor):: {% thumbnail '100x100' mymodel.profile_image %} To crop, anchoring the image to the top right (the ``ResizeToFill`` processor):: {% thumbnail '100x100' mymodel.profile_image anchor='tr' %} To resize without cropping (using the ``ResizeToFit`` processor):: {% thumbnail '100x100' mymodel.profile_image crop=0 %} """ bits = token.split_contents() tag_name, bits, html_attrs, varname = parse_ik_tag_bits(parser, bits) args, kwargs = _parse_args_kwargs(parser, bits, [], tag_name) if len(args) < 2: raise template.TemplateSyntaxError('The "%s" tag requires at least two' ' unnamed arguments: the dimensions and the source image.' % tag_name) elif len(args) > 3: raise template.TemplateSyntaxError('The "%s" tag accepts at most three' ' unnamed arguments: a generator id, the dimensions, and the' ' source image.' % tag_name) dimensions, source = args[-2:] generator_id = args[0] if len(args) > 2 else None if varname: return ThumbnailAssignmentNode(varname, generator_id, dimensions, source, kwargs) else: return ThumbnailImageTagNode(generator_id, dimensions, source, kwargs, html_attrs) matthewwithanm-django-imagekit-26cdc9d/imagekit/utils.py000066400000000000000000000110561525234025000236100ustar00rootroot00000000000000import logging import re from hashlib import md5 from importlib import import_module from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.core.files import File from pilkit.utils import * bad_memcached_key_chars = re.compile('[\u0000-\u001f\\s]+') _autodiscovered = False def get_nonabstract_descendants(model): """ Returns all non-abstract descendants of the model. """ if not model._meta.abstract: yield model for s in model.__subclasses__(): yield from get_nonabstract_descendants(s) def get_by_qname(path, desc): try: dot = path.rindex('.') except ValueError: raise ImproperlyConfigured("%s isn't a %s module." % (path, desc)) module, objname = path[:dot], path[dot + 1:] try: mod = import_module(module) except ImportError as e: raise ImproperlyConfigured('Error importing %s module %s: "%s"' % (desc, module, e)) try: obj = getattr(mod, objname) return obj except AttributeError: raise ImproperlyConfigured('%s module "%s" does not define "%s"' % (desc[0].upper() + desc[1:], module, objname)) _singletons = {} def get_singleton(class_path, desc): global _singletons cls = get_by_qname(class_path, desc) instance = _singletons.get(cls) if not instance: instance = _singletons[cls] = cls() return instance def autodiscover(): """ Auto-discover INSTALLED_APPS imagegenerators.py modules and fail silently when not present. This forces an import on them to register any admin bits they may want. Copied from django.contrib.admin """ global _autodiscovered if _autodiscovered: return from django.utils.module_loading import autodiscover_modules autodiscover_modules('imagegenerators') _autodiscovered = True def get_logger(logger_name='imagekit', add_null_handler=True): logger = logging.getLogger(logger_name) if add_null_handler: logger.addHandler(logging.NullHandler()) return logger def get_field_info(field_file): """ A utility for easily extracting information about the host model from a Django FileField (or subclass). This is especially useful for when you want to alter processors based on a property of the source model. For example:: class MySpec(ImageSpec): def __init__(self, source): instance, attname = get_field_info(source) self.processors = [SmartResize(instance.thumbnail_width, instance.thumbnail_height)] """ return ( getattr(field_file, 'instance', None), getattr(getattr(field_file, 'field', None), 'attname', None), ) def generate(generator): """ Calls the ``generate()`` method of a generator instance, and then wraps the result in a Django File object so Django knows how to save it. """ content = generator.generate() f = File(content) # The size of the File must be known or Django will try to open a file # without a name and raise an Exception. f.size = len(content.read()) # After getting the size reset the file pointer for future reads. content.seek(0) return f def call_strategy_method(file, method_name): strategy = getattr(file, 'cachefile_strategy', None) fn = getattr(strategy, method_name, None) if fn is not None: fn(file) def get_cache(): from django.core.cache import caches return caches[settings.IMAGEKIT_CACHE_BACKEND] def get_storage(): try: from django.core.files.storage import storages, InvalidStorageError except ImportError: # Django < 4.2 return get_singleton( settings.IMAGEKIT_DEFAULT_FILE_STORAGE, 'file storage backend' ) else: try: return storages[settings.IMAGEKIT_DEFAULT_FILE_STORAGE] except InvalidStorageError: return get_singleton( settings.IMAGEKIT_DEFAULT_FILE_STORAGE, 'file storage backend' ) def sanitize_cache_key(key): if settings.IMAGEKIT_USE_MEMCACHED_SAFE_CACHE_KEY: # Memcached keys can't contain whitespace or control characters. new_key = bad_memcached_key_chars.sub('', key) # The also can't be > 250 chars long. Since we don't know what the # user's cache ``KEY_FUNCTION`` setting is like, we'll limit it to 200. if len(new_key) >= 200: new_key = '%s:%s' % (new_key[:200 - 33], md5(key.encode('utf-8')).hexdigest()) key = new_key return key matthewwithanm-django-imagekit-26cdc9d/justfile000066400000000000000000000001161525234025000220470ustar00rootroot00000000000000publish: python -m build python -m twine upload dist/* test: tox matthewwithanm-django-imagekit-26cdc9d/pyproject.toml000066400000000000000000000034611525234025000232210ustar00rootroot00000000000000[build-system] requires = ["setuptools>=61", "wheel"] build-backend = "setuptools.build_meta" [project] name = "django-imagekit" dynamic = ["version"] description = "Automated image processing for Django models." readme = {file = "README.rst", content-type = "text/x-rst"} authors = [ {name = "Matthew Tretter", email = "m@tthewwithanm.com"}, ] maintainers = [ {name = "Venelin Stoykov", email = "venelin.stoykov@industria.tech"}, ] license = "BSD-3-Clause" classifiers = [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Utilities", ] requires-python = ">=3.9" dependencies = [ "django-appconf", "pilkit", ] [project.urls] Homepage = "http://github.com/matthewwithanm/django-imagekit/" [project.optional-dependencies] test = [ "beautifulsoup4", "Pillow", "pytest", "pytest-cov", "pytest-django", ] async = ["django-celery>=3.0"] async_rq = ["django-rq>=0.6.0"] async_dramatiq = ["django-dramatiq>=0.4.0"] [tool.setuptools] include-package-data = true zip-safe = false [tool.setuptools.packages.find] exclude = ["*.tests", "*.tests.*", "tests.*", "tests"] [tool.setuptools.dynamic] version = {attr = "imagekit.pkgmeta.__version__"} [tool.pytest.ini_options] django_find_project = false DJANGO_SETTINGS_MODULE = "tests.settings" matthewwithanm-django-imagekit-26cdc9d/tests/000077500000000000000000000000001525234025000214435ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/tests/__init__.py000066400000000000000000000000001525234025000235420ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/tests/conftest.py000066400000000000000000000003141525234025000236400ustar00rootroot00000000000000import pytest from .utils import clear_imagekit_test_files @pytest.fixture(scope='session', autouse=True) def imagekit_test_files_teardown(request): request.addfinalizer(clear_imagekit_test_files) matthewwithanm-django-imagekit-26cdc9d/tests/imagegenerators.py000066400000000000000000000006631525234025000251760ustar00rootroot00000000000000from imagekit import ImageSpec, register from imagekit.processors import ResizeToFill class TestSpec(ImageSpec): __test__ = False class ResizeTo1PixelSquare(ImageSpec): def __init__(self, width=None, height=None, anchor=None, crop=None, **kwargs): self.processors = [ResizeToFill(1, 1)] super().__init__(**kwargs) register.generator('testspec', TestSpec) register.generator('1pxsq', ResizeTo1PixelSquare) matthewwithanm-django-imagekit-26cdc9d/tests/media/000077500000000000000000000000001525234025000225225ustar00rootroot00000000000000matthewwithanm-django-imagekit-26cdc9d/tests/media/reference.png000066400000000000000000003511761525234025000252030ustar00rootroot00000000000000‰PNG  IHDRÓ?1€IDATxÚlýY¯mÙr&†}_ÄsÎÕíæ´Ùß{ÉK^òI‰"KªF€ Ê(ûA2,½0 ûø/~¬'°a ‚T– ’K%±Tl.y»ìožÌ<ÍîW3çá‡1×>;“<ÈÜXkíµW#â‹/¾à_üþ/ËÔå\P=QC…$ÊT³Š{aÀl¢‚̺HõGïè¯þj{SVÝIZ,( À =„CSh2HB "@#¨ H…;£2’¢`ôЏCHð¯"<Ü€$áˆp^+F„Y%Å""BSÒ”I%iµ›ÜC5圡 À=(jáB)¤¦D¯µÚB¡Ì�z|~¨µ’š’�5 ¢f*šsÁjVKóÒw�hQR¬VQ¡0u×gL‹°à¸÷ñ`¥NãõÍÅ«/?ùå_ÿ›?»ýæå0Yxˆ²Lcwe´Zs¿¡vòäQœ� «ÇÌÝaw½½+_¿¼zñúîóo.¯Ç©’âî$#€ˆ Ù.´[ í–vµ]‘ûû·Ûݽ]nWþíÃ÷òðéîíþ¯î_Þý-"BRD(®˜YT¬š*EîÞ0dûÙîG‘ð � …í‰Âgã „‘.__»½Ë~wzöøé³gf{‘ìt *ªîUs¦H­{·>ug�u÷Zp„€ îHf´‚‰PèÈ z‘`{F†Ô)3<"H‡(t¨¨l&‹Ê€KJáN%)âSˆ’wMÙjHÀa.@°#<VMIGˆHD!’„AMÆÐöÍA€ ‰`„S¯NAEÅ#F„GH35$ "h pŸÜ%i23¥R“»‘¬¥ä® ‡ÔŠ˜‚ð°&,]N«náiˆéšI©‰†Rkʽ@K¸.V¡Bãõá`¯^½ºÙ~öÍ7/^•‹Ww»©6ch†efªÚLÍÌš…Ýq3¯v‡v•ǧ{Óh¿RUiWï}£ÝçþqZBÀÝÛ¡ñÐÙž÷žó=[xÈÜGý{/½Rª lHƒ@3Ü£‡„ÂÝ)ânB9:RPnÍÜ…BaÀ¤ %"@ê?øƒ:êr™ rss{_öëê�ŠÔK­£„«ö"æ�qÜu“Å›Ëíþô¬Kj¡„0lÑ–¨ @Ô !áw2Á Q« ÜÔ ÅiÂpD�0P@�Â�3„h_§€Ò>A©LФ„ShCà ʣDx¬¨ ÜH¥*… Â�báæ$ÓÝM“À AD¡`„“4«Be„'é€p7 Ãq!án^ƒD(s´ï áæ¤X Š˜9Ì-Üë´èÁ2ÞMÓä{È4†•Zc´ Ó&¢Çâì)ºÕVä››íç/_þú7×û­™£:ŽVLJqý¡y5ëoæ~ãþ¼¿ÿ÷Ίf¯÷†«ª÷yüÃÜæoÇþ¿õïï|ÿ¾—_ˆPQ uÎÙ‘( ´c”B•ðv·ù€ t%A(Å„›�""@"HÒwg‹ÅówŸ>ÿÑþÅŸý×e1Öu/Cÿèù»”iwWM$²ª�—Ûo/»=û4…­79 p„ C© Ì„ QÖù·*Ά®‚êp$JaŠö[�ÔòX Ÿ¿Þ§Á€Æ”ÃÁžn]DBR<¼¶øÝÕZDR £ŬxÊ©U¿‘¤n„»�p)uŸ¤·RÉD¨H  ëºj…¢ê(Íf¬ÀVãT’nn ³ª¢ê&P(@Xk`&d‰˜“Ò°hÊ}—«T“Œnîeªã8í4¯óê¼{´Ñ<ðfÚI¹ÝîI¤$RïkÊ–ÏÜnDäœÛÕfÄ÷¿j—ªŠ™}Ï æ'«êï™þC‹o÷¼÷¢û:á¡#µÛÛÓÝ›þñ¡L¨B=†vOIK­ªJUÚIdæª"”j…¤t’ ÚWåN‘–O¢í@D@ˆô¿ûßþǽ÷Ápö8Þý½üOÿ#½ü•ût:'»ë²¿Éyõøpwmv“�¬²ÇÒçÒE-•š#‚‰p•p *)À:Dx@$`5@ ¶HŒ¤¨s ŸÈæ�TD ˆs&…5Ç—†;QÌáA°…U„€ Š„ˆ”R˜<÷}-%XU³ùÑÊ÷*IÝŠˆ€&ÕªªD�PF˜›ÙÂE›O†Ý.n5h„X5MY4ט„ÙQˆf!.ª´ ŠŒ&’ݪ[$ )Ó("š`%$àIsNf{ƒŠMS9„±HéÉ£Í;˜—;ÜòÍP‘aRæœkqêÃŒâ{‰Ðý ª)¸×vÇVÿ$Ü›G¡Ay÷&ûú^’ó½,è>]yãïÝàáòìÈÓÛRRbxÐ#hˆHªÌZͼZ§Úà –$4SŠG�pw'½N}ÖaÑ[­‹uZ-›“§é÷øÛ6däÎ/^ô›³H+–ýîæUJ*ðq¸yuqúü])¥2±>¹º~ûà +šVT¢6ˆ)¼�êæˆV”†F5*Ñ14ÊŒ¡&�ÁBCᆤ€#e¸GE` 1V�”D"Z�­€“ÊogfÌ%5îI*¨tštt<’D]�D˜YÑ ¤Ü9‚"Ž€…H ÷@ ! ?+SmEuÐÂC’ˆE‚á�©{ ÉaµÂ«F5­áiÎéN³¢)›ŒˆJxíRvXDõÀ›}yqqçc>ÔJ]B²œ=OOÎe“„CWH%…‰0´lÞ�Ö&ìI')"hW»=ÂDîCx3¡a„©Ò,Èq3ô!àóÐèÞò°êýöúðjË–ÑÇç…U@Z¸ÌY|~}ªjf DÀæÂÍX,³¤Åfsrv6œž¬OΞ>:[<{úl¹Zœ�m6ëG}—=y–^üæ[éËêü±…/Nÿ—×/ÄKy[³vW¯_ ýåW_¦E7•ºè½ë!2îXªmÖ"'Á îJº{iP \Ü n ½´AX„lNur*ÃFÑ ¨GÔcª ›&ŠºE‚ ›æ<�¨cM)‡5€@à áµÖ”³ÕÐN½J$—ª{dÍ¥ŒY$J$�Vi%FQE�Q Â€h w g«z#à5D–:vÝ"Ì BWc…ÔX5 ]ÃdÍ\¥Õàfa%TÝ tš8LBA¯¥†ÃƺÛío·w7‡ËýímJ+QéNñÑÙpöxµì&¤~áC—»!A‹D¡-ÊVþ´óhØþ#›Ùù}Á¬"­ßÒŒ±æBFU5ó€ðˆ™68µ™ï}5üH½¿úðxX|§üECJØÀ¸m©p4¯vŸ‰^�)%Ñ,CŸ¤÷”ëeßuÝ“ÇïnÖ«³Ç§«áüüÑÉjÙ=yüd½>[Ÿœžœä¡?YäNò¦_.Ȫ92%§å£eêẎÇ�±V^G‡v‡éП­¼„ZÍ‹´onb·ÛiÚû„$~yu!Ø}íTŒVÑ-{gJbµì@M "Šcœ´K’’¢Ž! FMæ!P4h¬nàðX@ФÎ}òêæYà ÂÉ ”/5DÅÆbV)-€Ìy¹€àìÄê$¤GD˜;„¹Öªâ¤z;ÔÜd£+餸yCÙBÔ,D¯BUF5…J;6<Ä=(ÙÜTÄzHQ‚%n %"¹U5„ÄTÊt{}wõúj3 ¶²’„™BH7§²aäÞüœà|D´BsWaØl°ßÃ|pllÝû†¨ ¾ö7àòA–?}î†9qUº{—Í›˜ûÍb8;=í–'ë~êWg�=Ú,óùéº[l��ç¡§ög›“®×aX.§ËeÎ: Ý =%­%õíËöаð`mÐÓè0�Nn¶‡Çë.Ûµ?#u’N®�ôÂz(1Y­ã¾æ”&‹RC ãîâÕË‹]—OR· Bs–ºåTwËpPDµ³z—¤ïˆ@].—ªd@µ‹2R`ÖCTáJj€ðrˆ˜�pgî"D)^k�êa�$QbWJ¡ÐÃU†ðpjB8 Q²2©*QŒŽ æžT݃„G àe†�jue„[è !‘a¥R„R…bQï¿ï0€– ¢¨ Ù 7‹–'#Ì«›¨TGFb‘ £CŠ8sîÃÃæ–A(ÇZÇøÝïILis>œ=Ï«ÕâñY¿Y-6çI—~µ¬›õzµÐ^a%ÀP�G¨¨×JQ%ÂàϪÆ9çx»ê5’^�ÂàÜÝÓ¤µVrþÔ"‚á¦"m•+Ûsf‚@�Ÿ„ FD¥Z- hrI]º>)—C·9RÊg'}ß Ëõæl³ØlN—«ÓwÞ{çÑéÓÔ•¡ßœ­6Ýr‘r·Z-»®¦Ôu�N”ÎŒ¢Éœ€˜àd@µ¨``€O«®×§g�R?„D€c–uFׂi—7h te7ŠÒÍ(ID½ìÓraÓM�Óî€*S-ÅÜB¢ÔiÚ ;¸S%á!*"¡Ý )Sˆ2Rˆ-„õ(ÊÌPG˜W @¯Î€Ur‡€<ªSÝ @³šroµ’ɽòvEó¢Žó0m_i*»²?Ôpí�Ðušr?$IFET„’q°’D,‚�p óð¨UНkÎÝ£ÇË´ìW›ÅI—׋ÅéyJ )e:×›'g�žž¿¹] 1Õš4Qs1w.¦C™¦E¤PÌ­µTÛ—/" ñ%Q™ÛCíð3oØbÃÑ[ûÐé@DxΩÖ0¤º„Q³² ]§]Ÿ4C×å´Z/–ë“!åõæ$õÝÉÉéébÙ/VëÕ�:Y­N—ËÅbÈëÕ‰æ´Z­– ÃrÓ-Ö}ßQ»4œ�ÙCÂéæ-/Àè*GËÕÐl½]h©M½ýl|i5=€ç‹æ¦CGÂh#%Kª¹¸kN}fò¬¡µ¸GÎ6åì~`Roþ?ûÙg_~u] ‘ò°î»”ÃUóf)OWËw7§ë:¦N7)ÙãÓ“gïx‚p³r/!T9í@§¼XõD?tyu¢L©ïU³¤HT¸§ ‚É#¬H ʾÕ.(GãÆ½¯Þ_æƒûèƒ_¥ã_ñþOÒv£U�»·ã¸?ìnOÏžt‹Þ­«ã$ÅÁÎëa lÛÅŸþÓZ_§7ÿÙ¢)2V™Ì0N7Û‰�ê–5-–2=‰$©ú”Ë~ïãB$U_ŸœY][݈öµN „•«ÕÇí¤}çaa¦ÝÊaˆjaUQ‡!0Mc¸í“¹OÓ�[¸CI&Br€^k…aE$D4bŒ€Ç³"Â"rرŠh JXÖT‚}¦ñ¦Æ4™™Û4&�,ù0ÖdXñ *j4&á°x¼Z­jŒåd±# ‘ýá0öa渖‹¾KC7«ÍB"ªÈÉ+š-S)Q­”Ų_Ù{}¥t]Nè»> i™úœ×Ý2 }~÷É»e?þáïþ^©ÁaÈY³ˆºä±ÔÃnwµ½º¾¾ysqùÍë×ß|{ùêââÍ˯ß\ß^]Ün¦·Ì¾¹]ZD9QÄû®Øry²\HH7ž<}Ô¯N‹ÍÉéj¹ˆåbµY?í3—Cê‡~Ý/O?é’¦®;?=•´ú.$¥>)²Ð®‡—�ˆ³‹€;âsFcpÌK3T¶vêlè|hÖøn\ÇwàþÎhäˆVñÀ@òþº¨eRÕ³ó'‹ÕZs·33À"ÈÒ[YpÂüÀßý�ã È7ü˃“‡a¨W#!Õ\…-ZpXõýæqî“]|›ÕÀZ½¡”î“.¯Ñês“ê)çÃÝ-ÝAÕ±µ´²ÃTEÙyû`„åPQl?Žÿò«¿yuó«�ùõË7Û[ÀF@ÂÍ�ºæäÊ9KŸ7£àø@ ‰–öŽÄq¾}ääXëÎq@ÌîÔܬñ¸Ž/0ÉÝU¤ëºÔ÷n“—©N»½YìJ‡ëò»gõóJ)œþ!PŸ~\Kßå’S0h‰ uQM=Ùœ?;Oéòv?¢X±ˆÄ–¶wÑ›MÐäN‡Ë.TV¯R¼™˜BDÔœnÕ&"ÌáS­áÔ ™…»{Ü»‹0\¬e_‚îÁ©¥šAîö#hc™ ±+õPmªãá°+ÖZ‰ÑÈ’´„+Å@s+Å$kÇ,Žª–DUÄÃ.Ò1*¡ ˜É‘öêÔéc­½2\a%¥”ö¥ !%`’3I!™ôÅ�Ÿ=]œœEHbšD© PGÝ=¬:%¬Ð 4©7Ò§èzhT¤Ì”r¿~~úèù‡ý½ílÿþÝß¼xýú›«7—·ÛmÝí»ÛõéÙ~øÛ?ù½?zòλÝúq¤ÎÙ!`Þ08¤_X³ºhíרe&˜f$©­p ³JKç�Žrï n0ÄÖŸ\¥¯ô,õÕƒ õh„g¸Ç¸5£¤jyÑõYrº«û‰u½;Ýí±Y{G H´lý`N¥kc°¹Ãb/Sä<˜&„iJ7·ÛÜwµîD´ÔR«¯¥Ld¢¨û$’\[oÛo>Kßî—5 ãë=}|÷òeº½Š›À/>Ç»"z$ƒ BQŸØ¿÷®þoÿü)û¨�˜»€$/Í•EÒ¡ë×N/³²›öÛÃíT7.�yõ©8$nnbî5¥¼ßî�`µ]Jêu/ûé`nX /VMçqšj¸1‚´iBroû½°ÚÞ‰N5¬F÷±ØÁ¦*Øî÷ ¬Ì”mAÒšR#~ “0)W(„kÊ™2¨=éfÅ5‰šÄ§NeŒVYv‰J%½P$>9s­Å=Ä«�9ç}CPݺn¹Zt�=ݬÏ$Éwçy”à8#°ˆ¹WÑŒ­ÅBg<àÁˆK€®ºaÙ{lJ97ŸÊ¦ý’2l§’H5.ÚÓ +àBoæETÀÙÚöa‰¨ �j ÂB?&GŽvkBt×Rj ê‘�N%$(C‰†²–†t Ѓ:ã:qŸEÅ1âÛ ámJt_ܧfþGJõã/¦ëËîw¯.¿zñùï OÇýÕzµ¸=Œ’þãÈÿ÷_ê_½™.:^ÿWøG_àƒ÷€v�bŒÄdÑÁð9VŒÓTÍ%i0å®+¨Q9Õ²Ÿê«Ûíz œ�Éæ"ä~œ"(D@j­Œ©Oã4)a—>01Žæá2moS © $Â#ª;ŠA>9Nw%,}©0ª›íÇѬ 4HÀ¨ !mÔˆ¢’ÚI-Ð@‹JT´„g ç,᥈  ª;,;K©@¸µ˜€ÔK¸ÀC”]ƒüà¨e Q 7XD”ý¤¢d *ÕEê»ïœ?çËÍZ‹Öê†��sDi#€! Á˜;·Ú —áó¼DkÊZ¥XHæÆ� qô½Z]ôi±ì½VP£LŒMƒH (†nAå±J{ˬ›9;"à^2o©Bކ¾Z3Ý Ô§=[²/5¨uî-KVÙI^Wöu’õ­#~,s[ìǪ÷'Ãñ4àÑ î+i¡¸§SÒë›+«˜n}¿X÷�.ww1îÄ3ÇÅ“ÓÖ.·C..óëéÍU¼ÿ.ô+¼{lðîJ°úÑ×·‰(÷´‘æ‚"<ÇYLÃÐëÐå“n5&{}3æØU6B;°ÜÝ,"’&·ˆZ‹JŠ@–îúf¯�2dš®c-a0„›‡E½ Xu  †1`Q'3‘Tý ì�4d''nûñ‘®¼†ˆÔÆð¤$Qˆ8]¤”Rû.“!YanpMJŸ(!ªBÉ]žTÍ€{­L=Qg. ÜQ“ô¤"R!ân(nn®’-fÞm K&Ô8}|þäütýø)úEĽ¶é`Ü[…ó˜(;` ˆï¦¢1Ó”1Ñ*¡4§OA i°E l4r(x�2¡s‡´jx& HÎäH€¤ø� *Rã7÷0„dÔvàá.@XëÙ·Y+ƒh@Ùꯀ$Üå4š¦ZÅŒ�öÚÀ·oÑWXüÌÁD£:´"ƒÇð<‹0��Eú?ÿ¬Nc=ìÊ8®”7‡»\x»êµØþÃÿ÷¯¦O^^½úöéúTîööé/ñ§ÿ pÀ;ÿ`úÓÿù£?µdÙSÂC(Á¹Öp÷:É8î–yH4{öÁvÜÕTöÛ©›ÊÝ~§=Ü B"H—«OœªjvD�X9¨äi5w6N`˜×Z AŠ”R€¨fS)LÙÝ#8Ncˆ47RJ­"Ù(4qw¤äVTób±p¯ŒÈýà^Ñpº0'ÒØYu½êƒ èVs—³—Üw”œ‚a¢´,AE›@PUxDXÎ9"ª{§$“G’‡+bîL©Áe:„›�µ„ª &2|*’r¨ˆ6B„�è{X´£–mˆ‡ ΃Ÿ-9`HPµeÎŽíï5Ä*½"Z�‚’œ3´RZ�*L RïXµžc�@o­•›Ñ؈Žs)Œ6 B�63`Ô6(Œ‚.T¢ÝÍcÁ�a�© eŽ€Ýèo{YqzHø}nsô„¹JæÛIˆÆj„@�þå/ÿ§³nðbꮹ?GœÀR¤Ww—¬ã?ú¯û«×ûĪn:üÑO°z‚º&6xþdµìªˆF «"tw�ºy�«aMvÝ:z,žÆñÕK_ßiÊÞ¥‰Â¤í�#D$—Æe7 ‰b•Âêµ°F) a:LcˆSØe—8lGª„*] NA—;w7³Ôu*SÀµ[„0ðÔ&žÃrÊ©ŽµKI‰6±΀¨š»ªL9u)—¨Ò¦”BQÍ0¥@è ‡vêÆIE½Žª91Rꢠ@Ÿú£R UÁ¾Kej“mhM*rw}yØ^/¦g:¸4M�yf ’@†îÐjP5f(Â$..´˜Î@RR­H£~Ô�É‚ "�ĨÌ.}�…!Ã�7ÆóÄÀõisJ- »Í�Öšc4 sfÓâÍtÍJN9ðfÍ1wÃØø·†ƒ<6²¾Ó›“¶WÑ€Ô qœoÂMbv’@Š EFîl¬Œã þh¹yQî4ç³ÔõÃzü��ø'ÿÊ¿ ”– cõƒ''ž³ûª–?2ȉ0R‹�ûñPÝRß/cR¢ï®R›ÇO˜�ØW‡‰æðZˤý°¯S®•HISñÒ2è@¥¸Œºi:dMæâÉ%îËõ2¬©ZY¥ išjY,ª{×A 2 ƒæ%§E«ñÒ‰pGJ½™�&©ƒ›j¶(½*EÍŠh×Ò¼$šs‚4jv´y_H¨j1M]4}¤ÈYª¹JŒN1“öÕI’–2°}·2¤r yq{}qu¹>¹ì4EêÖ˜šÑú\ ¨ ƒpVh•eÃÆ ´wáÊz]Gé„â€!“Dê4ŠøÄ2d©-}‡ÔИÐ6ß‚²A^ÇÂv¦�Þgؼ‡&IƱÐ&¢Ûô®¼¥íò}ƒ?¨`¥�;Íj›Á<÷2ûÃ|°‘~ä¾ áó?"Ÿm¦�Â{ïh…”uY‹)ÛùR½Œ˜Ü{j?¨l˜Ÿ¤uùé?æÿéÿÔ£‹Mxïïïý›w»á—ÕŠª¡ÁÚ‡i<ŒwŶ!ƒfݜ䈓åêT‘—ëe¿ZLeï]™v;ƒT÷~Ñ—jË~éáí÷… Ôq/èIë:л@,’J^�&¹­Š¢8•’�RFM�˜Ä.Tm”ŸØw\¹˜Ä$–”p·@ÍÒÆ]ÑaŠš¤÷hÕ¯¢ïVVd!ºÌ>ü@Õ$™ˆ°¦5“4$e·Ê$ÕBh·HNÑɪ"(Â@Î}êt… Æd†÷r`0òàð¬ùââêÉÙe·8aêîÑu0Ú´§‹z Ø šD ­†[ÃÝY1Q…>!‘ƒT‡:ŒÉu¡ÜÒ K¡íE\»P’ª�ðÈÑHáž‚¢ì[pþر:6§æÚ`¶Õ8^ ¶Ù‡ïñø®|Èi³Í1[?çâ¿�*$[;bÖI2g€€{µ�Òs®Lï�õH˜H5àÀšn)€ÈIUáæS˜�6mòêdóØ×Ê¿ùø“ œ<(ÊOäŸýéÿ×ÿl![@TF•ÀxèrêrŸÙå�QëòÙÓji³^COI‡â‡ñ:£Rõˆ×Ý¿÷ß\ šRŸ¼Àóêq’œ;<{òø·~ç‡�ž={vv*ÂÆôÑ~Ñ }—sØ�INJ�̹V¥Â-KØÞ³íÝÖ§2N{„{§¦é°ß漎2™›¤dÓ~Ñ'#O6@j¿€JY`%D¬–®ß˜»ÀÙe ëò ª€ ”Ìf½Ëý2˜7bîUu4uCÅD›H-LµÞ”]I:¤Ü3±“œT$wŽ}—uœJ¨³2�j2µ”ÃÐ/krÞxµ¾ï šsZž®5åŰô:Rdª¥Ž=J­”á볹k¢d<4:Ÿì$( �R‰¤%¤ˆî½i[4¸#Ü(ɧ ídš¸8ñÜr !:W’‘Q¦[”ŠR`µ¡¬Ð1ÁÖÙÈý@BIú”E»%å”á6�Ò&ÓëGÐ0wÏ]ç‘$÷Δ˜#—¶1Z¥Dpâ@š¢äEfÝ‘ ¥4é!· ˆO&–`¦ýÂû•hL�&^)†hôªºƒjAë ™QT•2‰Ð¤ƒh 3AmM·6 < Žc$–™¿Ö�ª�ïÒx¾Ëæ<^�­ÿá­]�Ï[¿t¾%÷ÇÛš„3öÙL½y¨Ð[à?º«#˜,OVv{«Ž$êu¤ ¬Œä`Òž¸ÔÚ¿ýã×øw®�FÔ“·ã¤¹~ð;?}öáÓ’fR3EÑt9;UMHJÑuRiü7‡ o)¯¥K=Œw7ÛíÍ›»»}�jX¬Î–Úáôñ;š—îµµ#Ý‹ÓݬNóLb:lû`¢ã4&Õ$k͹N7æpTÕ$’D@Q‘�*„‹æðe’.ç„ÖV’ä9 ª�‚}D¸•Zá“G$ÏIIjê]¨ªÕjR©ÕZÆbæa)i„±Jc;t·”¢‰$5# "a¦¹s3hkB#3…9š»ˆ öm�Õ¥§ Ç4PCré´Ë ì õâ o”ª@-Œ�Rb�;×µ# ¬ñŒƒç,Q©{FEu:Ñ4[Ã�j*ª¡#µ:CÂCØx·Î¹+5›í,þð]Øæxù{éБøü¶Þæ‘=ÞÚ÷÷kÿ[Ì¡½ñ§µ}8ÑØs4,‰l´£ùµÐ‰ =¹KrI‘í´Ý¨$Æ’’j wσMãUl?¼~9þëˆËÿÿûÿù <Õ½þrxòÃáý'P…(�#(÷: Q«ID@5`±z‡¹Åõ«—ŸüÕÏ_|óE­ãa{'©ë5=~ÐG¤! ý$C!nÕ€0+ÀÙQ¢ã,JaêÜ+¨ÍÝÌ-§Áýq›Ù¡G4±3‘M)�ÒfXy�\Hw! ÞE í¹RJî.¢ $Ú¬fwërOš¤ZÕ^#<Ì"¬D�¦i<Æq/dß©æ¡ÏšêR» 𔥵Ðn_n¨E“Ûhzl,ÃÿÑ Èî�T»eŸnµÞÊ8¡@á†YÌáÁ±ÂTº=u ÉÇÙÔ¨L (Ì.uw˜Á¯§WXGN¢{¤…èÂIaïP÷4óØÄóÅ[óÛ þnDZc8bZÍîœÓú�By?öLjð€ 1gSÑL^fr]~,€�°Ôg©eêR®‡-+$ž+RH‚¥úˆÜ]\|~n7þí‹òè ü§ÿgÔ÷Z }F›vDâêì‡ÍøUÐŒÞêüþš¯ÖÚ�aN0¦1·o^}ö‹¿üøW? KVª�—Rß¼úvõälœb1€’ØtœU*暟î•Ý2H½'â?1ƌƱ™PXSÿt"@= sg­=maBD9«Œ$ÀJhJhº‚ÞFïá¡i¢Ž* …O˜ÆÃå›Wo^ݼ~óònwÈj)óôôüÉÓÓÍúQ·°åz•  ƒ V† `„´!Iº$4ÞÎzÄL’üN~0ÛD@èÝ(çššG©{#4˜€«(hïØõ®®*môרµ°+èƒ6"H@ž›šJ, ¸§…@\�P÷†YÏ`î'[zÁæôC²Â1y¿÷Š·ÙR;¾šJîÛRÇè 0çÌžŠ�¹f˜Ñ¡æ3ÖÔVRN*Yz‰aX¯ò4õ5›`…€ö>Õífq6ݽÎý?W\¼ÀÉû@ õxý‹º^h}‚¬° J‹#Q�íLÇÜÆØ¬uŠYJÄÛd”�û»›Wß|õb:L@/V| ÀÍ£¼¡½•M • ÃHaRBÕ¹C`R13̶ݼ�HÚ&ðÛÐ÷,‚�ò|L½M=Ù~Î f†‡¨= ÐÔd9+ŸaHÔ*"SÙ¾þæËÏ>ûôÛ¯ß\]s»+fQË~sròôÉé»ï~ôãÿ�ù´99U4²™´—€lJ£ÇÐGh‹ƒzu�~/zÌréìyy´A P`’\»*^A›¤Žm�%$)ªC�Ô�õJeRjc¿5%ã>¨Ä0ÒF@Ôn#u*Õ%;zJv„�$-uKßèúwÜà¾]Û~ï~ì(cþŠæ7p$™ÛJ:ç>ðüX~t‰·“s¯¬u€ß($ôÃÉ2uئ]š Üh2è  F ‚•I­Ž»Û«×o^}öÅWûí�‘s’:Ý–iÿÍ×·¯¾þöÛooÆÝô£ßûý€��<§XÓiòiˆ9UÑ9œešSæˆÖ8Ž�Ì}³Ó¹÷Úo¥É>0Nqí$ŠH†[“=Ѱ@åL"`K©"L€€`¨ ‘¡Ib¤M¨…S'M�ÈÌ.Ù™AF$‹n>…1K¿¾=oÇ!1§wÜ›~Êœò7@‰ =>PkÔ¤9(<8Kb®Î)ô·‡æÛÆÓzÅGOž.xþæË×IÕ9¦Ø.;I‹®?É]L%ên:M{©/w˜z° €7ŸÉËK¾÷þÛY(XÃ�s\Ç—>A»öÁ½}ÓP…[Ùïw—w»ýä`-cqé5§$X¤Íjq~¶†…ˆ€™B¡"‚I$”pk[.Zµ-MÇ©ÚTYfpà¨D3K”%�]oe“Ûçt<7£åLB�0¬Rd–Hô€R4‚2§¨  Ÿ ”6D B„õn(Óhî4�šT“Ç×_¿,ŽPþ´ûƒe¿Z,×¥Ïö-ªM\nŒ"ŸOùÙdFCè©¥F™ep …ÖþðA¼œcaPÚX<­ÀÊìùB׬am£JÙ‹«xwtq&e¢hÂP ÑÆL’*C:çBhEh„4 m\ß™»Ï‘ü;gÞŒ‡úäÔ@‹Îàqø&r£¾Þ¸z€È ?à»u‡‘>úÁÓ¹“aè÷ Ú.YœY“Ö¸ÅaÑ<Œ€2!*ãF¤e Ò]&ÂCÑ$lÓ,?Í­ÅLhÃiª‡(Ìf½;úx³½½¾‚˜•ZÀÔå5Tßyïƒçï}ôèÑ{¹?¥è}IE6³VÓJêÃ뜔D%ÌZróº�9``Ò&�IÑÕððpQ}0=Rç:Ç@I÷I̈́I¨Âj@Dh!”$anmF%-–�«ÍöæU�Rë>B DhÎR̯.n~õë¯ÃɰXkr¢(#„*mÃõ éF�#\ uÔÖûè[X¼Ý¡Ù�piÙc´«¤×ooêc÷�y£4ErÉ­©p3ZÀ%(S%n#ŸsÌ4 ­DE4I-ˆ"0�PC ¦ªR]”’ƒ]PHP"Äg:¾%A|·”…Ïs&Ç#o®yxÔ?n)!ÛhÍ<%Ðæ-íy›ðÜçEíùšòp’XsÒEè&CŸsÄPÜm_)}·tà¦Ô¡ÊÐût8° ®n¡;”%ô)|£mAFjÃ�m&T›Ê#xôå9r$ECúÜ 7@­Ôýáöâö¦šY}¢öº\-Ö'§›áÙûï,—KIÝ,¾9kYÙ½:Ÿ¨†WŠÌâ{2/T8ò±€á1Gž/ ÃÙ{Å[í.My¸IFg|$Ü›èP„‡‡ä>æÞ) oë2Í܃h|H]R·èOŸ>y>ÞŒ}ñõgÕ)°¤9r%4‰«ÄÅÅ7֭χßʃ®×@ßRDBæ¢{f`Va:η*aq´ŒcYyÄÊ éÓ¹iã€Vçe D“ùmÑxF @�®½1×XD;‹tT£ŠôU±'À0¡HÔ{‡„(²¢:¼ÂÆ(» K÷(ò’ºhd¬`L$oäD׸'S¼MƒŽ9üý[kêØÊj2?³6)›¬·¿Íü9'�íh�Çx+!úüOÿÙª¼0!öW¯}ŸLzº$Qj—³—ÒeaPÅÎV½Ž£™ãÉ„G€|Hÿâÿµ{º^ý½?ª‹O¤ 5Ï&9¹Í§SjËÐoë�¢p¯‡òå—Ÿ}ù›OÍVC1¬Îu?öч?|òì}ÍY�©X­Ø–Ê0î�E÷Û*@S"F#éËYgJá´ª€3›JÓœùË\wF4Éòy ϱ žKQ9~–Mèx–áÆ1»$)šZ]ž5-†¤¹_å>K¢h“,iWË�q¼¹9ô‰çËXõEuEÑYûX„*�H³ ·ÝÒ6Ð’"¡)]Q•€„IcV!o9ø<6+Bȼg‚ó'ç"<ÅLÁ”Ƴ9–E¨S„.>¦ºçôZê×/Y¿A¹Œë/X^Æö«Ø½Àôæðõ¿Ú¿ú‹^3êÄ:Ò[1= *Â`Cáæ½G3‘ú-¯÷—�-âï0% �Ü÷ŠgõüùÏ8s°��5 È …¦ûßýû¯>ÿêæõW¯n/dq¢Ò÷åÊá)\“[—Ä% JqZÕN}|uô†ük”ÓáeqRºS‰6Øb•QPD¢ æÁ ×ãü^k\øœ”8ÇíáÍë7f]2 ç…d?=}üäñ“'ÏŸ¦$Údï�õM¸ƒAQ÷Ê–ü±­&œ™´ÏIˆ&8Ãc¦NH˜Í|$ wD%gü9T¡?xLÀç‡1M­à³²L ¼Ö†ÍÙ"" I›É9/—ïÇú¹ˆ2 Ú�`ñLò&Dœ ¨rÄÜ߈8ö�ãAæ.«tžk 6.6gG »ûÓò]škpGŠ`züÑ�7''¿ùUzóêëTwv½QBó8Þ¤Ôg$õ°HÔü"ÒÕþõÅôç?ÇÏþ—±;È^匱2Z›ÚB£pp±‰©•ˆ°ë9±T€Ð›`ÓÍíëË‹]Ÿªƒ’sÎ]—7g'ï¾÷Þf}.ÒA€&3)­•`mC%9Ü]è$‘ä¾Ý¨­ßÅQ�¿µÑ)/ÇP�ÖX@ v6æÛ¼lì¾,ŽQ7¯T%›ÙiD“[ôh�RA8à­zn5 � \PU6›óåÙfÜÕÛÇgWwûíîæâêÛÃþªZ?N|¶Zž^É›ërý+ô‰¾ÿG8ý}Ã@7@ÆJˆ“ÙÀ@ðcglj"ao5òt_G†ÇLfãdÒ� …ÖÈk­¢¶AÐI¸câŽ(£ûäÅ€Q^xxÉñ[jvs ‡Ð¼Øn_n.cÚ£ËjîÛßüÍ�¨.ש?“nMRò2‚ËÍ“tòL†wÒêq¬Ÿ1mBú@ v :€.6âyë8Çî; G–ïAU¼% ñ¸5°±FM±~4äôh{ûüÛ]E|üÉ¿ydY²¥¦px-aïX·ãnôráÝ�íõ5tOY8acH£^Ý7&BŒ ¬�M#z¥‡ÖŽð¶ fÐl‡Ûo¿ùÚ,YÆ:I¢H¬ÏNÎÏ×›³%U¥Ë ¢K­#(ÝX+ÌŒ԰¡™ÒvÚ5X ò nnãqä�·EÂ=B¨ÇÒ*’hµu¥p/ü-D“ƒ.˜[fР湻"•.õêí¹�›äŽ)‰®éÑuCµzrºy½®‡ßÚm_^m_ï/.~ÐÙc½­‡©Þl_|vZïúßy‹‰­4‡×�Áц�œ€À›;Ø17‰�èó>›�4oN8ޝÄñs˜™É0ÆL A!8ÀJ”ý8Nu?Y¹)õP-rÒ¡§(Q'ß^a¡¹SÍ‹•,Nãf äîÑ™E-7—œj‡íaì¼Ä4:^u¹Ô î_ý™M¾X�çõ�týÎðäY:û¡,žG~Fz¤…JŽH!3ç/‚2�ø·ÂömtŸücžSÃQv3,Æ£"òܼI!ê}ß ë“Çï\^¼û|q7=_¯o§©ŠGh°Nˆ¨µËëmŒÕËu=¼óòÊ|Õ�$€ ÷ï82‘Z…Ö”C ª%[£ÒŠOŒHÓ8í¦7¯/sNm«�Õš‡ÍjóÎûïxúä}¦ž’<‰É¢!î¡>2�¬TS· o‘!ÚØ :Gô¶Zx®›9¯LmZÛ ’ó¼v˰½U&ý¼•Ì퇀ÞfXŒÚC"Rìæ9¼ ú„Z[DT£’Tóª©oôh$ÕL«µOãù³÷Êx°ý»w»›ýËŸ?¾þ¥ìÊÝÝ~{÷z¿¿ÝýÌž°_üð–Ň¹;•n¶aV6ê� [Â�a¯w!zÌÀÚ6ªc"o‰ Ç]lÇ8êÁ¨ME™¡ˆð²«ÓöõËׯ/o¦»C�.W]Ç~uv’ÒéJ‡!¡ÐnZJ)pê°Ñn9jÍggi5°VLcÜ]R$É¢le,Ìu¢¸Hç´¿Cˆû~ýÉõy±y·_>éŸÿ¶.qý!ò¹¬6€†äàvÁ.�ã9@7ò¾&¾_ÃFó¦¡==¼Ï’@‘Hº½°åIwr¶XÈù“çr~öæöÅÂÆ‰!NH2/Yû½û�M*¢^û˜o_Ÿ÷'�ïÊJ§2¢NèâXa?(^âx>�€¢M­‚Ñd ´n¯¯oï¶YéVSJÆÈC~öîã§üËÓ…#[À©MR‰,¦š$$‰TÌÃe¶ =jAJ2 Õ �¿�¹›†#šrò[OÏßyö4xR" w·—0»½¸^®z¤œó†CNÃ@›°ßÆÕ·7š;÷èºÎ#¸~òÞpúüæ7Ÿ¾|ñµ�%:¯¥8}ww]êßÄ'}ùÙÏ>üãÚ�Q’M�ýˆsùßmg߇ÜïÌ;´%$u¼Ý}õòÛÃx·7ÀÇ~3äayròt³9ñÔ8žÞ>`ë_ˆa˜ØÈN jÌ+’�YX'Gq¾˜{àM¿�¸ËÍÅ!œWoÇ|‹#94Й‹VA H„@€h+‰bäý¸:ôXD!Žhxb›Îh¬;6Ô4®¾¸úä²íÍv{9•qˆÍ9×ONN?ö›7~³�³é"}SN¾Øœ}ðèùï¤!‡á0^ûݸ¦òä‰ó2çïtÊÒ 6Ê> Övu¬†"€ð€ÃyØï÷‡ëñ0½yýíîj|}ùâÍÕÅ8Z¯ö£üàîîî°¿œww×‡í·—Ãþæì§ïþiRNîÕ¶ºÕò°/ûí¶–ÚiNò0DxÀ0aÒƒ.O Ãww>•ZÍ)è†îÑÓ|òXo/¢_P,-,iª#wûëÐ Æ—ŸÿìÍ‹�Ÿ|ðÃ'ïÿhýÁïç³�ÈS.N#÷О"³ÂÜÑB”�`@¥õÒª¢Ò VháaÖÐídT©#Í0ô›õÓ/>ýùùówË/>ùµÕU%I�FešÆ:I(fØ 9�ã¶Že×äw Sœ)Ó÷4pÆ[/@ÈÓÕË_íî¶0 GׯÈè»ôôÉ"/dBöгº§ñÍЩ�Þz�ÁÚB(˜¶U�#AÇÁ¢Öõ9*ÌfíxlšñÇÄ™ÁìRsßxÞy,&Ì%5ºþœmÎo¬�çÜ£z(Ekå0BŽDµíÏÏ€Öéö‹_n¿ø¼"Bs<ý¨†ÕòñÓN7‡Û×±ßþÏûîôU‰»áôù�úÓ?ø'‹Å{Ãb³7X)b×…ÌÝÔ†a5+‹æ´ã `€øx ŠÕ2înR§ûí8Ž7¹ëK)w×ãÕõÅÍÕ›Û«7Ó®TLJÚ§SÑ~s²`<Ú×*ÓaÕûiž�¯N×Ùc_öc hÊ©RNYXQ«•ñPË^Ý =3X dº»½\ª†9Swµìú““NÎÒê¤îï¦ñV‚»ý¾¢€—¹Ëõó›ë—¿8ûê/ÏŸ¾ íûÕºÓ'Ýù;Xÿ�ýÙq‰zRË5‰H0 Ca%Â9oöq&åQF%I µ\mV§§ý¾,/_j¿ZXµÃÍ�Õ]Ù9#ÊD=�»ýÍîpØÈºKy¸+¥Ì#po›÷ÌׇåÉ1¤‚ÀŽ/¿úâ—ó$w"'¤TršŸ>{ý:"½ÕM½/+"@!« ï[k­„?>öÀ}þ9sÏç{ÎY»ÝÛøÛ©Ñ˜%]=ZÝ3¶Ú:ÁÄ2aMU.C„Ó tL†¶Úé-Þ8wdǃA¡àp}ñÉ¿žÃãE®T©LÓþòò¶¼æX˜Öww»ZnV‹3üò_ý×w7WòÇÿÉæéûË“Üò‰Êy&`–n<¨D•˜î.¿Ñ¤C7Ü\¿îûT§zs{»^,¾}ùåönì†Õ~{wùæÕÝÍ€ŠNÉ&Á|ÒuOó°È €Ÿ®Ïª]/¦7ï/ìäÙ)³T«@u†ˆºS«MoMD™Kw×¹ëtèiuÏš)×C•óGyèê~ÜO—ÓX»³§Á>¯i}fø¼L{À„ZÝ9Röãt{ð»ÝÝ«“õÓ|‹t7¬Ï7Ï~²üà蓟†nBR´ Õ¡â;X 3”ÒÚ”A=B ŠÜ�ÀHs›‚éNr=;\øÅîºÏù°èÆÎS^ŽeÇ„4úö°;M‹é0ÕÓõXb=î!‰%0í¤cÆy[æŒ`ÌlöXݼúò¯?M»Ýã¤ì²w^^{–ËåêÜØE+"áá¿yÄNÑÈFtmRˆæ+Bâ!÷#yÇã‘o/)÷åJ̯Yâh¨Þ:º1H*ò¼œž¡-É¡»C(Q›Ì ¤·‘�µ¥Ym@Éç–çœÑaܪ^¯Þ4ëáòe=ŒæŸ¸Ûš›õÔÀÝõ6¼žö8éõã_ÿù_æüïü{ÿ›áì¤.ؘÎ&…’¡‰d„±Öׯ¾]÷ƒ¬‡ÛëoGh)Ó‹7¯žž={ýÍ›«»k’ûÃ�.!ÚQCòЩȲëûõæébVëG¡X ¨šž÷ן ¸bPËxÛ–ÝMãA».ç¥Õ‰ªÌ½Óî6ÌAuMu,»«7@¸dMËÓgÃúì±ê"ºÞv…y=,j)ʰZïÞ¨©×ê¥F‰(²ï†UmŸnD�¸ÞÝ|½½y³zùåÙoý£ÅOþ×�A¡X�²u·y4E„"!­;¬�™ºï¥¤€ƒ¹“}E¤a±~ügçO¶¼ µñöv‡$eòœã`q`ÎS•ëýíɰì†Å€å–0D¾/ôÞö®›ÕòX@äzµûòË«¯>Çd�HÀ©†!¦gÏžèò¬bo †cŽb÷<y z·¬³7Žo»…÷b9o»$€»¼Å�gžá1ßñã Ç=‹®�“D¦‡Õ=Á1ó�ýˆ)D"K«G �6M¡Ík&ß’zÛ¦ÞvnX ×ìƒÝJNžçÃK;ì=ê4M¤ŒVjT‰¼¯Ó~¸Þo›òäöçÿýå“õ³?üO8¼ã‰*ÓÞ·q3íº`š`·w7·Ÿ~ú‹�žp÷æðñ—_.ë——ß–qüF?¿¹»\¬N“H–^³ÂÓf½qÁz¹Z­×yyº\Ën`Þ,ú¾ Xx½æîk¯7 1�¦¹§³Cçˆq¿3»É¢q·?Ü^ïo^Jä—ß.?Mý¹t¹_õe4í¥–»Ý-X‡Óeî×î£út—¥†Y¥yŸ¥úÌ},ÅÜî†e·;XJw�kAT�í¯­ìöw¯ž•éäwþ}çfVL(aET™R@PŒð(“W?lw»ñšeŸœ)Å ’‰¤]í{¾ÿüƒ/ë¯�'g�:;äñæUBWÂS-)-5Á}Sßu§‹5ªö ñPý‚G »ïEW½zõé/þz{æÉ«Š9j¬N�=}Ýà³œêƒ Ø\˜wŸdˆE�Ë÷žJ;{Â[÷;RŽñãÕcªö½ÿÖ}ÞÖß!°�ÄÀÜ•EŠ4tiy^çùöòúÅ')R¦V EÚÅ.«j‘ ·v·èùáb½ûÕŸ��?\vÿØï uÚoo¶»‹jš¼h^B0Ý]ýâ“�?ûôo¶¯¿ÙMåv{·Yt¥Ö€^쮋!§.wºZ�&Mý°X®OVCNÃjÑŸt‹�äÄyì$ÄQF—‰Çm­%|D×G8:PP–b¬±¿ô»Ûz}Wî®Æ»ëÛ›K¤Å‡?þ}ô)åÕòü\S†ÜŽ…fÄvwg“IDRÔšº�vW¶ßÏ.)!Ø×±�êMßwf$tšÆœºýáò›¿þ/·7g?ú·dñ8€�®£¤9›[­ÓÝõvûõöæî°½­6%2�áÔÚeY®yqÐ~µxççŸ|ò³Åprè·!]ª�y˜áI$"M¥ýVä°ZåÔ÷¹7$iÖË€{n÷l's:”§ëë_ÿzûízK%’#$œäêôôüÙ»UVĽý[»¿_kp�-2\�Æ×fÞ˜8îŠ#�ðžgÛÈèGDôÁ¤þîGßh�â�¹ÓÛ>Zy³Yžäº=ì·‡jlÊ«n‰œû¤ ßÉÝîö¯ÿŸI§îƒÿ Øo¯_^¾þæÕëWÛÛñ0î ¾úÝÝõ'Ÿ}®‚«ËWFU5£˜OÚõOß}òôñ³@ÞlÖ}×ça£Ò¥Ü‰¤h‹=Ú"= $Qõ²ÿ¶–‹´jÙiJhÛim ?ĸW„Xl±ì2žÜÔr¸ÛªE©»ÏþêχÇ�Oßùhùè‰èòô馌qyñJs7îFß—ÅfðŠtý*éj±8”ýx?=ˆÅ²ÏIK­š‡j%{H×ïv·9÷•w¯?ùR–óßþY‘ZøópØáj{{»¿»o^ÆÝa—¥Ó$‹“e2$€Æd©K(€Róróî{ïýäòæÕ³çO§íåµù¾¸Ì,nᇑ©ÀÑŸ¦UJ½†£›gÞ¾Kæþn%LÊ.}õ›ßüÍÇŒÔU/"”b)Ξ<í–ý)ü¸9ä¡ÅãÁ£=|p3cÑg‰„#ß{I§¡ßO'}�‰Žï²sçÃCfªýý#Ï>&q$ƒ8¤5¥<*DµiêÏ-§Êc%в*€6ùôùõ×?ó«Wºè¨©ÜÜÊú\U�—©¼â¨©_M1Ù:z�l¢Ë'»øÍõßü·§Fïß¹¸ºzñÅo¾¹¸¼yýrWÏ?šÈ뻋#¢ºöݰÔÐÄÇ''yÕ¿:éž>ÿðƒ>XnN5mr¿•H �h›w«Š¶%[V=èÓÝ›Ýå‹®O2xê;€°IX»NëèbwëQ’h “>úÓ3½|ÃiI!õîåKPßûñïuÃàV#ÂbUó°ÜíK�.3GÔ°*½OÛZGÖˆ~&I‚¨îBM"’¦R­efãt@¸ª½úâç§ý±,~¬^n§ÝÍþîõþfwãÕ5X«™ª®ÏŸœ?~2œ�'Aqä*©‰Ò Ü»A6�V×·o¤ëT_ßNy•½Tö9ÂOßþX¸»N�’>y²ÏSjÌòø[–úÐ^¨w»íñ>š<’‰,Vwe´}çÃ÷­?�™Yô lÏdZ/G5àY³õmt?¾,¹§†|×øÝ�·gÅC' ªÏ¬yiÖû�—®o©½(Úm0 †(q‚LQÊÄõþ°^\_<¾{õéþðº#ºè‡¼:;·ûi,::†:ôY4…ŠªŽûëÃgÿêpùBßýÓâÛ/?þúr7v�Ÿ>K)ï÷—‡ib ³éðøñùz1¬üàéÙã÷ßÙNf‘sç]g¿ônf®ÁÎm �¯Æép°ˆRë¡îî¾ý³ååÕÓ秉îVÏ™¥ d›ˆ©j°ŠY«v}Êu1äi<ìö‡.÷„]¾øâçÿ¿ÿö·þàO–'OªAEÃÇ`W‘¯oîDλNk=˜ùZò…™9H’¨)�ÖÎO³jnešl‘†Tx÷êú›_�o~u:Ü]îw»q·Ëè^tчw]Äæäñù{.ÎN¡)Å‘¦h¬âÅú¾ôh}õ*]ÜhÚ/–tŒe¿X,°»~ç½÷stùÃ÷xþxZœÑw¥–ŒïÛ¿oFâÛé—¿Ø^|mÓ.ÄÝçì!¼ÕnX,V £Ì©ÿùïùÀý-òýˆ>S½Þš¼ð;Í„ï¹S¼•Ì{øúÿŽwD=Žà_•€2&å–u[yâžyõK÷jÕÌw"-éJ,Îh”ƒv‹Hƒž Oþà?8Ûm×/^~ù³W_zwýõ£¤šºáô¢’Æ< îÒ÷B`¹^•rw(ûi¿S�iújÍÍÙêùjºâxõä��6gÏRÒ‹W+S7,ÜË{ï=}úìü|=¬†zþôÜé«%B$¦­ïöÔŽ’]­õ›Ë»×—ÛZ}’õv·ßnûºýäÓ¿yy{qÞÛ?ù­÷âÓí×J�Fs©)«Á‰NyGÉ·â·'�u:ä°$©»ž/óÉõÅËÿ¾ó#J¶Ã�ÎÅjyØ�º™.z¼‰j;‘ !!z‰ÃTï’&T”’Èèû\¦$! «$ÍSŸ†åzýÛ«gçO¿ýðÛ¯>‰iÜ^¼v–Ë>/¼V˜Ñ#-²ä cx¶�±:ﶇý_-ò¯»;ý¾¬—ÊzwýÆQ’j²ýO~ëýŸüäÇËÓSílo^aæPÒCV$ yÁépšÆè',d³J‹|Rm¤¸$üþ3ý䳟åzñ¸ßòz‡âE¼D­™©8ÏóºwÍm¼¹È½ W¯èºÅj±ìMö¥XÇ“~µ½còOþWëGï’ÝÐc{ûFÓ€p¤N†w*¾Ýãzð6lWB’jÊ‚&ßpÈ~²>+”)òa* Œb>NÞm äS5Mç¨ô¥¬L„ �ÎÇ1©�j#›p’(r*¦©[n6g>:Þ^¼ºÝ›…[Ô>§áÑãXv›�žæõ«õ~Úï^¦›ý#ÉfG‹|8gÖ­k½½ùÅ/ï®/�j¡ŠêfÂ}uvý“gèêéÝ÷3�{>Ñ÷fF�|öïäé³1sÄ¿Á{[31ùûËFEbîÏîGç8$†£Mk¨ns}9]|y}ñÅþæëéö›}“Üú܇z×÷Y቉‚ªªtwOà�ˆ`î|¿¥&ê"%cyöÎ�ßÿ]§›¯¿øæó¿¹xñë4•�„æ>1ÌÊaïáº}óz7VéE„‡qúöõµ…<úí§ýüúÍáöÚ¢ôìþø÷~ü»?ýQZ/@ 7x �Ôo Š.«u ³¨¤ÏýbÓ§³gO`1!!*Ná�ÿð÷Ÿ®G¾ú•í¶DfJª‘5•±Ôô“ Í$«¦Œ:’”ötWÖw—o—gÏ>¸¾¾Jʱ¤q²/?þóNž~´o_¿~Ñ g'?üí.©y /,ô06Jnt�‹”H)§Þ™R7 áîV+”Që¤aÐa)Ž�¶-Es;Þ'æuê‰F<v×—‰µÒM¼ ú�´ X’îälýþž]Ÿv»Ï?½¹¸ÈËÕ¡Ng'CÞ¬öƘ|ôÛr{8îVë�u„¬ÞZÿ}œn�’¦¯_¼úâ7¨DT�ºÌz©Ù»§¼X¬O‚ J0ͬþ­ÌçþÂÃ2 ™¨øÌ5;îÙ|Û‘˜É¡�8Ž)·9�cì{ÅB%=îE<‚½Ž ð¤[s÷âg/_}ùæåç¶¿RXDÉC/¹ƒÂbJ°p†¦Ñ¤V`¬±¦�ëg?wÓx™„uÌ’’` »µèH�˜°5æÕù�~wqz¦¹ûÍ'ï¶oÖ‹aØ]椢ZƲ« §(óÍõþnG0¦_¼”T ¯¾þê£gÏþð‡�~ôÃçiXÅxí¢"Ë0¤Õ˜ 3@|*V·šODzäNÙ!¨p¢ŽQÃmLƒøþ�Ä6/J侯åÚw>Ö‰*yµÌë­:ê ]§©èiyvvµ»Ý›ÙíÝn¬€íj¡äén÷ñ/þâÃZ%yÖþdµŒ€[µ2Öêu´œ9"¬†+UбÔÛíõ£Gën•0Mãþu˜äå)%Œ”¾_ÇáZûM��.À¢«$ëQ"ç�Œ€d.Ö–tïÉkl#TÕ¼º¤.º\�îv¶9ŽnµÛn¶ŸÆ‹Ã>.Þœö,v; ¦É`‡{íêïØkcAbW>ÿõþê%ÀF` +t¨pœ¦­žož,×cJ¢EÛ\yë1¥9ZÿmŒRîùvHc€ñˆGñ~a,î«‚y í} Øï7J1û‘xŠ#m£1&æA+Í»nübûòçŸÿâ¿+w¯îî^1²Š»Œš4¢«6‰1DÝ,vW‡Z ¥8˜(!ÝêüÝå“à¯ö_þmZ­Ï!ënx*°nX“‚èÌÓä{v'ç¿ý'ÿHòÉ_ÿ«¾}ýúÝõ"k:ìoÊX-èµâz·WmpS™ìã�ßÿíL6½ÓûONro6]”q× ëBV¤nÞØå›lº‹”¥[‚Š(0‡(SBiÃòÈËM(¥ì–gç\‘2ÝÞ²ÑÞIj™,¦-ÛÎWTäÕãÉY¦ÉC»1LÏŸ�®yÚ¬Üvû륫•ÃÝ•–b/>ÿE߯}7œ(ÄÍ›Wׯ_ ¹?lèÉ!Û4Šõ]ç5"ìv{µÔÓD�ê 1ÅnrÕ®K KŸ¬“t+äUŒY4ÀΙ-zÒR—¤[&ÖJuØ,FJ|"�ð æõr¹·÷ÉWý­•OÆ�•¼>ìãëÃå¡K½ôÌúíuDçðû¡°c†M‡Öîåå—_|­¡£o[' ,¦-&íñì½÷—« ÃUÙvy Ðtæ�ˆ�¹Gû’o}ÀMËäÁ®æY(8Ž¤æ·´ˆFw›÷O‹8¯Á{¾Z¼]è�ò6_ÿâ‹_þ7_ügãõ§’ª”NE%¡ÆÞöõZ wF7'"L4G„¶¶ÎÍŧëÓço^yõÅ_i._~º^œ€º</Öç§yý;0GH)5ÌÒÉ»ý½øÙ§¿|ùÉÇé@Og‹Ü‹½Iš÷c)\ÞY8`pÀ ÓëÝ¡|òî“ó'§Opº¨^X=u½ô+tRnûlH�GÛT™Ûb/õ°ƒ‡vÚ¦F¥ËÌ $²V7g®IºEgiƒÑ:û¨1�; ¦Ý¤âÔqùdeš.Å«óg¸¾A×ê&_¿ºJÝpºZ¯÷µLÛÝÝ¸Û kj¦{î¾½»¾Hš'�Ѫ%¥&­¤íg‚—øÞÃÉk¿½+á—]^õƒžÿè£þô�¨Ä(nÒ ‘¢¢+Ò$Ï)t�7é»ì�®hÛ½î5º¼(eÌ}—J‰^Îk¾žÆÝ�Ù0 ·Æ}*µT;í”÷�Ûû€Ë¶Z2^×/þºìî® “.7Í4ñ;{þô½¾Ï“gE—†™¢ 8Q”0'Å‘�ÑÃ÷PéwZ]†rÌåÜ~ÿ]¹Žú.�¶ | %”Å‚H—þÙ_ÿ˯>ý—ãöÆÖ͉±S$8Nû=ÜÍM”e‹H¸Ñ¡Q£Sl÷ãÿøßÿçSeìj·¸Õ,Û«W‹ûËOÓrq8<~ÿ÷>p÷éP(‹i*ÜŸv§?úÉOÿáŸý«¿ø||“ñÍŸüî�Ÿõ�÷˜n·åú¢A/¨ŽÑpøü°Ý½üÉýn×'I‹4,$/!¦qKIÚ )gèv˜¶—ß¼øÍæäÑ0,T¡¹‡tGªa¥VbÚÏA‰iëc©æÆqX.Q«×‘Ý@kélu¶>{Ö/ÏÈþ«W//^^£_¨êúô4çþúö°ß_=}òèÉæ½ÝÍõÍÕnqù:ŸÊÕËo®oÞxÕËëÛ2¹4lX÷ t]¿jŽnZÔ.¼\_¼™ÆºXö»]Ξ.>ú©ô›©N"C6¸T©šÀC�lSÔMyÒÓLP …@ ŠJ¨7é­Åp¾½»Nz8?{vw;¢Ü-d-T«u/è%…¹³w]¶NÝqúÅÁ ©ˆ-KM¯¿¹üú…‡©JŸ:(4Z�}‘:,òïþðgO¹F` ä6½Ñ”1�dtbn]hrâX|§H�{ú?ßVá ´9ø·µó=àó€¬ú6ÿã<:Îzßô"#c›ößÞ¾üª_�tëóÏ?þ¾þôÜm¯ÄoÈ�û(1ÞL…nᎡGcþ=’"%hG±ãú" 3TÃë}¹ÞG™ ¶Ù`Õq™ðˆ“î§mÙín>{óå¯Rêòê½åÙk¹IãÕâôÉåm¼úÚ6½Iüêt¡ËÉ®.PGˆ€Ý¬é?N¸®¨…»/íp³ÍìtyÆ®ƒvð»;Ð ½Â©cßCQ š—«ó'OËÂEUÁÚ–ÑÃ'¦%v/=L‹¤ÿ²þ,VÓ,KÏÃÞµöÞßð�gŒ9"çʬʬ©«»ºØÍîf7Å&)2%–† H´dÀ–‹´}cû X׆ol†-CÙ”ÕQÝî&ÙCU×<äœsÄÿñöÞk-_|ÿ‰Ì–ó"pâ ÈøÏ÷í½†÷}^cdÚ¦C߀ëà]ìZJD³g£™ÏC9V“ÅùyqÑ!Ä8—‡×Ž÷¯ãù£ö4­·BðÞ{ÿè“÷Ë7Krä¨\ôÛ¤š…”Ì¢­/{?.Õ´ë{/®ÇšÅú.™Æœ|fõx _m·Ûª2Çl*^¹ä ä)ȶ³n)¿5ó ˜W ÞBCdǪ6›–ž÷CŽ‹éj»^@JIØ|0•Þ³W1“|uä³[XB·¡¬®ëñôþz¹(JyU¨õÎU9ÆmR ¸÷êkÇG‡lŠf ç‰Ë¡n1"uSC +�˜(±hš\‡èœåêOk¤_hæ®n¥ÏUb´û'##ºz^¼*ÃÂØÅ:S”`>.VŸ|ûû¿÷;gçOÿò¿ùï*º§Ÿþ¬ëž8Û¦îÒ»l}ޱ͙0*A•G8” dÉ£Ö„�ˆ²XŸ0 Ö%¸+Y,{4 eI¤ùéOþÑœÛ^h즇£zÒwÛ¶Or¹‚VøÀÒk7!*"6„2ö 4=6šŒÔÄ~ò³‡·¾üÎþuÀš�:É}Š]5V3‚÷Èåˆ0ì¤A.L�-'˜ƒÙ.vKáPŒ©�æF\öí£�µYzr:Ú×¾7€]0Ó(±®&áæK“—¾´nÖ«åfyy²ê´Í¼júÃÙ‘qqqròüùÙÑÑÞ�›7?|ÿÃår}ãÆþèhÒ4Ë�?zïÚ|šRNMŠŠ¨Eá`L3�³šSª¦k»s6oR¹ÙüðÚ«óåÅz4¶@]¨¦Á»ÚQÌ\ƒ””ÀÁÎàá-'òü¢°V˜À’ ˆ-y W¸ØÞ:¾¶Y-5¶Ž½õ)‹«ê©l9õ´=³ÃÛdFqciãÚžDÈœ??;}üØ¥h„ÌLŽõ9]¤íõk·nß¼;ªæh;%ò[ó<#Ò)xX€p¢fâ»­Œ}æŸÅ�|®%À•õïO­¢íEÙ¿»>#v]]¤Ì+œ¶ÔŸPŽÒ§xqö»ÿÅúþÏ>þê×ß™\¿¹xôÓ¾=Ó¥?�}“ ìv?çQÔ|çP•Œ^…pÙc¹ÑlA€Q¡Ác\RQ¸kûUn6>£*À³BúLjžAÎG2‰'Ý:ì½�c|úäñú¢1sMö¸ì2Vø]û&‚V°î±Mˆ"H†‡�vIû5rär \åD±Ý,œ+«iMn„Ô©Ñfb)Á”bv>x§E`O…IŠd9/||jÙ#õ.%6¡d”º¼ZÅè²yç°ƒ†6]ûhyër´wèëÚÌ(õÐ@ˆÎzçÐ÷…&žä¾ôÐ`Œ ° �ϬŸ¯ç?¿Çý¬ùoYs®*¥:"ȼëÂóïw?û=“F­‘¨e}¶Y? .M¯Y19H›c³Ú4C¼eJ�’á*Ô Dߊe›Õ«¦�W3$ŨDVT…�§%ù²çÖ™²û\TÞdˆ‘Wïˆ�IÒ­º¢šV³»›Mûýïü!„¡‹0{byN2ÈaÓ¡,×H¤ ›˜7›¼ºUÏæZM‹ÅãGš&Ťo.÷G£ƒ[wîž?û¸ž__œ¯]6ë.ö˜Íkö£éxÎÇ…vr¶^.¶“É€œt$Œm'“¹O0J¢ãà6›FÍ»PúbTMç_üƯìßz V¦ûv{yñ¬ÙijÕÙ¶âm·�L÷ªrä]í FKÄ(ÅìU³#Vb�•¦ $¦9J§IÅ4¥�J|5�Ûv9+¿wpïF±¿_ŒGnºÏ#6êé>¤Ù@�¦d3¸^a™ åd®”ͳxÿãæÃw÷ßx Þ—GsÔcr£ùáµ^r¨ŠdšŒGóc%H¡ÅìHê9&½ä‹Ëåòâ<çœÊ¾¨**øâþÃÖ§ãÛóvÛ¯W«m³îúöÖí—LqzzVWõÑ­{ýóu)!f8g&DÞ£‹Ù„U²wÎ…Â@ïý8‡ñË¿ø›7¾øçx´¯ýÊ…ª¬«Él»´\œ­Îž,Ï/bŠuUùbL°ª §žªx5Ñ”‰omJ¹5‰ª–"lÚÅÔC†sp\ûI\U8uÖ÷Ù£îû>‰™DR%ó¤ìH™òFÖëíz¥©÷àH&q›²<]¯O¶§Êý½ã²òDjªîs uÙí¶T(!¤^JÚ[¤©�võÏ‹SüóM-þøÿlæI4„¬¼�ñ_ÕNlÄQž@—ÌR Ž ä¬m·Ö•\J«Òaÿî›_ùsßùÿ~œz›ÍÀ¨‚g¿Ë]HŠÊ#8(Á�úõ–ÉB·Û’ªy7 áHE.:,¶¨ p0…% BTVTL�G×ÃÏ¿ž×ëå§ßŸåõo|õÍz:)g£ËgË¥¥ËÅæÉÃ'O϶ۼm49ERä a sðO~ü4ž.n|üéþ|⼟ܨoíM®_£ªö£ŠË)ÊŠˆA²¢Å-àGÄ–°Ù¢o7Ïž>{ðÈMê×~õWªbQ7žLnß4Y÷D[SšÌ7õ\ƇËË‹`kpuqúDà}á«rÿÚµ›ÛØ.ÎO Æ®øñ¿›¢ˆJÛ´¥¯Š0Í«åE¿ÝîL](Ç#¿]fU� 3 j 1Ǩ�]å8'xªÕrÏn¿ý‹×^ú²+ffÌå-+;¡®¦“ñÞÞùé#"cRc×lVç"¹òeŸ;EÈ@¢`6É}×zX×7`Oæ%'†w…Ï’M´*tZ”¡œ”§92maÌ~jÍ&vÛY»Õqa + R¡E¿Ù,DSÖH(ͤ׸ÚnΚ€ñäàhTèKÆ››vÅØŽ ¹k¨Rœö(¼•IñÙ:ìÅàóõÏ‹âg—§¹ƒŠÒŽR?Ð4>/œN¶=ÉyË!ÂYrìšØ\^ÛŸÌ•ŽÃÈbJ£ÃéþÒ×’£¿wùü{ãUAä<| ¤V8a'˜ÎŠ>óéVOöò1®Í oÃÀN-0¯·ÆF{j‡Äh©·rÂõäúøÖ/MŽoÑè ´ÞvgϦÓÑü�7s梚fɇ7cqp çâjsyúèäÁÃçÏOú“�žÜß<8ÕDT—t°Ïâqÿùv±lŠÀ¥¯$~ptTÞ½wýðÎÍz¿Ø?¬F£dÆÞåÕ¹'góqØ›ƒG„l±K«gìÈ•…‹qsz¹yü©ú¾š™c7ž¤^Šý=7™øjVŒëÑüxÙÊÓç§Ee©_^;¾ö|ÑJê6m{!™Îöë¥f%â¢*š¦i“¬Öͨ*�LDÛ.We ø>‹™)eM*1 �R /µÝyó­ÉÝW^{ã-çG‹ó§£zê‚£2 ;2ãÔMÇÓÒ¿šsËäV›ÕâòÉÙÉÚ�T»Úyßw-ùà�Ur””bîÍ€,j=Ñ�+g¡pš1žT&ч\”•BbPˆ} *›…³`“©9Ï’±<Ù¬ÎEÍ”Õâ¶]÷Ù­ž·ÊûÇ×o¼úú­×ÞØ›Œ™á”É ÌJ„€”@ØÍ¦<{k„J€r1M˜]­u_Ô÷Ÿoj?ßìt>Wʃ™§ü"=…hçc¨¦^‰c/ä-ÅÖyÏ.ìÎ%« �½r^“�ö¾üWÿÌ­7—'ß9ùø¿LÛ�ÎÙG�Ya…'8ÎQRäËVï_`±Á^…iˆ£;Í­'U;<ªªuâ!'ƒ/mòÒìÞ/^¹šÞ–Õ©œŸ«ô£ýknr¦à du!@’”¥ìŽÇÇóÑñ+¯¿ÃøÖÇï>üÑÇÿè÷¿ó�Ÿ6}".PÏioêHSvTí]^ž]\4<ß´Ú¦mw²è7mßdÏóÃ[ów^õÍÃë·à ƒª÷Š&a5ˆ’$°ß! C­³ƒTL³•ûS™àŸ«øí…ºd`…«48Ú1ÄÍþt‘D0�Œl²l1çÔûÒz&oä•ÕûBÉÀÛ5íE@Œˆ4¹hެ Sã‚Ëcªo;˜Þú–nÄe<ýá�¹[¿ðº÷¬ýÒùbDzpÎŒ�Ò$¡ßêö2ö§ýúL6'¾_x£êú·\j<ÈÄ\aì±K³x�ŒÁ%5�?Œi†Ç!/^= “¥™¡ï±TC V8�&¸€A+h6Qç%$CÁŒ&Ùª·ãüHýW߈ÍV·=Ih§m4>_sñèÌÙüö½Ã׿TO÷ÛÍ¢Í9GTÓq×kÓžÆL)§.f„f:U£Ù¨ÉìfÓ½ýíöb<™hÊBäCÅ}·×¡>u;6 Ž‹®Í–ÃÅËe…ÔÀg0°jÑ ã5NO6ßþÃß›ÿ…¿|8ž«%&ŸSïá@̬Ó”ÛõªÐìŽ0mU#§jlV9�y鋪֔˜'*‘A†`9\ÅÅ @$ L)õæf$º^RgíVÖ«f‘˜ŠñT½êx„ª†è^.Fõå%/–‹²q>\Û¿;»~÷å×_�Nö9Ôvµ %Τfx7ÐÁÕ(Uë*ÕsÅÔ¬üœôj¢ÿ§4ýØMþ¯."!2"¹JŽv2½ ª/ìd´#λõòæã^4;¨A”stä%FK=i2ÇP¥,ƒ3B&éáØ¤a(8P˜múûùþo�þæÿ�ò[e]‚4È’ãF‰S»�ÜĘûísß^ÒöÉtoVßý*…=ŒfVNHt‡~�ó$ *Ê�æeìv)wD¤ÙŠÄ”{xngÏŸ<»jJ�,Ãó“1¹`—Kd@Ã$cmð€ÈCâlFŒ ÆqIwn¿öôûÿ�‹Òo7\Œ�›Øw±�1Éú£ÕéùË¿ü+Õh¿í’E2_J¤.kQì÷Ù­›/çØobj½†;“Q/“F\‚Ä\OÆ)r]TUé?~xv~Ñ7ÛMߟÖJÚ ` Ù�^ÞƒŒÁ½Ð‡?ùék¯¼2šÎ«ñDLІ šº]¸»Ø¬ªñÆÜ„!Ú.ºÍv»Y²÷f9 xq Ê®„,C ˆ!PÈÕ§’"r¤˜­‰±ïóW¾eÂÕïþVoŽKWÌDz·�P�š Fj6šº›×êXßðÕáÑÁøÖ­0ÛW¦@ê¡Æ õxÁµ5 Të©ú*s-¡á3 Ï0³D>3؆ñ…0H†êŸw¯ˆì…§Å}¶û�±Dd¤17 ³©FvpΩf2ë‰a’A×O]^û¤à�l˜í`°Ü™lT„M�.|{Vm[ù½ÿ8¿ñßלM³H…‰Æ~­y�r/)Ëê é|&—öðgrèýÑ/£(H28˜D‡H/cåLÚÙ71v$ùÊ–©ëf¹~¶~ø$?Û"  P…ct=®Íx²V«’¥5`AYn—ºsö `ÓÃ]hîPA·[IÒ§¶ßRd¨¢õ”úÕæÝñ/.7«Ñõ½ñünÁA¥OfOŸŸ›áÚÁ­,ùþ?.+wxtÃëÍéå²›LçeÁ)å£ë· îø8¬ÖÏJŒšfm(ÊzÊïêMwÒ*õQ¨Cå‚ †s%FÀÄáÎ(=ÿŸß¼wp�_FI>”1®}¨�f"d”MKgiK®`Ù¦Ô÷mÔØÃ p�~PwÁiƒfÈB©GNˆ”¬Ý’$›÷¶lìðn�¤³ë·hód긘öåȈ‘â–£²E½v=ìÍngA9B´ª2R5¾ŠgC2“ÁüHë*†1¬„yÈç,¼Ÿ-w?'z§»¶÷Å×CR�¸]nŠì¾³;<ÓŽã© Q8ë["�E°I6çÀìM”5‹&G{h·ô"àËÐ�9ï‘;@  dSV0©D“LJÛ?ùƒé�/5å›$Ðl ’ÔL’h†®×®_•Ü‹Å*­â·ÿ!~yìëß4.@J–´ÙR15Wî²euÈ”PÆšt³âÂÓðo�QNž,>þàé³vˆ­÷˜�1áú¡+kÞÅ ©A]�àP¨G s bä öà’ÛåóbR^^t}Î9S6¨Bzˆ¢Oà¦-Û䯶]µ×î퉣.õ·n½²Ü¶—g'M;¾¼ôŸ´¸8{æBÕvýÞ|.Y(k(Byúì©/8u’¥??;««qQ3+B° 3T4í®oïÁÀþ5á`�jµã u¶Åó³�>žŽŽ«PK“|Y$xS¡Ô,Á„É;W”æµxQi»bÈr¸åqK}4xJÉr´¬¶<ƒ*�öh<Æ„´¹žÒÝJ˾wÛS9š¹æ9»Š&‰š­»<õ¹G´ª•Eؘȱ©YV—#kÞ½oÌà-§ÙÿÓÝíçŸø+¡>®p tåx¼º˜”L ™v„TÙ%Ñg`~˜ùÁA³³AHÒ¸(B4õ0‰†HðªHrŽi³ Í’&%4ƒ ;�ì@ЈHKæT‘3¦™W¿ûÏFé ½DBÖ¨16Nz‰Mì;�ÛŠéÝ/u�ÿ@/©&–?þûù¯|ÝÓ±Q°dìJ“žÄ0Xä V�”¤Gìá °ÎrnŸ=üàѲ±I�ƒ &L'Åᬚ•£óåöIßî }‘ˆ@ñ 00°ZRÂtV¦~¡�˜/|•\°/ý¢ðd߸å®­ÛvuöüÖµ;EY|ñí¯}úîOúˆœû½£IUV½û“bttïî+Iâbq“¡|þü±#Ún79#¥FÄF£ÙzqZV>µmSJðÁ!0B�š±?Â�f%ÊÒFå0Ú#ÏnsÿýåÑM Eê¸mB%æÄ41»؇öSªyö»z4QóÚ·)·ž–gê@¼i­[™˜Å˜»¬™5g“F‹PñN:xY] Ú*<âFÞ�ûOŸ=]]¬¯ÍòÅeÙ|à.W†£J‹}(ØÄˆˆ‰’P2vdYvµ1ˆ¤(ÔUâ'Šrøì°§+?<}®ÐA¥Ïk}>‹MchwüƒL@sžT?/ŠDà;X) r.16-r/FÙ9³¢ ad’U²qѯ.FÝST#øª1TLdHU1fR¼f åÑ äžÜOßþÑWþzÎ1§ ÓÔõfì•:¥0šG÷rs_Ÿ|"l,ýþwö«+|ÝüHKfé­Ýb<šv(T‹|°a"”¶$í¦ë-R5¦_¸F¥³ºâ‚ݸ¬“ÙÁŒ` ` Þƒ†H(Á€)^vÈA3n…ôô¤»¼('[9/«ÐmR5AÉÔ.�¾¦z2r{ÇÓÛ¯ôñ}H5šÝJÉΟĄ˜dìx2ÙS‘ÉìpÙ¤ËÅi×ES�MJai»n>眪Â3£ë7qYŽaÓ­ÎWéh†@;Ì T(<ÏjöœC ï†ðúaUÊýöÙG?ø�—«òàú«Þ�Lû¥z*Ëɼ¨`ÒD ² W*�}^lýtbÝzóäi1h›9¨i§M9.G×®ëái' £@EÈBð¾·ÕÓÇïýàâ“ûBÚ.Ôfe¿5QÞ+µ¬‰‰s$5@AƒÇ‹<‘YY� ¹®³ J3Hù™¨ÍþÿÊž�\ùê‹��WÙá;æèŽb¾z*Y¾²³«˜é`| >ÎvvGg™Òzé™ ì˜9¸ÀEÎDD ÕÊÌÒö2Þÿaæ¨wˆ·«zJS#X"SI4�¢áÝïõP÷ÊŸíÌCzCN}o)#·0c'áúëò½ßœSpÛÆÿúÿœÿÒ¿_üºy§¾@JF†LDFlæ¦[Ê DF¸øüñåý¢txè¦c7D²‘J e™sdéý�ƒãP|@N0 (ᇆø*“] Ù°ÝÚùé³ÜäÚ„:J£)ÃY¿5Ea\T%–7Ë‹ÃÛ}jWg—‹‹íf{yûÖ«°‚P�´Û¦O}>;=5pQÐýG§¯¿ñ%ÖIÓx<šLf—ggeYö}ç ®ªñåÅj¹Êwf|g¯šì�œ»”µ Ò@UUõÄLf¢YäìÉê£Îçû<æØ÷¾ŒÇ“½ÃÛ¾®`�ˆÙb›ÄL[V65�q�ÃýìŽê×ß$Mñéã¼^åc'Ä㮨ÃhZ:• "Äœ]ÿ4¤¸¸8Y<{Ö�, @€^óåÅe�kŒ¼•c¨ã4”"Wb}R°D‹`ÁKYe?2«MË�;ç³ÏUÍCøLÙÏŸwö¾x >›i2É.üv…bæ�Àëàa09ÒðW ¯0üÐIbîWÅÄ—Ó`&p`²Ò�T3±ZÊŽ�¥.ž<¤ÉOÃ�¯¢ªM†Ìa@Ʀb¦*j–U“ÖŽ¬ƒ'€œ|ômNê·¿¹�sÍÓ¬�Këqˆ¤Øy T²»Ûü‡ÿúÿÿ�{…Ý6ö¤fÎ;R@epÉínAÉp ƒ5«Ë‡Ÿ|úñã”áI½° ES UM½A4€çSzº2Œ,ƒÎÃ;xƒ(² +¼ÇÉe|íjˆËXM¡ÛÀ1@lnTùÑ”Šz¹ÞùÉdüéGŸœŸ>®gÇåh¿¨êåå‰Â5ë'ÎYéh:s¨&“ú“râéx²^mŠÂ§®ß6›ür¹4‘—MÛ4=�g®|©ÑCé€á3863K2˜Ûhõà½õͻխ²žì±÷õèhÿf9.QŒ :Ø¥‹*Ù,Î&3íËüNìÇ®êµÌÛ5ÙZÆUVW…¯ª¼>«&9ÃÓâ$Ÿ>h9Ç,á2!ö«Äõ›q1ç «žÇSâÇÆ%PVÕRâÃ.SË+�Âçìî/-À•Ÿëêéÿì‰ÿ¼¶™æ†\:2†2†àäÇ@n÷J™ê×7ì‡"9F.Ǯ舳w †#1H£Æà�€IDAT€SãÒ…(’E»Í¦ùÉw‹E?~ù-®jÍ–MMroꕦ©]ž>~ô{{çgǯÞõÓÃPí9ˆ€ÈTRSÒ\L�»€jÒŽ C(Á–ÿø»³·Ö‹pOÉo»èO>™¾þ%Hï'ÇèNà€À™ä£¤íÿQ¯Å¿ù«6{ƒÆCúƒ#R%2„€S^¥ËÇË‹ó¥Øçüo½öÅ/§Üi1ǨÆåƒ½ãkóý—¿ü¥GŸ>øGÿïroÎ_ùÊk.¥ÅêÇ÷ÏåÎÍzyÑw½6JH¨ T¬G l;ôQ+µÞˆ³)c½J ž�ëTs·�32ˆV㺲¢ë¶IâdV==Ùz ±7ÇEYŒ˜ó¨*|¨%_'çs¸6“ÍzcÙmwtt¬"©—”}Ó¦’Óf½v#G<}nÔ§ÌFÄžHÌ]í<ÍPˆ�ˆ-giÏ=ðÓŸû›ûó;~´·kÍhØvM¿ÝPYLEa6÷wþ�¿J £ä›ÓþâÒ¶KŸ“W@Åðì]ßc»–ÓšVS_¹)ólB‡ø½?ztòøÉù¢a6ò[“äÆMZw96d¹žM¦{nã¹ú©Ái^æNŸÇ~žßÿù&€>�n¾Ò>\}ÇAˆÀÞ9�!øœ`Þå¿ ÆC  ØÀ±�™LŸ½·øà�]�æ”RŸ„"T‘Yû&§>'±,9mˆøb±yòè±m;¤&o¶ÎЧÆ‡È˜�Y�å»å²@² ¡$B¡„Ó é–*Ëýþ4Œï½‰bÜ,ŸÐG÷9�†E�€€"?{Nþýn±Hë–¼Ëý*÷}…Y‚‘Qîuq¿ùè½íJþÒßþ¦ûû*‘�óˆ9T.v)‘Tãêç~é�¾_9/OÏR¿}éº{çåW_¹sðÊë×Äu?}—]D68‡*àÆÜÏFnÛILPEê4E‹9û¾‡™EâÃ×^_GÙŸ]ïc�ëvkÄ5$³ó³ù^ß´lê}‚ÕÍæ2k7­«u£’SQV«ÅšQ4EÍY &j¦Y5ç$*È}Ün6«•mbÜ®W'O ¶9{J}Ÿbƒ¨è[_Nž½Ë»A•ì&VÞà.—ð�åëû‡Åþ-p%Ý~ÿ�†˜>2!“6]xõ ™çè$¯/©[åå‰mÎûÓOl}Žf±ýôÝõùâµßøkj”Ê‚ÞQרö�DîjŒæípZ}úÞÏÎ_šà`Fã‚öÇÅ|\Žx6uླe�­`« `{ÔT*�dH²œ3 <Óñ­£jÿh±í�¸WËQ6ëͨÝ!ç6ëÓ¾o�¨íÛª¬ONžjn� `nû\OF}»>?;Ó”»®[-×…çÂÙ³GO?ÛÁªŒ;‡¸sÄ£*»¸ž!ðÍû�r’yO’á@P¹X^ÞºuçòìÙdz`.ùaóGÌ}Œ’MwA 8¿Ù¬ëñ^Û_ä(˜fI’a)ÇÜÅ›”›ökÎ6Ïßž^«¿õ+öÒ_—Ôvu+‡£Ù›w_}åúÑùj[Lf£ùôÚñádvèÇ…Ñ•PÙ@ê,1˜È \Þe»\E*ý·pö§^Ø Üí.îz@Ùˆ�¯Þž8¶„+šÕ@9ñðŒèFz¥—  7DÔ9³¶½$6çL@4ÀY�¤‡ZÎ�÷%@¢ÍRUzçZ}rÙ<|úѼٟï_߬/U£+˳÷•+}&­=×£I×ÃvOÿ�¡Ã#l«y³¦Tß¼ÏÓo]äè¦ð%Lv¥�à2ìò¡¾–Rãœ'3ƒ<³Ó8õ–o~ãç3E¶‚ˆ Ir°l”IÒz¦”š¬ë/ýü?i¿[ä ¤ž$6Ù,¶ëõKõÝ1鵿b­«l‹SË*"WÏ™AB †g(ú„mG]2É) „Üh߇MÊ)"s³ÉÍMs±7›ªXŒÛél¦¹.FóÓÇÏÀI’K]ã87íJ¥¬ OŽOŸÜð`³îw¡Òbxåw÷h,8B@ˆ!™™!Ãñc…wj*¤yõéwüðµùK¿(’*@–Aö¨ÖyÉCålþl»ÝóU“b�œ{•PçöbÓ÷Ù¬ë×}$Ý.êl÷/ŸÇ6ýÜ͹Í*ä}TOÓïüs¿éÞ¸yëî�Û[‹‡·nM�ö÷�‹QI¡ݧùÔWxMõ¦DDD Ò!ž W‘DŸk>÷ë f‘]}-Žtxú ÈÇ0茇\c7|kØ•ØUPñ•`h÷î–5fSS5 6†Pc6»rä8ï¼!¨©:a�ýÝÃqq±|vöd½Y”£z2: ¥°KȺ¸0¿õå‹Þ) Ù=Ö¦cTÂ.,Ùyÿì»Lw¾*ó™ÒÃÕ�n˜™ìÓªý/ÄêIÇFƒ&¤M¿<‹g'ó›wht€¬Æ‰Ø›d@!­ª }‚‰("ºMé­÷tüʽͣ3ofÈ€ZN£²Rc_”]Ûß›:aË855é[�ƒ(\�D`µP€¨Ø>_ÛõÓuVWí^¿µ°w|íÆ»?þQl7ëíål~«(Êb4+BÝ­.bº,FÓÕª¹PM ,_N}9�B¿xþìôùÙùù饃�qû/ïѤ‚ŠõbìàÜÀîƒw»Ò†rÈU“PþäÝñöí·{±*f.¯ÆŒboYÉ™ÂB"â~ýÏ~ýÙ³‹eZ_ÆÓÑËßúWª£ãGÏ>µ¢¬÷æ)6zqŽËÕÅfQvúŠÓÑ1ãÆèÒo»ƒûæ�½ÃcŒÇ·îÍ�ŽB]‘ß]¸;8ó I™9"RŒ™ à�D¯þ΋#u»¡>1Æ” €¸a>ªCK1Ì8?c�Üîà'wÕG«�~÷ì®AvÖ7ïÿQóð=ö‘]ðÁç™Éyr.0,‘вƒón0²s“Ñd\Ä^Ún±¸ÜnÛÕê²—¾�9£ëRÚˆÍë<Éf (i`€ÕÚb{¶,gDgní£KOpîjõ—ÀP´®ù¤¸örR)¯µ_X×å,ó/üœ¨B“ÍîRlˆ”˜ ¤&ÑÔA³hë}·IÛºš.ž=.9°s&’(b »’ÌÄ33«'6³¾3°�DP FYqNÒ÷ýüú�Mp}×ì;ïF£ñzÛ…P�Ç#Úv}Lš’~ôÑ»uˆ£°™îøð8Ǩ*õhä�½Êv½¾¸hO.4ׯôò5¼z�êʯ8ó®žÁ1|1üðvò/fót2+ëŠCåÌ]1;,ê‘ó¹]Ô¢c.B]”õx4 ¾(Ë‘Ïw¹)¤bÍwŽÆ£ãz4¿ùÊ£YáGÕøròè£Ó‹“í“.iéèúÇ«x÷ ÷ÞÊoŽ&î+ˆ}ÃÕ¾u¨ª«Mí®Xß5°6èô•0p&Æ„ldŒÌ¤â‚˜{WÉ$™ C úÎÓ…ÁL bÈ íy±£� Ah“’;k9»"uΆi"Ø®&K» ÞvM¹7«}pàœ‘ÉúAX”óÆ€+B"I½šyçų�擉kš¶ïÑ$\.Óz“"Sk*J¥³u ý%8ËvƒÊÖ:˜ :@¸Äâ�>˜ÒvvïúeZ»"€öá+#wp æÆ¬èï}3÷­ˆšJ޽ä<¾}G 0"çÝú©±Á”Be¤.ǵɩϹW爸˜íÙø†<þ¸žïa�TIœaV—"1%U5vÞÌLÊÌÃ- sˆ=à` €»ÖT”~±^”G·r@·�ŠÔw&MÒÌ÷î\^\~ÿ?˜îÏ^ºqxtxpxpÈ¡4Ú,òé¨àv» Eqä§}·é³™Äçgg�žæàqk/ßà* ¨˜ÛÉó €‡ $¡,‘²ív¡ï`†zäêÚ…Pœô㽯¢˜íq(*1‡jÊ]’‹©‘ûþ�ÿî­7nݹS�÷oß{“‹™�êàrãaœÓæôl³YRío¾öÊ—ýWèÏü²¼ƒTs“ÒüªÚÊ’x k9bÆ@C&ù«™ÕðZðUMC;þ,�A޲#õ,ž¢G&•Á £�ÄÆ–J¤l»PF‚ �J48ÚyÀ3:+Øv"R _ (Ð!ù*Xsö“ßoŸ?*+ON, Ár6U•”ÌH5È{OÄ®(«ª,Ë‘ á l¾E]†ÒÞŽçÕÑÁè Æ^…y qaL<­1•«0sÝ54ÈöŒóšÞ¾Ë/]G0õØIæýyPç;Þ=ôL`BðÅd¯×µsÞH ì9³f³œÜ¹ÛÅ¢,&ì �ìÒ„œ@Î�È×e}° §�´ñÞÅØ—ã£Íâ$¥6k¼ý…7n¼|g´?;¼÷:oEwŒÞA3Ѐ$´.óX<Ø%ÇÌÈl=(î D°!�Ø^L~vY¹†!œ‰Lvw˜1›“™*A BåÎTØ;”ßNË𢃶«ÂË]ùáùªú¿Z é ”¦+ �iæÎªñÄY—cÁ“WUïœ+ƒhǼgrރՔȋæP ^%€°WÅmªªÔwb(|¥H3còI±�4U‚s‚•†hk0¨�LA‡\ž©=RŒ¨÷ð=4ìášàjØsM7Gxðcïd[Í eî{³žÉ™™ôk'59°«Ä¢]>ï×OÈ:ÍJP1H²œc;ªÇ닳sQ…­èª“ùÈgMPxöC¶qfv!x˜!*X·€C3ögÓÜ7©“\DOÅÅòB4å•s€D°2×e�²ª¼¯VëÍæòüìqRÙ?¸™¥ÏÂ}³}ÿÇß»ykÿì|‰z»1£Ã‡ceBÈÁA 1E°‘CÀ.ÈE‡•�‚ Ói¨Ë‘g%r !²dYÔú³‡ËÿxüÆÞj5>80Pœ±»GBD¾Yobkåd \žœ–“3_îiÜx’º˜ïÝ>¢Bµª¤ÚO~lPÚi(wîÄAxÞX¬• òÞy‡`Úmî†l'Âpú‚@2ØÒGŠâJ¢ oƒvµl h`:BŽ †ep€fâ°Sõl3(8¼ø›¯úê+*$²ûZwðOY›Û- ðeYä,§¾(KçØyW©ËìØ‡ŠU%FÕ<ä°3W¶¼5dE5’””]b€4i, �Š­G}‰áÔæ^&&SîÒ†i  xªþÀçû9ÌãD"È“ÿ0º17ÞÃ+_È6En1Àb¬w`BÊY·„”»¥#’”˜(Å$oMbÊš¶1n¶"LÌ(êy•99ïX4!X@QqP‹¦ 3óUf7žt›Ks†ÐÂÚù]&¡:³ªu›mQ�§{ûX=öìé¯íÜúø£oVÌEŠÉdo³Zšäéáµ¶_ÿοü“.¨îVûf�'ÄŽI͈PW`¢$†T‘= È9ëz€@³9³sŽz†�`Pá|2I1?ï‡oÜþz ûÛµ›ÎŒ&¶f˜ºóoüÆééI/\”»¼£sg®�:s`¤áNŒ‡Cƒœ™´ ý¦ ™ØA‡çÄl2˜¼Ôà�RüÙGíL'ç­dÉys~ÆÕòré@™”Œy¾—CWŽiTÊ´߸]ߺuíç¾%£Ò’í*±(¬Þœb&í™j˜9ŸLÔqA–Ìx1�:e¸mº.QÄ!!3 ±œ19]büt²7êÛ&¦Î;ß®·]Ü$ºÅvù4î“�>x÷ÃHJw÷ñÒ¾›TPS0TUÍÌ’5ÉpÙ“s0SÒ!ËÏêºÙÈy�)( ï=ƒsÃ�D ¡(LM tŠì¹à2IËÃòê/5¨÷M2�wuàþçÿÑ¿WNÍ�2U‚vDL& ��L »¯�M™^�¨pÕ¿Pªnö\m™^”ý¸W *�ÇDÙ!“%²Éf²DðÐûê0(2‘]£kƒƒ6ÿàwòïþKw~a›–ºM¿^¡¢ÜDÑ&j"•¾Ýn/Os³�—Xm·Ÿ~pþƒ¬¿÷£ûÿïmÞû‡4½sCË`‹§ŸüÉïO‹à<‹sdE(AðÎCÉù‚Œ˜“3# 3UYƒ¡ JŽÆ:”m* U1™ÊD>xAYhc…íö—C9¨ÒÁ1TwRn"¤Q$¢¨wC+ ×(@úa[ã²M…Gö¢}j“Ë&]_^»FÓCæÒ88 # Džˆˆ<ˆÙ{S8ÏjD4z?ßxé^ê×ÛÕE1™¦¨0a¢ ·¶Û.Vx°D(0cˆd–m�nÔõÝ:o¶ëÓ³Õåã¦[¯Ÿ?Zœ_¾÷~³Wà�ÛîÍ›U`õ�SØ‘SSâ�‘i7¡±�ì P¦ÂqQׯ W°c0|1èxƒª—™™v�¸L¤¢…g3qð¦½f¦ŒmÜ^{é-â D»Ð æ]”QüÃïé?ÿÇŽÉÀÚ¦M'MÛÅ®ï�LIÔ8g‰j9çœbÛ·‰ÕœjpÒžŸ^~ûÛ÷ÿþžîÿØ�×OÎ÷è f„Š\•TàKsµq¡\«ó ±/&4:vû÷öî½U†±õjj&ÆÎEQ”* ÝÍL™ÍLzfGäœóoÞ¡Ln`q¨BwÆÜØæl …RÆðI¤áO’ù¹K‰ fS¤ X+Ú¯•ÚAÈ›ÆÏöÊ›÷\©‘ÛûyÄgŽë!îņ§MÅÌ` ÌDP �½‡.ErÌ]1-o~ù·Þú2‘¤mãCäÒ‡›G“Qhã§[œeœlà³#§Jrpíx½8þäéÉýŸýèûçë³ö;?Z,.rZ¥—Žý[wƇe(¸§‚‚+Ø9"sÊêÉÔØ²P{‚ßE)@žëQð. †ö�‰ ä\H±gvÌŽ‰ È9™XÖ̬vTˆ�™!”#?yöøúë_Ïïì$2DDð(j£òÅ(“jœiÄÔ“•dÚµ’/²Û æ fd4¤fEصÈêvWÁ‡x í?DNed²L¦0ݹ²U… Ô�Å@;dônèÆèZø"?¹H¿õO9¥0Ÿ¶±e—¹,´Ý:8%ô} çst‘>T>�+ȲN)�Ç„»M™eý/¿Ý½{ÿÍ¿øM·72IFêG#bs(*r…à„˜Éf‘¡íýóýûˆ®¤=_OR·T\ªÅ” "’3±#rEá®îòœµSç+FÎãñöf�'©äÏ \�; àR¦ÝÒÁô ¼‡•D®&Zå)Œ@ ê` ]`lh–­tVUÆõì•/¡ÜS3Ï­¿�bb7ž}W5ÔÕdˆ´œ�I!E]k]ç~銎4Iô±m.<èß/ŠÒ²™¯Åos¶7Ç{óxxô!\âGÏñd�¯½N¯Õ¹}öñE/ÏNN,ÏϨ�¸u�_=½cïB¡Ú"Ç‹Ù�ñjÑšxfrÈ,–Œ`ÆŽU¬$;‚²šÀŒ²Q0!òÃQÊæ *ÌÞ—Äd ™ÔŠa €,VUeLÉ@1fÓ‰¹ìÍwþñöÿí/8ž‘ƒ‰÷wÿÇP¾ÀŒ ç³¼’]õæ6h¨AÃa|¥Î¿R3˜å+qÿg*ÿß»ê \$ŽÁœ /€ÀŒL 0S…™’€É3€€´ýáOûò{î“'öÏ¿_ÆäKnâ†Y…°êVI£ÁZjM®àDiTù²(D·Fžý�ަå¤à,GÑ>n�¾úÚä•›1gØWÆ쉜QInÌ®r~d~8÷�¶?{�³ˆ¤²š@D©K5¨ù¢$pQ€åÄyG�ÍÔ‡*xOäB¨Q»Ôôa½Ój ÂtPEF\\€]„Éο �gsLä¡ ftôj îz´kô”^}+\»¡JEY{v%½…í%ÁLz «d63dS1¨j&"ãÒÚK2BjȦÜI¿XP³Ù�f˜�L4³OGvû@§¼àb‹wÏq¹Œ…n?ºüÑ{©�t°‡¯¼NoÝÁ�9;¡´‘í";‰w_>¸óÎ[Ml»íF4[6&ФS5bbfG$�Hz€9_8gD*>v�À©QÊ9f•,}Î1jLI•º>õQb”¦écŒ9Zêú®Ïm»í“\œŸºÙÞ�»oš);‚û;÷ˆ!Ø0^±�¸˜®F<;ÁŒ�°;ò±[B]I– ÃU'ÀŸ=ô/¾^g@Gªd™-cXx [­a¾™‡å“Ú@n&d H¼OôÝÑYâ''›¸ÚXnÎS«Èíú¢§�}ioüú‘ì©lMãT$iî6UåÏž^JLÔÇv¹ÒMÚn·Ú¤ÕrÕ·qtãà�¿ô+ر3¾tE¥jàJ…‰¼cöä<² [o~ôÈ�göƒ¸Ïså]-}ÎÛåÄ`È”›9WŒˆH³¸P˜'r¥¶“Ö+Ìí>>W ëwu£ a…ŒÔƒI€ ä ”3Ä\€f f Ã9�áÜÂÝo}�ë1¸bW°™9ô .‘t+’ÙDÕÄlh €/\Þ®rÛ‰õ¦šû˜s´ØqV28Öµ­fR(QÎ’ OÇ|47W`+X4ôðDŸ/qsŠo¼Š—oÐñ„‚¡Ýˆu ±zLwß<ž¿|¯¸vmïú­G䌨,£D§ ¤FžÌ�¢ÆŒ®—¢`QÍY²JŒ©M©�±Ùv]ÛJÌ)¦SîcV5•¶‰ÄN“¨îæ•9iß9Ê1йÓåöɳ³oþ꟣Py.a5Ϧټ;2Þá^ôûÆv(Œˆ€�iÓûâ°!:Ò`ÆfQÉÔ èÅá}ÒùÕÔˆÔd%ïÌ $d$ðƒp±”ÖÐ..–gYËIx~ù´ªêÑ8ÿ•o¬óæò£‡)åéëÇiæî÷gñ«Ø‡'ëötCìf“R²%ÓMŽF”²ËßüwÿµH™3©�/kò%�œ+T™È,§èá™Øú¾_®¤1“W�’câJ¥eåº>Ô.-ÁBÎ�‡Kî]Qذwö0ÍÙ‡’ç“n~AK¸´[3í¶cÏEäAíÁ#åÎÍ+(�H¼Ç:4£M €àðÒ�›(ª¬Æ¾PbM‰œÓL¼ø\š4f #ÀLL rºmSNb­IÊM›ETÀ.�óðdbäØ;'œ�“Râ^mŽ_Ú_\Ƈ‡[s:œQ(lÄ(‚±ñ�ë£ç�·]ƒ¾×>J±?7~>zý[¿üÁýKg Î JΉì˜ ’ÅyŽ¢Þ1€> )‹eó€å$Ó"I‰9gŠ*&”Õ¼gv>æ(¨'æ’ÉÏJ8M¹YåÁ ›ô¶£â]7és<¶«"&«3.yFOöÂWeC–éNìÔ(zõ’ðUðâð@ fÎŽL4ÓŽt;ì§I-3 ë[IŸ~ø½ryi9Å®[=O«.Ú֯ܧöà—_—‘<úo~`Ï»z¼ÿãï}¿|¹<úÚÿìÿò‡ßøÍ—ÞûΣà B®gU\5ðœE…èÆ—^ß»ÝÄ5ÀTx8fòì|ÎqpäÙUÄžÒuD” !|êÍ&*|UZÁ�»zÄåzÝÖðžQ˜J´bF–¬ŽÙ9&„a"DüúáöÇça‹”±7…9PNHª°v�;íz,fäaãÒAåˆ\ˆlbDðHüž�ïíÁ‡Ú$F$¦Æ�¬ÔÙ•H%�Í„ ‰•E4u®,âb«ª R5ÑL’˜fšI‰Ô yvÊÞ™/J) RÂtTݹnFê}QÔ\ø0–íèÚ!•årµœ¿VͺìËÑ�/½D£Ú×µ¯æ·¿vs½Z=ýÁ�™‘aLN3©dU„Å’¡f0’‚fjÈòÊ^»|òhµê6Ä&†ÀN²öjš­®8%�’å¬Pá™*ÈeU0EGûåþ¡i1 ^wñVCwëwzØ�¸‹^!ˆ:0� F&$ذãÝ-Yweˆ‘ÂÎÓöyâðÊÛ C£Ø vÃS¥a� Fa™õïß·ý°ê:¡$º]¶›³n{iMŽÝkÿÊ/àÚ<$$!»÷Ë_{òý÷¿ÿOôô©ÌR±¾±¹ñõÛ_ý«þίœþÖÿ鿺ý�×f‹&W±PEà ¿þ×þ|Œ eÀ33<1)\QM” À|UyBð©Û6Ï.ªä¢öÎv.TcÀå,±‹…Y=ÚÃþ½³çï�˜P°°Š  7_Tj½'Ë=y�NÂÍmú°+©G=BU¡Ñ+##êØà �ì†¡Ò =×rJ rBŠ ÃVpxýªñ`“Uç<fÂÕLàØ4êg3h2#(1›ZÖ.·k´¤9‘ô½©RÊ$šDŒÉ„sYâ` ÇÎŒëªîsÌ¦ŽˆØ‚G(K6©+?:xitû5q4µn»\lŽKÏ™ fgJÚÛË_ÿÖ“O´ Uhf3ƒ#ÊjI2�]×nÝ®öfÕ|”›öƒïýøã�ýê¯~sùèÓ�]<]d"Vbe�aÙÀ1Q3b0Y&Ç”c?ð û¤,®V”.yzHÅÄ U|À–ìRÈ̘"S# U9“�%¥Á°4ø% ps AÞYvžÙ½V\Ñø(½ÿôôß4m“®•é|®h KÄ6›Îi½UçG!r|ýË/¿yû�þéw~rúÎ;ïüÁÿø'ïÞÿ�¿ñóîßïö~zzyùüàúõg³ryQ[°‰;zëFôÔ5}Q–)K˜ÎÀ¥IçKçÈ‘crežÌÂB޾ôÖò{?LëíÈW}§ä“óîì“'éò¼ ½»[ùÙt:yCìÒáÀ,šŠ¢ó›¨fqž�uìÅ:S³WŽ×§Ã²"æ+Ôç Á‰Â\a¹Â~Ë` ·  Ýø 4Ã9À#eŒ_º‘ ç�™¡&L0Óa¶ìLRN½™ZV"gfLhŸJ­IM'9pÎi²öâÂõØI†H"SÀùªÖLª²l9i"e `Ó±rṘL„uöÊkmÒ,"Ó£›±Ûørαå˜ÓŠ\|x뛿øíÿâ·ƒ+ʉËÙïOæ{{å|ïèÆ­0žO¯Iê‡îTsûö·~íÿ½¿×�÷ö^}åË{ûí��ç,'…ñ†—z;?¡>#Xî.ö{øûòü¿«Ý¦Ð Ç¥ó1çíY �Y»P›=*¦åúìù#»xþ4Ýx}ÿ�¯½’Yñ_ýêkO/ª‘ÞËé'¿ó'·îæë¯\ð½MGEä8Ý«&Õñüæ�É÷"kl"ÔûPyvÎÿ�+É�H4“×¼õ©QÀFnzïN:-©ï}ç‹0Ç.åÞüÞ‘›©weAatö§4ab¶Í‹§Û“OضDPe S¯ƒ¿ös‡§¿{2î\VXö;C0†h ëà=.—ØÛCŽp„®‡DEå1ž 0l2@:å:Y2s¤ Jfª2¨'�©¤ 昉œJ—5Ó°^1‰&YL5Ñ #ÊRŸÚÖùN„{˜3U3jS«h�#‰jÀ ŽaÊrt8=¼{7–u1­©žt)’óäʳY"®Ù¢")ŒÊ¬¦£;¯|ýW~qÆ•6ÞßËα¯¨¨\1¥PçœM* &ó}·ü ÿ½¿yÿ'?;|åKÍèYùá3Sda)tH“ƒ)`Z—•bÊDE¥j¡®a®_-¶ýꕯ}³Ø»fš=í¼óÈ톞 ݉v®Ô£Wã̬DTyf&&“agK»Å¯š)›Ð@¨)“›eÛmÁ–†Ž[Ù™ä]rïò«'Ê^3°í¿÷ÿø­îÃ�‚ÖÛ6ÇÈ|éÙ,f¥ ò}“?úýïÙE±þPdýÜ~ú“ûüÝü…õ7nÞœ]©R³_ú÷þú·È>yïg—nñžlîÌ¿÷ûïܘ¾ôößþk¿&ãIŠM0ds¦ hÉLΑ£Üãð6..4;fg޹�ùÉIÿè�¶‰UŠªHS{~üò Ç÷²hL�“NÛeÏ—‹Øõ}ZïÝœº;wdC6D.¬fÁÂ"9òìxôsœþè´ÌÂŽw ;! Ø�KÄ –[ÌF(fdjó=”x„²BJ(ÝhS²Ø£,aÎø6bÎÔ4KÍä,Ên³K9géû~0|ÂÎÊ.Ç&ÆB„ ML%‡”{À¢*¢i20ƒÁ�ðò+×§ÇGõí;£½Ã¾ÙˆÀyWV£œúURçÊBbÇ®h6+WgžTň}qôÆ—ÓùCgJV’#£A$hM=‘˜(´7ée»¸ûêmÍTÝÓ⻼æ,Ã,Æ!9Í©޹Üéh”³JpžêÉ*ñ5Ç0õW³zŠ}̘H¯~%¾2óš LØák+•¼£›Ù�ÇaQÒ¡’R#V·Rö ÙÈï4݈¦a{bOëÅYNX<;ùèý“жž�tS½týÎ;¿æö§Óéìüãû?ýÿÈ«šå¢.¹�yußKgöÚ¯\ÿñû§¨í?ÿOÿéoþÅ/_Ûs£²iÖAüÃû÷éã�ÆÇü³³³Þž?¾ð·½¾i‹É¬ÍcZ”ÞÎŒâöœàÐ¥¾žìÛúœœ!\OÿàOü¦Ñ¾óF~œóY%v0u‰½³ÌÑ2y¯–S2c¸è.>¸˜ß;ꛋÉõÊM¦Þ5–.É{¢@Ö¹àÖÏN‹êb¦ýšIàÃÄÕjðfcŒîŽá+xf+ ¤Ö�"ºä1£>ö\ŠÐ«PZ«†!ÀT%%t¹¦)5Œ"›yO°,@ß7ÈYcÏD)EÇN¸j×—*èÚ…ÂreŸz¨™˜IRÏ–‘Í<á�—ïÎnóá5Ìö VÖ5Ø1;I}N&·ԵÈ[fòÓÃPÍT…\pH-T“¾I× jჺààLÌR꼫•@�.¶%Xò¾$Ƈïþèéƒçl戤ŠV”hŽ,3‘‘×Ì€¨IVó\0� ?Û\ž*’£Âfà�©5èÜt0Ÿ VÝ%* êߌ5#V*˜#íh€9¦áðgb8eìˆ2ñç´Ciøþ°ûø¾–U¨4^ž}ò½­>¸_§>'ãýjï�×ïþü;£¯|-//S'nµwó�×NÞÿH —t矆88‡ÿäG§_ÿÖx»5ݬĖ�ž/ÆõœãzòÚ—ÞlÚmlóÅ>úÆoÞÚl¨¾~ýýï}ûÕ¯¾F%4h¼r–¬¬ˆª¡4M8®G…÷ÞmŸ|äȲvl vfB� 0r“™9�öfíf]„¬¾h›Ë¾ÙôÛ%ÎT�îAsóË_h.NBHFIt«)ª­}y~¶?áä  M…ÒêÉNjÒ¦�{i(6MãÎW  ˜�T�.~çGÓ¯¬u4åÙ5á:Û q ˜ëÍOÄ$Q:!˜H›S5(²e)«™•óÔç®ß¶‰º”ˆH5{¯9rŽºD)Káø­7n^{óKîÚu_í›FP4³f}^Vcɉ| iãfI¾àÒÌÏ0ÕH¡i‚+zI@HI‹jª*±ÒÁz�÷~bfš$õmî·j`Äíê|4;¸qëåjüƒf¹a—9’:f20“’(³sUE¬ï;罫&c?�EqýÍ/M¯Ý{å‹_d®`äÍ@4 b&ïfxq˜íaWž“Ï^•aÿeBÁÀDsn×Åù�蘠Ædp»É&`Lî“÷ÖÿÙo§“ÓB]¸£ðøéýîÉ%©4ìÂÌ«wŽ~î 4ßï.–”„}ÙžœðØÝþʶ‹æ»ï½Z¥ÌdfM.qú´ý«ÿÚ¯†:l7k.Ë�öapÞQ[>¼y3gý�¿NÏŸ_4ñìG?z~ñ$þ­ƒÃãë×Õ:^6‹�üäÚø`ì§³˜úPÕC. ù†íùÂMGã·ßŠÏ–=Öíz&…®S/½‡šY"ò�À”û¨Èʹm·ÒkQïo–}ºHÓ{qû¬]¶›¥Vبs@TÍ7Ž}®\èRéœ: ÀÄŒÐ/Q�? ,`¢ð’‘òŽ ¥ŠØÒÀ{ø„îÛŸHEåîö{‡\c†Š#§’3QÑÇ¥ó$bP#.»víX¥�€…ºF˜³%s9X&FPMŽ}J3;Ǫ’ÒÓ_¹yðò�òöu5´yÆ,Œ&‡’2SHíZâªÛnûþ¹/ÊÉü°o×e](Lå\\^®êqÈ¡èû¾¨:.&¾œsá•™ 9{Öœßw ;˜[2öæšd~ó¥¿ö·ÿGÿÏÿÃÿ>ŬFÙØ_(×§?ƒë�ó*â(+©?¸yøåoÄÿäÿê�­ßI¢ˆ„ÕpnçTìüØÃtÈ1úiù"ʘ@ Rß=’›GQ ÔcAÍ CR°§)¡3¢{ƒjFN­HÏbðE9½FUéC}qò8-V§ …=3INƒ&Ƴ½vëÖÝwÞ Ù¡@Åq5�«À9¨z•äœ5Ë‹Ü�™æÔGRQ6�¢œíe£P�Èñhv§Y^¤´™Ý|ýé‡NËPNG¾>2ôPµ»ó‡÷©_*Ô¹PŽ88Gfbåtþüd{rÑ×£Y=½éGóÉÁÞ¤˜Á‡b2qÅŒ]M®bÀ1kÎ;¢¢bð£ìüx–™ÄÀ;Å�!Lý] `°55¬Ê®@ŸÃoõÃMášf5# ƒåt0ÂJçÏ/þþ?5ÚoÏúvÛ¬6nJÝ&— ^²±Ve‚·µž¾÷°¸×¼zÇtþÑ'Ž#Q!d‰7 }óÚ˯Ü}óO>øÙ�Ÿ: e Pd…ˆ\‰9W†0vTBn—MÆ®ð•HÇÌ€9Ï “ÛÓÉ�;ÇnoÿääÙáí—\˜ænM®¨È±/kÉýz¹r"®`. g®o—�š�Ré\UŒ¦ «fóšŽ\9>¼}ëâþõTº-©m›KÇaï`VÖ_(ƾ¹x°]5Pʦ£qݧü…¿ð·ßä¹�êꑟH³æÑh=ÌÙ¯V«/R|P6)–1Ìu²¸ÿèïþ‡ƒäÿªý}E±[`³>8É�H‰ $t×çÏÎ 38²Áv¼CØëÕxP4ëæŸü“Ñçýò”r.ö�uär³Ò˜b׉ÚNQ4ñOo~ýË×Þ|-ÌÙÜå�æÌSUeÓàŠWž½´ó•Ã}…>~¾ü«õϾýæ=³Ä’žŸo»M|ò´q‰ºM÷ÆÛß¼ýί½õõ_;¸q¯¬fÛó ŠÙåì¸ q6%rjˆ‹ÅéûŸ¤Åjvý°K[³ìÎûZÚÎ… }—O7hrŠQEºõZÅ^²Á4‹²÷I+R–Íå:m:ŒÊŠÐk².õ1õÛn�º>Fmsñ…ÿÁÿÞΖñ£í[Õ+eÇvÞ¦óe\ll�m»±mg”�Ù¤7kù ‘¡¬hGBÒr{@8�^I²¹\K�@óaæ©’£eÑœc]Ö7ý¶���ßø³¿¹X,f³C.ÇÅè kâòñ#ƒ23 !”X_ùâ­o|uòòë‹õöðÞËàš\qyò¤žÍº¶%b²()‡à‹zlÈ9'2 EÁ®Þ,NŸ|ð³Éì`|t3§aìŠ±Š†²8}þÄSj.N¶ggCDž‹ñ~Q¹Ý<ûø]G€÷õô(çvúÚŸwÓ/·›çËŸý–o>ŽçãÓä¸*ö^…6X)‰`l¦;ÿ¡ØÃ´fÇ÷Ø1B` \L/ø²»jgPí ë„lW9Ut…ù +€í�>��˜ŽhøÂÃb�Ìuíâ»ß›,£•ÎÍf—ÍiÜ\r³¶¨ªN5g�6ž½õç�ê±+ÙU³üN•²›Ý¹=ÅÜ-ËQèÚ¥õæ`·oݸuïø×á ѺŸ}ç;Óë‡/½üf=™î^c”§�äd7n½QW‡áðv¾8éºn~íæâ“'Ж•\QCd<Y lÎÖDþâ“§qûÝ—ÿüÏ'ŽZsÚ.š“æ<¾u³/Fçï¾7áÂ…@@NÉÔT33Ì(™¸Pƒy|pðô£ûšX—}ž—#�¹tóh]‰mÁîúë_Bîg¯|åßþ_©;$S.ÞH’5—ݦÉýV»•uÛÔ<¥v©›ËÍù–RKýš'ýÅIw±Ô XäÁ¤í:.=q…œ Om³<ñ¯dA\if!ø®Ý˜ADsìóó—ýýeYϸ—ãëGw®�}ú$„´!""‹}¯Þ9›_þZ�Öã;/ëø`ZV–ùÀþñ 3ÓÎÔªQÕÄMÛlÌbU–Ë“'Õd^”!öi<™<~ÿgÕtäg×·}ÚV£= œL½ûGu¨ÉWeN¾š2S·¹lK¢œA~\ÍŽú®§Ã·¥¸öüÝÿ ‹ûã¢q9'âMÏ~Üæ¶zù_'xÓaô™‡óWrfvÛý'2H<ü‹(•+]ƒ^Y¹è ZküâáÞ;fÛ!Jwj»Jq¹’þ(ïÖö0"Õ¡?-ð½qÝ|²ê6‹ó÷ë&å¬*9 RêÕ”C™5Ï£ÄR+i;BaÒjÛùxr⤩šV"�§R)‚‰zÛ�žúi{ùTŸlÓ+GG/ß>}z²^­ÎOÏnÜ»øôÉK7Þ2?qt2™î“ÒÚ?ÓDµœ](,+Ãöøµ_í¤$Y92¦³j"–›†¦SÝžédª×»²Aóon\»N…eL¡vZ1bd•í¦Rw9,Ðä<mó†Ðt6v\ Ë­½�G÷ƒQÏ×S\-¦Ã�K«zјÂö·w؇nC‘Ò¥•$D­ ›Y×évú#�²÷ìǨ¸>¹ý•ù�¯ý­Á`×yoQÖ1¥�8wöòzkû”’/D$ë; ªÄ|ÑáEˆ /Z½ô´¯÷r�ž~>jÄ ~[ÂtÁoPO=k,ßH>ý)S4w>̺�woÇɉñŒ‰ÙGô.¢¡i›¶ØÝ>sS%rônVgÚª¬ƒÉ{kMŒ./6ƳI6Ș}ÍNF��Õ¬’1>ž=œÎÚeZù¦r³fû/úå²ÓÍC3V)Ô6ï‚FP @Øûåx†’çey²˜F—ÌV1ŸW_üÉŸú®?øÃ‰ÄUÁd¥ k¥ÉĘF¯¼2ûÖíÁ×5êŽ ­ÊÊê|J6U&7£lgcéë³–ÚÍÍ­¶ZxR 'Þ”yâ8�ãªZD')�ˆ!"§‰6™€¤³,çõäÝê”D£è!ˆËÊ$в:ï0RF\ ú¢L¹{�Íw¢¶¢-P¢—‰4È�4�çÓ'²˜7³I59œÍG¯ß6;ÿáö'ãrê–ãîæNJˆdŸ¾ãwÿ;F&/À–d  ÓâöOýµ½�-»½BTØÚ^á*—«\8 '\ãuUéœÏtRdXCL iEYÆúÅlrp°ïD»�Ïgãqµš_廀ÁØŽí�³Ò”š”ê 8q®c5_ önêNöèÝ7Ó;·Ye B¯?lo"’2‚rJ7©sëGYY|šêYC‰×m'II €¦‹ÉŽ|”l„¸žoÒE l}ÚQBOë…Eå)Ì.õÁ„ }t@j§´JulêÙqu+­Æ,øÄÞe|ƒ&7>ËðßûS³åyÃÖõçØ5îtŠ®i´po4¨|�B¡ÀM–±á”|…"¤ôr1ëËIß·Íû�A?ÏSÈnÿÌÏþпû„�$z …J‡UW‰˜D€Qq³lÂp£TŽØd“å´cí¨ìfÐ}ðó_Ûÿì ©«¡P ˆ )V”íîô>Ó·ßIŒ*…˜RªV‚).fY'ú¶Ò³,´Ë©©Íê¼á@(ËÊ·y¯§ P&kkßp„”b`D½ž®Å9‰Ò ¼sHFi‰¾ERmUÇØ6óÄÁ˜˜€($²Š #* Md¬µ™V’u��˜ŒugwïE9èŠT¤4�1Â^êE3~±€,@ R\þá<]ÄÝ#’<üÕŸ馼òkctG(3@J‘DŠ˜ %1°”Itʨ”UfTÙ¬fÉûäÚó£‡öÊóbmÖéf寸üìü|Þ�,û›cM·séôñݲЀF£q­+ ½jýè…ïZ<~øà�/çÖj;®*ÑW¡žôFV"'€$ÂnÙ.Ÿdý[ iÍ0¸8‚>5)âzB)ÌZD.¦4¿å; O¡:x�º Q=en~tFºˆJÈÓÁ4\Л?‚B¬�Hëß65¯ýº�ÙÙÙ4¹Ø®ý„J!¢°ã­5+_úý¿3v”uE½Z-Bƶß{ö{>~øúënìg§gkT�Ò$¡Uš€•JÁ B¿»Ñ6‹|·×œª „&�¼¯"dåæuúÒVm]ùºŠÕ"Vó%DÎ/]ζ/•M3¸q}yzZß;S|]™lÖgL¡•ñ[;ßû2t½Q  IŒ¶½âÒþÙø>´+ÅÉhKYá|l›Y™«:Ju¯Ó_�ϨmO�ïy£K!HO€D¡¸lD &Š `DQZKJ!$D�g)%ÄÀÁ‹0'D¤˜ß®7ŽÌ�…P[¥PD2›*_¡2Jø|ÍbTk¾Ò:Í)Ë�½Äpøþ·Š~)¨µ5‰Y[Å¢>]{žßûJõÁ¯]ÿÔ«8ÜEÒÀë¡6©ÐÎWóEo°)¡^žeYÆÞél€X7·YarR*­• �~´s@¶Pš®Ü¼1�­6EäFu6{[æôˆOïmî_�6lôµïþC¡mý‹<Ó6Ï6v¶Lg›(_-¦EgHº/)AJ×}2“âÉW²Áu¸øó¯‡BxÑh\7Ûiͨ"�((a}æ�‹_ë^4`è©­î#ÏÅG·ä§ß€§]á�Š„?ú·S}ï­öä�c·X� CŒ�ˆ]l"GPˆ•&vŸý�O.çÇ,˜wº½­mïÓÇ÷Œ¢ÞÍËXV͇Ol¦…Ù75€a@T¹¸¶¡&,ê%c…Q¡HÉ Ô–²€Pô7’ÉÃxšÚ( §ÉJŒŠTg»óÌÍz¡òCPdØSBJ±&_Âb>]�7?É”A![>½ ŠˆÒÆ<ú¥ÿúÚ¨„~_B}qž„:½! 'N!ËG¡­ò¼]Š!új© é¼ ÀÂèòµN¿Tä’ó {Z{—À’™ƒK—nÞzìªÖUвe=Ú«ã_;}ó×ónÞéo–�’”FD¶? ¬`ïI‰S¥€Ãäm”F H"‘>Rd �¬‰"À‰^¬YE.>Äh@D jZC6×}ä§×å‹°àÅ9çâ¹ÿôK’à‚- %hB‰¬òÒlõkMŠ”�‘%0 ØÖ§ïÿsÌÅ6µIš%‡jyvll¹qpÐTOfýaÙ»2âÄ�¼Bʲ¼×ô£,ë‹°O‰ #1¸ej)²„Q«€›½m]òó:8çšÅéƒ'ãsÓÛnMÙ»y­õóø+ëe0¾ðéWn<{UG­T§»ÑÙ¼¾³·wPRùÅ¿÷Ó8©%$BŠÎ§ºÕJµmel»ÄËT­«rÉ%‘Æ5 À3´­™y[Õiâë×ÇÕ×ïŸM’^@m§ö‰iŒÎ Kô€" SЉ}`')J’èƒP ŠSŠž£I¨¨ẗ„€È$!…À1DN)Ĭ¼ ‘#rFp ¾vmU-—ËÉÙ¬mtgc »F@Uõ$Oz÷‹7‡ª;¤˜8µËó# ­$�Y˜AkmRtõbI ‰¬Ò*¹ Heç'cP%‘2Y†Jwú#› |³„¸AQˆ_Iª4¥N¯ëÕêäÉý³“ÇwÞøêÑ7±Û¡N§(J ¨RŒ" ìÈX­1†(œPAëZO¬]lÑÕ! ¬ÿþ–çóEKÖž�’Ö”ä$tá¡€ …hú-~õô“½Î«®�ë÷àÅ=á#CË·oÌk¤\\ÌÇ?Ì­•=óìËoß>–´’´’LÀCH—>û‰l7ÌÆ4qîè4¦�½ø,º:6•£G›u3ÇB‰¡Â bòQ„›Õrxù ©VÉÔ�áöÉ?;yÒÖ“®”ƒ½M«þîFÐ�8™Åz^Ÿ¯&çÍéäà…�µÉu7FöÒ�Å“÷&ï¿UæÝ³'�îÎßéd���~Ôà—皺ŕKìÛ¨šaaú:{òÕ¯ï~ÇÇê®±YÏ·­R€d¼´›7®?893˜\lœÇ+BзµË2B¡Çm˳z˜å/îü±ßýƒ‡GçóÅùY¨É{ËEÑpâ‚RŠ0ø"ˆ„ • JòAeÚæª™Ï�L⤴ÖZQ ^‹Mƒ€Ö*¦dŒ�! ¡RjÝ‘Äqýw àCÔYBâ蚺NmL¾‰ η`{’’¡ u‡N>øµñë?uc�aˆ@™îhG˜Ö{ïBJ`”²½�æ”’³Y/ybcsˆQC1µJ&ÏÌÁ¥djåÄØ —ÓSe;F Fgêò­W^ûå_(rÕ)i4Ú,Šž6š’ÄÆ“J ’„• 9uÈš¼(hW�Sry9dvy§`ǘ¼Hºø¯Žë+ð:î¼®h£"õc?þ/x=D$HZp=éWpa’»øúü–¶¯ü–¼\ ³žÂø"zÔŽÏrЩnW‹)ÇÖ×-»º !涃Zm�kuncXIŸ•=v,’ÕU[tЬ,AÅ�ž�MÏêó‰×™)Š�!˜¼{åZ\Mfo¼uòÆÛ1dʘÔxb#ìí¬ÎO—‹z5÷„M†ƒ½"pøÞ»Eo rÍ)ÆÖEŸ|WËUXŽŸ ˜ÅtÎ-¹&v6o¼ôüh¸=:Ø›V‹ãÃ9&òóåá{Oš“sju¿ßÛÜêô†£¢ß�!¤ÄÓÓ¦’”8xæä}�5¶×¹jòèP¦­ETˆD)1§$DZ)Å‘……㺒×ç~ ¥'AàWÉ7Áµ1„ªª|3ÛÝÞ®çž2· ï¾þ•óÃ{~q®ù웿ðߌt½Ûï‚É©ìiÓO1!Qh’*2_× �D$|P¤bðíò�´1½áVÑɉ%r È1 3Hò-0j“Çv5=:i]è ·™�ÐØ2�ÕŒ ú�"ïph„SrKe˜£'à+e2Ю1à1¶õ̬SŒÂ@BB’í«òDQ]Dša T’€ ƒúñÿä?T€×áÃu[åÛÓÏ5—9­§�ÑžZºþÿÝŽOñAÝ�ªÓŸú?ýÕï~ùáxÖm�¾õ�,›¢(æ«EµZRL± HùõÏÿðÖVýÁÉù×ßl'sm3{q<~ðP…À® ‰I,‰âȦ´ Uä`7GU=ö­7e?�éô·[ï^þ?xåÓŸ”’ß¿[�—‹ñxãÆ ÚX·iQ .ßèݸÞÛÞ@átòËÿÍÿXêžÎ2°À!ìïô6 £Íé‡÷t„ê�íK“'�v®^ ®]NO�Þ~0yx®º…êæ1p ~9_.Wu²¼œºÅÑ*µ Üúä3Ãþhòèñ›_ø•Åáùg>û�Nñìx\˜LGçÂd9yxŽy× »ƒÁ.óúz œ€8¢çv¶ªNO )SòÌ1E“gh2DffmLŠ f&á”"®qúÇR!Rœ�†´‚‹ÏpÕjnó<…ØT‹ÐÌÛà‘ôx<Ÿ���йz1;üÚÏý½Í,õ );¥ÙÜÕÅ`m-YËr8ùÄ’% H½˜¬f eTÑÉ‚[fEM^ 'ŸbŽ@¬HïëÕøþ�Ãã“'J[äTöÊáVJRt«ÊµMj¦EÙE L¾Bôäü2µµ"B²`2W·„�¢ÏÊ‘Zã DÄ.³�@0®/¹k5©µ$N]ñq]Æô4Ôð4 é" !kXÝzøt6´®L^Œ—BBPòí7B3ýÒÿôß¿zóú&ë‡÷”e‘j¯µZ�UÝÎæÄŸ F†âÉbü;ûç–§g'_Cj�Å J<ä¡Uɹ©ŸÏ†û[f[³•�K7Ùr1ÜŽ«ZwL¹·™€T§ßžÎŽ?ûÛ>³ -ùjÿ¹ç&ŽÏŸ<¹ù±WAe)®RR~Ö>^’-Çåуé;w Óñû÷.—Y¯ÛÇÂè~qöðñâøRQ^õ…Ó÷ÍŽêèÞ;=:¢¼ïœRÓÉé;w”îWÑy0˜ if$yŒÃ­½k×v޾u÷ðñX +0ìÂ׿K?ðÇÏO¾}·MŒ¸^É ;ߎ]h‚HrÞ%üôüäΣöðq;žÓ:įˆ@lÞ)/˜í­�箪n‚ó­äyÑV…¤Bò ÊÀ:½ŒJ !�0'Â�"·ëÝ�SªnÆ‘%…èjˆàÚÆ˜îÙéQY(… j'Õ*�º¶[tz*/@8¥©£@)e‘´5Œ•²ã£»³“â¿Yv÷€¨³q)…×G`¥D\UÏ`h›¦n�Éî|pöè¾l›ç^Ú²¶k;ƒ”Z…ºi–Õb‚a%h€‘!&Ò–4¢Ö’ˆÄàµ5®¹Òʘ² m­”B@DPŒhè£:Kº Í� ©udù·Nu>zx¯È ×¹6¼ðMû»>×ÖÕñ—ßàKŠ2f¤$Â+Ï-7í ¼_ܾ×ë¾ÃîäèÉèêÞÉ·^k—»ûjС<ƒÁ Aõö"ÙÌP¢ ʾô»~ÐXÓxgòÒ¬ÜÉ�‡ÿåkGo=è^¾’B\Ûž>¸ÓÛÈg¾ytûÁóÙ­þ•Ñäøpy|®Y-bc}Ë1¶õ´³½5Y•÷»u»J¡Š:~t�÷_ÜgU�Îçg÷cÛvõBê—�ºi¢w1Š1Ú£s‡ Êí£¯|­ÿÒÍ�®g›»­—$.“ÌhJ@ " (Š) Z’ ¤˜EPÆ„Jášn… X€ƒ«‘À’�NÇmãŠN—¹FN� qgãJ3>‚ƒ}Pš²Ž¦š¾ÄdR3_߃ƒG÷ï!Е®1 I"2`‰Ù+›‰_-&gEÙI1Æ,ËÚÚ=~P3Á¥í="›R ÈÄ®õ"ÙÉÑiQfµ½22ʘ’1h¸u%áhmÄœÚFëL)ëÛ&ÆÖ(C\X»Zžúâ×›¼ ùëuk�.LªOë€O9ë…~Œ†§J|úÏŸÞ’? Š’„zú‹ÿ·Ÿ(Sc{eo°?i�TK[  V†{�`;?s»×v?ýùÏ=þâiæ1EL¾"P©°yb½�bÂØˆK'o¾_ì L§ûäñÉ{ôz2Vçó·�½aïÊU1b ‹¨H@L¡aç]ëªY«8|ð³_.ú£³Çž¸¶j›ö™ïýÄ¥gŸWêÃÜt�?¾üêþÃ'ST*RšlGÏ—Ó¹¸Í2;›Î•²®nEZvn:›tz›¯ýòû¿“»™Í Çn4Øøàõ·«Ã)¡]DO!ÅÒj QŒbæáæÎýt¯��Z·W•bft²xçÁ�_ý²f©«š™··F½ýQýÁ} B¨uë¥ó´hQÁì«o,ߺ½ù©—/¾Àè$ +޶!*“Äh† H˜Eï´Böh­‰Þ#¢2VBàä‘TJ€c!pˆíüø±óñôlé<ŽFªªßÍ7_~ÆÚöáÑ“½ë—Ë�„ uW˜!ÅèR4›Ï|ò)&¸öüs”¥A{·ÔD€*µ+IÞ›å6e›zÕ ?ñÙ«½î [–y‘¡²B( 1¶Á×M7.ß@ˆ©Y5ÎwË mQ×’Q)’)s¡%D ”³0ŠJ! ’ÅÀµ_ôÖŽ.XûŠäéùýifDëõ¾v…x*¤æ ˜Õ…ÔjÍù1OùiÆä£ÐÄG¯Hi5ýÿÙ_Zœœ�RÃÞf+u·coäE¿�UQ"é2ÓzxqÿÖw¿84£‰wm�B#‰I+­€Û¶$qµÓžëf)¢B:*{=k åÛ“Oµô¶ÚëÅ²ØØŠ!¢¥Œhk"È£·¼þ‹¿ñý?ðÝEÞÝØä”zC©–j>Ïî½qûüAï굫ƒý­�OÜäÆ{çØ§ÁÞžuÂÂDyŠxvô¤ñ�k°NA%¬šå,,×uú§ÿÓÏÿÁ?ÿÇçÁgÅÆùãÓÙxN€Ml$Dc2‹ä’Rtôx¼õÌ3€=gsr!¾uïɯ�3 �’ÉŠë/î³é½ûzÝ°Ñ TÐ ÄÉÅ!!9Äħ_{óìáã[?ôÙJi€v ª�HŒUTª Åš” F¤X!´- #`F¤”$zŸb¤èëåüx|öÕoŒWîMkP!ü;¿ÿåËÏ :� ÚrðhJ‘„‚‰×Ú í^E%®š뢃„Â"’„!²$€¨�.úC MœÐÔ&³6ëì_Ú^óŸØ­µ.:¤MŒ)øF‘l^*»ý¿ù%[!ÆÌ18m5†à‰¬€ø¶ÂL‘j�%$L©Ž)…¶FÔIšõÓ¦ïSÌš»½þ<_4[¢úñÿK•ȧƊ§PfdäD‚ë“ÒšùömáÖÓ[/<}'€r;û«þß?{r?%Ûyñå‡q9Gʲv¾ !)`^ͦ‹ñêÅïúL{zZ�Ï$±ç(*ë›NfT FBjÅ«8ÚÜ4Jï)aŠ€CômçàZqiTînƒ²ŠŒR™6Zé,+º�^ïÝ_ûz¾ò½Nf¢0BLÊd9iÐÊÆ¦9|ðèÁÝ>û#Ÿ?þð]‰ÉX«�F+»—.Ÿ?öUs2­BÐm´Ë…«šäø Õ“'§ój9ž¯žyéN«U\ÜûðH%NÖf>1¢‘Y“eýrY-ªªm+eˆ“àšÅšLX)À~5[Nžj“%HšSâÀÊ@¥ �@%)m5“à˜='Üì]þœpº�­MEëõî½@ýØ�ÿ%¼x�_„¾­oA$AÃ`Ö¯ˆ�¿… ž^.PpèùGÏâôIåÛYÓÏÏ^záكͭêäÌ0L�O™Lf ibí¦ÍjÑîFçÝôÔ7«�¢¶Š�:ý�íYc”«D ÈÁǶ©hkOc�gN sbdíÚ6ïöq#'›Ûî »ÄQbˆ.¸¦~ðÚ·._¹ŠL˜BQP1 ’6yV%`”j¶êt¹ �N‰–NBȉ«ª×·!-ëÐ&48öG³U‹ðÁƒÇ Í­ço€wwo?›±—ÀȤ‘bˆ„F•Ùh§?9žºÄt�R")°!ŒÑkaO zÃà ¾j||ñ�þ©“÷^ïö±mcŠ1!I"v!ÄUåœï_Þe!æ°ZŒ­é '"ˆ9˜YJð(1º6DYü§Y\SÍ''.ÔóÅê«oO*Áßÿ™Þ÷}bçã¯\ ;œb£S^dh66QåfgcÖ¨àZMTÏ'�\g8I¤tðõòôÉâl¢-@\]Œ&ÚºÖÆrônµ8|òЇå`´é]Pˆ ™N`±e�QˆyÞ�>?ºŸw:6Ë”*£RÈÑ”J礵ҹ26ø!‰´ÀQ!¤ü™rçe€5·Š/ ã›§m ‚røX˜•\lµ�ÔÓéçz¶³öƬ¿$ké?E9 øÕßýOl¿«SÖ«•T•Ûèî`a¥È'Çã£{O2IÚvr«¬æúxÖÙ,ÛjF(œ˜4‚”E®P°*®)‘(‚D¤m£/Œ€¨´a—3‚böJE£ÔìÞ�!…ÎÇzQ/ÀˆÎ´$H�S]Ú½úGÿ7&¬ÒWö×uPaµL„¢.P¨¢ÕÆpz�´\ÅA†ªítƒ�Ó³9x3_Ž«@¡�ãÉJ™€{]îôªÅeÂe é¾ðkËÕâ;?~é{ð•6ýNžH¹ÅììñøüÝUä“CÒÛò £Nçt±ª¡T•Ø}†Òˆ/2i#ŒÏδN:Ë0ët>ùÿÓ˜~á‹f{$M³:?ÀÄb2Q|3~óÝbwÇ^݇�î®\Û÷Œ-µó“åtÜN§@YôN@:E¶óê§`³ï ˆÈÇÔ´�0KŒg“Éb¿÷û†Û})MÚ¾´Í¡ ‘STm\D× ÕÄ�g*ëÛÎ@Ù MÉäeW$í?óâròè‚ÅéÉŽ¿¹sõR§Sà³¼§4¥º¶Y6ö›;­‡  Ñ¨ó! në Œä½/Þ¿Í1r@ÐI{ߨ¬Cˆ-reŠ˜B­¬F]²k„Ibtí*ÒI SeèË>>=ëÐÚW®~ì?ù�žÞq?úLôDWðÿsÎÁ§K1xza¼ø(L«ÿù¿ü«ÍÉãåê$#)”*”¹~pý3ßñé¿õ†²8¼¼_�/\%r{8}2]ŽWA»¤ EÇÚ²×Û�YZEpÚä6Ô-€Õ3[ UÌ QSð€h”eTJéŒçmXÌòA ½Be™)†¦vÕ÷ÛÛï7—û{·~äÏìe»ýùé¤mZ"E¶Ð€€ZïÝÜmWóƵ:3„jU×.„Ål¹¬À{7mSãp‰ÜH ‘ìál±fÆ(¤î>8¼ñL6ºÚ±}qiN&Õ²èl˜rÏLm>lýÞÉýlj  FDB!׎JT‚RûFc�('ï|å;þøŸ\¹zåc¯<÷ýÿÚ_üRŒQ.ž_À„1ªéd²ñì @­ªÛ�Ç¿þÕÕï¹Çîá‘Ô­Ì*ž×0›§qsþþ�ùƒcŽÜÝÞŒ!„Äu5ãP¹¶þàÎùÇ_ìï÷e÷Ò•K;[�þPi�cô‚jyrØí šHà�#ɘY‘ 6’jê68—w‡(éÑí;€öÚs¯ØNo½2jëy–w@0úšAÚj™•ƒ¼’bk-iKвn À QH¡è¼lë‡6Ó€¤´5 ¯Í ‘•6J›eÌXØ×œX1¬8¸ñÑq3›�n|‡ˆħLº@\­W[ë;Àz‚³>â_øL/ÞÀp±ö’$(xá,B¼g ô¯ý£ŸÌ—Ç£n¹™e›õ»½^O_ÞÚZÌNÎŽN$¤ë“ »ÏŽÇH(À¹)½~†¹IbHE‡‚øÔ.VµLZ)D­Ç„ˆDh2‚ �6J11'ÃØžN4b/—_}sòÍo×’ó*RjbT©³»Ñ½¹õ“/d½îøÃ‡ÚªÄ  §&¦ übåXá|:k*^,êºö‹&´@«ÄM'Òİ€‚1É}ÿå+7»ãÅ£óÓ‡ƒaùäð'¹Õ^¹9 ¢ôÁþÞÃ÷?ðÝÁpZ/Y0'„AX€D £(‰"TÂfw¯Ô[�Âñã¥ÓŸ<¸'ñBø©::2´MÊtö†‡¯}£ùÖí²vEL É’�KàPߦÀ; ¡9�žÝ{d– :¿hfcüñxþ®-©Ý=¸ÚßÝ¢¢È¼ŸIb"jÏ&e·KeOç}!kв#ëá'`¶y–•¦ÉÀho·,:@œÂJX”Ѩ”"Ñl2®æc×ÖE·k,‘±&ºšST-© P´1 h8Ú~rï½Ìf:ë’‚›ZŠ1ä6`­ˆ%!Ph—)6)9tµj�Nª»õÌo»ØJ=ÕÊGÏ{@\7ÂÖb£°&A ħû`† f \„GAQ@Ö鉊ägþöÿ®zòÁ¦ÎüÖ¨#R¨dj¿ÜÛ~óýwýJ&ç'©Ûèí!NW¾Ž lœ¿~mØÝ„$ÖèzÕ�F¢3¨”¨Ø4”wlYCŒIÄdcT™åÀ:‡µ^ 5[¥SluÕ›¢°ÎLØ“Üú¶¡ÆÅû�pü(}üesi5›õ¯ÁÄò6 )­l·lg­‹L¹…è]ÛºTœj3—Œ À‰Á#Dæµ9�Dá•Wz—öçG‡g¢ùSßó=o¾ök %a â°Þz¦¸~ðÒÑ�³˜R¬WË,ëµõJD�(…*„¨‚f.©Ü28ÌjÝü«ùw!éîÖžíöß~ý+ݾ]�½YûŽÚŠÑ˽o½Yîl¬Þ~´)‘Ù Ò™²Ñù˜R»N…%cL‚ˆuÕc9ÿù/ÅQ^ܺ-Ö“å~ßlÝ«›ý¬GÉ-ô“£GÚ(m{ÀAülÙݽ¡²\å2!êäI0RJXekXR¨‚k”(¥HRT´)¨?ŠËñ!��kCëQ¬1¥% +#ºØF…18Œ>F?ÜÚפ䵱&+´ÖÚè,Wmã´ñ)/•R®©„9Áѹ(@ÅH—]f�`×…ø§gvþvkKd½ÛJOù' ($I€×�ø‹Ã‘0Ê…Öñ"MÂÉ(õwÿæÿöèÍo�‚“t\Z>ŸÚ\[eæóº$½u¹ âó/Ýz”ž,ðWM±9XÎæ×/ßGà˜ª¦%k…)AHœRS£óh»e^ ´kE™å ˆˆŠˆUÁ©Ì‹-rXÏmI ™D-)‰ÎWÕbäÚƒ�8W’†ñ¢õ %´T­¬¡;[]DnÁ–[‰¤]LÛÆª!ŠYú¦BË,‚ÊKˆ‚QÖ{!¤²Ë·n¶¥A|HpÿÃ7€Ù%V(„€†6.í=>{÷èý³Ûç¬(:ç•fh9%Í’¢ŠȲ¨›ùÞóÛ­¯<áÁ ϾþõßÐy~t4-²îàÕQ}¼T~ž<» yëEûË?û¥[1A7+b»rM»³`l¬V IA<Ä2€rA$¹ªÖÀ°¬šGçôÌ+N�£%éR¨€ëÕ’‰X€«˜T¿˜,²å\eR=$#¨@*R…¶±Y†¨¢÷J«à—Š,Š?ø~ðnÿúM L�ü2ϳÝkÏY›“Ɉ¢_Îf“™",ºÝà43 3"©¬L¡Qºì‹“%§Æ�aŽÄœ‚WF+¤³¸¶#s`E&¸êuF:ïÆ¸Î}4Ö‘‹J/óSbùEäsmð‚u2ô‚”u!£^WÊ@Z#z ¬ ŠÔW~æÿ±¯Úþõ�•›Ïg¼XžÌ°¨œT™eœŒ:kv6·¶ºõáÔ�ž^º´çç‹£éxo4ºùüóËGãkÔ:�!1GIŒ\F6º3ì%qʱdÊBІ�o GöºÈ8¢#“Ö¨cB�µu9úºâºI,± µ¹Fù û~ñ L«|¸©DêàCœùS©ÔjºÄ�§è[ŸšV¢#Ç”˜¹]ÓS‘Uzšø@¸õÌ®±‹¥oÄjˆ‘Y·ž×€mF �çËjkwûøÉ2hS @”$Õ’*Œ^ ‰"�›ey=ŸÖãáÖÖÑÑã7¾õu!òÎ¥>,“Þ°[û{Ó‡g«Ã˜–Éj¬*p-žO›nºd·6’2dWu”H©BÚ3äVÙ= Æ ÂïO|Évßl]º„ ä˜Y‚ͤtã\Òß»´|ðxk|B£Qª— �¶9øÖItYw€(É·„S–$®Z,Å×½þˆ9Aò*+”Î0&×í™¶ZUóI u½jÊn)K)… IYË­#� ‰™!ú°˜/ŠNW“bá„H¹1L*ÅhUG|˜ÍŽ1¦v13ýËÊŽ"c(]Ôº˜�pÒÏJaõã?ö?R[?Mz^,>j=âGoħùÐ ¿öOÿŸ§¯ ¢SÐJ »æêÞÞÆFkgg�õ²"Ïõ`ãæ —_™n™oHP›Û;w¾u¯ž7Û—¯î^?ÀUŒuNQRӴŠUJ�)ßÜÔ¥ÕZ*L† Å”ˆ(ú×/“›µŒµÎÊ +"Ýøš#§¤š¦Uåj_»&±¢�Îþ§?ÝàÅâŠÓSl–  úñû @êÛÉ6¼”âÚ†º_áÓ4i�ýÜOþ­õ?ÿרŸRUW«å̵¾YµË¥ÿüøƒÝ­ËºÛQY>r6¿}‹ªZ@íÔøÉI˜7³ÙTúÅ�gnÔ§cö.9/I8¶¤T³¬�Í”!‘d4ÅD81qÝ4OSKyäˆlž§äÖ™VF‰Þ §è\[·¡m›zQU¡®}¶Ù¯#»ŒÞûÖ�æñd~tޤ‹Ì–½šŒIk¤‰2­£`wï`1çw&çÏý²m–MªÜüxë¦ò ul6èõ/ímZÃ&¶Ç`D€îݽ·þô¯ïZ¤ÖæSDE¤]‚ª†v‰Jg‘£ˆô;½r4x4�kT‘ÃÆ~1ÚVýï,,@«ºM DÀ@"¢g“)2T¯V˜é�KöñØ·Ý„`–u½ŽújMÝ~?WØÛÙnVsŽQ(’¢,BhÛÄÑs´ÀµŒÇ§—žßäàëÐVÞUÅp‡TžB¼ÿàÉùØ-ªP¤Öp(6ººÌ×Öˆ!¸1¦ ~™Ü|Ùw¾æ˜¢oE˜9°¯ê˜ �ÒŠSRÚ $E¼œÏµÍµ2¶C&oë…«¦M»È‹¡¶¥É3míôäPe™ÕµRÌ)¤]ëbS'}Ý,�N²«/7vÿʯ}ãSßý;¯=÷Ê·žë—÷Eí‘Dýø�ýÅ‹xâúdñ¸æ \ÀשE*;yýW¶Ýñw>{ë•[/ìîî òLGŸååjQ]ÙÞÅÈ;×ÐîøìöÏý«��=»1,ÊÎ÷ß;»sdD“îšÓãœÖ•6ŸB 1¤Ä­[¸¶v•7e™8*†Û ~Üáé“ñ|Ú°˜Íû$±)9‚„�"ŽÌ]Û,Ññâü¤šÎ–Ë&$]îõ§ux÷ö!¤Ú¥&@®©Û-�E�„µR1ò¤Z?>øÞÑülÆ­ $b�S¢±Ì­Í•Äv»ìè.œ›3°óñþ‘?õÆk¯)MAcˆ”B ‰�±ªÁUj¥‘È%¾|õʽ÷�$b¦·UjßÔ bp­€€µ”X”æ‹)õ²JÎ;£…SÒZïíÛÊùÅFJ“FA„Ø:AVšm™—ýÒZe‡2ÜîúºJIBˆˆb"‹pt¾¼ü±:—¶­´&AC¶XVí݇Ož<^Ú kTY/ÇÕ¬ «:@PY–8úf²8|Mp‘cTQé5>з¡­|½ª““Õ²‚$¤t^ô8Â�Rℜ<›Ì’6¾­›Õ¢Z­¬)ÊþuFY©²l1]h †(æq5‹u£ÁE˜Wíl9=žæûk7.§Èι_ú—_û�þ7w®]Àæ‘@žš™Ÿž‚Ô�ÿØ_X¯‹ËŸ×Øo�²ŽR¬ Ð@D÷¿ò ã7~9¸Y‘•FÓ`X\¿¼÷âóÏ]¿vùú¥+Õ±USÝ»·:YNÞ½W:¥ùìhqöøpçàZWÉK÷ÒN>Èž{ñYV ú…çкè\íØ;ñ1B¨�s©ØìµºiÛåÙY=5™[ÌŽŽcíH™\(›[ïBÕ,ChÀ¯ZÚà}dí•fM¹-n\»>_͸2¦õqb°ÑÑ™‘¨¬,%Ý{ÿÁ½»�c«Ù'´ž[¯ÛßTºûF›™¥z±°ÃRÊ‹ä ©{¾� ÃSërˆa½?2æÒÁ¥óÉœ“ZÎ’oÁ"ey&*;;›líìžO&-¢ÊT–%ö‹ÄìÛÌ$ޤUL¼Lx÷ôõ²þ‚)@BEJ"oŒl]ßР˜›š!IÂôòû7~ÿ¿¹õñ—ùî½åùÜûĉQ)\C•©Yµ«U D�]`ò~µœÕ§çMÙÝøÔw~¢åè|“yÉu‘Ü eÖgOž=ø 9ŽžS ¨3"+ŒÂ~9[žŸ�Ï»¦ªk¿Z¬êé™¶=‰ÜÖuSU¨…€¬É�t NØsJ‘é¢7ºD¤”¶�¼-{írA)Šw¡ªýt³¶�ŒëEÕ.ýd²´Û×àÒMŠÈžLªo¾ñáïûCº7ê§!~šŠ{ýö÷#ÌáÅj:>ÝÇ]ÁPéÛ_ú¥Ÿþ¯þúj¶R&öŠa¯—õºyžÙÝÝK£¢söþ¡ñ0Ou3¬ÓüÃôtÕÝ´½ûLfŠóÉ ¼XQâ�àpö¨3È­-¬)Η'!&«Ðv³ÊWýg¶LÙs\[E.øéɪi{¹\-ÏÏ�ÍAÒrÑ„åÑ•ü˜¹:HH¢$_¹Ð²kÃ|:i"»=°¶“|•êÚM}3M¹±”)Í´™MžìØ«±ÓuYùú×~“§žX‹aB œÖ A�*�0Fa­Z ÒjrfµH‹ÃÃâ¦BE 8Ƶò�\àœ ôÑ}ö³Ÿ8?9 ^À²€M¡©G»}¿r ÓÕÝÑݳéé¸ÝÛ É%¥QÖ´ÑQ×-yR°^…®_/1‚Q˜"èÃ¥kê´M~Y!VÀ¡l‚AçêJýÊñ,7Fƒ~î9ÆH@,ÂÂJ¡Ob >œn77·°ÈÜ~½iolžËg?ûÊÞÖ.jew.·qš8;9ŠË‡ƒ[ÏO:ƒ�­ÐT§G‡EP†²^.UFÝþFt ·ªÒB^Ìø×7õ´¹Î¶" ʽo|õ§þ¯?QfÝ™qËÊ·q6]² "IÃwî<Ó»ÑUz2©F;½k/Ýhç+Ó…Ø úyP‘£Ï³Ñìè´»ÝCÒí²ÅB7ŽO–‹E3_Üxþf¶Q¬B({Ý‚/ó ]3- Âôö£6"¥ ›7θ*Ϋ S é¼(Cëc‹¾u5ŸN+ïîúÛ»«ãÓv²ÈL‘õ:˺ÞÞ¾TÙˬèi2oίe ðÍ/£;�£ÄÅ„JÓúð§”$Iœ�‘Öå7-:Ï PÌ‹²Nga�wcH Ñ»õbÒZœ}±D¼÷àáÁ•Ëo}pÇ+tÀM]eJõ‚³V¹vî]ÙìMëÕb± –8sƒVë™ARº8Šr­a­ƒNQ…’B‚�«¸¸/º/\¤–™C®% µMÊ5s:i¦©Ú@,ÄDˆQT"MBšœ92¦ûî;o|ã[+ÝoýÃÇÿá¿÷êÞþ2¹éoŒO��§§FYÚÕ½ûvërÕž·7ö®¶wW�$·àPa„c¾q°Ù|óþÉ™¿r°"½±¹’\$?¯jEjckˆ@ÞHËÌ(À*ël*BáÚûˆÚ�Ê+W}ë×¾¾¡õÙ™ˆ’¬@±�a&=M½~êh2ä|Å��O¦·ïž}çw}*Ë»À´¦·)Àø冀 Ì€”¬)çkÐÅM`] @!Âo|ëŸü_þf¡Dº¹·)²Ñúj¶l´êl�ÙB§«)@ÞÝÎý7ß³ ˃½eµ\M&¡®ÉJTgcè|[/Ce +$[ôv»{C¿ôÓ¶¶™­ÇS?�“éæ×®Bëcˆ~µHQ2kQ«ä¸ØÛ‰n:½}Ú©»Æø²oã¬™ÇÕ<,XÌv0(矈äbo³ÏÊV“s£¤;ÚmmÄv©¯ÌWõo½ç}è,#«´I"ÖPˆžP+kb ¤ÑGÔh8�b%©g‹b»sx:©HFÂ…�”’È¢ø´V@ÁÚuñ¾emî|ý7¾,HŽÙ (€H<�Ž·/ ¥J�êùÒ£ k0õ%$@B“$iYë‰?�´ ið‰Éƒ5@ˆY�±‘lÏîH¡¤#P¢4B�¸ñÞ&ÄÒHÝ‚æ"7šÁƒ�‰(ˆlò¹�}æ¥wïÜÝØ»–uŠÏ~ÏïxáÕIQØYã¯n•*ÈÑñ™Qêý÷¿¹:"½îÒÍå`¸ÛøÕí÷‹��òÒŽGe‹Í­½íäȈ‰1HÞë¶®ùÔ÷|ç?ûg_Û½üòÃGï•ýaJlç3%ŠBÀÔ¸”ʼdˆ@ÚÕŽ¨2EO« H (àÔÛÚ^o9«±UhÊQ›Œ†¢mkË–¡“´Û6þÿƒŸtÕåƒm,àcËOý5ûçûO89Õ:ÚŒ²Æc¬BÈH8þð½¯ÿƒÿ6¸ùt<®§¶‚´´»½m+]&.'ÑqŠ%BÌdFëÜFå1$W¹Ä¾se»ìì´çÓ°j²^Ù4λ¥ÒÉ G¡~æ6¯\ZLÆ®YB5÷˜A±1@DNXÏÌQ f¶ìÞú¾�ß}ÿ['oÞïb±·»«34Y¡ ‹ºY.7®ìfÛÃ;ï}€«Ø¶M“`ûÚÎôìÔ·‚Ër“ÐÞüäÍ^óÝ/½ÕN§((ÂV‰#ˆÄ d "Ff"D¥šª:4�¥eÈ謯6®ìÞ?úPïR¬ HH ˆ”溆(�Öª/‚"Cchk4¼ûhùðØÏO!MAfЬQ@?õ=W'óðÚ×å[¸± �lJ]¬í5],sÖ£iT@xáÒ[ßݬ¡¼—˜ùÙ"U4;—Å w ]…HŽ˜iÉ ™$*§H±Óëî¼pýà™›£ëûýë»ùöŽ2 ŠP¶¼š T$Œ(Iâ’£ñ˜ÏNŸ¼ûÍ×¾ü�o —«›ßÿ}ß±³³7¹÷§`úÛë'¥:eR "Ôfvz˜ÐäƒÍ¡èt><~t/4s²¤\»kì÷ÊN¿£9!f•MI”±™¶mU®lyxÿƒo~áç B1(T§¯l�”¶ÃÝk,:aD=º{økÿâ+âïþ·þøK/×óŸúNeJYcΑä"ÌÆk€P"à ³Ë:ÿ“IPd|÷½Ç¿ô�_¸±ëš�xù* ¾{v~>²eZ&Ǽ Áí]º„Ýxf;ØÌ¸Ê3æË¯¾¬GÃêlÑH@Ã` JÄ ÅZ=Ú´Yd�'GÁ·ÁV)ßèÆäbÞí,Wóµ¯#%‡*ÛáÚÙƒ{ËñùèÊ%?_µ7m/&³\®\r[Ï]~|ÿÎì­w£H¦òÑåƒB‰WW R+^y¡lŒv¾ñÏ¿Ä+¯”Âuy ÌÚûÆRâHŠRR s�i“kƒ³Õ”QÐ¥¶�¥½››Ý¾Ô"Fa ˆÆ@w£ÜÙ¿|çÍw£GDXË2E¤×︫6Æ ¡€$Ayf‘N­í©îÐTU\X�<�2 €@Ð4@b�µ}J@ˆ.––,⪶,”É$¶]‰ç0à4Ä ^ATІ”íô_øÜ«û¯>pëZkƒ3Í™];íD)2)‚÷Õá£{¿ùë‚ùl2ÍòâàêÁàò¥lß›;û7/}ìsßñƒwíŸþýoþæ;œ}þ‡¿ÿ3¿û R¼·mE!IJ CЦ°ýmß²FCŠÃ¥«Ïlí\j«%se¬&BfáåÙmö(–LoƒPbBcÕE•Ei‚HڨѥýýgŸ?Æ"’D)q£³•€µRê§ÿÑ¿¸óÎYo¤´1óùéñɃù/�¯<{m{ïVž—ŒkÇ×:Ù €Y ÈzÈ)Àˆˆ‚$kÄÃìäèïÿíÿ|ϦaÞ+»ý��BI|øà‰xÛQ…¶ÕQí|–÷F™kõY¦Û7¯UíY˜\d›ALGïÞ Ë:Äz0Öӹʌ);ºW� ÏKÌó~³j›Ö÷¶úXh^5(z1®SÚä…61%"==:™ŽÏŒµ ¢3³œ:múE¥ åy³|ãÃEÀ’RãÛ6z†||¼ÖMëY×íÁå+¿ù…×È+cŒ�N­\B¨I+³žßhEH˜XP€¬6HIC–:¥PË‘eY-@›ÒtXgà¥Pv÷®,köˆ`@EH`À ÔÎ÷ÊAS�5:ð1¡†­]½ÚÅ8.•ÝÝÁi –Ð`¡S8@«!K$éé XÔ¢ƒ8 3(E!ø2Ïm­,fœ;i€ Néú'žû‘ý½/~ê%èe UÆ)?=ŽM}~6>{|8==[Ϫñ@…~žO—iãÆÕƒç?µýÒ³zc[€Ö¾“DºwíùßóïÿåOþ¶o~ý—þé/ÿ“/Ü}ý­ßñoÿÛ›/¼RFÕ²]NKÖÝXMï¶óù`w$ÑŠÒ Ðé�Ö:¥@¢�Ì�Á®_ͲN�¤™cVtãÚ¶B(H‘“åD™rsÙ{á•�'ðFñ »=Ü:ÔÊtBÀñùôðɹêh—`°3LÞ™¥oßzó›Å{ïô;7n½4ØÞ½PÝ¥H9 jD‘õ–Eq]VÇïýwõ/�6KQGG§ã³÷w sm´ÓïmV‹i_÷ÏŽJ9ì {ý³Ãv÷æs�~/�'™ -!Åî ;8Øš�œ¦àœ-+o•nÛè«¶n›PèÄy T«ªêç]Sæå`Ã×írœ²¬È‹îr:cßÌN*Žì|“©²õ\5ÓL:ýNòà±"©Á¡V!1%‚Åù²ñSb !a²…¥lXú•Ój'Š z µcl‚à($1J„ÄqJuÈ ë’�QR+i›Eò²Ç"­;·òäÑy¹s%±€`b`Ũ2(ŠÁÓ „έR0ìÁK/^xa+/X±D†7/�9ã¥Ïx±k / F &P‰! (Ç`ÄØÜîD€IDATý�m�£5Êd*U1ëËrFÃ}ï«è�þ7_¹ÉÆ‚«'ç‹'ž¼{g6y4ÜÚì¹ §½ïhìðÞ½o¾üâóŸzù_ïiè]»Yôºb¬…D.à´‰ J68øäç.¿ôÊäƒ×Þü•¯ÿÆ/üâî»o_}îår£_lïA§—uà¶‹ju¦S19«·ÂÉd%€hmœ«D"je¢H>$fï+J^)½­@ƒ€±}F­$u¤­²™Hžuúh 2‹ÄÙxRtGo¼~çtJd¥GÊæYbÁØbh!ˆ™ŒO擳O~öû›×gþÉÉ»@ZÖ¯R¼�‡Ñøøôïüù?i TY‡«† íÚîõí+EOÏ'¾>y"µs1ƒýËW�ïÝ¿ñÉÆ'çÛ’Uí2¬|=Y¹z v°ÑÝÚ\µm;G­�B³Z¶Ynö®îýâüä´šø¦Ž>5ÉÇ:º�Ë£¼ìÖ3_ϧÝnžÙb±X­ ìY·æí¬�Ú"Þlïïov2_·mHãóóªç½MFÛ,g =¨mb[�WŠDaÞ»1?¯ 2¥ŠÌB“…*ϺÚèº^EI"šQ¡T`“Îlµ¬bh$îlvÌ@=\<‚MA½†ƒ¨øçÿÆ:ý­¿öç>)¬’‹píê�×ߺ»XÀ|‹Ô3¸v�½üLÚeÊD$ÉT÷ú /e¥}pç½ålê]0™:»óSXLÈ 5uÁÝV&Exn…ˆ1j½‡åL’îü�ßõ{æ¦sË'·oŸ×ÑUnŒ6žù¹Á•Íá¥]•çÊXØ|ŽÜmK4*© bràª0;­gN磾ÎK`"ßVì=x·:ºo;Ý�M=Ü"ÁÕ«füx~üHa§{i¿¿µe;}nnº¨+ŠQÄÚœ…�¤è—Qâ½[¨µ –B `ò•Ò¶ÔåˆT˜ÛǾó­7._>+²zÕ&ÏdzÕÎöÎOüW?s8‰ ÆÂ§^¾qãú� R6W½ýkQwEˆ�HÙ�çg7÷®\ì.d`‚ÌBˆ«ñøÿóþk;ÛÃŒ¸Ì2Evgsß/ª¼k‡;ƒãûï§Év õðý÷m¯lfËÜI²ɬçÊÚîæ•¶Y Т^‘p1ÔmÉ׫™¶]äxøð¡sA%bmIe™ÎBLÃarq|~èRê”YÑ/µêå^Râr˜oì_¾÷Í77w¶} ÏÞìùäø1�>>›·«¶È`)I¤n¦bÞ4mQd¥-§ÔtÎ�çàÖ0“—,‰2  µ± Rl%* V £AA#Y_û&""(½Îž¶+—õ7£Ö䈆(tôè­k·~ИnµjÐ@  Él:ñ­Ì[tÑÕköÆUê±É³AÝ,ÁÂÑᣲÈ^|éc§çóÿ$nô —Ã| ��aÕ€Õ „Š$Ï&1–,ˆ� „"§§g‰—²Ù·Û{ÿµ¯„ù|{g÷ê§¿û³7. ÷v©èA‘Eº0ÉáÚ´Ì^åÛ)&…€«ÓúìÑ£o|Í/šÉá!]tóíýË:Ët '�pû“e/êc„œüíGâóÞ&¥±Jk¥Ã�Ýùj2yý7¾øë_»}ÿÄÕ‘®ßÜü?ú{{½‚%"Y¤ä›FH”ÊR À®mj$‰ADÄÍ':/ ¢3TJR•jRY\-¶¶öo=—F—®…¤¦³÷}PY±ñΖËX°.2åæèôìþròüÁ¾E¹•q´�Ä’¼÷ΛŸö´í’ä(OqÒÔËø·þ÷ñÉ=uõÆ3ÙV¥Î¬²Ý­nµœ>:ŸXTýƒ�Åá™é–ó¼SlØÞÞÖåìÞ×ÞÀÜÆ ¶ß�dl¦ ÄØJB ” !c;ºOÈ€¶ƒ]NÞ‡ ʾöD«NfbŠpv²ètI ˆoÒÝ7ß�·¯˜¼,û݇o¼ïRšž¯êji­-6û:—Ŭ -7.²àr|ÎÌbLXE/-²¿ˆxH"DIÈ!2è�¨@"IE ºþp»®¦‹ÅÜfÅ„dɲZô'‰ˆ)º€` ííõ¿ö/þ¦¤BXÛ|QœžÏcBˆ B°¹Ie‘ Fcó½ý+Ÿùáÿø§þÛ?ë—®]¦šÏÿÈ¿ñ…“÷ª¶µÜæ ˹�‡Ç0nÀEÈ4(Ä\(.Qi!DRìÇ$“sÙßÛûä÷=ûÊ«/ݼõb±»«»ÑšQ1J“ I(À¯ÂôèüÖ«ÕÛ_ýj%€¯ónY×ËW?õ ÜÛ><:9yçÑí×Þí º¤jê¶I5µ·ß¼Ûv».½t­»³gòL7EÐÍçÕùâɽ·¢�ËÕ‚|jî­S÷ÕÛóÙüü«ÿé_! nU#R*I ¾ÒZ»P…ätdÖ¢”�9çE– 'YOñA„G›å"¬IUUcL¯ññµ×î%�Ü Mˆ÷>.töh: ÃQ_OlVÛãØ®–éá�÷ž}ù3̨A!§uî?TÓõwþÆ5ÙÍ[ÕÒ+§Ö¤6‚wm³èlo†1^õjµ8m^9zøDezДٌ¼ׯVa´ÎªócÖúÊs/9ãÆ“ûˆªYUYQÚ¬kṡe¹Ù9ºóhëòUé¨ñcƒÄ‚h¡`‰@(IäÔ¶«y^ôÛz¥5m_Ù=:z0;÷¾v�Ì´Áµµ(R!É|1Á•n›„L:·‰9:ŽYa‡£Qð4[žjU®Y™Êb"”80¦XûœéRHRL 0±º¼µ ~±¨‘²¢`µÉ èÉøÜ.ú$€D¢€€äü�¿*[Ó˜ �4�d¶�´’ß)èåb1f… )Þõó7ö®]=yô q\L�ÿåÏþ¿IaÈ pdÔ´¹!,ŽaÖ@ S@ZAp ¯ !€~ü¥~ä¯ü¾í½ý|t ŒaaPñ3ˆFÈPvã0›Ÿ<¼s~÷ƒé£éùô$T3úà•�£.{ÃÁ¨@öjp0ðþí÷­íbQ\~õ[tÊNÙß¹Zt;Y¯#)„ÖWóÙñí·}ðØ¿ó^G›ýÏšAß—w/}üc‚Z~(Dßø“ó“÷Þ~gz>Qº[[¦Ýì,´ + ÔJtSÏÐêNV¤ ™‚ã…lˆS"@Ô˜—ð21aZï*-<||ÿ´g”2PW`3pM“yžeƒ½KŒÔúFCð$ɖÓ“³g^L '§oh�„‹³³_ø‰ÿƒž�ÚlèVÔét7ö·ž|ð¶R%åª_vmÇäÙ`6™vFùhóÒéƒGÃnwuz�›Ž'®bÀX¦šÔH¼±¿]s"Põb–e&&F†UÕ 7FÓéq»\f½�KŸ~þø½û°j•Ä„¶­£Ib›u 1ƳLB™³¢L�¯³�„­"M¶vKDëS$…È@Jùä!P’HŠR �Ngscoµš.›Ê²RJ{ßR I‰$D"¤�‚(¢5(^«˜¢ÒvkQ/W³Jƒ �ÑDÌÒ¦U>èÝ�§° –<(²…hk˜¥i}Lâ=$�” 1á¼–¶ÅÅR& è÷Õç>–wKßÉD+•’,ï*êÖ‹"Ê2 >j‹¾åĈ€Î±‹øÍ;²ò`ŒNPt#ƒN÷�üá?ôñOÜävr|úá›·WË'¿:[­Ž'™Hð¾mÂTk»{ikçÚµkÏÞܸr-Û©¬@›­³ò 8 @R*$¿Î�­kû(ÚJŒH @@…ÅÍ•PXN¦�Þ÷³¹[Ö«zQÏZS¤½[/oÝüx6èŠ1ˆ…!:F ÀëZW³jú‚#犫÷ßüúª­·FW›º°J$ïu•±¦ÜE•)´”̲ª›ùù)ƒ Î?yôhÙ†öó_žÍÚB“$VDÝÍ^Þk”Öýaï`çúúž„„y–ý�Ýúí? ¤õEL”0÷Ó?ñ7üÉ©v|ùZ¯ÛïhЧwä*¯ë @-$�†[óª±e|z›ly<©ù<7…ÎóÑþÞñÝ'¦Óñ³^�0µuë›zb­�A¼¤ËÏ=#ç'‹Ç':)B!M«»�mLÙfÙ“Nôã6.íùImI7¡%•ˆE–ûÆùÈÕ¼^­fd2½ÆƒAÒ¶¬ê�„Ö%”„##¡€"íVmC“ÑÁ0>ö*ˆY¡!H"–\‹c`A•Ûè‘QÆ,–‹U½0¶dßhcD‚¤±¶pâ'Ë“h”˜Rj„ƒ`H Â]Rj/MTΧ¦�*ÁNø„u™ÀX)B­ %‘”Ú:%Á$,Z!ˆ”¥Êž¿)o¼ÏÎC†T&¾umóùþ{WötÞ{ë+¿ú_þõÿûÙ' � «`§ÿü‹7o½xó™—žÛ¸¶³qé å]T–•M@À1¢`º€(Dt()—œ3D‰¸Ž¢jµ¾1 iÁr+ÅFÑÖÖh„)Šé G¿˜…ùY;›Íß_¼s^8ºú²íªì$d„µt»·ÙÕY;=ón!R5Îí?ûâѽ'LJÎ-¯Ý|Ét»`„Ɉ@J s "H Ø/–3k‡Ëù´á×¾ø�‡�ZkÁ×,ˆÖà°è ¡²6óËe;Xåy?Æ€¨¢Ž–R]MCdcQ �Hrÿèoþ�öу®§œ2Û¶býÉø<·{(`±<Ÿ æ)PŒ«·nŸUWˆÖϧùÕü™ïù×~óg~ÚvúbK"~N€ �S­±H‘ClwŸ¹aG�Írûäô ²ÞÎp{|xöéýó³Å¹oâÑáÉɽ»]]êÍîL5ƒËýä!<÷Ë<¸8¥=9©,ïĘR J4'å‚o‹DT`�²fDdMF›Ý›7ZtYiT²±iAiÀ¨@i­Y"h“iZkþ(x/(@ÐéæNêœpÊÐHŠŒ¾Ûë%§�íTá8ÓFE¬™%D̬„ˆÓJB‚6@Hà=ƒÈ�4h Ö�wÉ*æ •f$%(€ F.3 á呿«ío¼‹â!!´.}þû^þ³ÿÁŸî2ˆ©gÕ Wî_Ö¬{×oìö{¿û¹W>™ 7¡°¢ ºˆ„�D4B�$]t_É@"$a‚À¨eMÍAAB kˆÎDeAˆè\�vÍ`³¸†(i;¦æäñÙã»iYÙÂö/•»—ÑvQ8bž•ÛÛjšÆÓÓTgc÷…O_o›¶YÎÅäHA»&(ô:/…€Qi¥Š�ÝÝG÷-\óÎûw¾õÖt8D-4[²‹�S�„„=(\,&Z4Ö(bæ}·ì£8% Âáø ÿüÒlQênS»½«·/dÙno^›Í—‡Ç³óÓñb1‹Î)4ÌðÚ—_ã(lL®Õvoøâµ�¾ú•ík/„v59:ÞÚß§­.xØ-�æ“z´¹’G¤ u3­L'¯.|xøþßó#¿§ÎÄŽ†± í“©îú½áÎ W¥„"/¶7·™ùKÿøŸ†yèä=À ÁP‘Å”cÌjY'ö>aa¥•ò¨%Ø4BZŸmH�Öv¿gæ©6HA2 Òtx%YÏ qjÀ³¢œ„1i£UŒa¹¬LÇdYÁ" I+ÒÖ6ÅR’fc0ŒUœb� ˜Ð*%*¢ØQØ‹' ÚU�– .zÈšMaŽž¼D'0 IÈ(c«P-CÅ6±‹!áêø _¾¼»ûÃê�-:hLžUÞ\þügNßøõvfŠnf1ÆTµÏB§óáÁ�Ú—÷¯÷öFQ"§V]ŠÁÉÊ/;‡Ç—?ñb9”]c„o}ü™êɲ©Í|< ¸ñDÑ3–6DmuŠÌ�:Y/dÝA!•bd@d ’ot¯¾xãüöýòlƒŸbl1ë(Ì4‚ÄåFGgý(v2=Ó…4Ë*¥HÊ.–“"ë)ÒYYú¶î�ú*/Áj2Ÿ>ybJ² ƒ0ƒ´È6S A€ À¢—YË\ uŽK\+%AR„µ† €$H¨Q©<+?ý}ôõßø¹ñÑC!/`™QÐXŸœìâñ\~â¿øK¯~ÇÇS^$ Vë\†¢WÜì"‚* ÐSMÐÅMYP hn0:ha9 mÐEˆ÷Þ%à„*2GÔ´&¥”F!ëCK¢ÛéY}ïýóÉĿť—^-ö÷Ù5ÕìØÏgjÓéë�‘n‹ �Pr�D„Q™r4*·ö6¯^]=:|ç«ÊÊö‰¢R¦·¹ÓÙ¼RÏŽ 4¤”pô±ÉŠ!‘B2 ˜P@áØ"a–•¤øÎ»– Ò�ºÔWm¯§Š½l“U†‰tÁÑ+Ь |Dƒ�¸Óík“³€þæßûû¾ðŠf\�¢¡�íMï� �OÆÓ•˜2F¥I5mr@Êj4Xä›mÛ'Ï>"°¨;dzŸüÛÿÝw~ê…�Ým°jgw{s·Ã·®û•ç³±�v‹éÁ³7&ÇçOž=ÿ¹ï.Î&wÏ�O¢zÃö{õxñðÎ�f¹”Ôîåiô£ùµ¼/Ç£�ÑæÕgÏóþãǫբk¬%íCtÌ)F�÷ªï糕¯Ên'2Ô«&�HšHgYˆ¾;Ìê¥líœÞ½Ï,F[ AN¤-+Å%õú»ÏÜ0YŽŠ/›MÓ W÷ïß?¹ûˆ&1zbËÙP¥ Í¢i¦CJF iÅmÒ™- Õ4 Ar­Ä€ËZ ´½Pð)±äU-m�èE`AÈ4BRJ€P ©V›·~×'rx÷ë¿òè½·Åø�²Ì¶õ*ËÌÖÐýÅ?ûÏ¿übÊú¬3–5oD@Z‚¸Ž¿$X+R$bl¨m9p{|·�ŒÙ5å`³i*·Xø(ýáŽPXM'î¤Yžç[zçÖ+Y·“Àk›àÚªÂÁKBèllt6ºˆ1Î�ý|>~ühy6�ݽÛNæƒk£�k/v÷·U–ÍŸÜÇU;99g«7¯]ì^1½nÖíIª˜ÔÙ£{wÞy'?¸ñ›¿ö?زxá•ç®_ÙÞÝÝÕ˜D8jN~|ô`¸µ  …ˆ4"PÞé]ºrãÚõ³Ù|¹·ÙßêØØem4Ju ®Í´Y§ñ'"¨—+³¹ÉÂFçÁ§½Ë—SJHZßù¹¥P¢0u‡:@Ý¿zpz~|úáYð”R ær{´…4¯A“w†e{Ü&×j“/«†SD¥ë¦þâW¿ñܵ—®oé£A&ËU\�Î4e»{£vrT×¾¡´ûòõ¬WpttïþÙy_;\ÅVI²™-»e™ÛÏíÏÆç«ñé‹zÿÙ]¾ÒišéÃÇ¡iE DF#Œ�@¼°µÂ�’y™™Ü¦ÄMXE`­¬Ò@¤•ÉÀÂpÿ`5›·³¹Ø243B½ò-e Mé!ä]S%|øðAµjQµÚÚkׯa™ß|öÚæfÿîÛ÷a9–Õrµ¹7š/«ÅyjÚÅ¢îï66;•_�„Óʧ<#Ž8]ÕÑ+XUR·²òج"ÆH)%‘¤¦ 8oÍ0g#€‰Deˆ‰•BNB€_ÿÇaëÆÇ¿ëwÿ‘ÓGÿkç 2¹Q.E \”Åïø?¬»½¤ Áõ©F_´ûx­oP¡Ævž³4·Ó ±„¶Á£Ö�ÑfvpYõ6{ʤi!ø½b}¶¸»œ�®<ßÝÜ+†]°FPV@¢E@ˆÑ1`ðf�;7^„(nvRŸÕóéâøñì�ãØ‘`l¿<¸¥{V''gÅ|Ùß`5zæÕÁ‹?øÌ÷³êìœÿÇ_ýÒ¿ô¥û›#ûGþÈ}öÓ¯j2Â"&G�CãëÕ²7è#BJQ›,Ï˃«7~à·¼soTä=k§Kç£/‹Ò ï<ël€À(k9°Š)A"ÒJØkÓß¿r‰A?÷ÉO|øú[YŽªÌcl8º8=ùà�·9ÙB"ÔÚ¶‹åE¯U"1·ËÊ�õY®4B„6&ˆB©Jg‹Ù¨ô›Ç§×Ÿ{v|÷ƒg?õòÎKÏ=~ÿݢ߭tÜ¿z¹áôÁûï»VÍ*ß+ k0ùè\`qÙî°Û߯&“z9?ŸÆÔ@Z�<:ìvõäÔg¹R€$ ‹&� ‹9’F ”¤ìõ3TÅFÞÌšzrbPc’¬Sú½ÿ~â°Z¸ù¢I’‚«7‹�ó¦kV¡mèDP×óè¤IçËùêù�½¨Þ~÷îlºÚ.òèœ*ó¥‹ZëR#÷UB9(Ã2Ë ^è;Ç��Ñ‹iÍŒµ—ª•¹ƒà•O 1)Ð.$ˆAÚÆÔ¥#€ŒÁJ(fB‘Ç÷?yøð¿üÓ‚ŠQ¸m8+= ΖþGÿÄŸ,G£h !F‚Š$"DH5LÎÝýÓG·ÃbÕÙÞiêjúä(8gM?Ûêà žÍëYåÝ›‹YåkQV—›½Ñ&š²¼tùJ¯+ÑŸ=ü€ï&IÐ ˆ5Z›¬nZ$!”n·×ÙÚÍúýàò5mìšþF~p#¿òÂȵ�jáÄ!¢2¤-(½æ0 $D›�‰¸Áy‡ýêþèûÞß~øöoþÆ[ï}ØÖUJIR“Ðh4Å`T ÍškBkÿ™8-“Ï­½~s{ e¹:o˜êå”eo°¹ÛÔ3ÓÏI€(1#ªÛ…͆J°“Bµvbë£jNÝ¢ªë¼kŒÒbU¡“êöûS7Õ¹ÝÚÞ<;çY‡” àÎÖ¥ùb¾¨)y¿¹»ççͼA!u<™ÄÛpëÊΰ?8?<ëltÞû°^LGWžëÞ¸d« @ùÖ¾Z×Ð0oï^�“YUÍ&uÛ¸ùxöæ×_³º™MëÚßP·ßxG“~æÓ¯=ù£ M왓6š…û£Žê©Ö1¶�¯ëù 2êŽ:&/r›ç:ïn�’4'¦v~v¾h+–,7E™ØÔ!„舳n¡;»[)e £dØß;?¿ó›ï”âZ,Aܬ©6G»­«ÎÆâ"%ßr”$ñÉ|ÙD­Ò*Öº6‰’.ƒÌ�TRT‘ÙE L!±ðsI¡°À“ó8ê(#Ñ!‰…4€É´1(œ¼KBˆ¤¡­“süCŸÿ‘«/}.CQFp <àu²Fµóðàîùë_›ŸŸ Çí7ËkÃ'ï¾ÿö7¾ ùèÚsÏ|ì•ÑõkH™5:qÔYç Ó¨2Ñ&™nR+nP"J�ÐB"H“—Øpˆn¹RËi³œ¡o“IU­Âlúð­÷—ãÙõgžÙ¼q¥ÜÛ*77íö¾î�“*4�²X÷7•DdÉø„[º;Û/;ûW¾ë{Ï AJ­µýv>e×ÛU¦ÔH‰™XD˜j­®_½:òd´½“U-6z£�Óºb¡B¡U6Ĥ42JdçœGRÖÙ¾tó¢ ¨‹Ê­*•bÙ·ˆäQ�¾þܳÓóÙ3Ï\îon/�ÍÊ\uÌo?Î)+;Ý–]wÇÄi6>ªS"“Ê–½Ò¶ «•kVUmÈ¿�yG_ºþâ¯þó_‹ðÜç>‡y¶š.æ''“ùT”_·uõx¹ªÚ¶°Jû%ûðàÃ;››ÃÍ�½¡Ž,´±u�°yiwóÚÁìd•<�˜¨èX›ÔÖîþª­„³³Ö*Á¤†Pf–†ýè]Õ,ÎOO f• I«Â:V“Eo£˜,à�Måõg^¸úÒ­ó ÄÓIµšµØ yc÷F[“É1Ä"+clÕ´6·¼¬]ƒ…›-—ÕÜ¥$‡Qã´aPS“(EvŒ‘�� ‚Lþ|–mŒ`µ*À $Œh‰4 l]0Á{&°f+¹vãÆ'?÷yÉJV� C"aÅÁ=|ï�_üéöÞQw«ÛÙÛ¤ïÞyx÷Î`wç‡~ôßÜz5ÛÝbU®ç÷J¡0 ¯‹¯¨„ ¢!$ÂÌ ÂÚX¼‰œ²=Ê�¨™Š[DÕJ7Ù›Þv¿èm]ßÿo¿/Jí>{«Ü�é€)Àfö¢ÎCÈI1&Éå‘@7eÛš�Û;�$º³žžÞ6:v6sI) jI*3H*FéÊþûo¼¾Í›â2åʯ¢Î³²DÀ‚Ê P¤£ó†mŒQ[5ÜÞ!CÀ( zrïQ¦0`¨'snЂ2›Ýxù:‡à\ºtuGõ¯4msx:oÏœÉttugÐÏMdæédLÊ�R˜)"°øè��§—;‡ïœÙþ@aZŸ|ùçfçå�Íõ�÷ÞY®¢� ÒºÐïæÞD\.âdµ!«Õ ³³½e 7÷vV‹Å£»�Wm3žŒ7:}-‚˜˜ipi§®¬!Ö$ÖIba³Ð¶&#@!’ÅÙ)Py:Ÿ  O>§�:�)iôú£³ñáüÃ×ßu�§¢³89ö’93£T[ÕF ÔËUÃщʳ2¤ M®­"%˜Q'Nu‚6‚‰‚�A;–˜RdDBT¤„™ˆ%iÄñÜm°Ó�ÿ/Qÿù£ëš�wbk­;=áÍ•k§söÉçt<Ín6“H‘¢Æ’ 0²&X†1°Ãá?ð_a°6ì/¶Ë3ðŒ<Â�")±›dw³Ó9}ÒΡvå7>áNkùÃ[»õ­P(lìª÷ ë¾Öu]¿®¿aq‚°"Ř@|ë­ÃÌ€ˆŠµ.þèþ§fP'S¡ÒªÝ¤ùewyî/.¾úù/>ýÁOS³ Jy*³[ËëÕùýw>úþ?ÿ—»ßø ¬j6eB‹€†„››–'‘×EPYÇö+Eç[ÝH¶Õ.`d—"Újr9WRÎ Á Þü£{@¨qÀ¼Û_¯Ÿ?úÓ¿�ÏU�†‹«óàýí·?*¦{ÅΖØÕE0m;!z  ΀š¬AVR°κWÏŒF*H.sÞ–ü¤ÐÆn™R»wpѾxy¹\6Ϊb6/î;S2 !s!$Ò•í}L«ýƒCbµMykí³ —³ŒGã÷ïÍÏ–××—"9,š�;÷Š»ÓÜå>ÆñpÚ‹ìWÌòâ«sUJUT>z £‰l¥1ÆÔ‡æÑÉ˃éÁÈæ²žZ’‡�ž/þÖ÷¼n; £8Ç“nÓˆïÊrXXò}§2uýF˜ÞxëÝÉññæú<‘ʯ–mÓ]/N¯N/2FH‚ˆ$„\Ž'a¾(5lÖ©‹¨IqäÖ·‹Å¢ë= ,Ûë˜I‘P)c”%«�+I+›|·¼Z¶¾éš fÙÝ›­_^¤L!C×ö)c]ʹ0Bò›u1 ‡ƒ®Oýz#Á»¢|óÎNW¯®»ëõ&Šø aL) ’�˜AÉÍã_X´Ò´ì¸ iIRY¨4‰‡¥„ŒZð·Ö‡m~[2“÷{°{÷#vNÅðâ‡ñ“ÿæß,Ÿ?ƒžÞøðžÏn½sw|°wòêù{ßÿãýýªÚîÊäÿ‡žcbž¥vGÕðRI¿†F° ˜°»‰m«P2‚ðöÜ¢± Ê‚ Öåv;F…êÃÑ;³�Žî"§šüàñW?üwO?ù¦.Úª¾÷Þ{{ï~0<<(÷î�Ùñ$#e!$')9�L(Æ•?úìáÑîêî›Çnv,‚H[,ÙªÚ±Ö}ûûßüóý]�àÊÀV…¤Œ…-þ„@¡B²Š,ƒR€GÇ·\Q $ƒDêÜÛ­«jïð�Sâ>ÇMß,æª"U•'Ïvg „O¾zþôËG/ž¼œíMs@™¶KÃÑÀ�„7]bÀñÝýÍbn5%]NÛ6Å��Ñþá¨iýã—§)F�-„bJÚi"ŽÆ,̤”Ç\•- kë®ÙcêZÒ°ÞÌ—W‹Å’û˜cWÕŠ¢ÖÚåx:%—�2Óƒ X}`†fsv½\Ç$Òx˜�@UÚèb0£QÖU@ФuÎ4šÞw¹cBÝvífÓnË|ßûØ;3Ph ²Ñ�ÆÕÄh )[m‹áIå>6«5A鬪µ¥È•eѨ¬AfÔH, �,ÀöÀj�—T—Xh>ª„‹Q¤C`…$H"¤„QDrÀ”dÿÎôÏÿ ͸kþ«ÿýÿîÿñùWÏžßþÃ?øø?þ�ï}ïûo~ÿÛ÷¾óý÷~ówv?ú�áï™Ý»¹ÜAAók6Vê²Am—@‚JÐ X¥V„$ß „_w Á¯«è5šˆHnŠ£@ˆÐUXVª�nß9~ïƒÙo'£Ê®i.O_^õÕòÉç²YØ¢VÃ�Î7è.Èøº» �¥/?ÿìÿþû÷"«AmŒ3($Â)æ¢(�´Òvïàðòô9ôËÃÛwªñtÙw¡g­SŠ@Îh•VºœÜúûÿà )"T@¤þÅ·¿‰L׋¹µN)Ú0Wª.üâËçg—'g—¯^œ}ñËÏ_žžEçŽ�o­çmÛ÷Ú™èórÓô!ز#ON^•E™zv¨5âí;;a‘6«þüâÒhÓø¾¨kECÐFa¡„5Y3t•Û;¼ýñïýÎË‹Ë~µ™ÍjÔŒ¡_¯7mŸš¦?yù* dæÑtgàŒ=¨†ÃýqèZãÌ`´³^6± !´M³ÌŽšUÃHY2 ¦Õ·>þxq½t%FŸ ¬ªÝÝ½Â©Ò BAal»í¦ß(§µ >Í»~ÓåQ9œÔvHP,ˆX…XUEë£ÑC)¶mHžs`£´Õ¦@£™+g�Ž&¡i†eY Œ&�ªPøÎ­�ßûÍ�?¼µGݦ]ùd+Ö#ŠF‘9 úž™!gaÆàñø/ÿdz;ï€Ñ?úÿü¿ÿÏÿÇÿßGÝ}çÎþ¿ù_Þÿ»¿KGoJ=¢zÌå«1͈‚Jn°p @YjÄ ôí†Ð gMÞT"+PiËAD`”-(JDÙöâÉM?>¼Fªo{5ñ¦Má¦\gÛ¢ ˆ¨Êz°st|ÿíÛï}pç›ß¹õþ‡ã½”ÅòÕËõÉ©1\Üå¶A¥·e HßЦ™ëªøüËO?ÿêêÉ£G ò¸®´5¦ÄSŒF7ó+m ¦úüz¥T™+e|æBk¥ŒÖpxïíúÏþ3m "Új  þG¿û±Ÿ/†ƒb29¼}ïÍ@ýåÅÓÅÙõjÕ‡&úùbÕGF-*ãtgÚ´Ýbs�¶}ç}ØfsI“F`¬Ö’Òátß{oIYôgn½yçüÅ™ÏAiMΕ¥M9Öã!iÜ4M]½÷EI·Þ|£›“GÏKãh³nÖ‹9‹,.—mÛ®a΂wïî»Ai•+Œ]žžOvJØø6}hêÉhµö)±(EåÀ�ÇãÕ|™@š6ø®îU»‡ûD ú&¤>yß1³Ršs´Ö!ἎS¿ÜŸN´­à -^­Û³‹ëe{ÕuMU”ˆPÔ£¢r"™˜€|Π1 * 3Y�Ê R"ÿ»ïýÆ{ïT­´§g¼ñ9‰÷qûaäQ &L,¾“³©�—ßü­ßÿÎïý> †éßÿ×ÿÕúäò�þÑüƒÿééÞx�‹ñ¶Ó†Ñ(A`Ðê¦ÉxëüÙ6¡aÌBÔ(ZÃÍSœ RèßÐz…Hz‚A"@F(9JÜRÀ!“DAB@B”mi£i„×ܹ×W´h…¶ÐU­ÊJÆÅîÑøèîν·´5«‹Wg?úwñâ•Ö@J+må&´Ž@Z‘¤õW_ž\-ä嫳““'ì7£j «"DôѧœQäüô$¢L«u`m-Yk¡œì}ðõoýÝ?ú‡ÆÛFJ!@TÿøÞíIi¡…[®ãj±Þœ|úåÚ7={‰js+”BQ9çR+ÐÒu]³ñ>@H9cÌZ)è�Å‘&ĺѠzû÷\ÈÕpŠ.—óuÛ2îö½7šU›So´Ýl:DN�/¯Ï¡ ãYu5?�íî´mgT‘�¦ùê¢÷, ÁÜ9œßwsyJ-ۺܽµK¶Ô”ûu[ŒÆRWÏ¿Æ,¨ì �bâ®e]Œ§Ã½�Cäè—ýòò µ©”‚�$@$)¬6ZŸ\.;bΜ“Ø¢(ËQí\fj}»Þ„®Ï}H! eª\©-'µAâÎGÌ(¤ˆäÀš�X,iƒT%öWçý|CTÊèM×6œ0e YnR¿9aŠà{mþ³ùŸOï�qê`¶ó[ïûþÑÿ@†;€J�I@o™n †þåm ·e„m ˆ¶<”í„Ì+JŒ¼çèq‡’€#IFÉ s@`�â�#rF‰¯Q¡‚À”=AÜžá_/ž�¶Çgd� (( ÔÍ‘•¢"tu1ÛÝF]×=þì‹îúZ‰w•ÃmÈÖ=2šŒ>ÿü‹/|äåYxøäÕÁtx¸¿‡®0N+2«õúåÉEÎ9�Z·^€´¶ZiTf<�üOþËÿÕÝ;o#"‘"$ ’”0ëÝf0™èMHÏW/ÖˆêÝzw¸3®V›Þ_¯çWÑ'ŠáìÙÃ'!&aÔJGŽ$kdBPÚæØ·ë5 •4™Ž£ØU^ËÀB5)3³‹|íƒùåÂ:5(§ÏžœJN‡o´›öè­7Œ˜/?ý´èáldœYœ_îí6éàˇÏ³Ba$Òä&ãáîn¿>Œ/®d“N?{äÆ#èM›¬}ú·Ÿjm{Ii"”¤”µ•3®´]ÐÙ»v¹^]4J‰3«²¬´ážiu½HW¹Û Ä�J¥{‘e'˜£÷M,�s&µéb¹Úh9íì�ÁgD¥�µ*ú�H‘ñÁ² 0)Œ1÷M”Ú×Ú†´–)Ñ´,ç˶–,oPj;�È|ç›wÞù( ¢XëÙ×¾ ÊFTy[s& `Ë2ù5Üa‹Êy}l¿ƒ‚²-Á¦¼¦0¬¼þ6áu�ÿú @#jH$öT”9ôܵi±ì–›ì{.Jí ÂB8ôëUQØz÷ØîìfÉd‡~~Ñ_-$oªÙ˜9i$tÓ]0NP—ÉòvüBe§o|4½soݾúòó¿ü7ÿß;o¾}ÿÛ×ム„¤�ÀY÷›ßûèo?ùË©Írñ¿ýÓŸݹ»{[!UF—DnãûÕ¦#MÌ™ˆ�éÙþ-¢mÿÍVOSœ#*,ˆ¨�g‡›\*›—¯ü¼OÞþã#©˜bH¼suÝÿÅÏ2ëͦ·H«¶É�µ5}ÛBQR¶b&i¼Ttp0µÌËÓØ…ÞUÖ �%Ýnú¶W�Ÿ?é×ñàøöÎ;‡«Ëkði2Ÿ^=/ªjT:N²{°Û^/_=>UZíìî½q÷ö_ÿé¿'rO?›_Ÿ¥>0“6@•à²[¿xÑ_.8zöÓ_Ÿ]Šq?ûÌuޱ°EÂŒ€¡õ‘rbvÆX­ #¦4ó—sö’H|/ŠÌt2nÛ9�*7_´§¾� ˆÔ²Tš¸éçÖ81¢„FÃrVQÀ&Ó¥øøz1aVTÁ&$]V£2l¢/­*m‹BEîNNç�tiìý7ÞhÖç›n]Žs‘ÂÖoNÌŲ½XŪĜ€”€Ò@Àùwÿðï … ¤9 $ â&Ô n.}¾ÉyC0[Ì!B¦-ù�(ãêE¸:í/Ζ×Wzgá×/íê…«ø€Ö2ÄÔûÞÇÐ$çJ;°¦°]×Íç›´‰†;W•¦®ÊÁ8¤$Âë«ôêñó.€&TâCL«ëËj2Û»} ÂyµL½ïC0ŠÐM¤ÇãbïÎìö~5»N 2�*ª‰»÷­ïì½qëÅgŸ|þ—~pÿ�ƒ·ÞWÄHš¬ÙÝ?<˜ê³9G†ØÂÏ?_þwò£öOþ`0UmÒÕh\&�NÚñ�ú�ŒAbɘ„ãa2˜3’$dfÝȪ� qµè¤¡Ô½õ�ß—�CÂàCÈèªá³�gëùbp4+¹xq*<'2úÝo¼ÿôùãõY°Æ Çõí{÷Ú«'Ðø‚”ÑfT“ѤŸ§óÓóhk”ÂÔæz¾9ù³OÊÚß=\ŸŸ'“áŽÝ›M®W«§Ï_J¤ádR¤,êÿùoÝ»srzÕtþújèX*$Mä¯ç/¯æ$¬´ªë’ÛÐ^7‰£›L€d½¾vÅPH„E2pΤÁ7°òËzZ÷ÁÇ – ÆšMß8…ÃÑl1_víª*Œ�—‹ €Dœ£EmsN=ÄØ0¸½½ÛMû"6,tÛû„ê¬Y/C_õz42’À0ÜMï¼qLeácjÛõåÙfìT�Ê:ì–ëvÓoÚnG¤P¬6…v“r8öÝÉÕ|ÞgÐHJ€í¿qÿkŒö5®GËMmk‡’³"¸‘Ld øAxÝb}ƒ9ü5ã9¢¿æËÓöôÉâù züèÅäèþÙ/ÿÕx4¼sÿhpt J‘qY †UÕ{E`¬E7šPQÞ¦²$$D"ØRã³ Ÿ_wë.m–¾™×³=ÐäF£¢äÌ웸Þ4ëÕå³çó/O|µÜ,m5­Æêèî{Ç|xôÎ];ž *aKÜÙ¹õþï®/Ïüò‹«³û_ÿظBÛrvpðΛU¡6ÞƒL ‹ô7?új61¿ýû¿'®®¯”rLJ»óe[Õã="€PN°·s ²m®Lè RŠ9oKpDO�2Óó¸á<´~´~ú|ôÁ›œUžÛëv=_ô}4¤AzmQ+È ¿øÉÏ’Ê­uñî½úâáIèu58><ª#]>=QE•ˆ›åUµ³[�ë«—u1¿\�Í¢ÕEÌGãÓ‹³Üòtgºp\jhV~0ÜY®Zî6­1.‹ç Ji­Ôp0P$‚™mi:ŸX²Ò.lduvzp|—gbˆ„1ж3ˆêCKZqÞ»ªF's8£4ø~™Sp…qÃòìzÞäÌ Y#°°B• QB0®lÛ QMFâ0W¿ê��”OɧÜùX:ÇY÷¯ŸŽfÃÈ|q± BÅ oÒÇ�c’¢41ae á`�Rêþ ¸=™¾8??Y¬6}‚ ò‡_{GY�˜ñ º* *VF@ P»%ä ofmA‚žr›ËðìÁêìEò±œNßÿŽ)‹ý�­2æ�nÎÜ—E%d˜ª± ˜µI¸0ã]å,Ú L)ÊÜ$ÕkÑA€8Õ¤ä )*à,Æ)N ;Å~2ï½ÿ�Ø®Ö×׋‹sNtqöèÙ§_=}ðìè­ã·¿ùáî[šr@Öi=>¸ÿÍÉþÓ/þåOzï�·L=OF‡wÞ8yú‰Q3Tä?øágÏOç9ø&Æó‹õoýö÷$E`­µ–̤u9œ�Æ;H(À´õM1ÿº®õõé«bgrt¯}úhæÜõ«Ó‹ë+3m„Ÿ??{òà$öY‘j}ë¬@Ž S y+áWãÁá�ÝÙÞp}_þÞ7¿zôääáy5šè’Hðòäjqqf\Y@cr’Ù@ïFe�î•ïºÁ`Ðt1K?pVIlÛ«ý�Ý‹ùµVVOÊ*¶›Œ˜úÌ )æÒMáýߦè¯^¾êü*f©+£ªzÕóÅ:€B  -Çs"� ¦ñѱ•å�ÇÃÁ„Ç㑨Sxµ¾îQR&Î,›¶ËÌ­ïçmk.®SÎY€˜�)Tæ`«w'"É9eB`2 ‘ Ö·‡£±&Ïù¢õó®ûþÇ!°lÈ™,"oµFÙËÀä vË0G‚ 8âéËÏ~á¯mNûï¾[ß×ÓcP¡áfÕ_žö'ÏV/žsëß[B·3q“ÑéçÝÅÙäøëºÜ;œ�ïãx*j{Úf‚›NAdÚn T[…”3hÂ-’‘I!Ñ�¦ÅÎíÝ7=¾å?ö¿s±ž/ûÞcj—/»Ñ 0׃˜‚œHwî€_=øÉ�o½ÿ~1Û¹ÿá·ÿÕýIë8cÁùù§¯  Á¶69g@VÊ¢p(êŠ)ÑZ3óM¦@PôõUcÉu¦[4mWY–ôò«“EzzÞ¯.Þš�„àMeƒÊûè»fÑõVÃÔ¦KYáý·÷Ž�¦iÝþìÇ?µ®8ØTfqòìîí7šp!âûaµ¯�‹þ²–ƒÁðÅ““À´çJ¾|~]`µ{kò£¿øST®ÚÚ œÆn¹lί£Ä`ŒÊ)LÜdRF†ôÁíÉÅÃ3�º½^NöŽÖÍ‚$ÐN¹zºî‚7jz÷ý»§Ïž³.71­;/Qóä�Û·÷n/Î/ûùŠ7kß®03r¬/—g›q»ÐW”A‰E,™áÀİ €¶�XÚ‰ XKŒïNƒg×çÏS$LÌ�÷ŠH˜5©„À!”e9sFS°{¶kVštÂD6›Tè²2Nñ¦Û5ãàý¸v¼7ýàý2�‚C3é׃ÍV,g³m8FÈ7H7YèËÇÝógW_|švxppëÃß(n½Á âé£þÙƒ«—Ï×/Ÿq“ÜdävöÕd0‚ UYXwyöbí³Ôëv–+~ø•Þ�íß=ܽ5ºû”5h½õ¢Þ‚æXH# (’oN&ŠA#æ F#)EhõQUïgFHɯ–«õõêÁ' Â*Ęs–Þ~ò—?üÖßýÃÛwî¿YŸŸÎÏÎ_’è.sNéÛßýú;¾ÿüÁ¿xµãÌzÑVë(È^lº§ójˆ¡íwï^¥—” E1{­¨[.j€é›ÍЖ ‰DöVÛa= ¦·îÝ™î×mwé¯|lÚ£Û·ÑÁz¾ÔWkDú>vï�³¡OHJk­@Æà7íloš.t=ÄÀŒ@‚·DdJpnZ2Z+�™‰3 �FˆCTv\�_\Ô“=‹ ÷Á¸ 8M"ay½°%¾øêWB÷ÔVáÙÖ2HFQ€"€E„�)-ðìäü'? }þÅ—ëf0Þ9xûÍ�{÷Æï|8¼ûN6…؉ÃjPµl� zK7»¡lóƒ¯/OFƒ�··ƒ EPM�«�Xª½£êîýöÝ\].Ï^-^¾xùgÿf<í¿ûÑî÷ÍhÊ*ÖDXnæ#R�ã ¬îÞˆbø‘·ƒg''½ÝÁ$£½Ãw¾ÿýÏþê¯O¯Vm†ËEç 9£MÛ)kŠ¢uÃÁ‰I�³ )R¤ G#R(̤, ð¥Î9¢"Ô××sL|õxj W•¾éEI‘ g ÚP; yTÔ•ÖØ[¥E‘ŒÎŽf“nÒ^-Ãz 'G·‡j*Ö¯{F·±¿xñR‘\Í—ÊÚ£ñìúúT¡*¬–N¾x°³30…îÏÚ_}vr~¹ZvmB–”Ò;¾õ»ï·bŽ›U=¾ýáêW/Æ“!ÍÆi³ö¤ H<|çNY—}ö–mOS̤Ê!š)‚F1›«ë[{GbUÓ\sÊ®ï¸ádPŒª›—‹ç/€ƒª'”qŠ�×]ÛËÈNÕ˜“/^¾Œ1ÞXocDMm×UVõͪ*L=´­´,@ !c "LÑgá²2J)Ž1)EB€…¡k¼q”Å�ʺ‹-‚:*ÝõübÇH¡ÐRVÎæÜ*&!A‚6yÁ�ýu扆 X@‚h�ÈžÂ6×›Oöò'Ÿ|ù£Ÿ«aqç›_û;ÿ³ÿõèÖm5™@5b;  @ÉÍxÛ§îÍYâÆx¹�ßÀv£Lˆ‚¿þ€d»U%B°–Ì`<šŽoß>~÷ýf~uò«Oÿ䇛g_ v¦ÃÃãòøVC%ˆÈüN ¯Å¢J¶½˜h#)BÊ’" ˆQ^ÞνwR FUô~ÿ÷úï‹Ò5¯"&κ'U ªä8%`MKÔ¨µÒ4 …IefH1)­�$½Õ�t·ºÚ44ïúÕRyN™—=Ç”{ÅÍrqxç–lòx:Œ ¨B9ÒÒ�cìLÁ‘ œzõ¨+5 ÆãñäøìùÃ[£Gº7× ë\QX$­Ëzr|´˜·>6( Sß]‡xqÑ\xirØRÊ€“Ò4=šþùŸüÛ'¿ø²׿ó½¯) ™ÝàΟ8…M+1ZÊíríÛæz½T»d% $n"x%Ì1·š´R6A r 2ÚB¶hƒ_Í_¬}dìX±Ñ%!‡õ:v: ÏfcxÕ8C …!LgÃÐ÷=ˆn! $tZDE˜îîãxõø‘H¥H+ÍɃ#°s– ^k«Èhíz¿!›Çƒ� �µ¹O•ÎèwjÌ58²ó§X«èŠB)Ùø¦M:@I¼u8hF:ýÊŸ>¹xðô—òïÖ—Wn:üøŸýóƒ�ƒößÊTd ø†Y¼=@30Ü ³pëä@„[›¼¦%nÅÂím °%Iߤ0éõ$Aè´Ön4Úßi.N—'g«óó³3÷è«ý÷>¬÷o£&@s³‘“×ÜjÒ P@2ƒÒ¨èæ~$ìÍ- ´-gmôP*úÚ·¿ö×ûÉãË~gX x1ä´u¨laµ^¶A�µV�9Íf{€I„pÞ"¯1Æ`]À"¨7k¿œGQˆÂ›6Ì¿êº%‡DòÖÑX�†|~áS6vX×CÓ^6•ê[25'Ý/ף鴕…©N?ìšF›ÉÞÑÞÉé‰RZ”%æÝ£ýf3‡F�Ž÷6íEÛq»iјÍåi—täHŠj2†$+MqµŸní’A!H€ U©öÞ»¿|qöòW�ú§?{´±d¹¹ Ī ál ºêç©4–`é }íöu¡"†Ý½Ý¢ª+&ó埥fÓt›õúÄDòc¥÷wg©m8Adæ�H¤,­ïZWšvÓJ'L¨UÃŽvtq•»‹U»žZ«A@‹pJÁjMÌ}Ü4Ãamk§ir:MÔÙÉ+–d”º¾¸Þ½{´óÎ! F/Ãq¥U‰HQN†z0,»¶µC6Y@ùµöYξ¼úÛ¿>ýâñ“Ÿ~ºX¶{ÜûæßÿLJßûÝ4=ÞBýP@Áˆ  X`»S@È ~½2»QoÞ"róà'x}#l£7—ïvÆYn}4 Di=:²£Ãc¿¾ï×ëvqµxõ<®/‹ÑD×S²™ 4€l•øüšû÷ë¬Ýôji•›w‘†Sº¹ãÀ�wöÞzëÞ—ŸÎçÍF#‚ä,¡ªíð`6¬FËny³„°”²ìï£xû›‘BD¼Ñ¡$¥ H#¡¾ºÚ¤€k‰=À&w§¾ZÃØªÊ–:æA5ÊÁ+²op8¬¦Ö˜jóòzƒ(в.,¹‘éÛŽ±w…²Æ-¯N%{]�SŒ„’“ŸìN–až/®³or’ʆìt´;96ëUêÛ8™ WŽ÷gÕîøúl‘±­'…Ü.VàJÊaþâ ‡Ã{·——/±Èa¹JÙ‹±Q¸kô<¨'Óª=>¢]±{ïîd§~ùÕÓÒ•ÓãÛ›åêé“ççó/Ÿ­×Í:ÂÒ·!'d¾ùø‰äÖÚ¿9é™ ¶›µ©¡(ÔʪÀ‰GtÑ5$}1˜šb·uóØ ê äÌ ²DÉ bðÓÉÁxdƒN �GiûðéƒgíÕb.Ê2×òj¹Ü›³éXXŠJ šÑ`!‡°¾Ø,}ߥ°¨@8 (”La5ÿÉ_~ñ—uò|¾¹X½ñ�;ßûÿ¼þÆ÷r±ÃŒrãƒØú–Õë«x+Î oGø£r’×?)¨âÖ® ˆ ¸Go£(¯Ÿá|ã°¸�ªl·ÂĂƣ›î¸Éttp6ó¸Z\=}ôòÉ‹rïø�Þ¼ÊBŽ[öúÍËIrÒ€$’5R°V`JK– £�Ùή@4ä Ì4Ò:‡¡4!XÍ1 ô}(l9œì!8R”b4Æ!€pF¥ˆs&R YýÑ›»MâËÕIN›Ë‚&NOûà3¯—×£ýÝÁdvûî>9µYø¢.‹²^]ŸYN1e%}“úTë²� ¤”²ß¿û–6:‡ Z©]gç´ä¾íQÒŽ²Ï…Óã�Ñx<â¶-MåÅ8UíTU)$v­JâÊ`Ìž9’ÑJ[m°�¬1à,Cw÷ëïL¦³ë“'T¨ÙÑÞ`R_]__¯–—}øÅg_þàg¿üÛÇOõâä媹ìÂ:ú˜™4© âœq­Ö ÑçdìdÝ®£ööüzû Ì‘½�ÁZrF#à°š”ÓZY]T•�Ž\Y¯ç×[é4æ H"F˜u†éþa†>1?zñüË—W¿øêɪëUf ì±R�ïïÜÝÑÎT¥E`íL×µ9ö«fszµº{ûîdZ[kHÛ ;*éþòÁŸÿŃ_>^\…w¾sû;ÿé¿|ýû¹ÜÔøL ÛMÙÖª^g¸¶‘.Ü~o‘[úðv .(yû€ ŽBܾvQݰÓo,§¯³ÅÂ7èVÈøz_¨UQ›r@¤ŸñÙ_ýëÿ¾Riv´«œA¥ÄËÖ²$ €3#"2kwÆ&[}©ÖóBðÞ¸"¥´¼n?ûü³£7Žw»�–«®,ÊÉt7në‰”Ò A}ã7~k2ÝRšˆ¶[0ATZƒ�~0?_n² Œ�ކÚú ¬K›bo¦£÷¿÷n­Ê®iô´ï—¯Þ~룗Ͽì™K*+gBÇBLFrj]YÓl”£j°¸¾ÂÕ@³±�c»ÚÔ³ÉáaL¯"b­X0®=g? ‚‡è#ò笺aítžIÄXT0{ã(@ìËÎC”5§ä´f 3�Íò&t>̯æ/Ÿ],_=›¼uçÑË‹«}²Þl–]¸ìbÊ� !Ýlð @0'TJbÎ\i˜‘©ïü<Ÿ³‚/ž_.ýúÞl4L¥÷ëR&äœ{ï;¯–‹qر¥F@408ÕíÎüÕµNÊhR‘”“Q—Û///ãËÓÍ\ÂÖ�BÖ0çzX…]ו¶4†¶Õ›ÑY%ŠŽf“‹³W·oM}áJ[!�h“ç/ÿö§¿ø›/æ×pçƒÙ7ÿÉ?|ø±;æ&à{SJ @róÈßEÛ|Ìv¬QrS©²=ïn ý7‹ír aÛ3+’` ’Ûþ 9rF`À,H˜ÓMŽžÔ–;‹¦¬÷o}ð‡wv÷½VëÅ5*­Ë‘2V„‘¶ï¹9­Hʨ…ÎY¤Ü3HN HÂŒˆ|ÝÆðô´±*-ÓˆT]޵S)y¥­ˆ@&I=•F‡Jçœ5)D#™E)ÒŠ˜™Yˆ@võ\i¯Î{C+Fƒ€26%˜ìÝÿÆw¿»72›ó«ét¼9KÓªºxõüüù£¢¨F{ãÔ)€&ɰíz;rú¦÷e9ÐJ�&ƒv¾ÞË’ôãƒÑèx²^_é QtÜFtØ®ÖÖ ™¸4Ep™Å†v0f¸¾îýz^ŒÊÑNéÛ|ýâlÕœhívŽëZ…e´º‚8·g'×í²Ùľ}öìe¿6ª2//Cß+¥…ˆ @QD¦>È(Z“° ‹°(B%�rRZep GIÃÏ®§’þîÑq©Uè•×HÜw-b¾¾+Pƒ­cÑ%ÈÉóZ#)m+ç gf>¸õVU ¿üå'—`Ãàx¶¾l‡ÃQßµ"qrtûìÄjÀäFÚ*þêœ3—zVV!ZõíËË®]^}VÖe]”*ès�g?~|µŒþ t{u� >$`pVbú-^])Ô@ À@ ”"Ú¢SÎ Ñlg°[ ‡ËfÉábµù÷éÅ›ÓáÛ{Šcä¬D@B޲ÿÙÏ~þÅZ½ûáñ{¿ûû4<θ æÒÍÿÃ`°�*n//Ù"Ð ‹EH È`²Â( ˆ @QH2p†Ü!PˆÀÛÝm¼ùÇ…�2°àVÉ�|£6aJ[ '  4e9ÖýÆw݃ÿàúÙɽo}}¸säng) ð3 €cŠmŒ 2+¥X$'éš”:¸î$C6,ƪ#í\aT┲pF ¤”?üäòìã£Û÷ Q¶õóJ)á„ZoŸz6Zu ^¬Wªˆ<T.Å´ZW\,_�]=ñZåX¯¹°NPÎÏž§«Ž•*€‘t1®B�¤izûPëj±¾˜�Ûë3bì|Ÿˆ‚×�ž.단Ôåu³Y\îŒÞÚݲ}òÕÞ­fÓwÇTR{ц¶M‡û�&UÎc8?Ù<øòáÕbÍ’ 3ˆH=*¥:]™‚¯Ö§+†“ ó�?í¨Tµ)‘(eŠ)°ˆd "¦�Ò:mð]ÏJ©Ù°žTnX¨ÆŸ³bdÐÏ»®íýÞ`po?ú¤#ÄÜè˜R½Ho�W]]M%‡z2 €(h¹l®¿89 ŒÄ�@b)‡TW� Ö0¨´+`‚Äœ^­Ÿ9;ŒªÂ(E«Ž5e|òt0*Ç;«J©èù—¿xøjEoàûçïÔÇïl…y¤-èíµfrÓA%7©Ú"…íÖË,@˜� &F&ô�Z=÷KÈíª_\æl8µD€¦$ˆÆV"¨ŒeH[A$…Êi­q{B&¨�(9Ã6F/y+ï¡võìøÍƒ·×�þ懅•ò;•’(%ÛÏU*Í9IöyÛµÍ�AP€9õ^]\\‡`7b (·Ɔh[…bŒ‰LV)öí§?ÿñÞác‘‚›U)c¶[8Ô¨+c¡¯L™(¹¨µ¡ëÅåºëì¤ú·òß]^\G{+�Åæ’…îßûú«ó=roTU�wK^—“˜ùüŪ0šî…¦­êÚ’­û®]ö‹Ó3´õj¾zzÕ}¹YÝM~2-Ûùä­{üöw}�þü„V©(wã²²�Ï_½8yÚÔ¶áìâ"NF«Ì92kƒ>¦”eÕæÂæ�sºqEZ‰@OpÁ2ß$…kGè fêªÙ¸ö©Ýl:mª¾Û€Æ·¿ùn­�߬z&‰œ› Ò£áÕ•<‹)LŒš�­?˜šO^>ȬvKS8e0aÌ»’cßUõH+ÅžÝÞT�ÏÏ^=õäzÕy!mY# k;(Ui1³0$]X‚"Û²Üò ­³d%w>³ôý¸¤”½Ò8ßôTÖ“Ù¥kß-OÎÎ{–Ùý;÷¾ö›PŽàæe–²0©›×€‚øú ”ÂÄìˆ"ƒBA%È ®m\Àò<\Ÿøùoºæzqµ¼„Èë««¬3¢1 À(]×5£Š‘µ1ÚY[Aôd¤ªr²sdJ£Š±.À‚ŽD…„=* €À@gmÌ­·ßS˜9´ýfQ(«l""Qq"")EÌ™™·¢�ö›fyuNtcïL”c]ÌIØ(R”ÒHœ3*µÞ,´ð�Mo[Í´Þ¶¯¾îÖ°� ä8 ë±5v˜¢šŒ'¯Î^5mï {ºXôœ“»~ðÙA9³MiݤÎÒÏö–çVcÕéÉ|oÇù¸ql›6DW@lS;p«fÕ.¯¿¸^®4^Eÿo¿úÕÉŠÝ£W/«�>z#�<¡]ž\­ÖË#!ÅMŒ”%êLJ+EÚj“rJ9‹�Y6¾õñpÍI£ÚÔ²¥›Ìö¦û>mÆo¾©K“DP•F)EJ¥RßJï7"UÛuËÓÇó_}>(jL!:œÍöF·îŽ�÷L=,ë¡r#P9n[nòÉÀ®,n¿ûQHшæØw[DÈ–™9½Vg!§,"9IæþìôÙóÓ ë°P @!Õõ s„œµUÀœ$�IÊ8¥Î˜ˆ )Å™•Þ*TŠE4C@AèS ÍòdV_�êJ2ö„‰�µ1œTÎþÅâUZçÓ°YLêÚ®6d'ÜtdlÚ°X³÷B›‰#³7)fõaÛõ�šURh JmµÜß5�.ßÿà“ŸüèsÈ1 be•fåTÖ@9I‚ÌIf“’Dù.’5¥Ò¦ŽÓæ2A ”bJˆƒiQ-ºÛ;åR=l|{¹ô0qd7}ß­8q:œÞLÚÄ¢ã®[BÓw][8¢±‹€ÎOž.æ³™«Dâ˜8dLœµ×Z�WÐ"´!)Ÿ ‹×ÏFc±¼ R¦H1ç쪢°Pà ƒ+ "ÙG³VF+"ÖÊæ˜¸(J ¨:3êåòBéB0 sQ£ªë–�ür2)ehÌøîô�¯ƒŠJrBd`0ˆIT[‹$�[µ‡@…sµxÜ=y²~ôdþê¢Ú=ºýÇÿÜN@Øš¸̘“$�ðš,CÛ«ÀŒˆÌ’sæ(‚±ó¡ù¨_¬ÚùUôýj½\.›ÓŸü­ýyª«a5Þݺ3;œã)•# Ä¢¶=`Š £1Âb'M_T5*RKdYrJIDbòœ’q¦/¾zô伋ÇhB&MÆÖV]\ Š5–…�´äŒ€¤ŠÅu»˜/­h½}ð 0‹Ö:猈:CV¤��Pmš¤­ÒÖt1!¢"àrTÑ"9²(íŒÎ¶¢¾—ëîUˆOŸŸBÏïÝ�ÕZÅ€$¸\4Ͱ*ËÒ…6v>¬_mήä�\�__¾è{Ô0F™�•ÓyÞD@ áU+-‹4)Hš@2:‡CEe¡ ÀhÖ¥Sì‡SGª.¯ñZº3"ñØ ¶pdó“Š›©�áÌ Ú˜{Ι€>ùg_�ÊQé õ‹(dˆ†£"AðÜùGûæã{w”‚ÂùjíSÞ$ÌmŸº(ÊáNmú6j Öh¥±¬@˜g�Nem@´ÎذÚJ“hŒAP€ÊYÒ�SÎQ+¥ºR! BTÚYW¸b (yïP8ǵVg/ON�_Œvö?üú[·ïÝî�% hDÞ�ˆ0#!”ŒÜ1Y Û®^Ηtö´}ôùųGV»Á�wwÿñÑ›÷9Œúí…ÎcÖ„ š@l‘³l·`œ@PSÎ[% S",Ä&ƒÙN>Ê >†”¼Ï¾Ù\Ÿ-ÏÏO_>Y¾xüâñgÃÁdwowpçV}t¯žì’ш@¼uÂ!nť뫗³´‹uIªä­ÿ  iAL91ãõùê¿ø¢m@ ¸‚´¨,\U6ç”h’®ï´1Z‘¨¬Iï¼ûÑdºƒ(,‚J„E„(µÝÌ+Ñ ¢€©Š*ÅÂ8(ÒÌ™”Ù4ÎDœ«Äs‚�³¥1ãÒÑd˜¢�#çœqï`§(±issqzÝ'¦ ‡“]Ð�û|Ýwä½»;ûãšÈJJ}{mš®™zîsßg²¨…P¶…7)[gJC•.�² &»ûC;Ò¦�a“Ĩ‚Ûf›ö­?¼³Bljc %¦X9ƒ€ ìºë%‰³Z—´Ú¬½x4V‡œleÙéY10€1ô�©pÖä7>dĈ¦ ¾ÍœBƒ² 9JfaDBE!R„,Q|äÜl®5#!L#Ò4,ê�£â¤SÁLd jc•ͺ(r½s†c"í²ïœ+Q@tÒEYõm÷Õg?üxç[ßÿîhwJ¨ GH½ˆ0H DݤQ$ËÙçýÉãêð˜wnI9¢”aùÜõÓÅç_jíöÞÿzõÖGyç�®y´€€Hõs‹qƒ˜%…­¶$œÍëV„Ì - @E¤@¸plYL«élz÷­ã¿±º¾èWËöz~þòÙÓÇ�ìì«Û÷ÞÝ;¬&{eµ#�DÀÖ­©!áË/>Û{÷#3¨˜s΂Ï,)yÉz³j¾øüíf>(‘"X µÖ=‹s’¥'%DJ‘fᬠ†“÷¿þÝ?ú–µæÆÜ�˜3oÕ,"ÌÌ$ ÷§eëÎŒ$¬ PbEh…gÃa‡ÅªÛäÐ#bL9‹ Vh0ø> *™{¥ ú®‰/¯8 ê*6C„èK±ûÇ{ºp?~øètÕhE…QÓ²tZ;C®°©žø¶¯ yMJ!¤ÌY¼Ï± ÆP—8žaã…³RÔn®.š Õ4ž3ö&DaØÝU;õP‰YRÎŽ‘µ5œ䜯yÙ/¹íÖ®Â(Y Ÿ^Ï›“àœ²JÖLë‚´Q¨´q@2Ò¦c_)32bð…U ªç¾]æÐu˜IˆÜbæ,V; œCŽblî#öQrØ´Y›ŒRÃa¥­Q•RÚ8"M"Î9@Åœ“_£ˆ°÷�ÒÚYCT*.×ë§Þÿèm[1%ÎŒ™‘D„·Ò;Š„®½xò°¾:™½³ÒÃQ\_®}¹zôp÷½o•÷Þã·²Ýe( ˜c2¨ÔB5Ò•_>ù„Ûõb1W̬må¦ÃÁ ¨Ë)T•.JR´IÀ Hm-¢€ ·§ DDT®V¶°EU�örê}h§÷/¼úâù/~ðƒêWƒÝ{·Þxg¸äÊrÖÒV—;;O~õ3¯Êƒ·¿Îà%t ”sŽºn~yqý資¿ñõÏ_ýÌ kD4nPbUW!z̜ɰÕVмýûü�Ù A¸qn(@A@à̤P黳ªËN¹Â fß-MO®WmJY™JK°¥°®(6M™A‹®Ê Y¥ D�@=+†”!Çœ”j@)­M=¨-¨•4Ož>|x¾F@)†8_®7Óá0!H  @tUIµ=iTe 9ƒR´\vM„èc”SèB�ÍFHAQR’5áØ©œ2 Ï»¶Ïi8(«R+ §4­Hk�ê¦iºœ“¨œcŸ2 µ}ÆPˆ9zð ›e&I…F¥aX”…q–t5 )u}Ç Ub ’ždNHEï›.T Évë.®6kb ‡Áw>&†TXÝD(©K½�1ykÔÞÞñ¦÷µÝšÒ¢ä”Ë$‘ #u]ë´@V®ªÕüòüy1­‡Þ¹J!!@@Ê7GLqwnýÎC¸NaÝ|ù4ž½X¼xZïî›;jg_ræÕSì¼içyÓvçW�žÆéÛoýÎïý·ÿ‡ÿÓå‹ëÆgg1jUXUÍÊÙÞìxºS팇»»³ý�ÁÁ¡ªGh­v@%9mËt�€R‘QÚ¸êþ¨žíì¿uöüäÕç¿øÅ_þ�þégo|øîûßý­j<0Ú!SU�‡Ç'§g8Ü*¡óQ@|§‹æ“_~¢t�Ö†œîìh‹ FU=®º"o%V#€JªÉ^9‚Ò •ˆ)AÊÂ(¸-%"Î 1ëA©¸ñ5äÄL£ª.‹zëÖAãû.±$š&·X\­»€™îŽSð›v­Ñ…¬UÎ8£•u†}ÎÂ*ñ­0åˆmæ«®iί/» %õÁ2²Z‡¶Ò.c¾Zö ãÁØNw¦ÒsÊY$Y£úÐÕ#[£vncìcŒQæ›Eé`ÑfÐN!€ÕªGéY$rиÌýUßk«gƒÒU–![RÁ(;V#Ðë¾RÜMˆi¹icR%jn}Ê¢ˆ°² kñ9©v½<¥+?¶µvª®´@_” �uÄ""£á•eÈ©°>†a‰œ¡påõªq…U¤D’°2¶HÂ)¦�sú�ž¡à\‘³Ö.øŽÀ`R¦œ"£PH9‰ˆjÂúùãÇÃz¨m…-¥²l�…Á¢8gÌ�´´zøøâ³Ïºë³~}æ“§¯>§çyÓ­×ó0_5çëÐ5ͺ_‡pü5®ß¸¼˜{¡ÒYz _n¾‚ËÒȨ¶³É`¸knÝï ÷ön½å¦£¢1)$‹‰ ˆpÞÚL I8ãh´WÖE±;Ý»{øÙ§?ûÁ¿þË�^¶]üæüñ`Ljžá²MÆ@A¨XtHgÞëktÖL "@Y»Â ¡(£½o‰p,�µfj…Ð/ú�VÔw\hÅJ¡5Jcì1÷­��íË¢¸\wÉ÷ãQ=)-t2 Fõ®Ò‰9#ƒ¢a=0)E’� KÏì}ôý’EçŠÂM§ã¦éQX1DÎq½öíÚUZ“„° ­ÂH‰(眀Ëb€„�>Õn�!àή©²Ã)²[¡Ú[$Ch›—Ÿ�þíÏš§Ï®¯–ÊÒzqzþâ¿G,Rh�.õν�ûoÞ?<²N‰.Ÿ¿ü§ÿ‹ÿ¹ý¼ÝÄ�OIšõ´~¹¹èÖ}î›vüÅæôÁ9Y˜îWû³Ù[oî¿õ¾›Ž†»·µ5¨ ’&ÐÛßW€…‘*6Ö:s|üäó‹þöWþ?9ºÿ¶}·â|ç™ÑÖîÕ³gŽ¬Ñ¶íC³î>yú×õ·]Ÿöéç~Þ=Ú­µi9*åz“#‹¤Ì¥ެ4 ÆÑh�$å¶•XÛõ6k«…@RJ„˜™uíÔh8ØÛ½�ïE�ÞGô)-çóÕÕJ@ƒH<¬ëñÀµíFd F;ëIbf±¢H|¡»2!†¦é£Ž­Ãuêg³Ò³ZÆŒuŠ�6Æç 9ú°^‡œ4áùr‘2>ã5 rè àÞ¬PÕÄdµ”Úim„c¡µ5vZQDÔ‰‰ ÖËÕºÝ\÷¼Ùô¢(İ جD�˜Â¿l�5XÝk€b°,¢V2,M]0zR–È)]Æ(«öȵ]#˜SbB&­£$‚ˆMÛõÞä«ÅF벪T]9�LJYÍ$(™µÈ¸¬˜% N ­Ö‹œ™CkDR?®¬R²(¤>¬"‚"ÕÇèSÖ”a¹AIÖY…Fæ¯Wç?ø³ßúþohe+q…#`°E¢„Uûì‹“ŸüÍé_´çMÛ‰±ÒYïºél4:z·>¸_Œwë£[n0#ëPDÁœÆÎ#¤Ð÷!bhÛU]h¡Ùô�¿xúe¼ê¯_=õòììù«WŸ|±w´7º{w¸·Wí¸ÑXtEZ[ã¶ ÈœÓvôÞ–òÈhºÿþ7¿y5? ¶ß4ËËÐ'Àœ#ד}†Gç'—R2«ç�ŸÿÍ/¾||’\Sáû{å´Ô ì´u;Ž}J¨DDB&m5²æáx`H¥ì•´}‚[, D�$¡ˆÕQÕ#2#$±eAðN·¼nÖëÎ÷]Èí¦Ù\.sß´êÒŒ*7Ú)™mN1&ßï»àJ±ŠÎk�9'\w�&£Yµ�7Öº } d´BtTùˆP¤"¨Üù,ˆ)3 3K¹ R—4¶¶M´nÖ®t•À",S6¥Ñ‰×³á°4ÐÆ]Zi#¬vG£è×}· iˆ xÕ´ëņµê(qݲ1J2ƒ"§tèã¦}ïÅ}F+MN‘¡L8H‰-ŽrÌà´RjRcÌ¡ë»ÖçÒ9À$1fN)g†Üsåš®E­„3‚”¶ÖÆ€«¨* Q¨EOi˜…bˆ‰ÑľwJlYEFMä ™v�J»bc“3‘ªYXéBÀøÄ� Æ&vþÅéfÓüÕþ½Áññd¦4(E%R”Ü7'_]|öèÕƒW¯^­ÑCµS¾óþä�7‡·î ¦µŒU9A7! +Øú¥9€‚„�«Åæ,9 È(ï#AN)Å.Eÿ›wëÅf~Ñ­VÝérqñâù“çæÙÉ`<+÷'Õξ›NF³£Átê&û[2HfÎ,@ r HxûΛø÷þaâd:ž_<õâ|<9 ±Ï)׫奻˜Ÿ.Ú¿þùç_=ïJœ@+£L±Ø,•Ò“ÑHi†˜‰³A•8“Ú�À˜²ªÆ,¤”&@&QÂŒŠ@"€a$È9þÕÿõ?)«‰­ 0% ¤èƒR01“B ½Ï9kíºÕr9oæ—¯TîzŸP81i…ڎч؇Ԇw¡Wj�½_¶m̈¬ŠR5ýÚêAatB€¬7%w‘"êØ5mš\ŸúÌ· Þ„Á%™cdmÔN=0:•¶@e�5& £KcKƒŠ3*䜈¡¶% jbã³ȉ¹Ï*õ}öm™%§‰ŒÒ&ç‚ÏÌFKQVÂB¤´¦”€bâ-¹„³° �0 kµ²™KæÈ1“‡Îi›P‹ÄA2“BWEZiB”²(Zç¬FcLJ›œ²±CTLªT ‚÷„À‚J+sI,�PefïCbÅ1ÃzÝž-×·oÝúûüwn †ƒÁxWéZ%ýüÑ_þÉÉç�¯OæWg¯F;õ×ÿøö¾ö­áΑ-ƨØnziÛ8Ìz¹IJJÞzé ù­õ_ò6¾(9΀û¶ ¾Ý,®^={xú³­]^ûL…Ôõìèèî7¾~÷[ß1NDÎE(gŸbfíû6§œ™Ožþê§?ük­'|óë¨áËO>üèQµwû³/ž=¸òуQ°k¡P 5ŒJ+’G�ÇÔ�•Ò&cvÊhmµswïø÷þþ?1¶TøÚºÊ¬”Þ–JŠ€Â×Ù7m‹Zˆ“�f)¬MY+Í¡�"Ù9Ç �”Éå°.*½»_(R"j³^,æ«õzAb$KUhP›²¬%ë>ö9g5NséSòí–ÈšM»isY¸ñdª’J1)2ÃñdR00€’YåÈšAÍ×ë€ÒFö‘™%F(µœ5M 1û0G¢‰³Z3ƒ/΂3fZ§L$‚è3ƒ³e’FCǬ†ˆJšn™4(Î(Â…)cjsâÐth”Rœ}H1“Vzk‰ÂJ«µÖJk•s0š,s6ee‡ÃÔ¯ºØ÷±ïº�¦ÄŠ,€°$ÈZ„I|b$ÎÎúưVz<)‡£±ÑCæÀœŒÑFSLÞÚBa*ë2xÍË”bJAº.§I+Òj<*NÏN~ø×?þMøæ�{G€èÊ^'·9¾~vvöäÉj݃Æ{¿ñÝÛßøN}ô6*õº@:ñ�ãR,HØÖ@Rºfé€ ‚0 0�‚œIm©½ª¬”+ªr0žÌöÀOþäÙ³ÍEßUk¿:ÿMUOn¿1;˜öÌHÈS̤(g`Éœ2¡-¾éŠÍVó“éÁa9¬ÖóÅé*-Î.WlŒ…Ê@© gð.}/t8(kÒJD`ά”hEua•R˜r2Æ"*­ô6�ˆÌ �i{wèX‹ô3Þr“$uœB”¬Œã¾Ž  "ic˜E`¶·¿wtì»Mì¥Ëͦ۬ç>İî K ¨T]Ä�¢ ^Ä”ãÝ™pŽ"ØÇ^å¬ !fäö`:é½oš´Zõ“áØ’izo‹�>¶’1†�™ÍX[¥rŠ9±`šŽ´Ñ¤‚ï:ÈšÎ7ẙKN…%µ0†„DÆE9¨«Ú(VF�}, [ZÁob˜l.»„)´)GÔÆ€�dPÌÀ(D�8³HÌY´16& ¡'�Á Å15BâuQŽÊ:ÅÜv”–Ð÷žÅ,ÑÇ„^p¢…ÅæÅ*%NF{àhŒÍI+­s裠.M¡´èÄh!c�ª‡]×ÖNbt€¦µK€QB¸8{õ³ "Oöd:EæÍÅ—_�<{¸l‚O|tûöÁ›ï”ãæ›ñL¤_g倎€[²›…”�rÉ��™ @ °g~ adR@9›r°w÷�á­OÛ_}u±Â ¦^>êV!v1 Q’ÄêÐ÷1G`dsèc >kaœíÌbN¿XÇþ—O_½8çA�ÖÂPðh×ÔõÐo6]â¾—œ2"+a‹¨A2Ú b¹ÕH‚DŠ™ÝôÇoKY¶»–›!‰uîºÔ÷ådäc‹Aún�J)áÐeôMç Ê,¢fAdˆ ˆŒ±ÌàÊ‘­ëÙî01P»áàSçCu½¸ºBÃ)çˆTõ@[Óö�3ûCH ¸u¡ÜÞ˜úÌ]—K«�JƒrPê¢ï›U³Ž„ Tkµ…³M¾iEš´nûs^'V€¹¢œ…|�‹Åª,šLXfw2Ý) ‰Ù¢±F¬Aô-eMuH<sY¢°`Ûõ Šuæ”RJY!Ç\�(£cH@${ŽQ+k´aDml¡E+1N3›`cJ™!cÖb�àP(‡ú"+˜Û¦Í Q£%Ò¡÷¡)\I¤´"&h“�JÖºQ¬AfeŠA¡«v¹þù�õá׈½7V_œ\>=Y®×0šrwÇÎv…*Î Ø.†$’ĸ]amaÆ|“ fF@É´äÈœåuc œ‚ ÷ï½-îAŠÐ TFÄ”@&zO3+ŒÜƘRHÂ!&N>yßfV¾mgG»>ÇõÚÿüˇ�O„²—JíÙ`·°õhÌã�®_v>v1’)«1"*@BT šHêéô˜Ð0¡BÄ”3!")¢›zDÊ9m@Ÿœ¼´–2azfј�)!yêÚŽˆ˜“O8¨ÇF¹Þ·VY[T1IœÔÅõ úg³É$‘S*Êêðø�%'a¿ž†îNðMŸBŒty~Ý^¿ÄèK�ÐÖ…ž`ŽhËñrµ*­.œí$_ž5²-lÌ fÓ¢tæt±’Ô*k´&!â�€3hm™%ƒt1�#§1eT]Š$&äl ÜäȽZvñ|Þ•ÖX«gåxXæºTZmÿl„œ¤*kª T…îRÈà' ,>3ʺÉAeFH1ŠK†ˆ2m¶!Û¬‘}U¹�²’Q+Kе e@ÄÌl¬í}̘cÛ$ 2š‘3DÉ�DiC”²‚ª¨•Î)‰DR¨n × *KˆVåý�ñy>ï~þãOßþàÎl6¹ZÍÏÖÒ.Á”È�+RN´Ä¤ŒbP¢F¥%m9Ù€Y€@¢H‚­°²Ñi ŸfÙâ)¤në¬!àœbŠ I×£�z·æW 3�£ÁxŠÂÑ'œU ž9ÇІzCy½º”Ð…äWMó«_ž}öB2Ci�ìYp¶( � ce•s„­u\ `söXŠa„¼Uüu)’•² À²µïmݯëX´6,"B:æL©ð±Ù,6  Fƒ„TŠ WDÉ:%ÙtQŬ,…À#«IeÁ$YdoÚ6:qÌÑ+mûøê(ŒIÈ8¥ì B…GGûMs»[.–«yÛ†Œè½÷aãç M5A%ÕþžòÁ[…M›¦m}ÒZÍf£¾éª¢tzØç�U‹€!ç.¥·†3ÑÆ’ÑÌÉ61!BÖÚ(Ô4¨”± qãÃõ²©+Wi(�ªJUj(”SV¡(²R¨ŒÖˆ:rÎÙä8”š�{9ô]×NŒ˜;o\‘‘}—@k,ÂyÓ7]-„Œ)4¹¨�X“¶=sÎ ¬ N)ľM@Dä½VMY»ä[eˆH+B£53¿`ë €’|†ª¤º.´+/./ù£ܺ½¸Xœ7²ò(ë|_Û媳,Š¡!NÉk¥3 )€Ä¨Ô–Ä-ÂH,_'á“0#ç Q¶¯ÎAD8%Á,‘…91'üh2¼{ïðÑÓ:áoO&{SÞ´½BŒÞ7€}î7›µâ»$&ˆ!¬š«ÇÏ^þâ‹ÅƒW’¬È 1ÀÕr-Èe¿ÑÕ�’qè¬HGáDÈ‘¢˜B suUÏõ¶Ò‹Xo*�ø†IÛqH_]®KÝGƒ¶o69¶gg§EU¤Ét¶{|_¯…9èÛ^rZ]¯]¡ KΕÖ*e¨ª†œz¤ H6›&gФH$Š1�"l”û³éÎ,C&²)GA\-ýzÑß„”’”³³$E,iEN…®ž”@ŒKeœÉ™R ¨”Î’�¸pÅ´t†µ©ÊºÍ©oÖm×Å•6!Fç\J!eŽ!oz‘ÎÁ»5Ì ”0‰¶ÍÙ8 ˆÖ°Î1Š%­�J+Šti©äè;ßw1r昳0¤,DØwA� ©˜²OMJœYŒF§‰€4‘+q2+튢(E2¬!çŠÎcŒ’“Ä SÚhS"Ìœ´R1mrJëM$¥i2)ÏÏן|ö ôjƒ!€kó•‡fÙ(¤Ö¬«ªÖ¼"CZ‡ÊIBR$ÂD‰‘”€l1ºœ#$æ¼�„rÞ:ãˆ,Ç>1RŒ1çÀ)j[~ðÍoèÚ.6›7î¾=è¦ JQˆ!‡Mn|6~½Ùô«w¾Ï|5_~ñðÉó—ñdˆ0�@aÀ0XÁ]4me ‹íBK£ª�"­tÌ,ˆ ‚¢uQÚ�Œ²=¼ƒRŠY¶—?ç|ƒwÝö°qÖmëq8èM=Ù1µM*˺Ÿ¯êÚõ¾;={QYGD„*‹/ŒJ ¼o¸QÀµHë;F¥¬3±ïв&­1 »¢D–Ä)‡°­BزCH8ô)8g•t¤$“›L«Ý½iÊȾïëÕfÙûn- ¤Œ=„²¨•1ÄÆcçcNQ”™¯£5£6´ë�“ Á,Ò ÌÁo<[­� 팸¹,JdŽZ¬q}Jѧ®í³`“¤ó±$Œ½VÄm°V))g`©êÂ(¥P Wh…JWÄBƪÜHßpvsâ Y¶*pìºÜ±ä�C J¬f଩FΗ £°ríhX*Mœ ±ÒF” R•˜•ÖÂBy›XFI²×ÚÆD0A¶ +M‰³Ò:$c«š›µ9Xv€ ¾zyyðòéþ¦®‡³ÖÎ]a�Òf8T¾5n‚$Ä‘¬cP@Éß´\%Ùæ²0ä$öIkCd7)÷ T—"gÌ,ÂH„»³]ýµo§è5ô]sÔÀ›vÓG/½,[Ÿ}êâ¢mÛ~ÝŸž_œ]ǯ y¸¿ oÛé�8%ÅtÝER̨2{Ìéú*nó•ÎÀ8új‰ëÞ�26Xe¢ÒI+c�¡°6Ǧ´œ»:ôY‚ç´Üô1æÄÂbfD�à­¡¸éËMW—Eì:Ù×FYkÔ r, 3@¥$B´ZGÉ$ä}q¡ïÅô‘Y6½!­tR®lÚ Y@н™­�oû¼z/#~ñàl2üòÍãé`4 F¶š”ŽŠ.…RºS�©Ñ‹5É2 !^DPP8ó¶MM$÷> hñ ¥,žpJ!¥D1fÎZE™Mý&õÞsð±•ë>ç.äv¹ê|¾¼º>[]\÷kýÆ5¾ñÞðí£á¸`­ˆ½×ÚÝN�(@*—›õºÍ�åŽ^õ,¨]aŠ"ç„ÂÌ@Êi­Œ‚Ñ ´Ú“+2¯Û�™‘^¦•VDø�¾í‚O9q1°³ÊÎökG£ÑhïbçµÍ&…Þ{?Ou¡dÝwÑ´³{TŽc´…aFEº,µ5¢TRÀ9)ÒÛ°‚uŽSN‚ØõA8 �V…qÃÍêŒ+9Ç¢¨A©fÙ�ṳ́41ˆ”õ ùt}µØ4MêטÑ9×5‹ˆ •±‹ÕªOLÊæœD@)"ä¦÷Ä¡Y…eŸ „H‹$g-"ˆPò> {ï9‹�6’Cˆâ“ä˜ÕÍøHšrE Åv!ïŒÑ*?T)G"͉�¹) >$Q)‡>JŒ>p¦Ë.²@Dˆ Ók…ErV#r]”ÓÂÖ–²¤A5Ú¾YÅf¿`”$ ¬VeÙõ]L ´N9)R«.>{µxzÎàÖ÷ŠÃݽÉîlw8¸Á`ZŽFÎd¥�* WŒ­D¨­#­•ù¸ÒJ+9#s âc@ùÍ)2cÊ™cKÙ„˜CÊ9CN>ú¶�" ;¿‰©ç ¾ïC ‹Í¢ïùz¹9»œ¿ºÈýZÁ�`¨ß¾}ëî­éXAl[Á–D¥¬É¤5‹Ê1õ1 ‚ jz¤ƒÌ»Üõ��•hR`¬«P™�ã7¿÷[¿o¬•,H¨”É7e¼¸mÔÞV<""¡ÞïBömÛ Õ&øp"Ö­ç^éXW#ÌHieº®×ŠJW2d¿éÛb�BjÚ(Ü#!¡Ö+çöwsY9Ô6ö­dŽ~³rF“" tU‰¢3³RZiŒ'É{ã,`éêah;«ÑU,KX­Vœ��!öui‹ã¡ÝÔw>ÅͦÎqÓûàsŒÅ¨ès"21K5!’¾óI ¦ä3j€ÈªÐ!et|âµTd"‚dÚ…œIÜÌi­}Ÿ»n…äB×y–ÀœD€™A¢L� OÐ\¬Œ"Ä(ÚèÚIL ”W°/È&"f¬+CXûìI8K`èÖÒ[ DŒÒf¹ni(7ëSMQ£Œ\ç ¹ªÖ œ)D2@7öÎ)†TdÖ�¥ïƒRÌ [ÞßKµÙl²â˜.®ürùž¾Ø�¸ã½�éÞA50;CgëIél5ê W£ÒÞé Ñ£æ(H²�ÂíÄùP$Å9g†Ú˜E8äØlšÍÿ¿©?i¶,ÛÖÄ QÍ9×ÚÅ9^DÄ�yßÍW%i™R’2 z– “ Lf’IÐàGð× Aƒ � F'�L2ß»ux„û)v±ÖšsŽ‚Æ\ÇŸ¢áá~|Ÿ³÷šÅßø „ºµnµ/Ý 7jZ[í±.·õËÓëú|�?~zùù%® 2ÁqŠï¿+çÂÿà§Ó¤ M3Úñòò‡9=‰Ú˜9u ž§t4³Çy)x|o_îÛöÅÝ\ ba€4}üÅ/SJ€Lˆ87„Ä#=ÓÌRJD¼o‚ÿÃÿúŸu[8ü¾­ÞûE—uÛ³¹}xü0ç„vx8GÝl‡t”ì$þîáãÃÃ,Èm»·pt?gI¥jsF�ŽÓyÎs>¶~$bI‰ÍLrf ’T’ ‡I–¹hmº53ÃP ¤º)„§®]S:ÈœÐͽö0sð^+æ\ï÷v¹_/ òVk�¬[§Àª¶lµ©vòV¦$TT{k}«°x?¦GÄ <PÎ9qî¶D3C.Xëuíø}Yzí¯K5Ì’¦µ·!Kž±nAˆÌD„ÂŒà(Lî£ÄÄÉC¢[¬½ªY݂አd@ ÉÔI0M6@IÌqœ’ŒJS ÁO§ïÀlÛî„€ S*%€Z[ñm«›·û½Þ»®äìBøîqþþ»÷?üâ»2dúÛMQçIDATåiÂãáÉ<‰€ä`Ë\^éÓtø7¾9óýÇw§/‡¹0Ñ|zÀ$y:fHîÏe[6sgÊk»‡¦€/®Øúª-Ô*`»ß«wnõÖM[ë·õv»Ýî—þå÷׸+Âñ¾Mð0±»ÀéDEj]Ú«NÓ”àÞ ø0õ�î uKe"„¶m·åšE@dNç\f?Æz,ŽÀȈèÑÔËaÊeÎäo&|A$Œ±–Ò°³F‚3—†éññÃmÓØ@@N·u¹µíÛß­k¿73eFh«z˜úrûM�é0ã¿ýãç( S9ß?Ìqx,…’Ù–SÉó‰¤tk„bš‘ÝCÀ|Yú4"GïëÒ%UuÝ"Òt°Úº$))$aÀ”§­vw‹r8šÙývÓº‰��ç,„¡Š(“ô÷õVH o2·<¥ó·ß—ynÛ¶Þ*ªÅõåùöòeY}YÖµZ¸‰z.”¾™ætgÄYõ¶5¯½ŠH9‚yÓA]CD ²™ÍyF¨�mÙl1PópwàÀ˜NǶ.%'sRw5s5Wu´"tk}â 0 ô\ÀˆŽ )—Dßt�GÃ8'ÀÐÞ†yçZ;23´àcW%k=\·ÎI'+ª LtœUïj‡” ;¹7AGô4ç“ùû¹\omp]µwûòòå7¿}:Êñ�Ï�çÇ|<¥¼Ë9aí]¤8BmšQjï›®Ú\·­wÀÛí�o—å¾Ük×Zc3p�¨x| ï~$™å<±l·×qY2R_ê­6r·Ëò•÷ÞrNÎL$Úï‚æ½k2«¦6•Cši¢Dœ\…¦ P! ³î½#øáñK¶¾ÍsæL¦ä`×—'Aæé;U}úéO×—/Ï/÷¶‘öçÄĦ¨][_­÷€´.õ²ÜÍ­”:AÐáñA8¦iVí#R(ÂÖe½/[«x½ßR÷päû¦M• ºyoÆ’æ$¡Ý-LX„i–¸‚a­q…áËÖÔØÐ–åÄêÎ@®ªÀ½}xx8ò/¿ÿ~»ü|$x<ŸOgÌeÊ¿ÿø M¹0#ag>˜0“û²Þ¹LM�ضu�ç1qÎÅ€L †–© 1OStóäîæ1 3B¸v·EÊtøð‹0ŠíUû6ÍS>ÃL;täéðÈh½[ov]^Ÿ2Ï·ÛEž_þèµCEGí½Â(z .É‘zWÓX•Ð#Q2ïÓ<µÖÁ1MG‘H…—eûòt«ÛÖ :;¬ Ó”£Y@˜[Î%IR5ÕnJHÜÚæ.Ä’§ùXP½�H:žÏ^+ ,Â[ïÕº©¹†îcžXÕŠ�™!!’»§,Äœ2Q� #!vUô®˜$÷ЮV«"a«nÑ=T‹dAuH‡,)“õF˜‡¹$›„=0qÊ“¨·Ä졌ˆ„aäÀ¶‘°£tSèµµ¦æÐ‘=3±`y­Þ;.›Ü›žOýô°iõ6Žùiš$þæñŸý³ÿÁ?JˆœRD$|K£DäðþŠ¢»ã¿üoÿ�ˆÃ\9 pÌ)H­mÛºÞ.?}úéõéó�øt»>÷õKaàºjÓûó—OÅ  {�UÛf�ˆÀjÎ8•t>fV̉§ ΉúqÆ\ò»éL…8ñTŽ9Éñô! w}Ù6 FsuŒÌI2÷¾êõ&óL„%æl]Sž�\{G.sŠ$à$4|ŠÕÍ"Ü´B ”C.‡TÈzOIÒtlëÖ!JNÂ…p.R W³¨u[o54Zë]¿üôÓÏøÑ{Pí‹[­{¸µÛíÖk«²-/L³‚{ð|(SΙÅÃIR«ÑÚ¢ŠÛ¶šZ4¢¤MÍmS‹jGDf 箾*!r‘ìÑ�IL�A$§yž#ú\¦�€ná¡Æ"­6 r7ÛÖ¦î½{ ù<çÁŒ†$<|§ÖjÊ…ÀÑÜUR¦¡c¤À@7C"3¹Ý_ H¡—”{_�pÊS)0IöèS D4 ÈD)OÕn„ŒA,ÂÀ”]|]{9Otx·˜yð”§æ]X‡SJ§ÿåÿê¿üë¿þÇÄiYI˜%A`„³ð0]G SK)¹G„ !# „¢TàLà"r:>œNß}ÿëÞ[kÛý¶¾^~þôé�?ÿþ§[½o/ŸJž:rí¾¼¼œá€Ô–m«ËÝY±¹¹UÂЛ1Øüt�Óœ¦ß¿kS.‡S𨼾³‡Ç³£z@¡¬�ˆÎ ¹”$øZ—µVriÝ0VsŸŠ¦Ã¤î®KW™‰$P2„ðæ ЈgâŒÑ ›CD«Ú½…Ö®÷×<Ÿ£L%[$ÎHäeD YR ’_üú/ý߯—§çëëå§O¿[®íviö,ï(Ò«].îËý~½-kÜ×ffÏë6çƒL–Ëün~—§t¿]n·ˆ%Ïír¹_î±´–À[™&Dîj€‰;9hl,²õÆLj¦]�—šo÷RNx»eŒRfI%È%ibQ·Þ¡ÈÓtx~yéÝ|3-¤ ÚÍ‚<±Gs¢z¯€f%QW§ S*”;1E5†"~u€6L×궺»¸®hµ8$r³”rN¨ÖÊ9Qž�;Ô€®cHÁLsIYŠd)£r‹&T²‹®j׆·0’ =Ô4¥‚$ÝuJi*™™"Б3îœV§QF�€ G$ü»ùUu"qs@ö¨n{*"™RC¶$w@îºкÕÛõòé�º¾~þñËÓó�\¾¼Üš;_oO©ÕÖ´T5ÂÍ:“–Ä "Â~ùááÛ~˜9‰vaýøÃŸ�Î9‰¸FX“L‡ãY†—‚©‡ g°µÞ®È9³ä€0Åiâ,SÊ\² FïÕÁ“$¡dsX+ÓœeRk’zJM»äBL*| 0fÎcR.)…ï)B"Ûfë½½¼üôòùµ‘�{5_·ËåuÛn±m�RB�ÞõõõE�0œxšK*Äué`a%—$à/7ý|½[ç4yà²6,kïaÄ„�Hîàáàá­;’÷nÀE„! ç0!#BèT&ÞÚE(²\ï­öM›v$”T´wówff†°ð­Gw FkN3'FtÓ„,Œ �˜=š�0:C„vµœS¸!�P@¸‘¤d†ˆ’Ëù˜�K!ïîáÎ"f•%“$‰6Oœˆ10Gh«5ljÏKüq�¥k’¤rdŽo¾ýóÿì?ÿ¯ßü–¨ „ˆ `ŒÃŸp˜k±�œ›A"fB$æ°@r â¡a©$Ó ‰ÌzD€û¸_¨Láp–éññÝÿàWnZ»Ý.¯—/?ÿø§ßyº=?ÿ|x~î·;9Y»×í¶n÷t>ߟ~n0úºnŠüós¿ÞÌ™§IŽ”oúù¡är Tfbnmeøüñq*ÇI81LœŠtN¸l]7”³,R½Ýn·,kW�çÓ|<0˜™™ÚˆCb×~»,y*§éàÝ8FOÓÌRdš˜R˜×ûb¡½U&1usgÉHè`�03õÃaNéÛÓ1Õ­³¤m¹ö†·åp>ܽ—˶†+QÜ®—Ç¥y‡nõÖü¾®«ãqʤ=�¦$Ç>àùTÜ6õ˜\a–ä¡éekKmNݺ»³p�%Ô¥jÓ Þ¼+Þ—/¹dØ;ÈrYÛ\f<ž¨H:|œ—å¾Õj6m­«Ž³Ÿ8³ ”™Q3t w¯5Vî€AL5$!axaKB JL¹�»úðŸ53sDfòp×NH ˆÑ›-·ûñ”ÒÖs"ŠÎe²$@’Y(gf<Šä7ëî5E†8vÄî@bŽF½’çãé4ßE B˜BEÊî†@A”4̱›2 YpàïþÕã†;UÓ‘U;áø;ÃKHÍÕÍÞh¤ÈáŽÂÉL�VDÌ ÌÌëº|þüÓ—Ÿ~zúé˧ÿ¸ÝWÝ^1j[uÙ–Ö·Ëí 3']ï¦Bòáá�æÃLs v*4Íc—”Sy÷øþÛ)§¤àÄàj¦÷ûJ çiFsŒõöjA”%II #ûFSšÀ:‰œNó,Èl�úVÃx: ÐÁ T«0§$�èM‘ŒSw3&¡è¶nwI,9¹¦m]ëz±Î ¢}©Û’yþòåé�¿ùÿÝ6"™\_ÍäjÕ�¢©¹–,óü8OLˆÑjÛô¶âÒiìÌÀã�_^.ë–SšR”)ß—ûZi OÀ¿ÛZƒÉ4<bJâî`ABpžøýù®BáH€�ª)Ô¦@îÚ1³˜"Z¨)´V-|õp¢p 4s�Há<êüp"b†,\ͬ� óž4¶sp0¬ÃéˆY OSJˆå0103òÄŒLÂ\ëÒ;°DHDü¼è¿½z`˜}žÎý ùßûçÿâü/þæx8Eqzˬ4¡<`17%fIlcHÌ,ÈÄ`Ì I’Çk?®SAD3ŽÒcÈæn½WÁ<„]û>^†`‡ó‡‡Ç�þ—mj½éóë—§ÏŸúãož>=ÕûkßÚç§?ÊáåõÓ³š;eüéóë|�ç¾yô‡ÄÇïÞ=¦kŸó‘§ùsíFÔéx<óA% ìÝχ£3J„ÅÚWuÝzßÖ… ßÿr& 0[ € Ÿ>>�‡ÓTማêv»×m�NS*”8KÒ®ËrOI¢™¹›]¬EïêÇÃ{$ÒÚ‘yšáôîq[J_×VÍÊã¡Ãjúîáý‡ÿþrÝ®ÏWà ü´¬·Ï׵ݿ)¹” 1{°b�ÄØ•âF0U»4 6@·)I&{xÿ\îµÞÖûÚœI"š'”UÇ*‘=Ž˜µ{híjðùeE†,È %O‡äN„…S³PSÕsD@D‘”¦Ä„ø"(o­Bx¸¹A ­@fj™Ã"A¬ˆ„:�H™ш@ƒ(€�Ђ {uCH‰U"G3˜°PVÄB䀃PŒ�¸´( ‚@ˆlf̳K9>¾gÎîÁ½¯Dy6:¸ª""›9ãîêCñüûõC�0$$i± ãÈ]‹3c"twUc&Õ>þÐaŒ¹x8ƘÀ5Dj½‹�»C¸™?==]Ÿž__Ÿþô›×/Ÿž?FÈkÛ–—KxøívW¯¨+cWâ4•÷’ç9¥ÐÃñýáH�³H>�ÓTŽI ˆƒÍ‡ öÖA[wëÛm[/ërw'Lœ¥ÌÇ2—4‚˨E8 §,‡ó£ä)§) Üz‹ˆ<صEˆvíZû²,PrÎERN‚H)ŒP(²£¬—õzùlM™ ÷ÖóéÈm¹^ïërßî·¥¶¥×mۮͳHY»&:ÞÖE jëUmkq]ªG”©œ sI ¹\ï×®©×%¥bá™óËåuk ›zZ@¸‘El[ï œö1�FÂ’D$ˈ¢ð „eÎa@8BÎa9 ÍùA½Ö^qNÓ}»Ý×eºh(Œt!C�@„Æ EF6'äIDh[+1¦Ä)‰�r"ANb˜ÎD)@“DBIÍÝ݈$u̺-¿¿ª sÉ1‡ãá?ùOÿ‹÷Ÿü{C?$¤7A0'áQ@!¢@�ƒÇàN0 'Œ s…ŠBÄR²™•2›)A2ï$îNˆj=°ï–,ÄážDÆ1ðý?üêÏþ¬÷¦úÏ—Ûõv½^Ÿ_~üÝoï·årºÝŸpm—Ë‹“Þï×/¯[T~Ñmâ×^5­[›Nøùå2—9%˜¤<|8öZ9O“��y˜ešóé]„¸nZÛ¶n×—% <ÏÓÀr|<¯—çmíw Û4�rÉ €n Í4Ôzí«6pÁ`ÌMï$ Ôöq"Pá´Ö;è&y"¨” g><œ×åf‰—išr²c~ÿ¾›™;Ýo×vÛÔõzSuÓPW^’©/·×ÛšZ1b4cÂè½GˆØ$éÀa¹ â§ï>KkUÍn÷þ²vdï½­›æDó$ëÖÀ1€Q"3u0lëAr` F¸!…¸A�!6Uß^Kž7¡Y_ˆK¸ 03±¨1ÒÚïÚ• ˆ¥U퉀Á,ˆTëîæn‘¨JÊÀ#ÇŒ�‰ÌCÝ-�‚¢·X· ß¿ÿF$±GDÄ›: "Ž‘øo’0üý¿þ„ù(wÜ�‰ý«­)ùˆ¬DÀÁv$"bSeáñDZç[îrÈGDsƒ·ˆˆ!Bpw&"æˆØÔ;wÒ�È-–ååv{½½.Ÿ?ýt¹\~þùï®Ï¯—KµmivmÛr«�R²¾MDï?~|˜“Ö £çè�ïŽå0ÍóáÃ1¹cDÏÇ’Çž„H´.7 ÛB21äRæCÉ'á!ôCwÄy:3iX D"êëª\JJ�äA® ཱུÄa>.WF<>¼"³­©1%ëÍÐRÉÇpÀœ%lƒ ·¾µ»xA™z»iÓÔ–×®ô|mŸ¾üx[:ÔKH‰@mº“§D,¦î޽uD@JCãZ»™š3›!•Ȱ-[ëwbùùéõ¶™*¤Ì¦6r­™° #¹¸`LIÑÌ‘�2£$ÁðH" Ž¥ˆpz¯Ü]½EçĦæÄ„È�"T!€‰‚(±0!åi`$ôœ)3öÖ@HxN‰¥ÖuYúÖS³|ZÔï½C9b KN¥”o¾ÿá¿ü/þ÷�ï¿¡]ÄLîNÃ7œ8½!¤°¯ýðx ý&$vw¤áhîÌLˆ@áNÌ{˜²°ÈøowK)™¹0BðH… w'Qí‘<<ME˜ˆ±p‚$S‘Þb³ÈnP[kµæ\r±ãñ¡i_™æ@Y«ºÞˆPÀ««¹)X_BI%ä€nÝ # £áÆì$sß® n’“ QŠ ÂÌ‚Q»Á™LÇÓ4'a3.&nû‡“«Ÿï¯ß2Us_7[ï÷Ëõ~¹u«-\y‰•é Œ,B†±®ëek'Ê2åóûw2Í%‹÷õþš#ŽŠd|Y»“„›º4CA°p·a ¦Q[—´‹X™Á܉ÂÌ'w÷ºu!æŒnÆ~ŒD–$‡+rdbHädQkš²ƒ!&SƒL-L5ºZÉBŒhxoê ŒPÜmšK„ºP$ÞÊ�&U½µ»[‚|Þ z`„[í¹‚s“Â?þ’8ÀûžÔM�È„´¶°ÿC„èÖ‰s„’¡�s1"XØÍ <"ˆ€#”Y ÀGêZ�[EöÔ™=€�ÈÜwõ º«& ¦{ƒ‚‚ÝÌ‰Ì p´#ÜŽó4Òã‡o~ýëØÚöÏÿÃÿèéùóm¹ÿüÇß¾~þé~ýÓí¥­·»­°m°ö­ß­ÔûåÖs�ióã6'êï?>‚om¸/(Ä2åtˆwÅÞÍ ƒIʲ޻*º­,ÉÜÛ¶œŽç †ªn ½/ËV¦2å¾­·i>äÂB>¼7B:+w`¤„ÈäNÞîJ1CtIjm�e; TJò˜ÂÀ”Bk@?Ÿ�½Õ®ÉÎß}³¬·PêFŸŸ~Öµ>]ùúú\R¤œ"*"sïЗMVkÑc.vJ ç›y�Ô–SÊ뺦”UÛ²l˜¦pXïk³H”ÝÝEÃjw¦Þ\ˆ (Ð)”#Ô8B¹Ã&ro=ÀO%!l…!!zÝØ9q&@È©xß$ Kf«ÂÉÂÑ–­i ypk•0ÝWs÷0UÅ|¿ß¦©5}½*ЏÍØ "ÏÑCµ‹pºÚétšŒî†N6rÈ`Üâ„ÃàhDØ›‡[°ˆø· ‚è½°“8Ç~9ˆiEBBDwC 6Câ½°ñ€C,éƒFÞ[D ;"ÅŽŠ„DI$ÌR’.LûÍ@„€0ŠÇñ|÷¿þË¿ ˆ×/ŸŸŸž^¿¼|~úÃíé¾¼|zY—v»¶õӵꜧe£ßýø§ÓŒ?¾¼¼?‘—ãt(á·ùašæ,ÄÖÃ=Ì m›ðÁºiïðÞÛb�n—ët˜r"NLjÔz(ØZõvý9¥l±)gI™Ý]ÌÔ×­[ª2�H”�œ,¡i]#À°Æ€åº›*qHº’º»)/«5ëÛp#›ç €Ü©Ì¿hËú¸¡ú/o×Û²µûí‚1B{W€íyõül"s*³>¡ñ»Ç£ko4͹´ÞCm>OîÑÃÈ¥®ÛuiLéÒG*öÖ,%®îæ X­bTdzÝÖóÌi0dÀY}Κ˜%Š6'HÀçô`fJ‰q:•Y¨aX¹§¥¶ªµZ4�ªÍô²ºÃ=01Y$&*å€È]3#ðãÃAubq�€ Žá€2–^„»9!!b„«ø0•¥Q!�z]{g� "´Òý˜ƒ�Ãa8,"‰D ›±  a>ÈH$fw'B&ÍÂð+%¢p"F3§Áá¶FĈhj,A((r2Óo¿ÿ?üê¯Z_Uû²,—çŸn·ååËÏŸ>ýÝËç­^[œ× »ô¯—WdÏx)bï?ž±¨nY�°HD€C]+‡«)úVÃñåé©LE¤MåPÛÊI&3ä‚#zäz¹Ë»3¡1€n}õm½ÝRz@ÇãiÎyG—”µÖˆšKÆT{Kn[íw”CÜb"D'BôV,‚’„…»¬Ëb0|ŠæÃász÷þ‘»�Ý€#Â,ˆ,‚` ÷“Ö1˜‰=\ ÂÜ iä½í Âèv-2!8`€s ÇSGâ]@Œä£¤ ßQ§7 ^" ŽÄb@„Q¯1�Ù�ŸJ!#‚{03Ò€ª "†¿EOIñÇÃÇߌ»k«÷åvyþüû?üáËwßÿêåõi{þI×ûbí²T¼-—¥îöñ!gÔÓi’)‹n–RžÒ��1¡)rLØ»3Ò¶VIQ«IJŽÈ� 桸mµ±dî�“äÄ�²h]VWïõ¦ÁY’L˜$ ÀTˆ™ÀBûªÚ¡^¿H‚”§r8�»y§ ÞõV×DFYæÃÙj5]òr½‹¤¾v�p;ŸŽNÉDlÛ­õÞZOdÚª*-[lnÑ;X'ÉæL æf-Nçí¡Áã¦jÝzÇ$ª>Q7ñ„,¦÷³0#ôe±¥G�8ÍóÓe«U#€‰döÚÔÀ€Àƒáî–¢Ö¡Êb¶˜ÜËÍdj—ó!Å”O �çŒÈr(GdÁBððpZëæf¯d¥é¢°e…ä‹€ä÷ï~qxøŽ9‚y(JvïLÉÝG|<"¸¹›Ù05÷Äßþþïû*„€pbp3"ñQÐSì¯B4ê¢ùW3,Üm'ö ¶p Ð!Ç36Š+wgfwGþ[°ÀÔÃ#|2_wÙø"†[€ ⪌‚QUÇôVNV×uÝÚåòåO?þ›§ÏOÏOŸ?ÿáÛR ›oÛLÀLøþp,‡òpNˆ*€ó|ÊS&róžRî¦ëÖ<°õÆœQ8ÅðдPÐR îé„à°õˆýÝù‘/·µÖ%"¨µ–xTwñp>É4Þ–Ú5ÜÖ­Þr¦(ù,’˜˜Yš®}»¹CšæœÝÃÍ{õ¥­ëRI|žO�ïR))­o]ÆTʹµÏˆáÁ„Sï«ZÕŠ×åR×î® �›¡[ïî÷åz[lQé=:€[X¯Ìòp|p4ë}©uÊ…)}¾Þ¾Ü6œRÞêê r]m­583òWD0 3‚™ûn è Œ1Op(”%ñœ§C‘é4c¸L¥È„á-Ã×mÑûêˆ÷Ï�·nX&áDà")Ä_þ÷þÉüŸüo>œOH�d AûéIˆH4ÑŒ#0Û]‰Ø]ñ7ÿò¿y«–Ñ#h,×±˜ÆÑnfÌ<¬äTímÕŽð=·bLvDÓï¡7`S$4·Ý�lôwIµ®HˆÃº{L.DÝ|ÔH{ ÛÞÛãàýŽV<" Í4@›Âz_Ÿ¾üt{½|ùô»Ï_>}úÓoÚZ­5¿ß"ÖoŽ�a>gb�§<å §ãÁûÈlÀ}»À¶nœ¸ ¥’9 ÙæÑëY8=N…Ílí«yNF¦¡Ú$%b"Òc>:hs†¾µíVÊ!rJD4Šö hˆ@D�ž™)«n$“ykžo¯9èp<ÏÇ”f0¬ë:M‚yz€ÄNHŽmݬoëó§?�6…‚Tj«jÝo÷çjé^;Òñ^›¶n}ÃÑs$43v0[¡¯‹œ×~Ð2î·E1_¶,Æ×wõ¶¬ˆDa¶ ›�0�Ã4á#%ˆ­HÉeÎ"œ0K .jÚ Ï�ð¥ús ’áLˆ,ÌÄÿÁÿð_ü�þ§ÿÑÃñ„D C"ˆhØãŒJ;ÿg/³#Ì]¥[cL8®€@S%~Ã�¬3Š�¹Ùî¥BÄLnND&ž[Ìä6`¦ð(ëfAŒŒÉÃ!ˆ÷òß‹�ÝÐ#hÈØÌ iŸe8B³�!4�™ƒ›“ˆx�D!qqËÂ1çùýãcmÛ¿£½]ï×ëËëï~ûoŸ¿üþå§?\–î×öú%]Óqʉø|˜Pøp­¥d‘ ã$¬i>8xJYÍÌ"�4Ü»Ù(ÎTÍ�꺺2 fÎ ×RòBŽíæÁuÝl»®iA¦<ˆ�JÁ<2 P¨VE.E<-ÌDá]#8Í’3y"‰÷ˆÖšy}}Ñã±H)TæÃ||¯º¥œ¶m­D)çYr:ÌY3 |ÛêªjÄ…èÀœÜ±·ï–åºmõ^½÷²YÕ~ÖzßîkScV¢|G£2Q0Â5ÙZŸ§dÝNïÏÇãÔ{¿ß·ëë=&žËÖ¥Õ›ÙÒ†ÙØ¡3µî¸ô@Ó-1Tí¸9#Å\°ªe.žrN™8Ø�THMS03SŽ©Ðqš< Õ@‘b@—ˆàƒ¤ã:¦q”�›A|˜uÀ|Ю€ˆ­7ˆQÓ{ßkA€C„"†›` ZϨ¹Ü)ÀÜw1„ÛøÞcžáÄdnNÈ€ÀÄàaÀ¿NÓÈÝ‘P„!†5q"q@0D�›#p¸¿u„Xæó|ðÇw߯ñë?ÿ+ÕeY–/—çÛËÏ¿ÿí>ÿøwŸÿô'èËÓÓ ¹–Ó|Ì%æC�OÓéxÿ´Ü|»&S—)“Á$òryQ+ýz½z×nc�B‚‘$IÝ:±8a.s>ž¡9‰{D §œÒôñÃÃÿì?ýÏÿÑŸÿ€9ðT�̤̈jok:‘Ì=ˆ"$ ˆbŒ…!ŒIÀ=:‚1ÒN€Qüq 0ã¨Ý‰‰% ""I² " õžÍ•0�; ‚"œx˜u�û@Œ‡#9·ð½wDD ë!œ §Š<¢®hω`} d7<Dr�pctW…  S’¢åùü8ÿðË¿þŸüM°¶µëóÓÏÏŸ?ÿéw·Ÿž^ŸŸÖÛrXô!û”1¥,ä"䯉91&I@JîÄ€½@¨õ dnA�®¦¦Ì 0§9å\j½tgáèË-R––�'Δ ¹µˆÜº¥b!éh„ŽLà˜¢˜ô®®€I¦—Ëk)“ë§Ãé,“ä2—tpS“”hÅ#„Z@ ‹fx¿»èÄÂ9£G™KÊTN~ÔÇÚ´oõƒªöæî+`ßz]ÓÃËKÇ©®V¦IÊÄÂ6‹¤S0nëör¯«7ñ.I(ùùý/Y`ªUS¹ßìNȺ™k·Íª9 Í9hÊ\»"²Àc #†»m˜&!ÊD|8¼{<�Ý_~�çcÄè€Ñl` :^$ DZ¹ƒ,ÂX@£3îQåÌ à#ŠÌš$è/11]&Üùsƒ]� æ`ˆÄ„�¤ ¢`Á±1Ü{iïb…³©à(èÝ€!`(Žy×§Â^à¿5ÝáH_·ŠÅ[k>.�ˆ`Ädæìà@Ž(¦JîÀ„cìððnÎåx˜r ô®ÕZ]®k×§§úñwÏ_~¬—õåçO^«.×wB‡)3»c›J™ŽGd4LäŽá`ê›ZEH€!BŒÙ=8§ tÛ®:DÙÂ…³�ÂÒ½· Ú‚±Þî[ë­Ô<8iîÑ § £{ ËŒ(­‡½^r;VZ) å| pÀ8LßøtœÂ¼·ÞU{ ˆÐ-pÞîw"¢$ Ì ä9MRr)èMÛ#gÕ®m�¾7#k÷Ûê«)("@ð½‡Ý€ÙÏ?ç ᜧ2Pû"Ѓ¼·–%9:›úãé"É!�˜ $Ðv¢u„c`ЀGÃÂ%�€|X!2†9€ :PŒ ˆ âq3 ôhMˆàHFL~�"ÜÃQÑ„¢› ­�ÀN^ï’2 {g$ 7c„ADSÉIX?¸ù¯ÿìÏ[ý§u«·Ûëíòº½~¾>½´íµ××Ð¥õ>!õë-§”s" dÌ9183׺¥$¡Ö#2.S"önµ�9T#À »õІàëÖ$§î-ÃÔ[OE�°’5Ðæ(A‘9£ uJî½3™Â¶Ý—ÛíátÎ’M#n.D[’„n|í�jÇfxÎÓépfB陎§@­µ2!‹'‚¾Ý8Ÿ-‚Ir9°ðáôiF ®MîFìn_G"ácTÅŽÈDI‡¼ÓG;ºˆ°'ªb„«ø½å}Kٰϸf"\˜# öyÅè—€‡$ŽÑ"ú€ÐeˆÓ ¨G ™!£˜còþS1‚¼9šÆç{lEpŠ;BÅ•!Q¸Ž®=\Íåë m@ÅæÝcGÍ"œ)3q&d†`w7$&í »¤„%å›o¿ˆ^kïm[×ey]®_ž>ý¶Þ×öôSï÷¥÷É`*„žšm™Ó‰ !«"'"btEdSÛ(Û=IAÄBÄ<Í€@õ~7@oÙ18$¦4¹6ë ” 2 $ íÕÝÍ�ž/wº©HC×�$-1ç|˜�³d@÷š„PRò‹@ÌѰ¶-˜«¶2e Bd÷}[Ý-—™ÇÄÛ|>É<ÏkU°Çµõm½¢a­�Äó»Óí~;ÍG·ƒŸçûíz_6uÆ:ƣЬptŽÃ»€8È‚z¸n €‘Êà·º~|øŽ§™§#ÚÌbƒÍ°kz}ø›€êˆ âƒÉ„ ‚æfjÁiô²fNòpAð æxƒY"€Ó˜æŽÃuDI“»�“u`PÈTXÂ͇¥÷«qs2â1Ì"D AÔÃހ‘e?³Ý…( $Tñm¾Dˆ$a»^@zûð*Š€©HÉ­!bbñ3s  Ï,HB�D®aÎ`ÑYÈ;aáÈÜ¥¡)õði>ä2Oßү̶þ�ÿÙ¶n÷ÛÓz{}yúr½\Ÿ¿¸Ý��^rs$¤$ÙC‹¤îÚ¶;!mK'6"pè‚ÄÍ{JɇN$eW»÷EJî}�Bi©7F` ðfÌ91)uSÔ±ÞkßÌœIÔîn}š?¤žN–s>žOÔÕÜ�‘,åæ8"CDZ8†›ª'E”wpO“t(§9ø­n®µˆ÷¾öÅÔîÏ·”ηSQ÷Z·m]oµ1Zo@¢u='Œ°Ö¶Ã4SJÑØKÂD‘”|x|ühV[­Uûv»®·—ëí²¾ü\ë‚ë »º¸ô»`1WcLÁº¶ 8t¨áÉ#TL÷hSNâ®[¯DÎ’ j« �2s�.ÚÃFeJNCÖd)5GI„m齤¦ÝÖ«(iï¥Hß’›óñÁz §”؃˜“GpÊœP›BP ‰YDɉµoÚ+Qq2´HIÌ‘ó<D<œß…«™=Âûº­çó£Z;[‰ µÖXÛÚ¶Ö—µáÌÖA.uu—Ãá„„JàÖ×M§™"0±¸¶ãé| ˜D cJf�™Ã�˜ÂÃ]‘=Œ aÄb8�Ëf'¥ƒ; Ã"Þ“?`(H�(ÆÑN»ì�Úk5#bŒÑ~;Æ T¹9!!cˆjwx›ó¸P�Ð5Gìâ~ì0A0³™ÃWiѸ^¬#@`D¸Ù¨è18‹ §Âv8=¸"®ëVÛº¬/õúz»?ߟ^ýå¹ÝŸ¬¯ÆÔ‰Ð>ÛUüoÄØjEB3Ü('ÀݘS¸¹Ù½÷*µÈ©“Væ‚$jU$#GŒ0cIĨÍÀ¡ÕMï©1$CEB÷¨fêlîàî@hæ6:NP «, a‰%ªŽ"Qx90 0&ÊàS9rHE:fQÕt8jtS\·¶Ù $oÈG`‡�Rúp:NÓÉÂy€7îFÄŒ6(aC¾±Ó�Ü ˆ`ŒJ#@®—×—[�ç’¦<Ðú=+Öw¼‡™ßÈ•Á££¥Ýh#�(v˜è�g1ŽÁ7ª»`@0ì#3Ø¥0{EˆŽ cIA¢ ÈÉÄ]‡Ë±ïRëßÛ`ˆx��ˆÑhЉF à{£àˆO7 D€AqB`FPo’2 �ø¸H‡V"\ˆ#pçAàPuØa|Vã‹€·�IĤZ1ÜÍARi÷¬Y("ð<—œÒa:À‡_7ë¡×u¹Ôû}½^í~[®ŸëÓÏKuñN¾0—ˆÑðD¯ €BÃÑM˜u$K˜¥,�HªFHÛ²Yï‘ º[ÎŒdjU4Iê„ ­®ÐQ0lŸJºWbA„œÒ.—³Ž ÿj§•{(jëk5•Ä}è ]= ��Ñ V·4aFµž)QIÈÔÁ:q¤çîÞÔóä¦ÖmÊ)qÊ çÓñ�ψ@¨ˆe¬ò¯H&ÄXîNèo ^Ë›™äzo÷åù›�¿ çÁ›só¯äçq–ÃΜA"{ÁÝhèï0‚�Ýmè/ ‘ˆÆ·,Gä@ÃÚ 7BFˆ@ˆ¡†��h-DL�À)A¸©"í²þ¯n;S•yÈòaïþÁ¡‡úÞw¶íÅA¨F„ƒx!#AŒ;|ÿÍ€‡*†íø¾Ob°l\ƒ8̇™ˆFÃÍ\ ÷š�‡aå V…ØþIrÓ)•ž¦üÆÝ ·Öêfu¹-ËóÓ'¼ß¯¯Ÿ×ºÂr¯÷gæ)C¤)ÜB3Sï‰Üa}]ež1 �A¶µ3§~¯#¿\’�ˆö6Sé^™ÐT™%¢S@ÉŇÈ"Ì„»™»»0à`R¸¡8°»çWW»'*ª#+š,`8Sà¤�#ny>&W‡DÄZM�@ÀÝÝû¶i˜A {•¦‡‡wç9!qŒ�*fß qñNøD5t ú*“§ŸOL2Nìnˆ2”ùDL»öÅ ÍÁßô��ƒ�î�HÞ®¡ˆðÀ} îÄ5$„@à!ê7ö°1µ"÷½[Å©�áCƒ{ºÓïìý †{àÀgÍ`têû×ø �†e`E€<œ* FÇÒÃ�HÞ\Q�€0ÜÆ­2D°ƒØº‹t˜Ä¬ñðŽ fQU‡`&�Áeú*÷AÅã?�çÄ’"vPVˆFȈ0CæìÞSÊ)M‡ãÉÍÞüâW¿Ö^ëºÝ^?/÷¯Ûë—Ÿl¹Ü×û!ñLJˆŒ«x«Š½Ýª»iߘ™Ó4‡v‘y€înàæI`ÝZN9ÜYÊõúÊX(š™¦ù”s.ë² @ï5M%CPjß’Læ�YjÛ8Oy:‡™»˜*apÝî\J [8Y¬½2$"°ä€HÖ»MR×ÖcÄლVšAC$eíÊ‚Ûùq.ÓNÞM Þœ@w¶<Ž˜{"f&³Î;ʈáòòúa©¤ÁœNƒõC{–ü0óQvãhŽ1B’¸ûn¼!)G˜›1ó ŽŽln3D!ò1çwÕ8õÜ‘v/^Iá#Å ywóRã1€6ë8” Cã”(µTÇè*â­Bƒ€·bníÑ›5Ìhæ}�Ø‘ÁŒV5ÂÑÜÇ}‚î48³ƒvÌylqV7‰iáÉàÍŒc€XHŒîA˜œlXÂ|%ë"(b GâpØã �9íj!æìn“œ\æÃï>~¯½µ¶ºÙýòe­÷årÑÛ³]®‰Ûµ}I3kð­m@†-Í¶ÞæyVגЇÑŒ;Ò0ì—|ØÖ Ý6Î KuÑÔZg&uâŒ%åæ.|¶PN%�€‘uxn¦T\×+’¤ã�„P0´Þ ŸtÛz¯Ú‚e^jÏ9¡WíY¦Â†-jCpËL’±¶Þ(”¹`@Ì çÃt<†gð Ÿ�–oÔ“:d†Cb>æÙÌcFæod&Y¶�äxzüÞÍßìOö �½ì÷@žY£ǘ» .´nÏè{wPÑ#ˆ÷Šh/¥Ü]!�Ù¬#°¿Yk¹"û›ØŒ£SR„�ÆaLÅ­ÝwŠÑ€,ÇɼwŠD_-wÇ(7h¬§qŒ‚G\ÄPT¾a¶¯OG`&ôp‹pfö …; j¡;�™0BŒ“}·#JfNˆÈ”ÒÎÑE7µœ&÷1‡žÇnÖÑ}P„KгàжNeIÌù|þh®]{]—íö²Ý^r{Þnê_~_oŸÕ§œë­«g‚º­y>l­ó—!JÊ@µwâ Læ�ˆ–T†B‹0ãßañ¯n?0þß Gj zÜhkÅUËaJyŠŠÒa-4€mâ7æ�ïÄ×ãmq"w÷h�? qãï© o]cYä†))Â�vhÒ½] ñV½|]Oî°ß0û” †çõ€Vök=Ü;€¼…@„±K. Ü€˜´W$52ïPæW½ÿˆ¿†á¨A€ÀÄü6µxû¼Ã#ȇñÅx³$®ŽÌôæÌA(»ò?�‘܈y'ù ¾!` 7bB‡€Þû¨Ð† 0Føç”áHÈ ?œÏzׇ¾Bèý~Ñ_ÿ£uk[]êå¥Ý.õú)–k_ƒ’È)6ÓÐpª·Ê ÌÉz,QSÉ$S°�nD€0ðR·‰Jµ5L/ý5%Êi¢œ2"tUµpWw EtDs�@Fvl IÁUÒ±(t�­iÁ–ÊDÌf $Ç öš§’dëZÏçÇ÷�yJCVŽî.BƒñA4¤ `„P€ï¸;s2sOS&Ôd’7¾Œ.î•�û`ã|õ‚ñ‘»í»éMh „`¾“±yŸ¦ÁPˆ˜0Ô‰x¨�p” ±[™�„³·—çý›+£ï¼5âx»Þ6É›¿"W²“ä`è•-Þ@͈ m1Æ{�2€{p’pÃ�å�þ•;:ä�¢�6âoˆì”l„½ÛrH± ¢ØÇÖü÷£Ã0$¯È„L0´l㨮�ÞCbÿy†H–Mæ‚i¯ØtCH%ˆ!ådf)sW)këª�}ÛKÉáQ£"P!J΢$Àµëå~ëë"y6àŽ>͇Àxüø‹w¾E–7–Zìć·‚g°À™Ülj´ ÙÇ5,ˆtzxG,î®HŒ€„£"ä¯u ß”áw0p"TmyL(GÍæû w‘€àPfi�Óßo D� e|›b¸v–4t-n�™b1iXY¾-…@$rï€`C÷ÃDȆês”!o)™C0ŠÅØ={ƒˆ%¥a¼cJæ€ èc®„Ä쮀ˆÃocogwÖnðÃ3ˆ�Fw±3@p\M&"±_Ø{±·ï-ŒáN£{Õˆî¨ÉÌ"€™‘ÜÜ´�~)ÞB¡tì=¢a±AžR!¢ˆr<½wÿ¥j­µ}\ïµ·åå‹nÛrý¼ÝoMk_¡[æ£õE눭5âlÍ1J!挑‘6oÕ:Ýîk`Ls΀Œ¢ãÆt„質A`ݬÌS·°¾nÍV]ò|æ ˆŠSXU–“H>FTGsÚ\Q¨D¸Z?žO¿øþ‡ã¡PÐZX„EAÕS½“�e;V¼» E<ìê" 8ÌNe˜×1½µ‰LnÆ,áºÏDÜŒ˜ðm.‹$F<ªøïŽÁxOÒ`ˆ·>)Ü!`¯¯FÍÀĶÅ„ nJ˜åÓ½FÀ8ƒ }Ìžó pÜ€ö•¾±Ÿ�ˆn:U$6ïщx—¨wP3P¯) §¯ïvA§Á¥P@'f[ ‰ †ø˜Á`˜�Œ6D"Âðq U3˜Ç¨ÖGñˆ°óþF ¸ŸR°O1 !ÄMG’'¾U‰¼N.o$s „a;5š6H€�ßIé�òñx|ˆûö—­ê}y­Û²ÜVk×ûõsX«—g.ØÖ«D7æ»Lƒ Mœ"ÍÄu¹/€á mµ”2±`J@XXĬ[8;®ËBLл&wT-îfUÍÍÌ¡ö…#¯­ª‡·®ÁÁ@"ÂR?þòWßOó$L>Ê¿ñ¨Æ¨ ݉É͇ÕÚ𯒈0ÛYÓCÛ( íü˜coCÕ�9ÇãÃhjÀF»À!ˆÑÃw�Ü‹`pÔhŒUÈL‰ó8×Í„GVý¨>@¯ªD4Œ¾)Bnéao�(Žý¤èÃk,#NÀnF øöm†öØKn�ELÛ —ŽRÆÍÑ£�ÀÍ=,XE†müû&دÔxƒ¤öb1"ÆÐ`´__/· âý¾B1wzË'„ÝN÷¿>˜tDû� 4Ž(¤w#’Q¶!ñ€›=b\j£× @â}¤h€äo?é8ÀÃøk“8ú ‘)g:�ÎðÖ[­Û¶Þ½×ÛËOý~EˆëzíÙÃÚU­!Bbât Æ„[�2ø#D¸Õ-§’E˜˜)™f((®ÛFˆ"Œ­uSÃÖe«œ’v4&j�šok[hŸEd‘_ýƒøáÃ÷„ˆ²ã&ˆè><È»O¸ Àpoèv]! SP”y>My&¤ð¡Ë`€pï¸GŒ_ì‹ä #Ê8ó0ÂÍYvŠ%:"á@oTu˜òº+!ê%£Úö€Á‚¯½0&ˆn±£0µÜ­!ˆ¢í Ð®{ÜRãaöÞˆÑ͈ŽC|mÁÝÔ€mܼ›ÇÅ. ‚!ì$w™ºßÇý»süÛtwyç�¥ÁW¨wëpæ›S�ƒ÷–i¸ ŽÑ<Žñç€A�u´7Hàj�0h8» V Äx(æ6€Å �RgX[òG ÀèRb OÜ{'¢Ø·ð^^ Á ©ê˜Å Èñá0Ÿüñ½[|øî‡\ï—oLU›µ›mõöú ×û]�"VC,‡bÚ ÈÂ&ï˜#¢³P¸©�²HÝ¡{GJLáÖ{ÝnDØ»rBÓ­BõM«º·m ’O�>þâÏþ¢ÌGbq3 �^ÒWòÎøu@zûG¾Ã0¾bDDä2çùð@±Gyüýpjà6˜^J„î=˜Pµ ¿ÎÑ¿…hÐp!¦Þ;¾1'˜F,‚šq"±Px˜9ı D·�ôïXäÈWC‡ Àèo>îÃB‚Ì}¸ÄÁ0`#bï}Ìy ‰ÃX„æÊ,j�v¹'óxGˆÄ fnæà ‰}”  ¡£ðØa¥ÁÚÞS@ œEFBBÀ˜I‡… Ë>¸oÜǨlXÇkv¼™ÇþQ‚›3§ñ Ç 36îûà!x XJÉ\ÇLxŸ¼CÚ1�fF¤ða­°Óƒý ec”Ý¡ Ý|·`@Ìe¢äSD?Ÿ­«n‹Öõ϶öb Öëçº-]Ù¶¥×Åê]8»m œ‰Ü£Z—ð^k` 3÷¾º…dB NÜl�@­î’Äȼ»#eÝÖ:(#@…™~ýÿâñÃ;&Üã^†.ï D„˜ÌšUä€�ˆÞ¬ˆADªäÃû“dÜí;}°€ØÃökê<Tψ™i¬�ŒÇ±4v¶"¸‰ŒrÛTGòB"6sf´®°¯ã1KÕp¼™‚b¸»uOÂc€àî¸Ù;@„Ùè�ǘh8ó>"x³ $B3ØY�Ãg ÂÍÆÇå¡îádª–3aà(Ô)RÄH€Fˆ·Ä´QÅAÄpZוí`óhMÂ|Œ!Hv¥Ñð8–=R˜0Ó0Ü•xã¢"ºñàk kƒàð@t<¥ˆ@¦Æ€£.‚á6†�á„DÈÃìu¸ºª0E„íC"á&ˆ�¦»”|°&‡%Ä ü͇SDLÓtöoݼ}üU«­Õ;èvßÖu©õþ\×K«Kæ  Ú«¹9F€ æÀY!�$æÌù”!»“o+¤ì�Î9µÖ·Ú'"Å|@˜þì/þÑ_üå¿ûîñ;v B¤ ñ`¿bþƒj»ö ýÍ}TµîAà;EBÞ?œyÜÎ;›-"ÑÞT½±)bÿd5Žð@Š·Æ÷�= £Ý$“AšÇpÜc`0Ì}€F˸_¡ªøe<ï}_ù(wÜ#€TwUî8]7o�ðMí«l—h¯ÑvR*§¯¦ƒša¦{V&°C|Bi°awBÒÀ®öÞˆÍ0dà{{õæ½µ³Üb/ÕFIBáNÄf#•h×Ch±³=�iE»j{L›wcíñáŒXN§ÁšE$’< ìÈì?ì—)bìÜÃ@v0½ Çà™ݱãp¹Ü§>R¤§™Óè§ É4?„?¸÷Gîm]/ý^oëêý l‹×Ͷ5t]U3$æÝšÖÈ)™q€"¥Ôݽt аÍ –o¾ùá/þâ?>~3MF©,€{ѼÃ* f„¨ªú† •æñQ�V3¥"§ß Ëàí }˜'îãF.SŠ@àÝF‚" öæÏý P4ë<¤áƒ)�„dˆPNÿš£ñæjìol@Ä‘uîÞÕX(Ü‘8Þü}8© ¢r�ᙇ¾QDØØ*;¬<°™` –_ì1EènnÆ"á_''cø8¾f'¬|ÝÑ&¤á èCŒñf«a¸«—Æ;p0Z!P(bàa»Ñ¹GÇï*¾²‹Ç°mÜ®Zov TÂ$DÁ’r™ülLµÝßõzY+…ù²\¶¶ Úz¿µzëëÍ«¯®�‰TÕtÔ1¢@ÛrõÀÛU!ˆKþî›ïÿúŸüÓ_üðë<Í1žõ°,� ,Ucö‰óq�!DWÇ‹P„ýÿ?BO¦P².tEXtcomment CREATOR: GIMP PNM Filter Version 1.1 8åâ—IEND®B`‚matthewwithanm-django-imagekit-26cdc9d/tests/models.py000066400000000000000000000040661525234025000233060ustar00rootroot00000000000000from django.db import models from imagekit import ImageSpec from imagekit.models import ImageSpecField, ProcessedImageField from imagekit.processors import Adjust, ResizeToFill, SmartCrop class Thumbnail(ImageSpec): processors = [ResizeToFill(100, 60)] format = 'JPEG' options = {'quality': 60} class ImageModel(models.Model): image = models.ImageField(upload_to='b') class Photo(models.Model): original_image = models.ImageField(upload_to='photos') # Implicit source field thumbnail = ImageSpecField([Adjust(contrast=1.2, sharpness=1.1), ResizeToFill(50, 50)], format='JPEG', options={'quality': 90}) smartcropped_thumbnail = ImageSpecField([Adjust(contrast=1.2, sharpness=1.1), SmartCrop(50, 50)], source='original_image', format='JPEG', options={'quality': 90}) class ProcessedImageFieldModel(models.Model): processed = ProcessedImageField([SmartCrop(50, 50)], format='JPEG', options={'quality': 90}, upload_to='p') class ProcessedImageFieldWithSpecModel(models.Model): processed = ProcessedImageField(spec=Thumbnail, upload_to='p') class CountingCacheFileStrategy: def __init__(self): self.on_existence_required_count = 0 self.on_content_required_count = 0 self.on_source_saved_count = 0 def on_existence_required(self, file): self.on_existence_required_count += 1 def on_content_required(self, file): self.on_content_required_count += 1 def on_source_saved(self, file): self.on_source_saved_count += 1 class AbstractImageModel(models.Model): original_image = models.ImageField(upload_to='photos') abstract_class_spec = ImageSpecField(source='original_image', format='JPEG', cachefile_strategy=CountingCacheFileStrategy()) class Meta: abstract = True class ConcreteImageModel(AbstractImageModel): pass class ConcreteImageModelSubclass(ConcreteImageModel): pass matthewwithanm-django-imagekit-26cdc9d/tests/settings.py000066400000000000000000000021761525234025000236630ustar00rootroot00000000000000import os ADMINS = ( ('test@example.com', 'TEST-R'), ) BASE_PATH = os.path.abspath(os.path.dirname(__file__)) MEDIA_ROOT = os.path.normpath(os.path.join(BASE_PATH, 'media')) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': 'imagekit.db', }, } SECRET_KEY = '_uobce43e5osp8xgzle*yag2_16%y$sf*5(12vfg25hpnxik_*' INSTALLED_APPS = [ 'django.contrib.auth', 'django.contrib.contenttypes', 'imagekit', 'tests', ] CACHE_BACKEND = 'locmem://' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.contrib.auth.context_processors.auth', 'django.template.context_processors.debug', 'django.template.context_processors.i18n', 'django.template.context_processors.media', 'django.template.context_processors.static', 'django.template.context_processors.tz', 'django.contrib.messages.context_processors.messages', ], }, }, ] matthewwithanm-django-imagekit-26cdc9d/tests/test_abstract_models.py000066400000000000000000000005511525234025000262230ustar00rootroot00000000000000from imagekit.utils import get_nonabstract_descendants from .models import (AbstractImageModel, ConcreteImageModel, ConcreteImageModelSubclass) def test_nonabstract_descendants_generator(): descendants = list(get_nonabstract_descendants(AbstractImageModel)) assert descendants == [ConcreteImageModel, ConcreteImageModelSubclass] matthewwithanm-django-imagekit-26cdc9d/tests/test_cachefiles.py000066400000000000000000000104711525234025000251450ustar00rootroot00000000000000from hashlib import md5 from unittest import mock import os import pytest from django.conf import settings from imagekit.cachefiles import ImageCacheFile, LazyImageCacheFile from imagekit.cachefiles.backends import Simple from .imagegenerators import TestSpec from .utils import (DummyAsyncCacheFileBackend, assert_file_is_falsy, assert_file_is_truthy, get_image_file, get_unique_image_file) def test_no_source_falsiness(): """ Ensure cache files generated from sourceless specs are falsy. """ spec = TestSpec(source=None) file = ImageCacheFile(spec) assert_file_is_falsy(file) def test_sync_backend_truthiness(): """ Ensure that a cachefile with a synchronous cache file backend (the default) is truthy. """ with get_unique_image_file() as source_file: spec = TestSpec(source=source_file) file = ImageCacheFile(spec) assert_file_is_truthy(file) def test_async_backend_falsiness(): """ Ensure that a cachefile with an asynchronous cache file backend is falsy. """ with get_unique_image_file() as source_file: spec = TestSpec(source=source_file) file = ImageCacheFile(spec, cachefile_backend=DummyAsyncCacheFileBackend()) assert_file_is_falsy(file) def test_no_source_error(): spec = TestSpec(source=None) file = ImageCacheFile(spec) with pytest.raises(TestSpec.MissingSource): file.generate() def test_repr_does_not_send_existence_required(): """ Ensure that `__repr__` method does not send `existance_required` signal Cachefile strategy may be configured to generate file on `existance_required`. To generate images, backend passes `ImageCacheFile` instance to worker. Both celery and RQ calls `__repr__` method for each argument to enque call. And if `__repr__` of object will send this signal, we will get endless recursion """ with mock.patch('imagekit.cachefiles.existence_required') as signal: # import here to apply mock from imagekit.cachefiles import ImageCacheFile with get_unique_image_file() as source_file: spec = TestSpec(source=source_file) file = ImageCacheFile( spec, cachefile_backend=DummyAsyncCacheFileBackend() ) file.__repr__() assert signal.send.called is False def test_memcached_cache_key(): """ Ensure the default cachefile backend is sanitizing its cache key for memcached by default. """ class MockFile: def __init__(self, name): self.name = name backend = Simple() extra_char_count = len('state-') + len(settings.IMAGEKIT_CACHE_PREFIX) length = 199 - extra_char_count filename = '1' * length file = MockFile(filename) assert backend.get_key(file) == '%s%s-state' % (settings.IMAGEKIT_CACHE_PREFIX, file.name) length = 200 - extra_char_count filename = '1' * length file = MockFile(filename) assert backend.get_key(file) == '%s%s:%s' % ( settings.IMAGEKIT_CACHE_PREFIX, '1' * (200 - len(':') - 32 - len(settings.IMAGEKIT_CACHE_PREFIX)), md5(('%s%s-state' % (settings.IMAGEKIT_CACHE_PREFIX, filename)).encode('utf-8')).hexdigest()) def test_lazyfile_stringification(): file = LazyImageCacheFile('testspec', source=None) assert str(file) == '' assert repr(file) == '' with get_image_file() as source_file: file = LazyImageCacheFile('testspec', source=source_file) file.name = 'a.jpg' assert str(file) == 'a.jpg' assert repr(file) == '' def test_generate_file_already_exists(caplog): with get_unique_image_file() as source_file: spec = TestSpec(source=source_file) file_1 = ImageCacheFile(spec) file_1._generate() # generate another cache image with the same name file_2 = ImageCacheFile(spec, name=file_1.name) file_2._generate() assert len(caplog.records) == 1 storage, name, actual_name, cachefile_backend = caplog.records[0].args assert storage == file_2.storage assert name == file_2.name assert actual_name != name assert os.path.basename(actual_name) in storage.listdir(os.path.dirname(actual_name))[1] assert cachefile_backend == file_2.cachefile_backend matthewwithanm-django-imagekit-26cdc9d/tests/test_closing_fieldfiles.py000066400000000000000000000015121525234025000266770ustar00rootroot00000000000000import pytest from .models import Thumbnail from .utils import create_photo @pytest.mark.django_db(transaction=True) def test_do_not_leak_open_files(): instance = create_photo('leak-test.jpg') source_file = instance.original_image # Ensure the FieldFile is closed before generation source_file.close() image_generator = Thumbnail(source=source_file) image_generator.generate() assert source_file.closed @pytest.mark.django_db(transaction=True) def test_do_not_close_open_files_after_generate(): instance = create_photo('do-not-close-test.jpg') source_file = instance.original_image # Ensure the FieldFile is opened before generation source_file.open() image_generator = Thumbnail(source=source_file) image_generator.generate() assert not source_file.closed source_file.close() matthewwithanm-django-imagekit-26cdc9d/tests/test_fields.py000066400000000000000000000033571525234025000243320ustar00rootroot00000000000000import pytest from django import forms from django.core.files.base import File from django.core.files.uploadedfile import SimpleUploadedFile from imagekit import forms as ikforms from imagekit.processors import SmartCrop from . import imagegenerators # noqa from .models import (ImageModel, ProcessedImageFieldModel, ProcessedImageFieldWithSpecModel) from .utils import get_image_file @pytest.mark.django_db(transaction=True) def test_model_processedimagefield(): instance = ProcessedImageFieldModel() with File(get_image_file()) as file: instance.processed.save('whatever.jpeg', file) instance.save() assert instance.processed.width == 50 assert instance.processed.height == 50 @pytest.mark.django_db(transaction=True) def test_model_processedimagefield_with_spec(): instance = ProcessedImageFieldWithSpecModel() with File(get_image_file()) as file: instance.processed.save('whatever.jpeg', file) instance.save() assert instance.processed.width == 100 assert instance.processed.height == 60 @pytest.mark.django_db(transaction=True) def test_form_processedimagefield(): class TestForm(forms.ModelForm): image = ikforms.ProcessedImageField(spec_id='tests:testform_image', processors=[SmartCrop(50, 50)], format='JPEG') class Meta: model = ImageModel fields = 'image', with get_image_file() as upload_file: files = { 'image': SimpleUploadedFile('abc.jpg', upload_file.read()) } form = TestForm({}, files) instance = form.save() assert instance.image.width == 50 assert instance.image.height == 50 matthewwithanm-django-imagekit-26cdc9d/tests/test_generateimage_tag.py000066400000000000000000000032131525234025000265030ustar00rootroot00000000000000import pytest from django.template import TemplateSyntaxError from . import imagegenerators # noqa from .utils import clear_imagekit_cache, get_html_attrs, render_tag def test_img_tag(): ttag = r"""{% generateimage 'testspec' source=img %}""" clear_imagekit_cache() attrs = get_html_attrs(ttag) expected_attrs = {'src', 'width', 'height'} assert set(attrs.keys()) == expected_attrs for k in expected_attrs: assert attrs[k].strip() != '' def test_img_tag_attrs(): ttag = r"""{% generateimage 'testspec' source=img -- alt="Hello" %}""" clear_imagekit_cache() attrs = get_html_attrs(ttag) assert attrs.get('alt') == 'Hello' def test_dangling_html_attrs_delimiter(): ttag = r"""{% generateimage 'testspec' source=img -- %}""" with pytest.raises(TemplateSyntaxError): render_tag(ttag) def test_html_attrs_assignment(): """ You can either use generateimage as an assignment tag or specify html attrs, but not both. """ ttag = r"""{% generateimage 'testspec' source=img -- alt="Hello" as th %}""" with pytest.raises(TemplateSyntaxError): render_tag(ttag) def test_single_dimension_attr(): """ If you only provide one of width or height, the other should not be added. """ ttag = r"""{% generateimage 'testspec' source=img -- width="50" %}""" clear_imagekit_cache() attrs = get_html_attrs(ttag) assert 'height' not in attrs def test_assignment_tag(): ttag = r"""{% generateimage 'testspec' source=img as th %}{{ th.url }}{{ th.height }}{{ th.width }}""" clear_imagekit_cache() html = render_tag(ttag) assert html.strip() != '' matthewwithanm-django-imagekit-26cdc9d/tests/test_no_extra_queries.py000066400000000000000000000006641525234025000264360ustar00rootroot00000000000000from unittest.mock import Mock, PropertyMock, patch from .models import Photo def test_dont_access_source(): """ Touching the source may trigger an unneeded query. See """ pmock = PropertyMock() pmock.__get__ = Mock() with patch.object(Photo, 'original_image', pmock): photo = Photo() # noqa assert not pmock.__get__.called matthewwithanm-django-imagekit-26cdc9d/tests/test_optimistic_strategy.py000066400000000000000000000025021525234025000271610ustar00rootroot00000000000000from unittest.mock import Mock from django.core.files.storage import FileSystemStorage from imagekit.cachefiles import ImageCacheFile from imagekit.cachefiles.backends import Simple as SimpleCFBackend from imagekit.cachefiles.strategies import Optimistic as OptimisticStrategy from .utils import create_image class ImageGenerator: def generate(self): return create_image() def get_hash(self): return 'abc123' def get_image_cache_file(): storage = Mock(FileSystemStorage) backend = SimpleCFBackend() strategy = OptimisticStrategy() generator = ImageGenerator() return ImageCacheFile(generator, storage=storage, cachefile_backend=backend, cachefile_strategy=strategy) def test_no_io_on_bool(): """ When checking the truthiness of an ImageCacheFile, the storage shouldn't perform IO operations. """ with get_image_cache_file() as file: bool(file) assert not file.storage.exists.called assert not file.storage.open.called def test_no_io_on_url(): """ When getting the URL of an ImageCacheFile, the storage shouldn't be checked. """ with get_image_cache_file() as file: file.url assert not file.storage.exists.called assert not file.storage.open.called matthewwithanm-django-imagekit-26cdc9d/tests/test_serialization.py000066400000000000000000000026521525234025000257360ustar00rootroot00000000000000""" Make sure that the various IK classes can be successfully serialized and deserialized. This is important when using IK with Celery. """ import pytest from imagekit.cachefiles import ImageCacheFile from .imagegenerators import TestSpec from .utils import (clear_imagekit_cache, create_photo, get_unique_image_file, pickleback) @pytest.mark.django_db(transaction=True) def test_imagespecfield(): clear_imagekit_cache() instance = create_photo('pickletest2.jpg') thumbnail = pickleback(instance.thumbnail) thumbnail.generate() @pytest.mark.django_db(transaction=True) def test_circular_ref(): """ A model instance with a spec field in its dict shouldn't raise a KeyError. This corresponds to #234 """ clear_imagekit_cache() instance = create_photo('pickletest3.jpg') instance.thumbnail # Cause thumbnail to be added to instance's __dict__ pickleback(instance) def test_cachefiles(): clear_imagekit_cache() with get_unique_image_file() as source_file: spec = TestSpec(source=source_file) file = ImageCacheFile(spec) file.url # remove link to file from spec source generator # test __getstate__ of ImageCacheFile file.generator.source = None restored_file = pickleback(file) assert file is not restored_file # Assertion for #437 and #451 assert file.storage is restored_file.storage matthewwithanm-django-imagekit-26cdc9d/tests/test_settings.py000066400000000000000000000040711525234025000247160ustar00rootroot00000000000000import django from django.test import override_settings import pytest from imagekit.conf import ImageKitConf, settings from imagekit.utils import get_storage @pytest.mark.skipif( django.VERSION < (4, 2), reason="STORAGES was introduced in Django 4.2", ) def test_custom_storages(): with override_settings( STORAGES={ "default": { "BACKEND": "tests.utils.CustomStorage", } }, ): conf = ImageKitConf() assert conf.configure_default_file_storage(None) == "default" @pytest.mark.skipif( django.VERSION >= (5, 1), reason="DEFAULT_FILE_STORAGE is removed in Django 5.1.", ) def test_custom_default_file_storage(): with override_settings(DEFAULT_FILE_STORAGE="tests.utils.CustomStorage"): # If we don’t remove this, Django 4.2 will keep the old value. del settings.STORAGES conf = ImageKitConf() if django.VERSION >= (4, 2): assert conf.configure_default_file_storage(None) == "default" else: assert ( conf.configure_default_file_storage(None) == "tests.utils.CustomStorage" ) def test_get_storage_default(): from django.core.files.storage import FileSystemStorage assert isinstance(get_storage(), FileSystemStorage) @pytest.mark.skipif( django.VERSION >= (5, 1), reason="DEFAULT_FILE_STORAGE is removed in Django 5.1.", ) def test_get_storage_custom_path(): from tests.utils import CustomStorage with override_settings(IMAGEKIT_DEFAULT_FILE_STORAGE="tests.utils.CustomStorage"): assert isinstance(get_storage(), CustomStorage) @pytest.mark.skipif( django.VERSION < (4, 2), reason="STORAGES was introduced in Django 4.2", ) def test_get_storage_custom_key(): from tests.utils import CustomStorage with override_settings( STORAGES={ "custom": { "BACKEND": "tests.utils.CustomStorage", } }, IMAGEKIT_DEFAULT_FILE_STORAGE="custom", ): assert isinstance(get_storage(), CustomStorage) matthewwithanm-django-imagekit-26cdc9d/tests/test_sourcegroups.py000066400000000000000000000036371525234025000256250ustar00rootroot00000000000000import pytest from django.core.files import File from imagekit.signals import source_saved from imagekit.specs.sourcegroups import ImageFieldSourceGroup from .models import AbstractImageModel, ConcreteImageModel, ImageModel from .utils import get_image_file def make_counting_receiver(source_group): def receiver(sender, *args, **kwargs): if sender is source_group: receiver.count += 1 receiver.count = 0 return receiver @pytest.mark.django_db(transaction=True) def test_source_saved_signal(): """ Creating a new instance with an image causes the source_saved signal to be dispatched. """ source_group = ImageFieldSourceGroup(ImageModel, 'image') receiver = make_counting_receiver(source_group) source_saved.connect(receiver) with File(get_image_file(), name='reference.png') as image: ImageModel.objects.create(image=image) assert receiver.count == 1 @pytest.mark.django_db(transaction=True) def test_no_source_saved_signal(): """ Creating a new instance without an image shouldn't cause the source_saved signal to be dispatched. https://github.com/matthewwithanm/django-imagekit/issues/214 """ source_group = ImageFieldSourceGroup(ImageModel, 'image') receiver = make_counting_receiver(source_group) source_saved.connect(receiver) ImageModel.objects.create() assert receiver.count == 0 @pytest.mark.django_db(transaction=True) def test_abstract_model_signals(): """ Source groups created for abstract models must cause signals to be dispatched on their concrete subclasses. """ source_group = ImageFieldSourceGroup(AbstractImageModel, 'original_image') receiver = make_counting_receiver(source_group) source_saved.connect(receiver) with File(get_image_file(), name='reference.png') as image: ConcreteImageModel.objects.create(original_image=image) assert receiver.count == 1 matthewwithanm-django-imagekit-26cdc9d/tests/test_state_cache.py000066400000000000000000000253371525234025000253310ustar00rootroot00000000000000""" Tests for request-local state cache functionality. """ from unittest import mock import pytest from django.conf import settings from imagekit.cachefiles import ImageCacheFile from imagekit.cachefiles.backends import Simple, CachedFileBackend, CacheFileState from imagekit.cachefiles.state import use_cachefile_state_cache, prefetch_cachefile_states from .imagegenerators import TestSpec, ResizeTo1PixelSquare from .utils import get_unique_image_file, clear_imagekit_cache def test_get_state_uses_request_local_cache_without_hitting_django_cache(): """ Ensure get_state() consults request-local cache first and doesn't call Django cache.get() for pre-seeded keys. """ clear_imagekit_cache() with get_unique_image_file() as source_file: spec = TestSpec(source=source_file) file = ImageCacheFile(spec) backend = file.cachefile_backend # Spy on cache.get cache_get = mock.patch.object(backend.cache, 'get') with cache_get as mock_get: # First call - should hit cache mock_get.return_value = CacheFileState.DOES_NOT_EXIST state1 = backend.get_state(file) assert state1 == CacheFileState.DOES_NOT_EXIST assert mock_get.call_count == 1 # Now activate request-local cache and pre-seed it state_cache = {backend.get_key(file): CacheFileState.EXISTS} with use_cachefile_state_cache(state_cache): mock_get.reset_mock() # Should get state from request-local cache, not Django cache state2 = backend.get_state(file) assert state2 == CacheFileState.EXISTS assert mock_get.call_count == 0 def test_get_state_with_unknown_state_still_updates_request_local_cache(): """ Ensure get_state() with check_if_unknown=True stores newly discovered state in the request-local cache. """ clear_imagekit_cache() with get_unique_image_file() as source_file: spec = TestSpec(source=source_file) file = ImageCacheFile(spec) backend = file.cachefile_backend state_cache = {} with use_cachefile_state_cache(state_cache): # First call with check_if_unknown=True (file doesn't exist yet) # This should call cache.get() (returns None), check storage, # and store DOES_NOT_EXIST in both Django cache and request-local cache state = backend.get_state(file) assert state == CacheFileState.DOES_NOT_EXIST # Verify request-local cache was updated key = backend.get_key(file) assert key in state_cache assert state_cache[key] == CacheFileState.DOES_NOT_EXIST def test_prefetch_cachefile_states_uses_get_many_once_and_populates_mapping(): """ Ensure prefetch_cachefile_states() calls cache.get_many() once and populates the state_cache with both hits and misses. """ clear_imagekit_cache() # Create multiple files with different specs to get unique cache keys files = [] # Create 3 different specs with different sources for _ in range(3): with get_unique_image_file() as source_file: spec = TestSpec(source=source_file) file = ImageCacheFile(spec) files.append(file) backend = files[0].cachefile_backend # Prefetch states - use the actual backend cache state_cache = {} prefetch_cachefile_states(files, cache=backend.cache, state_cache=state_cache) # Verify state_cache was populated with all unique keys assert len(state_cache) == 3 # All should be None (misses) since no states are in the cache for key, value in state_cache.items(): assert value is None def test_prefetch_uses_active_request_local_cache_when_none_provided(): """ Ensure prefetch_cachefile_states() uses active request-local cache when state_cache parameter is not provided. """ clear_imagekit_cache() with get_unique_image_file() as source_file: spec = TestSpec(source=source_file) file = ImageCacheFile(spec) backend = file.cachefile_backend key = backend.get_key(file) with mock.patch.object(backend.cache, 'get_many') as mock_get_many: mock_get_many.return_value = {key: CacheFileState.EXISTS} # Activate request-local cache with use_cachefile_state_cache() as state_cache: prefetch_cachefile_states([file]) # Verify active cache was populated assert key in state_cache assert state_cache[key] == CacheFileState.EXISTS def test_prefetch_does_nothing_when_no_active_cache_and_none_provided(): """ Ensure prefetch_cachefile_states() is a no-op when no state_cache is provided and no active request-local cache exists. """ clear_imagekit_cache() with get_unique_image_file() as source_file: spec = TestSpec(source=source_file) file = ImageCacheFile(spec) backend = file.cachefile_backend with mock.patch.object(backend.cache, 'get_many') as mock_get_many: prefetch_cachefile_states([file]) # Should not call get_many since there's no cache to populate assert mock_get_many.call_count == 0 def test_set_state_updates_request_local_cache(): """ Ensure set_state() updates the active request-local cache (write-through). """ clear_imagekit_cache() with get_unique_image_file() as source_file: spec = TestSpec(source=source_file) file = ImageCacheFile(spec) backend = file.cachefile_backend state_cache = {} with use_cachefile_state_cache(state_cache): # Set state backend.set_state(file, CacheFileState.GENERATING) # Verify request-local cache was updated key = backend.get_key(file) assert key in state_cache assert state_cache[key] == CacheFileState.GENERATING def test_multiple_get_state_calls_only_hit_cache_once_after_prefetch(): """ Ensure that after prefetching, multiple get_state() calls don't hit the Django cache. """ clear_imagekit_cache() # Create multiple files files = [] with get_unique_image_file() as source_file: for i in range(5): spec = TestSpec(source=source_file) file = ImageCacheFile(spec) files.append(file) backend = files[0].cachefile_backend with mock.patch.object(backend.cache, 'get') as mock_get, \ mock.patch.object(backend.cache, 'get_many') as mock_get_many: # Set up get_many to return all files as existing keys = [backend.get_key(f) for f in files] mock_get_many.return_value = {k: CacheFileState.EXISTS for k in keys} # Activate request-local cache and prefetch with use_cachefile_state_cache() as state_cache: prefetch_cachefile_states(files, state_cache=state_cache) # Mock get_many should have been called once assert mock_get_many.call_count == 1 assert mock_get.call_count == 0 # Now call get_state for each file multiple times for _ in range(3): for file in files: state = backend.get_state(file) assert state == CacheFileState.EXISTS # Verify no additional cache.get() calls assert mock_get.call_count == 0 def test_prefetch_groups_by_backend_cache_when_cache_not_provided(): """ Ensure prefetch_cachefile_states() uses each file's backend cache when no explicit cache is passed. This supports projects that mix cachefile backends (and potentially cache aliases). """ clear_imagekit_cache() cache_a = mock.Mock() cache_b = mock.Mock() backend_a = CachedFileBackend() backend_b = CachedFileBackend() backend_a._cache = cache_a backend_b._cache = cache_b with get_unique_image_file() as source_file_a, get_unique_image_file() as source_file_b: spec_a = TestSpec(source=source_file_a) spec_b = TestSpec(source=source_file_b) file_a = ImageCacheFile(spec_a, cachefile_backend=backend_a) file_b = ImageCacheFile(spec_b, cachefile_backend=backend_b) key_a = backend_a.get_key(file_a) key_b = backend_b.get_key(file_b) cache_a.get_many.return_value = {key_a: CacheFileState.EXISTS} cache_b.get_many.return_value = {key_b: CacheFileState.GENERATING} state_cache = {} prefetch_cachefile_states([file_a, file_b], state_cache=state_cache) cache_a.get_many.assert_called_once_with({key_a}) cache_b.get_many.assert_called_once_with({key_b}) assert state_cache[key_a] == CacheFileState.EXISTS assert state_cache[key_b] == CacheFileState.GENERATING def test_prefetch_uses_provided_cache_for_all_backends(): """Ensure the `cache=` kwarg overrides per-backend caches.""" clear_imagekit_cache() shared_cache = mock.Mock() cache_a = mock.Mock() cache_b = mock.Mock() backend_a = CachedFileBackend() backend_b = CachedFileBackend() backend_a._cache = cache_a backend_b._cache = cache_b with get_unique_image_file() as source_file_a, get_unique_image_file() as source_file_b: spec_a = TestSpec(source=source_file_a) spec_b = TestSpec(source=source_file_b) file_a = ImageCacheFile(spec_a, cachefile_backend=backend_a) file_b = ImageCacheFile(spec_b, cachefile_backend=backend_b) key_a = backend_a.get_key(file_a) key_b = backend_b.get_key(file_b) shared_cache.get_many.return_value = { key_a: CacheFileState.EXISTS, key_b: CacheFileState.EXISTS, } state_cache = {} prefetch_cachefile_states([file_a, file_b], cache=shared_cache, state_cache=state_cache) shared_cache.get_many.assert_called_once_with({key_a, key_b}) assert cache_a.get_many.call_count == 0 assert cache_b.get_many.call_count == 0 assert state_cache[key_a] == CacheFileState.EXISTS assert state_cache[key_b] == CacheFileState.EXISTS def test_use_cachefile_state_cache_creates_new_dict_if_none_provided(): """ Ensure use_cachefile_state_cache() creates a new dict if None is passed. """ clear_imagekit_cache() with use_cachefile_state_cache() as state_cache: # Should get a dict assert isinstance(state_cache, dict) # Should be empty assert len(state_cache) == 0 # Can add values state_cache['test_key'] = 'test_value' assert state_cache['test_key'] == 'test_value' # After context exit, the cache should no longer be active from imagekit.cachefiles.state import get_active_state_cache assert get_active_state_cache() is None matthewwithanm-django-imagekit-26cdc9d/tests/test_thumbnail_tag.py000066400000000000000000000055401525234025000256760ustar00rootroot00000000000000import pytest import re from django.template import TemplateSyntaxError from . import imagegenerators # noqa from .utils import clear_imagekit_cache, get_html_attrs, render_tag def test_img_tag(): ttag = r"""{% thumbnail '100x100' img %}""" clear_imagekit_cache() attrs = get_html_attrs(ttag) expected_attrs = {'src', 'width', 'height'} assert set(attrs.keys()) == expected_attrs for k in expected_attrs: assert attrs[k].strip() != '' def test_img_tag_anchor(): ttag = r"""{% thumbnail '100x100' img anchor='c' %}""" clear_imagekit_cache() attrs = get_html_attrs(ttag) expected_attrs = {'src', 'width', 'height'} assert set(attrs.keys()) == expected_attrs for k in expected_attrs: assert attrs[k].strip() != '' def test_img_tag_attrs(): ttag = r"""{% thumbnail '100x100' img -- alt="Hello" %}""" clear_imagekit_cache() attrs = get_html_attrs(ttag) assert attrs.get('alt') == 'Hello' def test_dangling_html_attrs_delimiter(): ttag = r"""{% thumbnail '100x100' img -- %}""" with pytest.raises(TemplateSyntaxError): render_tag(ttag) def test_not_enough_args(): ttag = r"""{% thumbnail '100x100' %}""" with pytest.raises(TemplateSyntaxError): render_tag(ttag) def test_too_many_args(): ttag = r"""{% thumbnail 'generator_id' '100x100' img 'extra' %}""" with pytest.raises(TemplateSyntaxError): render_tag(ttag) def test_html_attrs_assignment(): """ You can either use thumbnail as an assignment tag or specify html attrs, but not both. """ ttag = r"""{% thumbnail '100x100' img -- alt="Hello" as th %}""" with pytest.raises(TemplateSyntaxError): render_tag(ttag) def test_assignment_tag(): ttag = r"""{% thumbnail '100x100' img as th %}{{ th.url }}""" clear_imagekit_cache() html = render_tag(ttag) assert html != '' def test_assignment_tag_anchor(): ttag = r"""{% thumbnail '100x100' img anchor='c' as th %}{{ th.url }}""" clear_imagekit_cache() html = render_tag(ttag) assert html != '' def test_single_dimension(): ttag = r"""{% thumbnail '100x' img as th %}{{ th.width }}""" clear_imagekit_cache() html = render_tag(ttag) assert html == '100' def test_alternate_generator(): ttag = r"""{% thumbnail '1pxsq' '100x' img as th %}{{ th.width }}""" clear_imagekit_cache() html = render_tag(ttag) assert html == '1' def test_srcset_arg(): ttag = r"""{% thumbnail '100x' img srcset="1.5 2" %}""" clear_imagekit_cache() html = render_tag(ttag) srcset_regex = re.compile('srcset=".* 1x ,.* 1\\.5x ,.* 2.0x"') assert srcset_regex.search(html) is not None def test_alternate_format(): ttag = r"""{% thumbnail '100x' img format='webp' as th %}{{ th.url }}""" clear_imagekit_cache() html = render_tag(ttag) assert html.endswith('webp') matthewwithanm-django-imagekit-26cdc9d/tests/test_utils.py000066400000000000000000000022061525234025000242140ustar00rootroot00000000000000import django from django.test import override_settings import pytest from imagekit.utils import get_storage def test_get_storage_default(): from django.core.files.storage import default_storage if django.VERSION >= (4, 2): assert get_storage() == default_storage else: assert isinstance(get_storage(), type(default_storage._wrapped)) @pytest.mark.skipif( django.VERSION >= (5, 1), reason="DEFAULT_FILE_STORAGE is removed in Django 5.1.", ) def test_get_storage_custom_import_path(): from tests.utils import CustomStorage with override_settings(IMAGEKIT_DEFAULT_FILE_STORAGE="tests.utils.CustomStorage"): assert isinstance(get_storage(), CustomStorage) @pytest.mark.skipif( django.VERSION < (4, 2), reason="STORAGES was introduced in Django 4.2", ) def test_get_storage_custom_key(): from tests.utils import CustomStorage with override_settings( STORAGES={ "custom": { "BACKEND": "tests.utils.CustomStorage", } }, IMAGEKIT_DEFAULT_FILE_STORAGE="custom", ): assert isinstance(get_storage(), CustomStorage) matthewwithanm-django-imagekit-26cdc9d/tests/utils.py000066400000000000000000000053261525234025000231630ustar00rootroot00000000000000import os import pickle import shutil from io import BytesIO from tempfile import NamedTemporaryFile from bs4 import BeautifulSoup from django.core.files import File from django.core.files.storage import FileSystemStorage from django.template import Context, Template from PIL import Image from imagekit.cachefiles.backends import Simple from imagekit.conf import settings from imagekit.utils import get_cache from .models import Photo def get_image_file(): """ See also: http://en.wikipedia.org/wiki/Lenna http://sipi.usc.edu/database/database.php?volume=misc&image=12 https://lintian.debian.org/tags/license-problem-non-free-img-lenna.html https://github.com/libav/libav/commit/8895bf7b78650c0c21c88cec0484e138ec511a4b """ path = os.path.join(settings.MEDIA_ROOT, 'reference.png') return open(path, 'r+b') def get_unique_image_file(): file = NamedTemporaryFile() with get_image_file() as image: file.write(image.read()) return file def create_image(): return Image.open(get_image_file()) def create_instance(model_class, image_name): instance = model_class() img = File(get_image_file()) instance.original_image.save(image_name, img) instance.save() img.close() return instance def create_photo(name): return create_instance(Photo, name) def pickleback(obj): pickled = BytesIO() pickle.dump(obj, pickled) pickled.seek(0) return pickle.load(pickled) def render_tag(ttag): with get_image_file() as img: template = Template('{%% load imagekit %%}%s' % ttag) context = Context({'img': img}) return template.render(context) def get_html_attrs(ttag): return BeautifulSoup(render_tag(ttag), features="html.parser").img.attrs def assert_file_is_falsy(file): assert not bool(file), 'File is not falsy' def assert_file_is_truthy(file): assert bool(file), 'File is not truthy' class CustomStorage(FileSystemStorage): pass class DummyAsyncCacheFileBackend(Simple): """ A cache file backend meant to simulate async generation. """ is_async = True def generate(self, file, force=False): pass def clear_imagekit_cache(): cache = get_cache() cache.clear() # Clear IMAGEKIT_CACHEFILE_DIR cache_dir = os.path.join(settings.MEDIA_ROOT, settings.IMAGEKIT_CACHEFILE_DIR) if os.path.exists(cache_dir): shutil.rmtree(cache_dir) def clear_imagekit_test_files(): clear_imagekit_cache() for fname in os.listdir(settings.MEDIA_ROOT): if fname != 'reference.png': path = os.path.join(settings.MEDIA_ROOT, fname) if os.path.isdir(path): shutil.rmtree(path) else: os.remove(path) matthewwithanm-django-imagekit-26cdc9d/tox.ini000066400000000000000000000016261525234025000216210ustar00rootroot00000000000000[tox] envlist = django32-py3{9,10} django42-py3{9,10,11,12} django52-py3{10,11,12,13,14} django60-py3{13,14} django61-py3{13,14} djangomain-py3{13,14} coverage-report [gh-actions] python = 3.9: py39 3.10: py310 3.11: py311, coverage-report 3.12: py312 3.13: py313 3.14: py314 [testenv] deps = .[test] django32: django~=3.2.0 django42: django~=4.2.0 django51: django~=5.1.0 django52: django~=5.2.0 django60: django~=6.0.0 django61: django~=6.1.0 djangomain: https://github.com/django/django/archive/refs/heads/main.zip setenv = COVERAGE_FILE=.coverage.{envname} commands = python -Wdefault -m pytest --cov --cov-report term-missing:skip-covered ignore_outcome = djangomain: true [testenv:coverage-report] deps = coverage skip_install = true setenv = COVERAGE_FILE=.coverage commands = coverage combine coverage report