pax_global_header00006660000000000000000000000064132137040570014514gustar00rootroot0000000000000052 comment=4cc2e2169920ed22c87bf23d7721a2bb84d1a059 django-simple-captcha-0.5.6/000077500000000000000000000000001321370405700156565ustar00rootroot00000000000000django-simple-captcha-0.5.6/.pep8000066400000000000000000000001121321370405700165250ustar00rootroot00000000000000[flake8] ignore = E501 exclude = south_migrations,migrations,.venv_*,docs django-simple-captcha-0.5.6/CHANGES000066400000000000000000000147221321370405700166570ustar00rootroot00000000000000Version 0.5.6 ------------- * Updated render method to adapt for Django 2.1 (PR #120, thanks @skozan) * Improved compatibility with Django 2.0, tests against Django 2.0a1 (PR #121, thanks @Kondou-ger) * Dropped support for PIL (use Pillow instead) * Updated documentation (Fixes #122, thanks @claudep) * Test against Django 2.0b1 * Return a Ranged Response when returning WAV audio to support Safari (Fixes #123, thanks @po5i) * Optionally inject brown noise into the generated WAV audio file, to avoid rainbow-table attacks (Fixes #124, thanks @appleorange1) * Test against Django 2.0 Version 0.5.5 ------------- * I messed the 0.5.4 release, re-releasing as 0.5.5 Version 0.5.4 ------------- * Removed a couple gremlins (PR #113, thanks @Pawamoy) * Added autocapitalize="off", autocorrect="off" and spellcheck="false" to the genreated field (PR #116, thanks @rdonnelly) * Test against Django 1.11 * Drop support of Django 1.7 ("it'll probably still work") Version 0.5.3 ------------- * Ability to pass a per-field challenge generator function (Fixes #109) * Added a feature to get captchas from a data pool of pre-created captchas (PR #110, thanks @skozan) * Cleanup to remove old code handling timezones for no longer supported Django versions * Fix for "Size must be a tuple" issue with Pillow 3.4.0 (Fixes #111) Version 0.5.2 ------------- * Use any mutliplication uperator instead of "*". (Fixes #77 via PR #104, thanks @honsdomi and @isergey) * Test against Django 1.10 Version 0.5.1 ------------- * Fine tuning MANIFEST.in * Prevent testproject from installing into site-packages Version 0.5.0 ------------- * Adds missing includes in MANIFEST.in Version 0.4.7 ------------- * Supported Django versions are now 1.7, 1.8 and 1.9 * Trying to fix the TravisCI build errors * Use Django templates to render the individual fields, as well as the assembled Captcha Field (Issue #31) Version 0.4.6 ------------- * Fixes an UnicodeDecodeError which was apparently only triggered during testing on TravisCI (I hope) * Support for Django 2.0 urlpatterns syntax (PR #82, Thanks @R3v1L) * settings.CAPTCHA_FONT_PATH may be a list, in which case a font is picked randomly (Issue #51 fixed in PR #88, Thanks @inflrscns) Version 0.4.5 ------------- * Test with tox * Test against Django 1.8 final * Added ability to force a fixed image size (PR #76, Thanks @superqwer) Version 0.4.4 ------------- * Added id_prefix argument (fixes issue #37) Version 0.4.3 ------------- * Add null noise helper (Thanks @xrmx) * Test against Django 1.7b4 * Added Spanish translations (Thanks @dragosdobrota) * Massive cleanup (pep8, translations) * Support for transparent background color. (Thanks @curaloucura) * Support both Django 1.7 migrations and South migrations. Please note, you *must* add the following to your settings, if you are using South migrations and Django 1.6 or lower. * Make sure autocomplete="off" is only applied to the text input, not the hidden input (Issue #68, thanks @narrowfail) * Fixed some grammar in the documentation. (Thanks @rikrian) * Return an HTTP 410 GONE error code for expired captcha images, to avoid crawlers from trying to reindex them (PR #70, thanks @joshuajonah) * Fixed title markup in documentation (#74, thanks @pavlov99) * Test against Django 1.7.1 Version 0.4.2 ------------- * Added autocomplete="off" to the input (Issue #57, thanks @Vincent-Vega) * Fixed the format (msgfmt -c) of most PO and MO files distributed with the project * Added Bulgarian translations. (Thanks @vstoykov) * Added Japanese translations. (Thanks, Keisuke URAGO) * Added Ukrainian translations. (Thanks, @FuriousCoder) * Added support for Python 3.2. (Thanks, @amrhassan) Version 0.4.1 ------------- * Dropped support for Django 1.3 * Fixed support of newer versions of Pillow (2.1 and above. Pillow 2.2.2 is now required) Thanks @viaregio (Issue #50) Version 0.4.0 ------------- * Perfom some tests at package installation, to check whether PIL or Pillow are already installed. (Issue #46) * Added Slovak translations. (Thanks @ciklysta) Version 0.3.9 ------------- * Run most tests both with a regular Form and a ModelForm, to avoid regressions such as Issue #40 * Handle the special case where CaptchaFields are instantiated with required=False (Issue #42, thanks @DrMeers) * Fixed a misspelled setting, we now support both spellings, but the docs suggest the correct one (Issue #36, thanks @sayadn) * Added Django 1.6b to testrunner and adapted the test cases to support Django 1.6's new test discovery * Added German translations. (Thanks @digi604) * Frozen the version of Pillow to 2.0.0, as 2.1.0 seems to be truncating the output image -- Issue #44, Thanks @andruby * Added Polish translations. (Thanks @stilzdev) Version 0.3.8 ------------- * Fixed a critical bug (Issue #40) that would generate two captcha objects, and the test would always fail. Thanks @pengqi for the heads-up. Version 0.3.7 ------------- * Improved Django 1.5 and Django HEAD (1.6) compatibility (thanks @uruz) * Python3 compatibility (requires six and Pillow >= 2.0) * Added zh_CN localization (thanks @mingchen) * Make sure the generated challenge is a string type (the math challenge was probably broken -- Issue #33, thanks @YDS19872712) * Massive cleanup and refactoring (Issue #38, thanks @tepez) * Test refactoring to test a couple generators that weren't tested by default Version 0.3.6 ------------- * Django 1.5 compatibility (only affects tests) * Italian localization (thanks @arjunadeltoso) * Russian localization (thanks @mikek) * Fixed issue #17 - Append content-length to response (thanks @shchemelevev) * Merged PR #19 - AJAX refresh of captcha (thanks @artofhuman) * Merged PR #22 - Use op.popen instead of subprocess.call to generate the audio CAPTCHA (thanks @beda42) * Fixed issue #10 - uniformize spelling of "CAPTCHA" (thanks @mikek) * Fixed issue #12 - Raise error when try to initialize CaptchaTextInput alone and/or when try to initialize CaptchaField with widget keyword argument (thanks @vstoykov) * Merged PR #15 - Allow a 'test mode' where the string 'PASSED' always validates the CAPTCHA (thanks @beda42) * Dutch translation (thanks @leonderijke) * Turkish translation (thanks @gkmngrgn) Version 0.3.5 ------------- * Fixes issue #4: Fixes id_for_label malfunction with prefixed forms (thanks @lolek09) Version 0.3.4 ------------- * Fixes issue #3: regression on Django 1.4 when USE_TZ is False Version 0.3.3 ------------- * Django 1.4 Time zones compatibility * PEP 8 love Version 0.3.2 ------------- * Added a test project to run tests * Added South migrations django-simple-captcha-0.5.6/LICENSE000066400000000000000000000020501321370405700166600ustar00rootroot00000000000000Copyright (c) 2008 - 2014 Marco Bonetti Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. django-simple-captcha-0.5.6/MANIFEST.in000066400000000000000000000007031321370405700174140ustar00rootroot00000000000000include MANIFEST.in include LICENSE include README.rst include CHANGES include tox.ini include .pep8 recursive-include captcha/fonts * recursive-include captcha/locale * recursive-include captcha/templates * recursive-include testproject * recursive-include docs * exclude testproject/django-simple-captcha.db prune .tox prune docs/_build prune htmlcov global-exclude *pyc global-exclude coverage.xml global-exclude .DS_Store global-exclude .coverage django-simple-captcha-0.5.6/PKG-INFO000066400000000000000000000015241321370405700167550ustar00rootroot00000000000000Metadata-Version: 1.1 Name: django-simple-captcha Version: 0.5.6 Summary: A very simple, yet powerful, Django captcha application Home-page: https://github.com/mbi/django-simple-captcha Author: Marco Bonetti Author-email: mbonetti@gmail.com License: MIT Description-Content-Type: UNKNOWN Description: UNKNOWN Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Topic :: Security Classifier: Topic :: Internet :: WWW/HTTP Classifier: Framework :: Django django-simple-captcha-0.5.6/README.rst000066400000000000000000000025221321370405700173460ustar00rootroot00000000000000********************* Django Simple Captcha ********************* .. image:: https://travis-ci.org/mbi/django-simple-captcha.png?branch=master :target: http://travis-ci.org/mbi/django-simple-captcha Django Simple Captcha is an extremely simple, yet highly customizable Django application to add captcha images to any Django form. .. image:: http://django-simple-captcha.readthedocs.io/en/latest/_images/captcha3.png Features ++++++++ * Very simple to setup and deploy, yet very configurable * Can use custom challenges (e.g. random chars, simple maths, dictionary word, ...) * Custom generators, noise and filter functions alter the look of the generated image * Supports text-to-speech audio output of the challenge text, for improved accessibility * Ajax refresh Requirements ++++++++++++ * Django 1.8+ * A recent version of the Pillow compiled with FreeType support * Flite is required for text-to-speech (audio) output, but not mandatory Python 3 compatibility ++++++++++++++++++++++ The current development version supports Python3 via the `six `_ compatibility layer. You will need to install `Pillow `_ because PIL doesn't support Python3 yet. Documentation +++++++++++++ Read the `documentation online `_. django-simple-captcha-0.5.6/captcha/000077500000000000000000000000001321370405700172615ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/__init__.py000066400000000000000000000002241321370405700213700ustar00rootroot00000000000000VERSION = (0, 5, 6) def get_version(svn=False): "Return the version as a human-format string." return '.'.join([str(i) for i in VERSION]) django-simple-captcha-0.5.6/captcha/conf/000077500000000000000000000000001321370405700202065ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/conf/__init__.py000066400000000000000000000000001321370405700223050ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/conf/settings.py000066400000000000000000000063541321370405700224300ustar00rootroot00000000000000import os from django.conf import settings CAPTCHA_FONT_PATH = getattr(settings, 'CAPTCHA_FONT_PATH', os.path.normpath(os.path.join(os.path.dirname(__file__), '..', 'fonts/Vera.ttf'))) CAPTCHA_FONT_SIZE = getattr(settings, 'CAPTCHA_FONT_SIZE', 22) CAPTCHA_LETTER_ROTATION = getattr(settings, 'CAPTCHA_LETTER_ROTATION', (-35, 35)) CAPTCHA_BACKGROUND_COLOR = getattr(settings, 'CAPTCHA_BACKGROUND_COLOR', '#ffffff') CAPTCHA_FOREGROUND_COLOR = getattr(settings, 'CAPTCHA_FOREGROUND_COLOR', '#001100') CAPTCHA_CHALLENGE_FUNCT = getattr(settings, 'CAPTCHA_CHALLENGE_FUNCT', 'captcha.helpers.random_char_challenge') CAPTCHA_NOISE_FUNCTIONS = getattr(settings, 'CAPTCHA_NOISE_FUNCTIONS', ('captcha.helpers.noise_arcs', 'captcha.helpers.noise_dots',)) CAPTCHA_FILTER_FUNCTIONS = getattr(settings, 'CAPTCHA_FILTER_FUNCTIONS', ('captcha.helpers.post_smooth',)) CAPTCHA_WORDS_DICTIONARY = getattr(settings, 'CAPTCHA_WORDS_DICTIONARY', '/usr/share/dict/words') CAPTCHA_PUNCTUATION = getattr(settings, 'CAPTCHA_PUNCTUATION', '''_"',.;:-''') CAPTCHA_FLITE_PATH = getattr(settings, 'CAPTCHA_FLITE_PATH', None) CAPTCHA_SOX_PATH = getattr(settings, 'CAPTCHA_SOX_PATH', None) CAPTCHA_TIMEOUT = getattr(settings, 'CAPTCHA_TIMEOUT', 5) # Minutes CAPTCHA_LENGTH = int(getattr(settings, 'CAPTCHA_LENGTH', 4)) # Chars # CAPTCHA_IMAGE_BEFORE_FIELD = getattr(settings, 'CAPTCHA_IMAGE_BEFORE_FIELD', True) CAPTCHA_DICTIONARY_MIN_LENGTH = getattr(settings, 'CAPTCHA_DICTIONARY_MIN_LENGTH', 0) CAPTCHA_DICTIONARY_MAX_LENGTH = getattr(settings, 'CAPTCHA_DICTIONARY_MAX_LENGTH', 99) CAPTCHA_IMAGE_SIZE = getattr(settings, 'CAPTCHA_IMAGE_SIZE', None) CAPTCHA_IMAGE_TEMPLATE = getattr(settings, 'CAPTCHA_IMAGE_TEMPLATE', 'captcha/image.html') CAPTCHA_HIDDEN_FIELD_TEMPLATE = getattr(settings, 'CAPTCHA_HIDDEN_FIELD_TEMPLATE', 'captcha/hidden_field.html') CAPTCHA_TEXT_FIELD_TEMPLATE = getattr(settings, 'CAPTCHA_TEXT_FIELD_TEMPLATE', 'captcha/text_field.html') CAPTCHA_FIELD_TEMPLATE = getattr(settings, 'CAPTCHA_FIELD_TEMPLATE', 'captcha/field.html') CAPTCHA_OUTPUT_FORMAT = getattr(settings, 'CAPTCHA_OUTPUT_FORMAT', None) CAPTCHA_MATH_CHALLENGE_OPERATOR = getattr(settings, 'CAPTCHA_MATH_CHALLENGE_OPERATOR', '*') CAPTCHA_GET_FROM_POOL = getattr(settings, 'CAPTCHA_GET_FROM_POOL', False) CAPTCHA_GET_FROM_POOL_TIMEOUT = getattr(settings, 'CAPTCHA_GET_FROM_POOL_TIMEOUT', 5) CAPTCHA_TEST_MODE = getattr(settings, 'CAPTCHA_TEST_MODE', getattr(settings, 'CATPCHA_TEST_MODE', False)) # Failsafe if CAPTCHA_DICTIONARY_MIN_LENGTH > CAPTCHA_DICTIONARY_MAX_LENGTH: CAPTCHA_DICTIONARY_MIN_LENGTH, CAPTCHA_DICTIONARY_MAX_LENGTH = CAPTCHA_DICTIONARY_MAX_LENGTH, CAPTCHA_DICTIONARY_MIN_LENGTH def _callable_from_string(string_or_callable): if callable(string_or_callable): return string_or_callable else: return getattr(__import__('.'.join(string_or_callable.split('.')[:-1]), {}, {}, ['']), string_or_callable.split('.')[-1]) def get_challenge(generator=None): return _callable_from_string(generator or CAPTCHA_CHALLENGE_FUNCT) def noise_functions(): if CAPTCHA_NOISE_FUNCTIONS: return map(_callable_from_string, CAPTCHA_NOISE_FUNCTIONS) return [] def filter_functions(): if CAPTCHA_FILTER_FUNCTIONS: return map(_callable_from_string, CAPTCHA_FILTER_FUNCTIONS) return [] django-simple-captcha-0.5.6/captcha/fields.py000066400000000000000000000172351321370405700211110ustar00rootroot00000000000000from captcha.conf import settings from captcha.models import CaptchaStore import django from django.core.exceptions import ImproperlyConfigured if django.VERSION < (1, 10): # NOQA from django.core.urlresolvers import reverse, NoReverseMatch # NOQA else: # NOQA from django.urls import reverse, NoReverseMatch # NOQA from django.forms import ValidationError from django.forms.fields import CharField, MultiValueField from django.forms.widgets import TextInput, MultiWidget, HiddenInput from django.utils.translation import ugettext_lazy from django.utils import timezone from django.template.loader import render_to_string from django.utils.safestring import mark_safe from six import u class BaseCaptchaTextInput(MultiWidget): """ Base class for Captcha widgets """ def __init__(self, attrs=None): widgets = ( HiddenInput(attrs), TextInput(attrs), ) super(BaseCaptchaTextInput, self).__init__(widgets, attrs) def decompress(self, value): if value: return value.split(',') return [None, None] def fetch_captcha_store(self, name, value, attrs=None, generator=None): """ Fetches a new CaptchaStore This has to be called inside render """ try: reverse('captcha-image', args=('dummy',)) except NoReverseMatch: raise ImproperlyConfigured('Make sure you\'ve included captcha.urls as explained in the INSTALLATION section on http://readthedocs.org/docs/django-simple-captcha/en/latest/usage.html#installation') if settings.CAPTCHA_GET_FROM_POOL: key = CaptchaStore.pick() else: key = CaptchaStore.generate_key(generator) # these can be used by format_output and render self._value = [key, u('')] self._key = key self.id_ = self.build_attrs(attrs).get('id', None) def id_for_label(self, id_): if id_: return id_ + '_1' return id_ def image_url(self): return reverse('captcha-image', kwargs={'key': self._key}) def audio_url(self): return reverse('captcha-audio', kwargs={'key': self._key}) if settings.CAPTCHA_FLITE_PATH else None def refresh_url(self): return reverse('captcha-refresh') class CaptchaTextInput(BaseCaptchaTextInput): def __init__(self, attrs=None, **kwargs): self._args = kwargs self._args['output_format'] = self._args.get('output_format') or settings.CAPTCHA_OUTPUT_FORMAT self._args['field_template'] = self._args.get('field_template') or settings.CAPTCHA_FIELD_TEMPLATE # self._args['id_prefix'] = self._args.get('id_prefix') if self._args['output_format'] is None and self._args['field_template'] is None: raise ImproperlyConfigured('You MUST define either CAPTCHA_FIELD_TEMPLATE or CAPTCHA_OUTPUT_FORMAT setting. Please refer to http://readthedocs.org/docs/django-simple-captcha/en/latest/usage.html#installation') if self._args['output_format']: for key in ('image', 'hidden_field', 'text_field'): if '%%(%s)s' % key not in self._args['output_format']: raise ImproperlyConfigured('All of %s must be present in your CAPTCHA_OUTPUT_FORMAT setting. Could not find %s' % ( ', '.join(['%%(%s)s' % k for k in ('image', 'hidden_field', 'text_field')]), '%%(%s)s' % key )) super(CaptchaTextInput, self).__init__(attrs) def build_attrs(self, *args, **kwargs): ret = super(CaptchaTextInput, self).build_attrs(*args, **kwargs) if self._args.get('id_prefix') and 'id' in ret: ret['id'] = '%s_%s' % (self._args.get('id_prefix'), ret['id']) return ret def id_for_label(self, id_): ret = super(CaptchaTextInput, self).id_for_label(id_) if self._args.get('id_prefix') and 'id' in ret: ret = '%s_%s' % (self._args.get('id_prefix'), ret) return ret def format_output(self, rendered_widgets): # hidden_field, text_field = rendered_widgets if self._args['output_format']: ret = self._args['output_format'] % { 'image': self.image_and_audio, 'hidden_field': self.hidden_field, 'text_field': self.text_field } return ret elif self._args['field_template']: context = { 'image': mark_safe(self.image_and_audio), 'hidden_field': mark_safe(self.hidden_field), 'text_field': mark_safe(self.text_field) } return render_to_string(settings.CAPTCHA_FIELD_TEMPLATE, context) def render(self, name, value, attrs=None, renderer=None): self.fetch_captcha_store(name, value, attrs, self._args.get('generator')) context = { 'image': self.image_url(), 'name': name, 'key': self._key, 'id': u'%s_%s' % (self._args.get('id_prefix'), attrs.get('id')) if self._args.get('id_prefix') else attrs.get('id') } if settings.CAPTCHA_FLITE_PATH: context.update({'audio': self.audio_url()}) self.image_and_audio = render_to_string(settings.CAPTCHA_IMAGE_TEMPLATE, context) self.hidden_field = render_to_string(settings.CAPTCHA_HIDDEN_FIELD_TEMPLATE, context) self.text_field = render_to_string(settings.CAPTCHA_TEXT_FIELD_TEMPLATE, context) extra_kwargs = {} if django.VERSION >= (1, 11): # https://docs.djangoproject.com/en/1.11/ref/forms/widgets/#django.forms.Widget.render extra_kwargs['renderer'] = renderer return super(CaptchaTextInput, self).render(name, self._value, attrs=attrs, **extra_kwargs) def _render(self, template_name, context, renderer=None): return self.format_output(None) class CaptchaField(MultiValueField): def __init__(self, *args, **kwargs): fields = ( CharField(show_hidden_initial=True), CharField(), ) if 'error_messages' not in kwargs or 'invalid' not in kwargs.get('error_messages'): if 'error_messages' not in kwargs: kwargs['error_messages'] = {} kwargs['error_messages'].update({'invalid': ugettext_lazy('Invalid CAPTCHA')}) kwargs['widget'] = kwargs.pop('widget', CaptchaTextInput( output_format=kwargs.pop('output_format', None), id_prefix=kwargs.pop('id_prefix', None), generator=kwargs.pop('generator', None) )) super(CaptchaField, self).__init__(fields, *args, **kwargs) def compress(self, data_list): if data_list: return ','.join(data_list) return None def clean(self, value): super(CaptchaField, self).clean(value) response, value[1] = (value[1] or '').strip().lower(), '' if not settings.CAPTCHA_GET_FROM_POOL: CaptchaStore.remove_expired() if settings.CAPTCHA_TEST_MODE and response.lower() == 'passed': # automatically pass the test try: # try to delete the captcha based on its hash CaptchaStore.objects.get(hashkey=value[0]).delete() except CaptchaStore.DoesNotExist: # ignore errors pass elif not self.required and not response: pass else: try: CaptchaStore.objects.get(response=response, hashkey=value[0], expiration__gt=timezone.now()).delete() except CaptchaStore.DoesNotExist: raise ValidationError(getattr(self, 'error_messages', {}).get('invalid', ugettext_lazy('Invalid CAPTCHA'))) return value django-simple-captcha-0.5.6/captcha/fonts/000077500000000000000000000000001321370405700204125ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/fonts/COPYRIGHT.TXT000066400000000000000000000135021321370405700223640ustar00rootroot00000000000000Bitstream Vera Fonts Copyright The fonts have a generous copyright, allowing derivative works (as long as "Bitstream" or "Vera" are not in the names), and full redistribution (so long as they are not *sold* by themselves). They can be be bundled, redistributed and sold with any software. The fonts are distributed under the following copyright: Copyright ========= Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org. Copyright FAQ ============= 1. I don't understand the resale restriction... What gives? Bitstream is giving away these fonts, but wishes to ensure its competitors can't just drop the fonts as is into a font sale system and sell them as is. It seems fair that if Bitstream can't make money from the Bitstream Vera fonts, their competitors should not be able to do so either. You can sell the fonts as part of any software package, however. 2. I want to package these fonts separately for distribution and sale as part of a larger software package or system. Can I do so? Yes. A RPM or Debian package is a "larger software package" to begin with, and you aren't selling them independently by themselves. See 1. above. 3. Are derivative works allowed? Yes! 4. Can I change or add to the font(s)? Yes, but you must change the name(s) of the font(s). 5. Under what terms are derivative works allowed? You must change the name(s) of the fonts. This is to ensure the quality of the fonts, both to protect Bitstream and Gnome. We want to ensure that if an application has opened a font specifically of these names, it gets what it expects (though of course, using fontconfig, substitutions could still could have occurred during font opening). You must include the Bitstream copyright. Additional copyrights can be added, as per copyright law. Happy Font Hacking! 6. If I have improvements for Bitstream Vera, is it possible they might get adopted in future versions? Yes. The contract between the Gnome Foundation and Bitstream has provisions for working with Bitstream to ensure quality additions to the Bitstream Vera font family. Please contact us if you have such additions. Note, that in general, we will want such additions for the entire family, not just a single font, and that you'll have to keep both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add glyphs to the font, they must be stylistically in keeping with Vera's design. Vera cannot become a "ransom note" font. Jim Lyles will be providing a document describing the design elements used in Vera, as a guide and aid for people interested in contributing to Vera. 7. I want to sell a software package that uses these fonts: Can I do so? Sure. Bundle the fonts with your software and sell your software with the fonts. That is the intent of the copyright. 8. If applications have built the names "Bitstream Vera" into them, can I override this somehow to use fonts of my choosing? This depends on exact details of the software. Most open source systems and software (e.g., Gnome, KDE, etc.) are now converting to use fontconfig (see www.fontconfig.org) to handle font configuration, selection and substitution; it has provisions for overriding font names and subsituting alternatives. An example is provided by the supplied local.conf file, which chooses the family Bitstream Vera for "sans", "serif" and "monospace". Other software (e.g., the XFree86 core server) has other mechanisms for font substitution. django-simple-captcha-0.5.6/captcha/fonts/README.TXT000066400000000000000000000005001321370405700217430ustar00rootroot00000000000000Contained herin is the Bitstream Vera font family. The Copyright information is found in the COPYRIGHT.TXT file (along with being incoporated into the fonts themselves). The releases notes are found in the file "RELEASENOTES.TXT". We hope you enjoy Vera! Bitstream, Inc. The Gnome Project django-simple-captcha-0.5.6/captcha/fonts/Vera.ttf000066400000000000000000002006141321370405700220310ustar00rootroot00000000000000OS/2_cpVPCLTъ^6cmaplXcvt 9fpgm&`gaspH glyf tA&~hdmx4!Hhead݄T6hheaEoL$hmtx Ǝ0kernRՙ-loca=maxpG:, nameټȵpostZ/prep; h::_:: dM0l   p t  &   Y &  &   c . 5 `  s 0 & {Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.comCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.com5fqu-J3T99NR7s`s3VV9s3D{o{RoHT3fs +b-{T#\q#H99`#fy```{w``b{{Rffw;{J/}oo5jo{-{T7fD)fs@%2%%A:B2SAS//2ݖ}ٻ֊A}G}G͖2ƅ%]%]@@%d%d%A2dA  d   A(]%]@%..%A  %d%@~}}~}}|d{T{%zyxw v utsrqponl!kjBjSih}gBfedcba:`^ ][ZYX YX WW2VUTUBTSSRQJQP ONMNMLKJKJIJI IH GFEDC-CBAK@?>=>=<=<; <@; :987876765 65 43 21 21 0/ 0 / .- .- ,2+*%+d*)*%)('%(A'%&% &% $#"!! d d BBBdB-B}d       -d@--d++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++, %Id@QX Y!-,%Id@QX Y!-,  P y PXY%%# P y PXY%-,KPX EDY!-,%E`D-,KSX%%EDY!!-,ED-ff@ /10!%!!fsr)5 @@ <2991/0K TX @ 878Y P ]%3#3#5qeM@1<20KTKT[X@878Y@0 @ P ` p ]#!#o$++`@1      91/<<<<<<<2220@   ]!! !3!!!!#!#!5!!5!T%Dh$ig8R>hggh`TifaabbNm!(/@U" '&( /)/))/B" ) *!#*- ) " & 0<<<1/299990KSX99Y"K TX0@00878YK TKT[KT[X000@878Y#.'5.546753.'>54&dijfod]SS\dtzq{---@A$*.U# jXV`OnZXhq) #'3@6$%&%&'$'B .$ &($4'!%   ! + 1 49912<0KSXY"K TK T[K T[KT[KT[K T[X4@44878Y"32654&'2#"&546"32654&%3#2#"&546WccWUccUVcbWWcd1Zܻۻa ۻۼ 0@      !         B  (('+'$ .  .'.'!!199999991/9990KSX99999999Y"2]@ " ) **&:4D ^YZ UZZY0g{ "-  ' (   2'') #**(/2; 49?2J LKFO2VZ Y UY\_2j i`2uy z 2229]]3267 >73#'#"5467.54632.#"[UԠ_I{;B h]hΆ02޸SUWDi;#QX?@Yr~YW׀c?}<$$/1oX3goB@ 10KTKT[X@878Y@ @P`p]#o+{ O@  29910KTX@878YKTX@878Y#&547{>;o @ <99103#654<:=JN@,       <2<2991<22990%#'%%73%g:r:g:PrPbybcy #@   <<1/<<0!!#!5!-Ө-Ӫ--@ 1073#ӤR@d10!!d1/073#B-@B/9910KSXY"3#m #@  10"32'2#"  P3343ssyzZ K@B  1/20KSXY"KTX  @878Y]7!5%3!!JeJsHHժJ@'B   91/20KSX9Y"KTKT[KT[X@878Y@2UVVzzvtvust]]%!!567>54&#"5>32Ls3aM_xzXE[w:mIwBC12\ps({@.    #)&  )99190KTKT[X)@))878Y@ daa d!]!"&'532654&+532654&#"5>32?^jTmǹSrsY %Đ%%12wps{$& Ѳ|d @   B    <291/<290KSXY"K TK T[X@878Y@* *HYiw+&+6NO O Vfuz ]] !33##!55^%3`du@#    190KTKT[X@878YKTX@878Y!!>32!"&'532654&#",X,$^hZkʭQTժ 10$& $X@$  "% " !%190@]]"32654&.#">32# !2 LL;kPL;y$&W]ybhc@B991/0KSXY"KTX@878Y@X9Hg]]!#!3V+ #/C@% '-'0 $*$ !0991990"32654&%&&54632#"$54632654&#"HŚV г "Əُattt$X@# %!"" %190@]]7532#"543 !"&2654&#"LK:lL>$& V\s[#@<21/073#3### %@  <2103#3#ӤR#٬@^M@*B$#29190KSXY" 5Ѧ`@ #<210!!!!^O@+B$#<9190KSXY"55//m$p@+$     &%99991/9990K TX%@%%878Yy z z ]%3##546?>54&#"5>32ſ8ZZ93lOa^gHZX/'eVY5^1YnFC98ŸLVV/5<4q L@2  L4307$7CM34( (+(I+*(I,=M<9912990K TK T[KT[KT[KT[XMMM@878Y@ NN/N?N]32654&#"#"&5463253>54&'&$#"3267#"$'&5476$32|{zy!orqp ˘s'6@   0210].# !267# !2'ffjzSb_^^_HHghG.@   2 99991/0`]3 !%! )5BhPa/w.,~ .@   21/0 ]!!!!!!9>ժF# )@ 21/0 ]!!!!#ZpPժH7s9@ 43 1990%!5!# !2&&# !26uu^opkSUmnHF_`%; ,@ 8  221/<20P ]3!3#!#"d+991/0KTX@878Y@ 0@P`]3#+f M@  9 991990KTX  @878Y@ 0 @ P ` ]3+53265M?nj @(B  291/<290KSXY"]@ ((764GFCUgvw    (+*66650 A@E@@@ b`hgwp  ,]q]q3! !#3wH1j%@ :1/0@ 0P]3!!_ժ @4  B    >  91/<290KSXY"p]@V   && & 45 i|{y   #,'( 4<VY ej vy ]]! !###-}-+3 y@B6 991/<2990KSXY" ]@068HGif FIWXeiy ]]!3!#j+s #@  310"32' ! ':xyLHH[[bb:@   ? 291/0@ ?_]32654&#%!2+#8/ϒs R@*  B     39991990KSX9Y""32#'# ! '? !#y;:xLHHab[T@5  B    ?  299991/<9990KSX9Y"@]@Bz%%%&'&&& 66FFhuuw]]#.+#! 32654&#A{>ٿJx~hb؍O'~@<    B %( "-"(9999190KSX99Y")])/)O)].#"!"&'532654&/.54$32Hs_wzj{r{i76vce+ٶ0/EF~n|-&J@@@1/20K TX@878Y@  @ p ]!!#!ժ+)K@   8A1299990KTX@878Y]332653! ˮ®u\*$h@'B91/290KSXY"P]@b*GGZ} *&&))% 833<<7HEEIIGYVfiizvvyyu)]]!3 3J+D {@I      B     91/<2290KSXY"]@  ($ >>4 0 LMB @ Yjkg ` {|      !   # $ %  <:5306 9 ? 0FFJ@E@BBB@@ D M @@XVY Pfgab```d d d wv{xwtyywpx   []]3 3 3# #D:9:9+=; ]@F      B    91/<290KSXY"K TK T[KT[X  @878Y@ '' 486 KX[fkww       &()&(' ) 54<;:;4 4 8 ? H O X _ eejjhiil l xyyx}  x   @]]3 3 # #su \Y+3{@(B@@ 91/290KSXY" ]@<5000F@@@QQQe &)78@ ghxp ]]3 3#f9\ @BB 991/0KSXY"K TK T[X @ 878Y@@ )&8HGH    / 59? GJO UYfio wx ]]!!!5!sP=g՚oXS@C210K TX@878YKTKT[X@878Y!#3!XB-@B/9910KSXY"#mo<@C<10KTKT[X@878Y!53#5oXޏ@ 91290##HHu-10!5f1@ D10K TKT[X@878Y #ofv{-{ %@'   #   E&22991/9990@n0000 0!0"?'@@@@ @!@"PPPP P!P"P'p' !"'''000 0!@@@ @!PPP P!``` `!ppp p! !]]"326=7#5#"&5463!54&#"5>32߬o?`TeZ3f{bsٴ)Lfa..'' 8@  G F221/0`]4&#"326>32#"&'#3姒:{{:/Rdaadq{?@  HE210@ ].#"3267#"!2NPƳPNM]-U5++++$$>:#qZ8@G E221/0`]3#5#"3232654&#":||ǧ^daDDaq{p@$   KE9190@)?p?????,// , ooooo ]q]!3267# 32.#" ͷjbck)^Z44*,8 Cė/p@     L<<991/22990K TX@878YKTX@878Y@P]#"!!##535463cM/ѹPhc/яNqVZ{ (J@#  &#' & G E)221/990`***]4&#"326!"&'5326=#"3253aQQR9||9=,*[cb::bcd4@  N  F21/<90`]#4&#"#3>32d||Bu\edy+@F<21/0@  @ P ` p ]3#3#`Vy D@   O  F<2991990@ @P`p]3+532653#F1iL`a( @)B F 291/<90KSXY" ]@_ ')+Vfgsw    ('(++@ h` ]q]33 ##%kǹi#y"F1/0@ @P`p]3#{"Z@&   PPF#291/<<<290@0$P$p$$$$$$$ ]>32#4&#"#4&#"#3>32)Erurw?yz|v\`gb|d{6@  N  F21/<90`]#4&#"#3>32d||Bu\`edqu{ J@  QE10@#?{{   {  {]"32654&'2#"s98V{>@ GF2210@ `]%#3>32#"&4&#"326s:{{8 daaqVZ{ >@   GE2210@ `]32654&#"#"3253#/s:||:/daDDadJ{0@    F21/90P].#"#3>32JI,:.˾`fco{'@<  S  SB %( R"E(9999190KSX99Y"']@m   . , , , ; ; ; ; $( ( *//*(() )!$'      '/)?)_))))))]]q.#"#"&'532654&/.54632NZb?ĥZlfae@f?((TT@I!*##55YQKP%$78@  F<<2991/<2990]!!;#"&5#53w{KsբN`>X`6@    NF21/290`]332653#5#"&||Cua{fc=`@'B91/290KSXY"K TX@878YKTKT[X@878Y@Hj{  &&)) 55::0FFIIFH@VVYYPffiigh`ut{{uz>]]3 3#=^^\`TV5` @IU U U U   B     91/<2290KSXY"K TKT[KT[KT[K T[X  @878YK TK T[KT[X @ 878Y@" 5 IIF @ [[U P nnf yy          %%#'!%""%' $ ! # 9669 0FHF@B@@@D D D @@VVVPQRRPS T U cdejejjjn a g ouuy}x}zzxy  { v } @/   y]]333# #V`jjj;y` Z@F      B   91/<290KSXY"K TKT[KT[KT[X  @878YKTX @ 878Y@   & =1 UWX f vzvt        )&% * :9746 9 0 IFE J @ YVYYWVYVV Y P o x  /]] # # 3 dkr))`HJq=V`@C        B     9129990KSX2Y"K TKT[X@878YKTX@878Y@     # 5 I O N Z Z j        '$$  )( % $ $ ' ** 755008 6 6 8 990A@@@@@@@@B E G II@TQQUPPVUVW W U U YYPffh ii`{xx   e]]+5326?3 3N|lLT3!;^^hzHTNlX` @B 2991/0KSXY"K TK T[X @ 878YKTX  @878Y@B&GI  + 690 @@E@@CWY_ ``f``b ]]!!!5!qjL}e`ۓ%$@4 %   !  % $  C %<<29999999199999990K TX%%%@878Y&]#"&=4&+5326=46;#"3>l==k>DV[noZVtsݓXX10#$@6%   #%#C %<2<9999999199999990K TX%@%%878YKTX%%%@878Y&]326=467.=4&+532;#"+FUZooZUF?l>>l?VWstݔ1#@  1990#"'&'&'&#"56632326ian ^Xbian ^V1OD;>MSOE<>LhN'$uhm !@T   !!  ! !!!B     !  VV!"2299999991/<9990KSXY" #]@  s P#f iu {yyv v!# ]]4&#"326!.54632#!#TY?@WX??Y!X=>sr?<҈_Z?YWA?XXN)sIsrFv)su''&-k'(u3^'1usN'2'u)N'8u{-f'DR{-f'DCR{-f'DR{-'DR{-7'DR{-'DRqu{'Fqf'Hqf'HCqf'Hq'Hof'f'C\f'F'd7'Qquf'Rsquf'RCsquf'Rsqu'Rsqu7'RsXf'X{Xf'XC{Xf'X{X'X{9; '@  YW Y <<1<203!!#!5!oo\]u=  @  Z[Z10"32654&'2#"&546PnnPPnoO@v+..ooPOmmOOp1.-rB#!Q@+     "  "<<<221<9990%&&'667#&73JDFHAMf fIX⸹)**'# 32!b`@!    <<1/2<2990K TX@878Y66].#"!!!!53#535632NL=ty-=))׏/я\= >@54&.#"#"&'532654/.5467.54632{?>?>S8alӃ\]>9̭IXW:fqր][;;ȦI.Z.L-[.K''PGZsweZ54m@''TLf{xf[1,pE3!   \ 104632#"&3~|}}||};9 %@]] 91290!###&&54$yfNݸ/@0-'!  **.  !' $'$-F099991/990@@'(     ! "&  : :!MM I!I"jj  ]]4632#"&'532654&/.5467.#"#:A9`@IPAtx;e\`Wqqs`/Q*%jd_[?T>7;[gp/8L`@6EBC?2H09JC 9 $HE301BKL?gwyVpMI`3D/IC@&=>:A$104G$ 7aD=0^* D^ J21/02#"$'&5476$"32676654&'&&&&#"3267#"&54632mmllmmmmllmm^^``^^⃄^]]^\^BB@zBCFInmmmmnnmmmmng^^^傁^^__^]⃅]^^! "'F >@!    b b cbc91<<2<<903#######5Jq7rqr/B^^sRf1@ D10K TKT[X@878Y3#fF)@dd1<20K TK T[X@878YK TK T[KT[KT[X@878YKTKT[X@878Y@````pppp]3#%3#^y'>@"     <291<2<<990!!!!!'7!5!7!}/H{};fըfӪH@9  B     <291/<0KSXY"]@gww  ]!!!!!!#!59=qժF՞f +@< +,  )&  *&& &,+,* # )#3,99999999199999990@*WZWU!je!{vu! FYVjddj(|svz( ]] 324&'.#"&5!27!"&''3>_'y=_''NOy;WfNPƀ[gX@CHp@CpDfbMKYg[KKX /@- !$'!!0 $*0999919990@     $$$   $$ $ ***///***55500055 5 :::???:::EEE@@@EE E JJJOOOJJJV !"&'()]]32654&#".#"326#"&54632>32#"&1TevYR1UfvYRF^_HDa^/XZie7XXjeߦ~᧯w .@     <2<21/<<0!!#!5!!!-Ө-}} T@.B $# <2291/90KSXY" 5!!@po V@/B$ # <<291/90KSXY"55!5AǪR@F  B     fe f e<2299991/2<2<290KSXY"K TX@878Y@(' ' ')((79  ]]!#!5!5'!5!3 3!!!c`Tþ{yT9{3{JD{3V` M@%  !   NF!2912<990"`""]3326533267#"&'#"&'#% )I#ER2bf*V H<9 NPOONNh-)b@'! '!* $$*9991990K TK T[KT[KT[KT[X*@**878Y>54&#"#"&54632#"&54324&#"32IH7$$0e՘ݢe WOmVPmmWKt,>bFأ[t}t{w; ]@    91990@0QVPZ spvupz  Z pp{ t  ]]!! !!5 7AJI3!wq@gg120!#!# }/#@1 " $ #" #h#$9999991/<229990K TX$$$@878Y@V             ##(]]#3267#"&5467!##"#>3!i/7.%7vy"Pµ)6< yJ\:1fd.xo@E}/%&@  & iji&1026732#"&'&&#"#"&546327j Pd@7*8  kOeD=!0 l9TA6?&#Hn!bSA8?Ss;)_@3(%%  * "(kl"k *22999199990!!#5#"&5463354&#"56632"32655P,]uu>DIE~bRhP{@p?Dq[[""CO@Mr`d.@  klk 9910!!2#"&546"32654&PXγгi~hi}|P{ݿܾsN@@"   mm  9991/<20%!5654#"!5!&5! Dz?1/aL"a*>w؍{o{3>@C'-%= 4%:.-*1 %?47&%7& =&-7"E?<9999912<<29990@0+0,0-0.0/00@+@,@-@.@/@0P+P,P-P.P/P0+0@@@@@@@@@??? ??0,0-0.0/@,@-@.@/P,P-P.P/ooo oo`,`-`.`/p,p-p.p/,-./]q].#">32!3267#"&'#"&5463!54&#"5>32"326=DJԄ ̷hddjMI؏`TeZ߬o0Z^Z55*,ywxx..''`f{bsٴ)H +@<+,&  )&  *&& &,+,* # #Q)E,22999999199999990@p(?-YVUV jf!{    { z{ {!"#$%{&%--&YVUZ(ifej(ztvz($$]] 32654&'.#".5327#"&'')gA\*g>}66]C_56`?`!*(Ou))Hn.Mw834OMx43N $@/  !# #%" " "!& %999919990KTKT[KT[X%%%@878Y@ ttttv]33267#"&546?>7>5#537ZZ:3mN`^gIYX0&DeWX5^1YnFC98ŸLVV/5<65 b@ <2991/0K TX @ 878YKTKT[KT[X  @878Y P ]#53#3+e^@ 10!#!^=} *@    91903##'%\sB}}`s-Pb;V#@@   B   !$  $912299990KSX29Y"K TX$$$@878Y.#"!!#"&'53267#5!>32&P,`r<::d/4a/am"?$Ɨ5dzɏ!!J;?@.9*-" *19" <-<<219999990#"'&'&'&#"56632326#"'&'&'&#"56632326ian ^Xbian ^Vgian ^Xbian ^VoNE;=LTNE;=KڲOE;=LSNE;=K`8@91/90@cmpxyvn]] !3!^DC?%# @I    B   o o n<2991<2990KSXY"55%-+#-+#RRH# @I  B   o op<<991<2990KSXY"5%5+-+-#^R^  ^R^   #@   1/<<220%3#%3#%3#hk'$uh^'$us^'2'us ;@   299991/220!!!!! !# !39OAg@AժF|pm|q{'3@1 . ("%4"1 K1 Q+E499912<2290@%?5_5p55555????? ooooo ]q].#"!3267#"&'#"32>32%"32654& H ̷jbdjQGьBN5Z44*,nmnm98olkp݇y/10!!yy/10!!ym '@   1<20#53#53ӤRӤR??m '@   1<203#%3#ӤRӤRլ@@@ 10#53ӤR?@ q103#ӤR՘?o )@ r <<103#3#!!oA#u"@91990  9%-=V'\^N'<su+@B10KSXY"3#-\^R#/@I -'! - -'!0 *$0* $ $(st*(s099999999919999999907'#"&''7&&5467'766324&#"326{r%$&(r;t=:x=q%%&&s7t@?s9q(&%%s>v:@t8s'%$|pprs#G@%Bon29190KSXY"5s-+#R#I@&Bop<9190KSXY"5+-#^R^  /J@(   L<2<2991/<22990K TX@878YKTX@878Y@0P]]#!##53546;#"3#JcM`/яNPhc/J@!    L<<991/<22990K TX@878YKTX@878Y@0P ]!#!"!!##53546JcM/ѹ{Phc/яN9;>@   Y W Y <<2<<2122220%!#!5!!5!3!!!oooo\\HF103#F@ 10%3#ӤR@m '@    1<20%3#%3#ӤRfӤR@@q L #'3?K@D$%&%&'$'B@ .(F4 :&$L%IC'1+C =  1 =I 7+ ! L9912<<2220KSXY"KTK T[K T[K T[K T[KT[XL@LL878Y"32654&'2#"&5462#"&546!3#"32654&2#"&546"32654&WddWUccUt%ZVcbWWcdWccWUccܻۻۻۼܻۻhm'$um'(uhk'$uN'(uk'(uk',/u`m',/uXN',/u;k',/usk'2'usm'2'usk'2'u)k'8u)m'8u)k'8uy` F1/0@ @P`p]3#`?f7@ u91290K TKT[X@878Y3#'#fJ7c@$   VwVv99991<<99990K TK T[X@878Y'.#"#>3232673#"&9! &$}f[&@%9! &$}f[&@Z7IR!7IRb+/10K TKT[X@878Y!!V)9H W@ VV1<0K TX@878YKTKT[KT[X@878Y332673#"&v aWV` v HKKJLDf,@ d10K TX@878Y3# _@ V xV10K TK T[X@878YK TK T[K T[X@878Y4&#"3267#"&54632X@AWWA@Xzssss?XW@AWX@sss#u@  ' 1/90!#"&'532654&'T76xv.W+"J/;<+->i0Y[ 0.W=fB@991<20K TKT[X@878Y3#3#߉fxLu @   '1/90!33267#"&546w-+76 >&Dzs5=X.. W]0i?f7@ u91<90K TKT[X@878Y373xu ?@   : y<<991/900P]3%!!'79Pw^Mo;jnH ^@  z z <<991/90KTX @ 878Y@ @ P ` sz p ]37#'7Ǹ}Lɸ{JZjXjm'6uof'V\m'=uXf']@ <210##    g@    2  y<291/220@(   ]]! )#53!!3 !iP`P5~.,qu('@^%{&%#${##{#({'(#&'('%$%(('"#" ! B('&%"! ## #)&' ! (%#" QE)999999919990KSXY"?*]@v%+("/#/$)%-&-'*(6%F%X X!` `!f"u u!u"%#%$&&&''(6$6%F$E%Z Z!b b!z{     {zzv v!x"**']].#"32654&#"5432''%'3%F2X)6 ~r4*!M!ü޼z&77kc\̑oabk'<su=Vf'\^ =@   ? 2291/0@ ?_]332+#32654&#'ђV>@ GF2210@ `]%#3>32#"&4&#"326s:{{8daa-10!!ת? @M    B   <291<290KSXY" '77w55v8vL57y5yy5 ,@   |]|| 12035733! c)t'+n^J@$}}B ~9190KSX2Y"!!56754&#"56632 "?XhU4zHM98rn81^BQ##{l0b(H@'    #)~&~ )999190#"&'532654&##532654&#"56632 \e9}F4wCmxolV^^ad_(fQI7Z`mR|yOFJLl?<:=svcE`''5 d?''5db''5 dsm'* uqVZH'JP', /uu'6ou{'Vs'k'&-uqf'Fs'm'&-uqf'Fq$J@$ "    GE%<<1/<20`&&&]!5!533##5#"3232654&#"F:||ǧN}}daDDad10!!dHF103#F1@: "+ /) 2+"!)#&  , & &*!/<29999999999122<20K TK T[K T[KT[KT[KT[X222@878Y@z  1Ti lnooooiko o!o"o#n$l%i'i-  !"#$%&'()*+,-2   USjg ]].#"!!!!3267#"#734&5465#7332[f A78 ʝf[Y`(77(6bbiZȻ{.# .{ZiHH"{/ #/{"G)@ dd1<20KTKT[X@878YKTK T[KT[X@878YKTKT[X@878YKTX@878Y@````pppp]3#%3#^ys@B10KSXY"K TX@878YKTX@878Y@ %%6FVjg //]]3#7Ju@!  VV 99991<2990K TX@878YKTX@878Y ]'.#"#4632326=3#"&9 $(}gV$=09" (}gT";9! 2-ev 3)dw @B10KSXY"K TX@878YKTX@878Y@*$$5CUU//]]#ę1w@ 91<90K TX@878YKTX@878YKTX@878Y@ //- ]3#'#Ӌ1@ 91290K TK T[K T[K T[X@878YKTX@878YKTX@878Y@ "  ]373Ӌ ? @   ] <291<290KTKT[KT[KT[K T[K T[X@878YKTKT[X@878Y@T /9IFYi       "5GK S[ e]] !33##5!55bf]my9 j@ VV120K TX@878YKTX@878YKTKT[X@878Y332673#"&v cSRav 6978w{zf103#  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>: ~1BSax~ & 0 : !""""+"H"e%  0AR^x}  0 9 !""""+"H"`%^ChVjq_8 (Bbcdefghjikmlnoqprsutvwxzy{}|~f55q=3=dd?y}s)3s\\?uLsLsyD{={\{fqqq/q999qqJ+o#7=V;=3XyysLs{{{{{{fqqqqq9999qqqqq9\3 'sLfR#hd+/s`N{H?55=ZyyLss/q%%=V^33 / /9% qyy\\\\;LsLsLs9#LF+o{\3X3 q=55^5bb3sq\+osfqsfqqds 5?+   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~     sfthyphenperiodcenteredEuroc6459c6460c6461c6462c6463c6466c6467c6468c6469""""XO!nE~Le  R s  X : i  = z /Eu)pP@"m#{CwRw [ r !5!B!!!" ""#"0"="J"W"d"q"~"""""""""## ##'#4#A#N#[#h##$4$%3%S%&&'K''((X()_*%*\**+z+,D,,-P-..R./0A011!1P12H2z23F3p3p3}3334z44445595g55556[667C77888J999)969C9P9]9j9w99999999::{::;;^;;;<"<_<<<<<<=c>;>H>U>>>?a??@:@K@\@m@z@@@@@@@@A@AVAkBEBBC_CCDUDE*E?- x$%&')*K+-r./2934K57D9:;< =IQR&UYZ\bdg9xy&z&{&|&}&9 999 K$$$$$9$&$*$2$4$6$7a$8$9}$:$;$= settings.CAPTCHA_DICTIONARY_MIN_LENGTH and len(word) <= settings.CAPTCHA_DICTIONARY_MAX_LENGTH: break return word.upper(), word.lower() def huge_words_and_punctuation_challenge(): "Yay, undocumneted. Mostly used to test Issue 39 - http://code.google.com/p/django-simple-captcha/issues/detail?id=39" fd = open(settings.CAPTCHA_WORDS_DICTIONARY, 'rb') l = fd.readlines() fd.close() word = '' while True: word1 = random.choice(l).strip() word2 = random.choice(l).strip() punct = random.choice(settings.CAPTCHA_PUNCTUATION) word = '%s%s%s' % (word1, punct, word2) if len(word) >= settings.CAPTCHA_DICTIONARY_MIN_LENGTH and len(word) <= settings.CAPTCHA_DICTIONARY_MAX_LENGTH: break return word.upper(), word.lower() def noise_arcs(draw, image): size = image.size draw.arc([-20, -20, size[0], 20], 0, 295, fill=settings.CAPTCHA_FOREGROUND_COLOR) draw.line([-20, 20, size[0] + 20, size[1] - 20], fill=settings.CAPTCHA_FOREGROUND_COLOR) draw.line([-20, 0, size[0] + 20, size[1]], fill=settings.CAPTCHA_FOREGROUND_COLOR) return draw def noise_dots(draw, image): size = image.size for p in range(int(size[0] * size[1] * 0.1)): draw.point((random.randint(0, size[0]), random.randint(0, size[1])), fill=settings.CAPTCHA_FOREGROUND_COLOR) return draw def noise_null(draw, image): return draw def post_smooth(image): from PIL import ImageFilter return image.filter(ImageFilter.SMOOTH) def captcha_image_url(key): """Return url to image. Need for ajax refresh and, etc""" return reverse('captcha-image', args=[key]) def captcha_audio_url(key): """Return url to image. Need for ajax refresh and, etc""" return reverse('captcha-audio', args=[key]) django-simple-captcha-0.5.6/captcha/locale/000077500000000000000000000000001321370405700205205ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/bg/000077500000000000000000000000001321370405700211105ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/bg/LC_MESSAGES/000077500000000000000000000000001321370405700226755ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/bg/LC_MESSAGES/django.mo000066400000000000000000000012661321370405700245010ustar00rootroot00000000000000<\pq=0W-Invalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: django-simple-captcha 0.4.1 Report-Msgid-Bugs-To: POT-Creation-Date: 2014-02-10 14:43+0200 PO-Revision-Date: 2014-02-10 15:00+0200 Last-Translator: Venelin Stoykov Language-Team: bg Language: bg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1) Сгрешен текстЧуй текста като аудио файлТова поле е задължителноdjango-simple-captcha-0.5.6/captcha/locale/bg/LC_MESSAGES/django.po000066400000000000000000000020441321370405700244770ustar00rootroot00000000000000# django-simple-captcha Bulgarian translation # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the django-simple-captcha package. # Venelin Stoykov , 2014. # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha 0.4.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-02-10 14:43+0200\n" "PO-Revision-Date: 2014-02-10 15:00+0200\n" "Last-Translator: Venelin Stoykov \n" "Language-Team: bg \n" "Language: bg\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: fields.py:91 msgid "Play CAPTCHA as audio file" msgstr "Чуй текста като аудио файл" #: fields.py:106 fields.py:135 tests/tests.py:99 tests/tests.py:239 #: tests/tests.py:246 msgid "Invalid CAPTCHA" msgstr "Сгрешен текст" #: tests/tests.py:125 msgid "This field is required." msgstr "Това поле е задължително" django-simple-captcha-0.5.6/captcha/locale/cs/000077500000000000000000000000001321370405700211255ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/cs/LC_MESSAGES/000077500000000000000000000000001321370405700227125ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/cs/LC_MESSAGES/django.mo000066400000000000000000000011761321370405700245160ustar00rootroot00000000000000<\pq|1#CgInvalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: 0.3.5 Report-Msgid-Bugs-To: POT-Creation-Date: 2012-10-09 07:05+0200 PO-Revision-Date: 2012-10-09 07:08+0200 Last-Translator: Beda Kosata Language-Team: Czech <> Language: cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; Neplatná CAPTCHAPřehrát captchu jako audio souborToto pole je povinné.django-simple-captcha-0.5.6/captcha/locale/cs/LC_MESSAGES/django.po000066400000000000000000000016661321370405700245250ustar00rootroot00000000000000# Czech translation of django-simple-captcha. # Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Beda Kosata , 2012. # msgid "" msgstr "" "Project-Id-Version: 0.3.5\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-10-09 07:05+0200\n" "PO-Revision-Date: 2012-10-09 07:08+0200\n" "Last-Translator: Beda Kosata \n" "Language-Team: Czech <>\n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" #: fields.py:50 msgid "Play CAPTCHA as audio file" msgstr "Přehrát captchu jako audio soubor" #: fields.py:67 fields.py:99 tests/__init__.py:62 msgid "Invalid CAPTCHA" msgstr "Neplatná CAPTCHA" #: tests/__init__.py:88 msgid "This field is required." msgstr "Toto pole je povinné." django-simple-captcha-0.5.6/captcha/locale/de/000077500000000000000000000000001321370405700211105ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/de/LC_MESSAGES/000077500000000000000000000000001321370405700226755ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/de/LC_MESSAGES/django.mo000066400000000000000000000012431321370405700244740ustar00rootroot00000000000000<\pqQ!eInvalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: django-simple-captcha Report-Msgid-Bugs-To: POT-Creation-Date: 2013-07-16 12:06+0200 PO-Revision-Date: 2013-07-16 12:10+0100 Last-Translator: Patrick Lauber Language-Team: DE Language: de MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1); X-Generator: Poedit 1.5.7 Ungültiges CAPTCHACAPTCHA als Audiodatei abspielen.Dieses Feld wird benötigt.django-simple-captcha-0.5.6/captcha/locale/de/LC_MESSAGES/django.po000066400000000000000000000017521321370405700245040ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-07-16 12:06+0200\n" "PO-Revision-Date: 2013-07-16 12:10+0100\n" "Last-Translator: Patrick Lauber \n" "Language-Team: DE \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 1.5.7\n" #: fields.py:90 msgid "Play CAPTCHA as audio file" msgstr "CAPTCHA als Audiodatei abspielen." #: fields.py:105 fields.py:134 tests/tests.py:99 tests/tests.py:239 #: tests/tests.py:246 msgid "Invalid CAPTCHA" msgstr "Ungültiges CAPTCHA" #: tests/tests.py:125 msgid "This field is required." msgstr "Dieses Feld wird benötigt." django-simple-captcha-0.5.6/captcha/locale/en/000077500000000000000000000000001321370405700211225ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/en/LC_MESSAGES/000077500000000000000000000000001321370405700227075ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/en/LC_MESSAGES/django.po000066400000000000000000000016101321370405700245070ustar00rootroot00000000000000# django-simple-captcha French translation. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Patrick Samson , 2010. # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha 0.2.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-07-25 11:44+0300\n" "PO-Revision-Date: 2010-09-16 12:16+0200\n" "Last-Translator: Marco Bonetti \n" "Language-Team: en \n" "Language: en\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n>1;\n" #: fields.py:49 msgid "Play CAPTCHA as audio file" msgstr "Play CAPTCHA as audio file" #: fields.py:66 fields.py:89 tests/__init__.py:62 msgid "Invalid CAPTCHA" msgstr "" #: tests/__init__.py:88 msgid "This field is required." msgstr "" django-simple-captcha-0.5.6/captcha/locale/es/000077500000000000000000000000001321370405700211275ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/es/LC_MESSAGES/000077500000000000000000000000001321370405700227145ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/es/LC_MESSAGES/django.mo000066400000000000000000000012011321370405700245050ustar00rootroot00000000000000<\pq7JfInvalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: django-simple-captcha Report-Msgid-Bugs-To: POT-Creation-Date: 2013-07-16 12:06+0200 PO-Revision-Date: 2014-05-20 21:22+0100 Last-Translator: https://github.com/dragosdobrota Language-Team: es Language: es MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1); X-Generator: Poedit 1.6.5 CAPTCHA no válidoReproducir CAPTCHA de audioEste campo es obligatorio.django-simple-captcha-0.5.6/captcha/locale/es/LC_MESSAGES/django.po000066400000000000000000000017101321370405700245150ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-07-16 12:06+0200\n" "PO-Revision-Date: 2014-05-20 21:22+0100\n" "Last-Translator: https://github.com/dragosdobrota\n" "Language-Team: es\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 1.6.5\n" #: fields.py:90 msgid "Play CAPTCHA as audio file" msgstr "Reproducir CAPTCHA de audio" #: fields.py:105 fields.py:134 tests/tests.py:99 tests/tests.py:239 #: tests/tests.py:246 msgid "Invalid CAPTCHA" msgstr "CAPTCHA no válido" #: tests/tests.py:125 msgid "This field is required." msgstr "Este campo es obligatorio." django-simple-captcha-0.5.6/captcha/locale/fr/000077500000000000000000000000001321370405700211275ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/fr/LC_MESSAGES/000077500000000000000000000000001321370405700227145ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/fr/LC_MESSAGES/django.mo000066400000000000000000000012021321370405700245060ustar00rootroot00000000000000<\pq6HhInvalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: django-simple-captcha 0.2.0 Report-Msgid-Bugs-To: POT-Creation-Date: 2012-07-25 11:44+0300 PO-Revision-Date: 2010-09-16 12:16+0200 Last-Translator: Patrick Samson Language-Team: fr Language: fr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=n>1; Réponse invalideJouer en tant que fichier audioCe champ est obligatoire.django-simple-captcha-0.5.6/captcha/locale/fr/LC_MESSAGES/django.po000066400000000000000000000016701321370405700245220ustar00rootroot00000000000000# django-simple-captcha French translation. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Patrick Samson , 2010. # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha 0.2.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-07-25 11:44+0300\n" "PO-Revision-Date: 2010-09-16 12:16+0200\n" "Last-Translator: Patrick Samson \n" "Language-Team: fr \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n>1;\n" #: fields.py:49 msgid "Play CAPTCHA as audio file" msgstr "Jouer en tant que fichier audio" #: fields.py:66 fields.py:89 tests/__init__.py:62 msgid "Invalid CAPTCHA" msgstr "Réponse invalide" #: tests/__init__.py:88 msgid "This field is required." msgstr "Ce champ est obligatoire." django-simple-captcha-0.5.6/captcha/locale/it/000077500000000000000000000000001321370405700211345ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/it/LC_MESSAGES/000077500000000000000000000000001321370405700227215ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/it/LC_MESSAGES/django.mo000066400000000000000000000012401321370405700245150ustar00rootroot00000000000000<\pqFdInvalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: django-simple-captcha 0.3.6 Report-Msgid-Bugs-To: POT-Creation-Date: 2012-11-14 02:53+0000 PO-Revision-Date: 2012-11-14 02:53+0000 Last-Translator: Arjuna Del Toso MIME-Version: 1.0 Language-Team: Arjuna Del Toso Language: it Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=n>1; Parola di controllo sbagliataAscolta la parola di controlloQuesto campo è obbligatoriodjango-simple-captcha-0.5.6/captcha/locale/it/LC_MESSAGES/django.po000066400000000000000000000017421321370405700245270ustar00rootroot00000000000000# django-simple-captcha Italian translation. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Arjuna Del Toso , 2012 # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha 0.3.6\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-11-14 02:53+0000\n" "PO-Revision-Date: 2012-11-14 02:53+0000\n" "Last-Translator: Arjuna Del Toso \n" "MIME-Version: 1.0\n" "Language-Team: Arjuna Del Toso \n" "Language: it\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n>1;\n" #: .\fields.py:56 msgid "Play CAPTCHA as audio file" msgstr "Ascolta la parola di controllo" #: .\fields.py:71 .\fields.py:96 .\tests\__init__.py:70 msgid "Invalid CAPTCHA" msgstr "Parola di controllo sbagliata" #: .\tests\__init__.py:97 msgid "This field is required." msgstr "Questo campo è obbligatorio" django-simple-captcha-0.5.6/captcha/locale/ja/000077500000000000000000000000001321370405700211125ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/ja/LC_MESSAGES/000077500000000000000000000000001321370405700226775ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/ja/LC_MESSAGES/django.mo000066400000000000000000000012451321370405700245000ustar00rootroot00000000000000<\pq":+]Invalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: django-simple-captcha Report-Msgid-Bugs-To: POT-Creation-Date: 2014-02-13 07:11+0900 PO-Revision-Date: 2014-02-13 07:11+0900 Last-Translator: Keisuke URAGO Language-Team: Keisuke URAGO Language: ja MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=1; plural=0; CAPTCHAの値が違っていますCAPTCHAをオーディオで読み上げるこの項目は必須ですdjango-simple-captcha-0.5.6/captcha/locale/ja/LC_MESSAGES/django.po000066400000000000000000000017571321370405700245130ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Keisuke URAGO , 2014. # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-02-13 07:11+0900\n" "PO-Revision-Date: 2014-02-13 07:11+0900\n" "Last-Translator: Keisuke URAGO \n" "Language-Team: Keisuke URAGO \n" "Language: ja\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" #: fields.py:90 msgid "Play CAPTCHA as audio file" msgstr "CAPTCHAをオーディオで読み上げる" #: fields.py:105 fields.py:134 tests/tests.py:99 tests/tests.py:239 #: tests/tests.py:246 msgid "Invalid CAPTCHA" msgstr "CAPTCHAの値が違っています" #: tests/tests.py:125 msgid "This field is required." msgstr "この項目は必須です" django-simple-captcha-0.5.6/captcha/locale/nl/000077500000000000000000000000001321370405700211315ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/nl/LC_MESSAGES/000077500000000000000000000000001321370405700227165ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/nl/LC_MESSAGES/django.mo000066400000000000000000000012371321370405700245200ustar00rootroot00000000000000<\pq%@!fInvalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: django-simple-captcha 0.3.6 Report-Msgid-Bugs-To: POT-Creation-Date: 2013-02-15 13:26+0100 PO-Revision-Date: 2013-02-15 13:26+0100 Last-Translator: Leon de Rijke MIME-Version: 1.0 Language-Team: Leon de Rijke Language: nl Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1) CAPTCHA ongeldig, probeer het opnieuwSpeel CAPTCHA als audiobestand afDit veld is verplicht.django-simple-captcha-0.5.6/captcha/locale/nl/LC_MESSAGES/django.po000066400000000000000000000020001321370405700245100ustar00rootroot00000000000000# django-simple-captcha Dutch translation. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Leon de Rijke , 2013. # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha 0.3.6\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-02-15 13:26+0100\n" "PO-Revision-Date: 2013-02-15 13:26+0100\n" "Last-Translator: Leon de Rijke \n" "MIME-Version: 1.0\n" "Language-Team: Leon de Rijke \n" "Language: nl\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: fields.py:50 msgid "Play CAPTCHA as audio file" msgstr "Speel CAPTCHA als audiobestand af" #: fields.py:67 fields.py:94 tests/__init__.py:64 tests/__init__.py:186 #: tests/__init__.py:193 msgid "Invalid CAPTCHA" msgstr "CAPTCHA ongeldig, probeer het opnieuw" #: tests/__init__.py:90 msgid "This field is required." msgstr "Dit veld is verplicht." django-simple-captcha-0.5.6/captcha/locale/pl/000077500000000000000000000000001321370405700211335ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/pl/LC_MESSAGES/000077500000000000000000000000001321370405700227205ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/pl/LC_MESSAGES/django.mo000066400000000000000000000013211321370405700245140ustar00rootroot00000000000000<\pqu'Invalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: django-simple-captcha 0.3.6 Report-Msgid-Bugs-To: POT-Creation-Date: 2013-08-18 18:49+0200 PO-Revision-Date: 2013-08-18 18:52+0200 Last-Translator: Sławomir Zborowski Language-Team: Polisch Language: pl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2) Niepoprawnie wpisana CAPTCHAOdtwórz CAPTCHĘ jako plik dźwiękowyTo pole jest wymagane.django-simple-captcha-0.5.6/captcha/locale/pl/LC_MESSAGES/django.po000066400000000000000000000021231321370405700245200ustar00rootroot00000000000000# Polish translation for django-simple-captcha. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the django-simple-captcha package. # Sławomir Zborowski , 2013. # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha 0.3.6\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-08-18 18:49+0200\n" "PO-Revision-Date: 2013-08-18 18:52+0200\n" "Last-Translator: Sławomir Zborowski \n" "Language-Team: Polisch\n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2)\n" #: fields.py:90 msgid "Play CAPTCHA as audio file" msgstr "Odtwórz CAPTCHĘ jako plik dźwiękowy" #: fields.py:105 fields.py:134 tests/tests.py:99 tests/tests.py:239 #: tests/tests.py:246 msgid "Invalid CAPTCHA" msgstr "Niepoprawnie wpisana CAPTCHA" #: tests/tests.py:125 msgid "This field is required." msgstr "To pole jest wymagane." django-simple-captcha-0.5.6/captcha/locale/pt_BR/000077500000000000000000000000001321370405700215265ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/pt_BR/LC_MESSAGES/000077500000000000000000000000001321370405700233135ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/pt_BR/LC_MESSAGES/django.mo000066400000000000000000000012161321370405700251120ustar00rootroot00000000000000<\pqEXrInvalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: django-simple-captcha 0.3.7 Report-Msgid-Bugs-To: POT-Creation-Date: 2013-05-18 10:58-0300 PO-Revision-Date: 2013-05-18 13:12-0300 Last-Translator: Alisson Patricio Language-Team: Alisson Patricio Language: pt_br MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n > 1); Resposta inválidaOuça o arquivo de áudioEste campo é obrigatório.django-simple-captcha-0.5.6/captcha/locale/pt_BR/LC_MESSAGES/django.po000066400000000000000000000020011321370405700251060ustar00rootroot00000000000000# django-simple-captcha Portuguese (Brazilian) translation. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Alisson Patricio , 2013. # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha 0.3.7\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-05-18 10:58-0300\n" "PO-Revision-Date: 2013-05-18 13:12-0300\n" "Last-Translator: Alisson Patricio \n" "Language-Team: Alisson Patricio \n" "Language: pt_br\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: fields.py:49 msgid "Play CAPTCHA as audio file" msgstr "Ouça o arquivo de áudio" #: fields.py:66 fields.py:93 tests/__init__.py:69 #: tests/__init__.py:198 tests/__init__.py:205 msgid "Invalid CAPTCHA" msgstr "Resposta inválida" #: tests/__init__.py:95 msgid "This field is required." msgstr "Este campo é obrigatório." django-simple-captcha-0.5.6/captcha/locale/ru/000077500000000000000000000000001321370405700211465ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/ru/LC_MESSAGES/000077500000000000000000000000001321370405700227335ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/ru/LC_MESSAGES/django.mo000066400000000000000000000013751321370405700245400ustar00rootroot00000000000000<\pqXDtCInvalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: django-simple-captcha 0.3.7 Report-Msgid-Bugs-To: POT-Creation-Date: 2012-07-25 11:17+0300 PO-Revision-Date: 2012-07-25 11:17+0300 Last-Translator: Language-Team: ru Language: ru MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2) Неверный ответВоспроизвести CAPTCHA в виде аудио файлаЭто поле обязательно для заполнения.django-simple-captcha-0.5.6/captcha/locale/ru/LC_MESSAGES/django.po000066400000000000000000000020351321370405700245350ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha 0.3.7\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-07-25 11:17+0300\n" "PO-Revision-Date: 2012-07-25 11:17+0300\n" "Last-Translator: \n" "Language-Team: ru \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" #: fields.py:49 msgid "Play CAPTCHA as audio file" msgstr "Воспроизвести CAPTCHA в виде аудио файла" #: fields.py:66 fields.py:89 tests/__init__.py:62 msgid "Invalid CAPTCHA" msgstr "Неверный ответ" #: tests/__init__.py:88 msgid "This field is required." msgstr "Это поле обязательно для заполнения." django-simple-captcha-0.5.6/captcha/locale/sk/000077500000000000000000000000001321370405700211355ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/sk/LC_MESSAGES/000077500000000000000000000000001321370405700227225ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/sk/LC_MESSAGES/django.mo000066400000000000000000000012071321370405700245210ustar00rootroot00000000000000<\pq<!NpInvalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: django-simple-captcha 0.3.7 Report-Msgid-Bugs-To: POT-Creation-Date: 2013-10-15 17:16+0200 PO-Revision-Date: 2013-10-15 17:16+0200 Last-Translator: Pavol Otto Language-Team: SK Language: sk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; Neplatná CAPTCHAPrehrať captchu ako audio súborToto pole je povinné.django-simple-captcha-0.5.6/captcha/locale/sk/LC_MESSAGES/django.po000066400000000000000000000017421321370405700245300ustar00rootroot00000000000000# Slovak translation of django-simple-captcha. # Copyright (C) 2013 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Pavol Otto , 2013. # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha 0.3.7\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-10-15 17:16+0200\n" "PO-Revision-Date: 2013-10-15 17:16+0200\n" "Last-Translator: Pavol Otto \n" "Language-Team: SK\n" "Language: sk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" #: fields.py:90 msgid "Play CAPTCHA as audio file" msgstr "Prehrať captchu ako audio súbor" #: fields.py:105 fields.py:134 tests/tests.py:99 tests/tests.py:239 #: tests/tests.py:246 msgid "Invalid CAPTCHA" msgstr "Neplatná CAPTCHA" #: tests/tests.py:125 msgid "This field is required." msgstr "Toto pole je povinné." django-simple-captcha-0.5.6/captcha/locale/tr/000077500000000000000000000000001321370405700211455ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/tr/LC_MESSAGES/000077500000000000000000000000001321370405700227325ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/tr/LC_MESSAGES/django.mo000066400000000000000000000012061321370405700245300ustar00rootroot00000000000000<\pq@ QrInvalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: django-simple-captcha 0.3.6 Report-Msgid-Bugs-To: POT-Creation-Date: 2013-01-19 16:33-0200 PO-Revision-Date: 2013-01-19 20:52+0200 Last-Translator: Gokmen Gorgen Language-Team: TR Gokmen Gorgen Language: tr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=1; plural=0 Geçersiz değerDeğeri ses dosyası olarak çalBu alan zorunludur.django-simple-captcha-0.5.6/captcha/locale/tr/LC_MESSAGES/django.po000066400000000000000000000017221321370405700245360ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha 0.3.6\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-01-19 16:33-0200\n" "PO-Revision-Date: 2013-01-19 20:52+0200\n" "Last-Translator: Gokmen Gorgen \n" "Language-Team: TR Gokmen Gorgen \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0\n" #: fields.py:50 msgid "Play CAPTCHA as audio file" msgstr "Değeri ses dosyası olarak çal" #: fields.py:67 fields.py:94 tests/__init__.py:64 tests/__init__.py:186 #: tests/__init__.py:193 msgid "Invalid CAPTCHA" msgstr "Geçersiz değer" #: tests/__init__.py:90 msgid "This field is required." msgstr "Bu alan zorunludur." django-simple-captcha-0.5.6/captcha/locale/uk/000077500000000000000000000000001321370405700211375ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/uk/LC_MESSAGES/000077500000000000000000000000001321370405700227245ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/uk/LC_MESSAGES/django.mo000066400000000000000000000013641321370405700245270ustar00rootroot00000000000000<\pq*h6)Invalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: django-simple-captcha 0.3.6 Report-Msgid-Bugs-To: POT-Creation-Date: 2014-02-21 22:05+0200 PO-Revision-Date: 2014-02-21 22:05+0200 Last-Translator: @FuriousCoder Language-Team: uk @FuriousCoder Language: uk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); Неправильна відповідь.Відтворити CAPTCHA як аудіо файл.Це поле є обов'язковим.django-simple-captcha-0.5.6/captcha/locale/uk/LC_MESSAGES/django.po000066400000000000000000000020721321370405700245270ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha 0.3.6\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-02-21 22:05+0200\n" "PO-Revision-Date: 2014-02-21 22:05+0200\n" "Last-Translator: @FuriousCoder\n" "Language-Team: uk @FuriousCoder\n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #: fields.py:91 msgid "Play CAPTCHA as audio file" msgstr "Відтворити CAPTCHA як аудіо файл." #: fields.py:106 fields.py:135 tests/tests.py:99 tests/tests.py:239 #: tests/tests.py:246 msgid "Invalid CAPTCHA" msgstr "Неправильна відповідь." #: tests/tests.py:125 msgid "This field is required." msgstr "Це поле є обов'язковим." django-simple-captcha-0.5.6/captcha/locale/zh_CN/000077500000000000000000000000001321370405700215215ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/zh_CN/LC_MESSAGES/000077500000000000000000000000001321370405700233065ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/zh_CN/LC_MESSAGES/django.mo000066400000000000000000000012031321370405700251010ustar00rootroot00000000000000<\pq8!HjInvalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: django-simple-captcha 0.3.6 Report-Msgid-Bugs-To: POT-Creation-Date: 2013-03-01 05:04+0800 PO-Revision-Date: 2013-03-01 05:04+0800 Last-Translator: Ming Chen Language-Team: zh_cn Ming Chen Language: zh_cn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=1; plural=0 认证码错误使用语音方式播放认证码这个字段是必须的django-simple-captcha-0.5.6/captcha/locale/zh_CN/LC_MESSAGES/django.po000066400000000000000000000017551321370405700251200ustar00rootroot00000000000000# django-simple-captcha Chinese Simplified translation. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Ming Chen , 2013. # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha 0.3.6\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-03-01 05:04+0800\n" "PO-Revision-Date: 2013-03-01 05:04+0800\n" "Last-Translator: Ming Chen \n" "Language-Team: zh_cn Ming Chen \n" "Language: zh_cn\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0\n" #: fields.py:49 msgid "Play CAPTCHA as audio file" msgstr "使用语音方式播放认证码" #: fields.py:66 fields.py:93 tests/__init__.py:69 tests/__init__.py:198 #: tests/__init__.py:205 msgid "Invalid CAPTCHA" msgstr "认证码错误" #: tests/__init__.py:95 msgid "This field is required." msgstr "这个字段是必须的" django-simple-captcha-0.5.6/captcha/locale/zh_Hans/000077500000000000000000000000001321370405700221125ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/zh_Hans/LC_MESSAGES/000077500000000000000000000000001321370405700236775ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/locale/zh_Hans/LC_MESSAGES/django.mo000066400000000000000000000012031321370405700254720ustar00rootroot00000000000000<\pq8!HjInvalid CAPTCHAPlay CAPTCHA as audio fileThis field is required.Project-Id-Version: django-simple-captcha 0.3.6 Report-Msgid-Bugs-To: POT-Creation-Date: 2013-03-01 05:04+0800 PO-Revision-Date: 2013-03-01 05:04+0800 Last-Translator: Ming Chen Language-Team: zh_cn Ming Chen Language: zh_cn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=1; plural=0 认证码错误使用语音方式播放认证码这个字段是必须的django-simple-captcha-0.5.6/captcha/locale/zh_Hans/LC_MESSAGES/django.po000066400000000000000000000017551321370405700255110ustar00rootroot00000000000000# django-simple-captcha Chinese Simplified translation. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Ming Chen , 2013. # msgid "" msgstr "" "Project-Id-Version: django-simple-captcha 0.3.6\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-03-01 05:04+0800\n" "PO-Revision-Date: 2013-03-01 05:04+0800\n" "Last-Translator: Ming Chen \n" "Language-Team: zh_cn Ming Chen \n" "Language: zh_cn\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0\n" #: fields.py:49 msgid "Play CAPTCHA as audio file" msgstr "使用语音方式播放认证码" #: fields.py:66 fields.py:93 tests/__init__.py:69 tests/__init__.py:198 #: tests/__init__.py:205 msgid "Invalid CAPTCHA" msgstr "认证码错误" #: tests/__init__.py:95 msgid "This field is required." msgstr "这个字段是必须的" django-simple-captcha-0.5.6/captcha/management/000077500000000000000000000000001321370405700213755ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/management/__init__.py000066400000000000000000000000001321370405700234740ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/management/commands/000077500000000000000000000000001321370405700231765ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/management/commands/__init__.py000066400000000000000000000000001321370405700252750ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/management/commands/captcha_clean.py000066400000000000000000000015341321370405700263200ustar00rootroot00000000000000from django.core.management.base import BaseCommand from django.utils import timezone import sys class Command(BaseCommand): help = "Clean up expired captcha hashkeys." def handle(self, **options): from captcha.models import CaptchaStore verbose = int(options.get('verbosity')) expired_keys = CaptchaStore.objects.filter(expiration__lte=timezone.now()).count() if verbose >= 1: print("Currently %d expired hashkeys" % expired_keys) try: CaptchaStore.remove_expired() except: if verbose >= 1: print("Unable to delete expired hashkeys.") sys.exit(1) if verbose >= 1: if expired_keys > 0: print("%d expired hashkeys removed." % expired_keys) else: print("No keys to remove.") django-simple-captcha-0.5.6/captcha/management/commands/captcha_create_pool.py000066400000000000000000000021341321370405700275270ustar00rootroot00000000000000from django.core.management.base import BaseCommand from django.db import transaction from captcha.models import CaptchaStore class Command(BaseCommand): help = "Create a pool of random captchas." def add_arguments(self, parser): parser.add_argument('--pool-size', type=int, default=1000, help='Number of new captchas to create, default=1000') parser.add_argument('--cleanup-expired', action='store_true', default=True, help='Cleanup expired captchas after creating new ones') @transaction.atomic() def handle(self, **options): verbose = int(options.get('verbosity')) count = options.get('pool_size') CaptchaStore.create_pool(count) verbose and self.stdout.write('Created %d new captchas\n' % count) options.get('cleanup_expired') and CaptchaStore.remove_expired() options.get('cleanup_expired') and verbose and self.stdout.write('Expired captchas cleaned up\n') django-simple-captcha-0.5.6/captcha/migrations/000077500000000000000000000000001321370405700214355ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/migrations/0001_initial.py000066400000000000000000000013661321370405700241060ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models, migrations class Migration(migrations.Migration): dependencies = [ ] operations = [ migrations.CreateModel( name='CaptchaStore', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('challenge', models.CharField(max_length=32)), ('response', models.CharField(max_length=32)), ('hashkey', models.CharField(unique=True, max_length=40)), ('expiration', models.DateTimeField()), ], options={ }, bases=(models.Model,), ), ] django-simple-captcha-0.5.6/captcha/migrations/__init__.py000066400000000000000000000011421321370405700235440ustar00rootroot00000000000000""" Django migrations for django-simple-captcha app This package does not contain South migrations. South migrations can be found in the ``south_migrations`` package. """ SOUTH_ERROR_MESSAGE = """\n For South support, customize the SOUTH_MIGRATION_MODULES setting like so: SOUTH_MIGRATION_MODULES = { 'captcha': 'captcha.south_migrations', } """ # Ensure the user is not using Django 1.6 or below with South try: from django.db import migrations # noqa except ImportError: from django.core.exceptions import ImproperlyConfigured raise ImproperlyConfigured(SOUTH_ERROR_MESSAGE)django-simple-captcha-0.5.6/captcha/models.py000066400000000000000000000053521321370405700211230ustar00rootroot00000000000000from captcha.conf import settings as captcha_settings from django.db import models from django.utils import timezone from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import smart_text import datetime import hashlib import logging import random import time # Heavily based on session key generation in Django # Use the system (hardware-based) random number generator if it exists. if hasattr(random, 'SystemRandom'): randrange = random.SystemRandom().randrange else: randrange = random.randrange MAX_RANDOM_KEY = 18446744073709551616 # 2 << 63 logger = logging.getLogger(__name__) @python_2_unicode_compatible class CaptchaStore(models.Model): challenge = models.CharField(blank=False, max_length=32) response = models.CharField(blank=False, max_length=32) hashkey = models.CharField(blank=False, max_length=40, unique=True) expiration = models.DateTimeField(blank=False) def save(self, *args, **kwargs): self.response = self.response.lower() if not self.expiration: self.expiration = timezone.now() + datetime.timedelta(minutes=int(captcha_settings.CAPTCHA_TIMEOUT)) if not self.hashkey: key_ = ( smart_text(randrange(0, MAX_RANDOM_KEY)) + smart_text(time.time()) + smart_text(self.challenge, errors='ignore') + smart_text(self.response, errors='ignore') ).encode('utf8') self.hashkey = hashlib.sha1(key_).hexdigest() del(key_) super(CaptchaStore, self).save(*args, **kwargs) def __str__(self): return self.challenge def remove_expired(cls): cls.objects.filter(expiration__lte=timezone.now()).delete() remove_expired = classmethod(remove_expired) @classmethod def generate_key(cls, generator=None): challenge, response = captcha_settings.get_challenge(generator)() store = cls.objects.create(challenge=challenge, response=response) return store.hashkey @classmethod def pick(cls): if not captcha_settings.CAPTCHA_GET_FROM_POOL: return cls.generate_key() def fallback(): logger.error("Couldn't get a captcha from pool, generating") return cls.generate_key() # Pick up a random item from pool minimum_expiration = timezone.now() + datetime.timedelta(minutes=int(captcha_settings.CAPTCHA_GET_FROM_POOL_TIMEOUT)) store = cls.objects.filter(expiration__gt=minimum_expiration).order_by('?').first() return (store and store.hashkey) or fallback() @classmethod def create_pool(cls, count=1000): assert count > 0 while count > 0: cls.generate_key() count -= 1 django-simple-captcha-0.5.6/captcha/south_migrations/000077500000000000000000000000001321370405700226575ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/south_migrations/0001_initial.py000066400000000000000000000027631321370405700253320ustar00rootroot00000000000000# encoding: utf-8 import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models class Migration(SchemaMigration): def forwards(self, orm): # Adding model 'CaptchaStore' db.create_table('captcha_captchastore', ( ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ('challenge', self.gf('django.db.models.fields.CharField')(max_length=32)), ('response', self.gf('django.db.models.fields.CharField')(max_length=32)), ('hashkey', self.gf('django.db.models.fields.CharField')(unique=True, max_length=40)), ('expiration', self.gf('django.db.models.fields.DateTimeField')()), )) db.send_create_signal('captcha', ['CaptchaStore']) def backwards(self, orm): # Deleting model 'CaptchaStore' db.delete_table('captcha_captchastore') models = { 'captcha.captchastore': { 'Meta': {'object_name': 'CaptchaStore'}, 'challenge': ('django.db.models.fields.CharField', [], {'max_length': '32'}), 'expiration': ('django.db.models.fields.DateTimeField', [], {}), 'hashkey': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'response': ('django.db.models.fields.CharField', [], {'max_length': '32'}) } } complete_apps = ['captcha'] django-simple-captcha-0.5.6/captcha/south_migrations/__init__.py000066400000000000000000000000001321370405700247560ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/templates/000077500000000000000000000000001321370405700212575ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/templates/captcha/000077500000000000000000000000001321370405700226625ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/templates/captcha/field.html000066400000000000000000000000501321370405700246260ustar00rootroot00000000000000{{image}}{{hidden_field}}{{text_field}} django-simple-captcha-0.5.6/captcha/templates/captcha/hidden_field.html000066400000000000000000000001101321370405700261360ustar00rootroot00000000000000 django-simple-captcha-0.5.6/captcha/templates/captcha/image.html000066400000000000000000000003471321370405700246360ustar00rootroot00000000000000{% load i18n %} {% spaceless %} {% if audio %}{% endif %}captcha{% if audio %}{% endif %} {% endspaceless %}django-simple-captcha-0.5.6/captcha/templates/captcha/text_field.html000066400000000000000000000002031321370405700256720ustar00rootroot00000000000000 django-simple-captcha-0.5.6/captcha/tests/000077500000000000000000000000001321370405700204235ustar00rootroot00000000000000django-simple-captcha-0.5.6/captcha/tests/__init__.py000066400000000000000000000000721321370405700225330ustar00rootroot00000000000000from .tests import CaptchaCase, trivial_challenge # NOQA django-simple-captcha-0.5.6/captcha/tests/tests.py000066400000000000000000000520331321370405700221420ustar00rootroot00000000000000# -*- coding: utf-8 -*- from captcha.conf import settings from captcha.fields import CaptchaField, CaptchaTextInput from captcha.models import CaptchaStore import django from django.core import management from django.core.exceptions import ImproperlyConfigured if django.VERSION < (1, 10): # NOQA from django.core.urlresolvers import reverse # NOQA else: # NOQA from django.urls import reverse # NOQA from django.test import TestCase, override_settings from django.utils.translation import ugettext_lazy from django.utils import timezone import datetime import json import re import six from testfixtures import LogCapture import os try: from cStringIO import StringIO except ImportError: from io import BytesIO as StringIO from six import u, text_type from PIL import Image @override_settings(ROOT_URLCONF='captcha.tests.urls') class CaptchaCase(TestCase): def setUp(self): self.stores = {} self.__current_settings_output_format = settings.CAPTCHA_OUTPUT_FORMAT self.__current_settings_dictionary = settings.CAPTCHA_WORDS_DICTIONARY self.__current_settings_punctuation = settings.CAPTCHA_PUNCTUATION tested_helpers = ['captcha.helpers.math_challenge', 'captcha.helpers.random_char_challenge', 'captcha.helpers.unicode_challenge'] if os.path.exists('/usr/share/dict/words'): settings.CAPTCHA_WORDS_DICTIONARY = '/usr/share/dict/words' settings.CAPTCHA_PUNCTUATION = ';-,.' tested_helpers.append('captcha.helpers.word_challenge') tested_helpers.append('captcha.helpers.huge_words_and_punctuation_challenge') for helper in tested_helpers: challenge, response = settings._callable_from_string(helper)() self.stores[helper.rsplit('.', 1)[-1].replace('_challenge', '_store')], _ = CaptchaStore.objects.get_or_create(challenge=challenge, response=response) challenge, response = settings.get_challenge()() self.stores['default_store'], _ = CaptchaStore.objects.get_or_create(challenge=challenge, response=response) self.default_store = self.stores['default_store'] def tearDown(self): settings.CAPTCHA_OUTPUT_FORMAT = self.__current_settings_output_format settings.CAPTCHA_WORDS_DICTIONARY = self.__current_settings_dictionary settings.CAPTCHA_PUNCTUATION = self.__current_settings_punctuation def __extract_hash_and_response(self, r): hash_ = re.findall(r'value="([0-9a-f]+)"', str(r.content))[0] response = CaptchaStore.objects.get(hashkey=hash_).response return hash_, response def test_image(self): for key in [store.hashkey for store in six.itervalues(self.stores)]: response = self.client.get(reverse('captcha-image', kwargs=dict(key=key))) self.assertEqual(response.status_code, 200) self.assertTrue(response.has_header('content-type')) self.assertEqual(response._headers.get('content-type'), ('Content-Type', 'image/png')) def test_audio(self): if not settings.CAPTCHA_FLITE_PATH: return for key in (self.stores.get('math_store').hashkey, self.stores.get('math_store').hashkey, self.default_store.hashkey): response = self.client.get(reverse('captcha-audio', kwargs=dict(key=key))) self.assertEqual(response.status_code, 200) self.assertTrue(response.ranged_file.size > 1024) self.assertTrue(response.has_header('content-type')) self.assertEqual(response._headers.get('content-type'), ('Content-Type', 'audio/wav')) def test_form_submit(self): r = self.client.get(reverse('captcha-test')) self.assertEqual(r.status_code, 200) hash_, response = self.__extract_hash_and_response(r) r = self.client.post(reverse('captcha-test'), dict(captcha_0=hash_, captcha_1=response, subject='xxx', sender='asasd@asdasd.com')) self.assertEqual(r.status_code, 200) self.assertTrue(str(r.content).find('Form validated') > 0) r = self.client.post(reverse('captcha-test'), dict(captcha_0=hash_, captcha_1=response, subject='xxx', sender='asasd@asdasd.com')) self.assertEqual(r.status_code, 200) self.assertFalse(str(r.content).find('Form validated') > 0) def test_modelform(self): r = self.client.get(reverse('captcha-test-model-form')) self.assertEqual(r.status_code, 200) hash_, response = self.__extract_hash_and_response(r) r = self.client.post(reverse('captcha-test-model-form'), dict(captcha_0=hash_, captcha_1=response, subject='xxx', sender='asasd@asdasd.com')) self.assertEqual(r.status_code, 200) self.assertTrue(str(r.content).find('Form validated') > 0) r = self.client.post(reverse('captcha-test-model-form'), dict(captcha_0=hash_, captcha_1=response, subject='xxx', sender='asasd@asdasd.com')) self.assertEqual(r.status_code, 200) self.assertFalse(str(r.content).find('Form validated') > 0) def test_wrong_submit(self): for urlname in ('captcha-test', 'captcha-test-model-form'): r = self.client.get(reverse(urlname)) self.assertEqual(r.status_code, 200) r = self.client.post(reverse(urlname), dict(captcha_0='abc', captcha_1='wrong response', subject='xxx', sender='asasd@asdasd.com')) self.assertFormError(r, 'form', 'captcha', ugettext_lazy('Invalid CAPTCHA')) def test_deleted_expired(self): self.default_store.expiration = timezone.now() - datetime.timedelta(minutes=5) self.default_store.save() hash_ = self.default_store.hashkey r = self.client.post(reverse('captcha-test'), dict(captcha_0=hash_, captcha_1=self.default_store.response, subject='xxx', sender='asasd@asdasd.com')) self.assertEqual(r.status_code, 200) self.assertFalse('Form validated' in str(r.content)) # expired -> deleted try: CaptchaStore.objects.get(hashkey=hash_) self.fail() except: pass def test_custom_error_message(self): r = self.client.get(reverse('captcha-test-custom-error-message')) self.assertEqual(r.status_code, 200) # Wrong answer r = self.client.post(reverse('captcha-test-custom-error-message'), dict(captcha_0='abc', captcha_1='wrong response')) self.assertFormError(r, 'form', 'captcha', 'TEST CUSTOM ERROR MESSAGE') # empty answer r = self.client.post(reverse('captcha-test-custom-error-message'), dict(captcha_0='abc', captcha_1='')) self.assertFormError(r, 'form', 'captcha', ugettext_lazy('This field is required.')) def test_repeated_challenge(self): CaptchaStore.objects.create(challenge='xxx', response='xxx') try: CaptchaStore.objects.create(challenge='xxx', response='xxx') except Exception: self.fail() def test_repeated_challenge_form_submit(self): __current_challange_function = settings.CAPTCHA_CHALLENGE_FUNCT for urlname in ('captcha-test', 'captcha-test-model-form'): settings.CAPTCHA_CHALLENGE_FUNCT = 'captcha.tests.trivial_challenge' r1 = self.client.get(reverse(urlname)) r2 = self.client.get(reverse(urlname)) self.assertEqual(r1.status_code, 200) self.assertEqual(r2.status_code, 200) if re.findall(r'value="([0-9a-f]+)"', str(r1.content)): hash_1 = re.findall(r'value="([0-9a-f]+)"', str(r1.content))[0] else: self.fail() if re.findall(r'value="([0-9a-f]+)"', str(r2.content)): hash_2 = re.findall(r'value="([0-9a-f]+)"', str(r2.content))[0] else: self.fail() try: store_1 = CaptchaStore.objects.get(hashkey=hash_1) store_2 = CaptchaStore.objects.get(hashkey=hash_2) except: self.fail() self.assertTrue(store_1.pk != store_2.pk) self.assertTrue(store_1.response == store_2.response) self.assertTrue(hash_1 != hash_2) r1 = self.client.post(reverse(urlname), dict(captcha_0=hash_1, captcha_1=store_1.response, subject='xxx', sender='asasd@asdasd.com')) self.assertEqual(r1.status_code, 200) self.assertTrue(str(r1.content).find('Form validated') > 0) try: store_2 = CaptchaStore.objects.get(hashkey=hash_2) except: self.fail() r2 = self.client.post(reverse(urlname), dict(captcha_0=hash_2, captcha_1=store_2.response, subject='xxx', sender='asasd@asdasd.com')) self.assertEqual(r2.status_code, 200) self.assertTrue(str(r2.content).find('Form validated') > 0) settings.CAPTCHA_CHALLENGE_FUNCT = __current_challange_function def test_output_format(self): for urlname in ('captcha-test', 'captcha-test-model-form'): settings.CAPTCHA_OUTPUT_FORMAT = u('%(image)s

Hello, captcha world

%(hidden_field)s%(text_field)s') r = self.client.get(reverse(urlname)) self.assertEqual(r.status_code, 200) self.assertTrue('

Hello, captcha world

' in str(r.content)) def test_invalid_output_format(self): for urlname in ('captcha-test', 'captcha-test-model-form'): settings.CAPTCHA_OUTPUT_FORMAT = u('%(image)s') try: self.client.get(reverse(urlname)) self.fail() except ImproperlyConfigured as e: self.assertTrue('CAPTCHA_OUTPUT_FORMAT' in str(e)) def test_per_form_format(self): settings.CAPTCHA_OUTPUT_FORMAT = u('%(image)s testCustomFormatString %(hidden_field)s %(text_field)s') r = self.client.get(reverse('captcha-test')) self.assertTrue('testCustomFormatString' in str(r.content)) r = self.client.get(reverse('test_per_form_format')) self.assertTrue('testPerFieldCustomFormatString' in str(r.content)) def test_custom_generator(self): r = self.client.get(reverse('test_custom_generator')) hash_, response = self.__extract_hash_and_response(r) self.assertEqual(response, u'111111') def test_issue31_proper_abel(self): settings.CAPTCHA_OUTPUT_FORMAT = u('%(image)s %(hidden_field)s %(text_field)s') r = self.client.get(reverse('captcha-test')) self.assertTrue('' in six.text_type(r.content)) self.assertTrue('id="form1_id_captcha1_1"' in six.text_type(r.content)) self.assertTrue('' in six.text_type(r.content)) self.assertTrue('id="form2_id_captcha2_1"' in six.text_type(r.content)) def test_image_size(self): __current_test_mode_setting = settings.CAPTCHA_IMAGE_SIZE for key in [store.hashkey for store in six.itervalues(self.stores)]: settings.CAPTCHA_IMAGE_SIZE = (201, 97) response = self.client.get(reverse('captcha-image', kwargs=dict(key=key))) self.assertEqual(response.status_code, 200) self.assertTrue(response.has_header('content-type')) self.assertEqual(response._headers.get('content-type'), ('Content-Type', 'image/png')) self.assertEqual(Image.open(StringIO(response.content)).size, (201, 97)) settings.CAPTCHA_IMAGE_SIZE = __current_test_mode_setting def test_multiple_fonts(self): vera = os.path.join(os.path.dirname(__file__), '..', 'fonts', 'Vera.ttf') __current_test_mode_setting = settings.CAPTCHA_FONT_PATH settings.CAPTCHA_FONT_PATH = vera for key in [store.hashkey for store in six.itervalues(self.stores)]: response = self.client.get(reverse('captcha-image', kwargs=dict(key=key))) self.assertEqual(response.status_code, 200) self.assertEqual(response._headers.get('content-type'), ('Content-Type', 'image/png')) settings.CAPTCHA_FONT_PATH = [vera, vera, vera] for key in [store.hashkey for store in six.itervalues(self.stores)]: response = self.client.get(reverse('captcha-image', kwargs=dict(key=key))) self.assertEqual(response.status_code, 200) self.assertEqual(response._headers.get('content-type'), ('Content-Type', 'image/png')) settings.CAPTCHA_FONT_PATH = False for key in [store.hashkey for store in six.itervalues(self.stores)]: try: response = self.client.get(reverse('captcha-image', kwargs=dict(key=key))) self.fail() except ImproperlyConfigured: pass settings.CAPTCHA_FONT_PATH = __current_test_mode_setting def test_template_overrides(self): __current_test_mode_setting = settings.CAPTCHA_IMAGE_TEMPLATE settings.CAPTCHA_IMAGE_TEMPLATE = 'captcha_test/image.html' for urlname in ('captcha-test', 'captcha-test-model-form'): settings.CAPTCHA_CHALLENGE_FUNCT = 'captcha.tests.trivial_challenge' r = self.client.get(reverse(urlname)) self.assertTrue('captcha-template-test' in six.text_type(r.content)) settings.CAPTCHA_IMAGE_TEMPLATE = __current_test_mode_setting def test_math_challenge(self): __current_test_mode_setting = settings.CAPTCHA_MATH_CHALLENGE_OPERATOR settings.CAPTCHA_MATH_CHALLENGE_OPERATOR = '~' helper = 'captcha.helpers.math_challenge' challenge, response = settings._callable_from_string(helper)() while settings.CAPTCHA_MATH_CHALLENGE_OPERATOR not in challenge: challenge, response = settings._callable_from_string(helper)() self.assertEqual(response, text_type(eval(challenge.replace(settings.CAPTCHA_MATH_CHALLENGE_OPERATOR, '*')[:-1]))) settings.CAPTCHA_MATH_CHALLENGE_OPERATOR = __current_test_mode_setting def test_get_from_pool(self): __current_test_get_from_pool_setting = settings.CAPTCHA_GET_FROM_POOL __current_test_get_from_pool_timeout_setting = settings.CAPTCHA_GET_FROM_POOL_TIMEOUT __current_test_timeout_setting = settings.CAPTCHA_TIMEOUT settings.CAPTCHA_GET_FROM_POOL = True settings.CAPTCHA_GET_FROM_POOL_TIMEOUT = 5 settings.CAPTCHA_TIMEOUT = 90 CaptchaStore.objects.all().delete() # Delete objects created during SetUp POOL_SIZE = 10 CaptchaStore.create_pool(count=POOL_SIZE) self.assertEqual(CaptchaStore.objects.count(), POOL_SIZE) pool = CaptchaStore.objects.values_list('hashkey', flat=True) random_pick = CaptchaStore.pick() self.assertIn(random_pick, pool) # pick() should not create any extra captcha self.assertEqual(CaptchaStore.objects.count(), POOL_SIZE) settings.CAPTCHA_GET_FROM_POOL = __current_test_get_from_pool_setting settings.CAPTCHA_GET_FROM_POOL_TIMEOUT = __current_test_get_from_pool_timeout_setting settings.CAPTCHA_TIMEOUT = __current_test_timeout_setting def test_captcha_create_pool(self): CaptchaStore.objects.all().delete() # Delete objects created during SetUp POOL_SIZE = 10 management.call_command('captcha_create_pool', pool_size=POOL_SIZE, verbosity=0) self.assertEqual(CaptchaStore.objects.count(), POOL_SIZE) def test_empty_pool_fallback(self): __current_test_get_from_pool_setting = settings.CAPTCHA_GET_FROM_POOL settings.CAPTCHA_GET_FROM_POOL = True CaptchaStore.objects.all().delete() # Delete objects created during SetUp with LogCapture() as l: CaptchaStore.pick() l.check(('captcha.models', 'ERROR', "Couldn't get a captcha from pool, generating"),) self.assertEqual(CaptchaStore.objects.count(), 1) settings.CAPTCHA_GET_FROM_POOL = __current_test_get_from_pool_setting def trivial_challenge(): return 'trivial', 'trivial' django-simple-captcha-0.5.6/captcha/tests/urls.py000066400000000000000000000014301321370405700217600ustar00rootroot00000000000000from django.conf.urls import url, include from .views import ( test, test_model_form, test_custom_error_message, test_per_form_format, test_non_required, test_id_prefix, test_custom_generator ) urlpatterns = [ url(r'test/$', test, name='captcha-test'), url(r'test-modelform/$', test_model_form, name='captcha-test-model-form'), url(r'test2/$', test_custom_error_message, name='captcha-test-custom-error-message'), url(r'test3/$', test_per_form_format, name='test_per_form_format'), url(r'custom-generator/$', test_custom_generator, name='test_custom_generator'), url(r'test-non-required/$', test_non_required, name='captcha-test-non-required'), url(r'test-id-prefix/$', test_id_prefix, name='captcha-test-id-prefix'), url(r'', include('captcha.urls')), ] django-simple-captcha-0.5.6/captcha/tests/views.py000066400000000000000000000077051321370405700221430ustar00rootroot00000000000000from django import forms from captcha.fields import CaptchaField from django.http import HttpResponse from django.contrib.auth.models import User from six import u import django try: from django.template import engines, RequestContext __is_18 = True except ImportError: from django.template import RequestContext, loader __is_18 = False TEST_TEMPLATE = r''' captcha test {% if passed %}

Form validated

{% endif %} {% if form.errors %} {{form.errors}} {% endif %}
{{form.as_p}}

''' def _get_template(template_string): if __is_18: return engines['django'].from_string(template_string) else: return loader.get_template_from_string(template_string) def _test(request, form_class): passed = False if request.POST: form = form_class(request.POST) if form.is_valid(): passed = True else: form = form_class() t = _get_template(TEST_TEMPLATE) if django.VERSION >= (1, 9): return HttpResponse( t.render(context=dict(passed=passed, form=form), request=request)) else: return HttpResponse( t.render(RequestContext(request, dict(passed=passed, form=form)))) def test(request): class CaptchaTestForm(forms.Form): subject = forms.CharField(max_length=100) sender = forms.EmailField() captcha = CaptchaField(help_text='asdasd') return _test(request, CaptchaTestForm) def test_model_form(request): class CaptchaTestModelForm(forms.ModelForm): subject = forms.CharField(max_length=100) sender = forms.EmailField() captcha = CaptchaField(help_text='asdasd') class Meta: model = User fields = ('subject', 'sender', 'captcha', ) return _test(request, CaptchaTestModelForm) def test_custom_generator(request): class CaptchaTestModelForm(forms.ModelForm): subject = forms.CharField(max_length=100) sender = forms.EmailField() captcha = CaptchaField(generator=lambda: ('111111', '111111')) class Meta: model = User fields = ('subject', 'sender', 'captcha', ) return _test(request, CaptchaTestModelForm) def test_custom_error_message(request): class CaptchaTestErrorMessageForm(forms.Form): captcha = CaptchaField( help_text='asdasd', error_messages=dict(invalid='TEST CUSTOM ERROR MESSAGE') ) return _test(request, CaptchaTestErrorMessageForm) def test_per_form_format(request): class CaptchaTestFormatForm(forms.Form): captcha = CaptchaField( help_text='asdasd', error_messages=dict(invalid='TEST CUSTOM ERROR MESSAGE'), output_format=( u( '%(image)s testPerFieldCustomFormatString ' '%(hidden_field)s %(text_field)s' ) ) ) return _test(request, CaptchaTestFormatForm) def test_non_required(request): class CaptchaTestForm(forms.Form): sender = forms.EmailField() subject = forms.CharField(max_length=100) captcha = CaptchaField(help_text='asdasd', required=False) return _test(request, CaptchaTestForm) def test_id_prefix(request): class CaptchaTestForm(forms.Form): sender = forms.EmailField() subject = forms.CharField(max_length=100) captcha1 = CaptchaField(id_prefix="form1") captcha2 = CaptchaField(id_prefix="form2") return _test(request, CaptchaTestForm) django-simple-captcha-0.5.6/captcha/urls.py000066400000000000000000000006551321370405700206260ustar00rootroot00000000000000from django.conf.urls import url from captcha import views urlpatterns = [ url(r'image/(?P\w+)/$', views.captcha_image, name='captcha-image', kwargs={'scale': 1}), url(r'image/(?P\w+)@2/$', views.captcha_image, name='captcha-image-2x', kwargs={'scale': 2}), url(r'audio/(?P\w+).wav$', views.captcha_audio, name='captcha-audio'), url(r'refresh/$', views.captcha_refresh, name='captcha-refresh'), ] django-simple-captcha-0.5.6/captcha/views.py000066400000000000000000000135121321370405700207720ustar00rootroot00000000000000from captcha.conf import settings from captcha.helpers import captcha_image_url, captcha_audio_url from captcha.models import CaptchaStore from django.http import HttpResponse, Http404 from django.core.exceptions import ImproperlyConfigured from ranged_response import RangedFileResponse import random import tempfile import os import subprocess import six try: from cStringIO import StringIO except ImportError: from io import BytesIO as StringIO from PIL import Image, ImageDraw, ImageFont try: import json except ImportError: from django.utils import simplejson as json # Distance of the drawn text from the top of the captcha image DISTNACE_FROM_TOP = 4 def getsize(font, text): if hasattr(font, 'getoffset'): return tuple([x + y for x, y in zip(font.getsize(text), font.getoffset(text))]) else: return font.getsize(text) def makeimg(size): if settings.CAPTCHA_BACKGROUND_COLOR == "transparent": image = Image.new('RGBA', size) else: image = Image.new('RGB', size, settings.CAPTCHA_BACKGROUND_COLOR) return image def captcha_image(request, key, scale=1): try: store = CaptchaStore.objects.get(hashkey=key) except CaptchaStore.DoesNotExist: # HTTP 410 Gone status so that crawlers don't index these expired urls. return HttpResponse(status=410) text = store.challenge if isinstance(settings.CAPTCHA_FONT_PATH, six.string_types): fontpath = settings.CAPTCHA_FONT_PATH elif isinstance(settings.CAPTCHA_FONT_PATH, (list, tuple)): fontpath = random.choice(settings.CAPTCHA_FONT_PATH) else: raise ImproperlyConfigured('settings.CAPTCHA_FONT_PATH needs to be a path to a font or list of paths to fonts') if fontpath.lower().strip().endswith('ttf'): font = ImageFont.truetype(fontpath, settings.CAPTCHA_FONT_SIZE * scale) else: font = ImageFont.load(fontpath) if settings.CAPTCHA_IMAGE_SIZE: size = settings.CAPTCHA_IMAGE_SIZE else: size = getsize(font, text) size = (size[0] * 2, int(size[1] * 1.4)) image = makeimg(size) xpos = 2 charlist = [] for char in text: if char in settings.CAPTCHA_PUNCTUATION and len(charlist) >= 1: charlist[-1] += char else: charlist.append(char) for char in charlist: fgimage = Image.new('RGB', size, settings.CAPTCHA_FOREGROUND_COLOR) charimage = Image.new('L', getsize(font, ' %s ' % char), '#000000') chardraw = ImageDraw.Draw(charimage) chardraw.text((0, 0), ' %s ' % char, font=font, fill='#ffffff') if settings.CAPTCHA_LETTER_ROTATION: charimage = charimage.rotate(random.randrange(*settings.CAPTCHA_LETTER_ROTATION), expand=0, resample=Image.BICUBIC) charimage = charimage.crop(charimage.getbbox()) maskimage = Image.new('L', size) maskimage.paste(charimage, (xpos, DISTNACE_FROM_TOP, xpos + charimage.size[0], DISTNACE_FROM_TOP + charimage.size[1])) size = maskimage.size image = Image.composite(fgimage, image, maskimage) xpos = xpos + 2 + charimage.size[0] if settings.CAPTCHA_IMAGE_SIZE: # centering captcha on the image tmpimg = makeimg(size) tmpimg.paste(image, (int((size[0] - xpos) / 2), int((size[1] - charimage.size[1]) / 2 - DISTNACE_FROM_TOP))) image = tmpimg.crop((0, 0, size[0], size[1])) else: image = image.crop((0, 0, xpos + 1, size[1])) draw = ImageDraw.Draw(image) for f in settings.noise_functions(): draw = f(draw, image) for f in settings.filter_functions(): image = f(image) out = StringIO() image.save(out, "PNG") out.seek(0) response = HttpResponse(content_type='image/png') response.write(out.read()) response['Content-length'] = out.tell() return response def captcha_audio(request, key): if settings.CAPTCHA_FLITE_PATH: try: store = CaptchaStore.objects.get(hashkey=key) except CaptchaStore.DoesNotExist: # HTTP 410 Gone status so that crawlers don't index these expired urls. return HttpResponse(status=410) text = store.challenge if 'captcha.helpers.math_challenge' == settings.CAPTCHA_CHALLENGE_FUNCT: text = text.replace('*', 'times').replace('-', 'minus') else: text = ', '.join(list(text)) path = str(os.path.join(tempfile.gettempdir(), '%s.wav' % key)) subprocess.call([settings.CAPTCHA_FLITE_PATH, "-t", text, "-o", path]) # Add arbitrary noise if sox is installed if settings.CAPTCHA_SOX_PATH: arbnoisepath = str(os.path.join(tempfile.gettempdir(), '%s_arbitrary.wav') % key) mergedpath = str(os.path.join(tempfile.gettempdir(), '%s_merged.wav') % key) subprocess.call([settings.CAPTCHA_SOX_PATH, '-r', '8000', '-n', arbnoisepath, 'synth', '2', 'brownnoise', 'gain', '-15']) subprocess.call([settings.CAPTCHA_SOX_PATH, '-m', arbnoisepath, path, '-t', 'wavpcm', '-b', '16', mergedpath]) os.remove(arbnoisepath) os.remove(path) os.rename(mergedpath, path) if os.path.isfile(path): response = RangedFileResponse(request, open(path, 'rb'), content_type='audio/wav') response['Content-Disposition'] = 'attachment; filename="{}.wav"'.format(key) return response raise Http404 def captcha_refresh(request): """ Return json with new captcha for ajax refresh request """ if not request.is_ajax(): raise Http404 new_key = CaptchaStore.pick() to_json_response = { 'key': new_key, 'image_url': captcha_image_url(new_key), 'audio_url': captcha_audio_url(new_key) if settings.CAPTCHA_FLITE_PATH else None } return HttpResponse(json.dumps(to_json_response), content_type='application/json') django-simple-captcha-0.5.6/django_simple_captcha.egg-info/000077500000000000000000000000001321370405700236465ustar00rootroot00000000000000django-simple-captcha-0.5.6/django_simple_captcha.egg-info/PKG-INFO000066400000000000000000000015241321370405700247450ustar00rootroot00000000000000Metadata-Version: 1.1 Name: django-simple-captcha Version: 0.5.6 Summary: A very simple, yet powerful, Django captcha application Home-page: https://github.com/mbi/django-simple-captcha Author: Marco Bonetti Author-email: mbonetti@gmail.com License: MIT Description-Content-Type: UNKNOWN Description: UNKNOWN Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Topic :: Security Classifier: Topic :: Internet :: WWW/HTTP Classifier: Framework :: Django django-simple-captcha-0.5.6/django_simple_captcha.egg-info/SOURCES.txt000066400000000000000000000077411321370405700255430ustar00rootroot00000000000000.pep8 CHANGES LICENSE MANIFEST.in README.rst setup.cfg setup.py tox.ini captcha/__init__.py captcha/fields.py captcha/helpers.py captcha/models.py captcha/urls.py captcha/views.py captcha/conf/__init__.py captcha/conf/settings.py captcha/fonts/COPYRIGHT.TXT captcha/fonts/README.TXT captcha/fonts/Vera.ttf captcha/locale/bg/LC_MESSAGES/django.mo captcha/locale/bg/LC_MESSAGES/django.po captcha/locale/cs/LC_MESSAGES/django.mo captcha/locale/cs/LC_MESSAGES/django.po captcha/locale/de/LC_MESSAGES/django.mo captcha/locale/de/LC_MESSAGES/django.po captcha/locale/en/LC_MESSAGES/django.po captcha/locale/es/LC_MESSAGES/django.mo captcha/locale/es/LC_MESSAGES/django.po captcha/locale/fr/LC_MESSAGES/django.mo captcha/locale/fr/LC_MESSAGES/django.po captcha/locale/it/LC_MESSAGES/django.mo captcha/locale/it/LC_MESSAGES/django.po captcha/locale/ja/LC_MESSAGES/django.mo captcha/locale/ja/LC_MESSAGES/django.po captcha/locale/nl/LC_MESSAGES/django.mo captcha/locale/nl/LC_MESSAGES/django.po captcha/locale/pl/LC_MESSAGES/django.mo captcha/locale/pl/LC_MESSAGES/django.po captcha/locale/pt_BR/LC_MESSAGES/django.mo captcha/locale/pt_BR/LC_MESSAGES/django.po captcha/locale/ru/LC_MESSAGES/django.mo captcha/locale/ru/LC_MESSAGES/django.po captcha/locale/sk/LC_MESSAGES/django.mo captcha/locale/sk/LC_MESSAGES/django.po captcha/locale/tr/LC_MESSAGES/django.mo captcha/locale/tr/LC_MESSAGES/django.po captcha/locale/uk/LC_MESSAGES/django.mo captcha/locale/uk/LC_MESSAGES/django.po captcha/locale/zh_CN/LC_MESSAGES/django.mo captcha/locale/zh_CN/LC_MESSAGES/django.po captcha/locale/zh_Hans/LC_MESSAGES/django.mo captcha/locale/zh_Hans/LC_MESSAGES/django.po captcha/management/__init__.py captcha/management/commands/__init__.py captcha/management/commands/captcha_clean.py captcha/management/commands/captcha_create_pool.py captcha/migrations/0001_initial.py captcha/migrations/__init__.py captcha/south_migrations/0001_initial.py captcha/south_migrations/__init__.py captcha/templates/captcha/field.html captcha/templates/captcha/hidden_field.html captcha/templates/captcha/image.html captcha/templates/captcha/text_field.html captcha/tests/__init__.py captcha/tests/tests.py captcha/tests/urls.py captcha/tests/views.py django_simple_captcha.egg-info/PKG-INFO django_simple_captcha.egg-info/SOURCES.txt django_simple_captcha.egg-info/dependency_links.txt django_simple_captcha.egg-info/not-zip-safe django_simple_captcha.egg-info/requires.txt django_simple_captcha.egg-info/top_level.txt docs/Makefile docs/advanced.rst docs/conf.py docs/index.rst docs/usage.rst docs/_static/captcha3.png docs/_static/dict.png docs/_static/math.png docs/_static/random_chars.png testproject/.coveragerc testproject/__init__.py testproject/coverage.sh testproject/forms.py testproject/manage.py testproject/settings.py testproject/urls.py testproject/views.py testproject/htmlcov/_Users_marco_Code_django-simple-captcha_captcha___init___py.html testproject/htmlcov/_Users_marco_Code_django-simple-captcha_captcha_conf___init___py.html testproject/htmlcov/_Users_marco_Code_django-simple-captcha_captcha_conf_settings_py.html testproject/htmlcov/_Users_marco_Code_django-simple-captcha_captcha_fields_py.html testproject/htmlcov/_Users_marco_Code_django-simple-captcha_captcha_helpers_py.html testproject/htmlcov/_Users_marco_Code_django-simple-captcha_captcha_models_py.html testproject/htmlcov/_Users_marco_Code_django-simple-captcha_captcha_urls_py.html testproject/htmlcov/_Users_marco_Code_django-simple-captcha_captcha_views_py.html testproject/htmlcov/coverage_html.js testproject/htmlcov/index.html testproject/htmlcov/jquery.ba-throttle-debounce.min.js testproject/htmlcov/jquery.hotkeys.js testproject/htmlcov/jquery.isonscreen.js testproject/htmlcov/jquery.min.js testproject/htmlcov/jquery.tablesorter.min.js testproject/htmlcov/keybd_closed.png testproject/htmlcov/keybd_open.png testproject/htmlcov/status.json testproject/htmlcov/style.css testproject/templates/home.html testproject/templates/captcha_test/image.html testproject/templates/captcha_test/image_html5_audio.htmldjango-simple-captcha-0.5.6/django_simple_captcha.egg-info/dependency_links.txt000066400000000000000000000000011321370405700277140ustar00rootroot00000000000000 django-simple-captcha-0.5.6/django_simple_captcha.egg-info/not-zip-safe000066400000000000000000000000011321370405700260740ustar00rootroot00000000000000 django-simple-captcha-0.5.6/django_simple_captcha.egg-info/requires.txt000066400000000000000000000001161321370405700262440ustar00rootroot00000000000000setuptools six>=1.2.0 Django>=1.7 Pillow>=2.2.2 django-ranged-response==0.2.0 django-simple-captcha-0.5.6/django_simple_captcha.egg-info/top_level.txt000066400000000000000000000000101321370405700263670ustar00rootroot00000000000000captcha django-simple-captcha-0.5.6/docs/000077500000000000000000000000001321370405700166065ustar00rootroot00000000000000django-simple-captcha-0.5.6/docs/Makefile000066400000000000000000000061201321370405700202450ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = 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) . .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest 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 " 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 " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @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." 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/DjangoSimpleCaptcha.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/DjangoSimpleCaptcha.qhc" latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." 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." django-simple-captcha-0.5.6/docs/_static/000077500000000000000000000000001321370405700202345ustar00rootroot00000000000000django-simple-captcha-0.5.6/docs/_static/captcha3.png000066400000000000000000000226411321370405700224350ustar00rootroot00000000000000PNG  IHDR(}9DpiCCPICC Profilex{4T{fZ0'aEm:]\rLZ鶲r wg+yVV^x~R+9{kbj_Zǯߠ(wfíwߍGoѢz-C#ܣ>^Y/x/C_9wwfuvw^O}&;w ?d~L3W~~\W`^}p_9qWKt(Gp7%poq8O+$t$\$%r%Hde6 % {De"A|(%Nꊴ4S~1qc^˸ȔN"B^._/OU0TQx`l%#ZTSwDU_r'lF@S3>D<}4(OkG5-鈯%b$Ct qc4sωCj#)!Zux4! D=-Quu;S42Ȼ{4Mf56o)yl718y-\`,rҴ S|Y;?ݮYp:hLXx;S*o``uű/Vq”B /c8G^vŌ!Ѩ.8i̘f vBCĻzcpRUkXĄYo^<,d1iq#S+4ݺCz/ZV=C]s\Dx!>@L@if{kj:ձ̅?Yw(%zկDyB#`U_.;[V{IeWuj/On![?]8019f9ht%,\Pн?gwWNIĎ6?_'+ӫDYB# )@[K}]/jZ"Xw+G6瞳xf[hk[$2oZX: u!@"=P6;=DN?{ @ijfG`ċ݋O{@mF@Yhk˨=B_ZEq-YP:.D{m2Fq ukK90D<8Ե^[́ 9šu\xڒeρ/u"@ז,s`x|qkQ^*---WiZ~u 9ss%J!kA:|YMtt鸍9O2G&ѫڈ$U?bO͂-#!iT%Ϝ<׺~h,̵u*/08~* dBb׌;4"!49͡5o-s矙4;,9Ō%MԄM湫 uSwww>(Tq&/JŸGWy,U`|gK.0}&$1vϿ:D@5"cXg`hEzz'#|9u$3K&cZ4ka5seThҗ̊^:oָ⬍;Q,yキxr|aGtĄ(beL/8*vUTyO*U+i j/]%=gpH!^XؗIYw[gr9SBsՃyʵ u 1U3Օl }7䄹S"L5Lo,.`Ǖ9WOO?4v !J$(vaDi#Q]cXܿx 'w7Ud A@IBo~(n\Ry߼ҫ)7JʊFt\-:F3ԝ8S2ـ)L5JU8jy}ZUiBʹmogr:)0kcd-XV,$cɑUQp[<{}L2=>$be7r5'F Mힱlጩ)?p+Z6k=RG颚QCw2yOV-% 1Io;ÆbIpDy1`VU^0w4Z7ZWUJ-䯟EFh5QS(Ʉ"NVt,cѨʙkNRU6BŔwQHnXρ~0^SdJ lpA2"8'M&¡D􇹍+uţ#6›qD@<&p&xqO1$ 8=YK˯v.33q,vG=#q<ޮ]Һ:5zN9BCOkL2+P'++9=phAct`W̍6tHV_|IQyzzZ2AU_}'mɣǏAM&㓫SKZBFykP/nybuO ͑$Y\w7di+~dN4#XR,kF폀ØonOg-Y;5O,a:r2fFp\&)hMă@uuum]sTwb(SUdInjO@Sy;ᦺtk 2TV\ŲP=msgΖu é+eW zS`g^_ZTߘkmī6~̰1Kg O 'ֽi$W1>-k: ax"fp`pltw;yBo/o>R?VUUUtל_l $hRbn= Tākӳr@n \HWW5u `d*Bgx)qwμH ]?] {_ 7=I5tL8ikfp?}a}1rbFI<pN^B&!`#j)ۯ::>Up2pki..`&\bB~9Sz ֍(&XOb)MW1G mgȀUU 3&~52#탿6|&c~ń'b\j_IhE®"yfIi/'~ρ'xv-۶_-[+(=|T|T"]v蜜9^10VP7\_XhՂu2n/ooSfbUu 5S._9Q:ͷ8+:w80ȶa7|IkSЅxO*8SO  T|i7QO>ݻvo"# 6sS+=Sx؉c`,@0~KA`AzAO6ok#}vƯHO m)ܴ|r~VMa" VoNLlqCdxB1O-Daa}S1ܾk{3PJN//@X:|R0Q\a"[  񕱷EdE."G<:7,+z{R[ IliM-Agf 1E[gm-zĘ˧$ߐ0~-{6<¨B1jtle':Mػ/B#o)R **Z:'ā e!x'V%'%B'Rх"xѷ癍*|Vd>X~i?6EJ.wfNRpTafj~*1V!lmÚ ӼG>e┞=4PiF|GuGAt[لZ5_jq!C#0)P^I&MgkfzcEM/wn`*pkb$nn 7>oiE*1-\ X) [sR腕Y#4>1.61AK_w=5*mߨpЁ(ʡR#%i[U0][$\!^F5*4=P̴"w?~ n9x^3~tQš<nR 4Cߠlli('8um/o((/t A_PV`Ayxjauadx`O:'BE*ă<a}A< r"nӈ3F!X@bȹJʡ !VBBqhvFז.bipؑþm@ *C P~b)-;G9_x@RWFs:KbH2@*~/xuY@ˡ` YB?_|-` !rCM b˒Y'+"摒ybpwWZ![R}χ(-XKsE@|<`] @ZLI?p"SxP !`uxV L bB%V&5N۰>%NEooo|J}#Y NgϞϝ;bԚ>]x^ѵk!Cs"vFNA#FqݺuC78?ĉk׮%EEE{]iO\<;_?7~\Dψ%77{ׯ]s<`1pbʕ&M[]ej3L'g'VϜ^3\__[Wصk0@,7NkCQܦMqkc+Z˸O]R_a OOv1ڰCa250mٲ Ki;A;-<!OF$,~A~^wgNCK=<^?Z)_Wsx#RZP"nD";yf\\b!xx  (gM|#vMpS+/yiʜs;3JeYI~LeUڇh1gµ2xVܩkfЃqJT"@uUU]}ub\xx!c SX!Spl7caf_S9soZUǚ?VqS}KO|lNm>_.5yE]f${W֨u-gԨjj_?Aɾ?n0= 66aᖛ{Fɪ6?XqQ":[Ka/Ʃ{<"^#yzz"oĻ~DSub}9Ffn fE2jHJ6}{obLݻ/pH_pP7$ TR"qug9 만 nn;xaGL7Xq)UJ$zDV8(̟ilS*b +!,mRE;HxјXPπ,'uҒZNVoZпܟ`) 4{?{MJ\p$WʼnIe _(=Iz*'Mf Hbਗ਼CB}y=-|FL\i0 X V}ڎagԀ!fh~ M1GQo~Qpȑ F=.O ww8 **[|c;[.hœߘGb͊ _|b=*;ю9=y.]̲glDXjKNΨ3.Pȑ#LJJ {p@D+UZ&qWzbbِjZ+zcA3͒wN#3QUT֪{`)$m=5U(u{\msgQNkS"n>p@QQ?ԯKlNMI(Fy.\:Sm%DJdD<$U ]/lsL B6l3B @3 @ij !`: l68S+D<8 Dt:R2wgUWt_x~R+ٕ{bZ\S\#nPR/]sfݭ wݍGo٤|%C#чOnzzY}m//^9+gvuv_Oz&;w >d|٫kf|/J_㿹|w="o;?' DTx8^,Н UpSӡKR?|!Tx0EL3bۂ B{}eqM|sTot\brHte.HD&{$Nz(-Z抬,KvĔGs;#?^>NB"AXd=rGe)+W,WwjjccގM7kK}5p zOJ"[4'OܬRBWAٔҩVh PN˝mHӘdo8dYjsT玞nIҝohmnco n}CņINM.Y437}w+OW+5KW#J"&-8D'`SG[D>{- g.]?zōZm}ᎊ I%)λTK8iuV}#+&[.'+ci'';)*yAIzɭKkuQSnKÚϨmv/i:ޚ [mُ1K%t;)"˳](*nBI8Q[g qi^I_L0&a6fH !ͪ!M sXaNM(oGO%@`@ [~_cA%m;#[I!/b1S&FFoT* pHYs  IDATx XSWO  @B*2NkvZkZ?N #ZTZ$` .!{ {{qo0ڈe^l" Q;  @Jse*Ҩ w 2AHi;Ȼ(t{Ҭu4$@DtM\Fb&C'@J)Y$b41! Iϔ,1R  ҤgJ)M̄bHi3%D@L&fB1D@z4陒E" &@J3" =RL" P )Mzd L(HO&=SHHib&C'@J)Y$b41!Ti&FMfkj:{&͒="&t-ǷyfeoZa|\iDOH4Wko/Ufi~n\x]銯֭:U΍s2q/=b+:=Ug~aQUۑчdp)BZ(2P׽[H\jYk[ƆfEYW@ڈ`XĬ 2\~P38h6VU~ݣWӹwhqwg`b)Q mUs ֽ鵕+ù~'m^0< ]"Rwa׶lِRVaU T!}M@>bm9#I&GC uk2NB3iCDZjjbX f>~f"NꡭYL1OѰmD*~#;f}x0c?UPLzI|>@ibm,7jon^)S*  j}X@k6L_uPՔz6y6nm+OZ=r#"@!{Y)}7f~,8#{Գx>1[:r;Ǚ mصkڬbCֆi &WO2UYɄj_m|v]Xy+;vT{Jk6W=z6o0}Fof 2}Ɲ4z}eR[8}y{ft_nfmZ.\~E&mDc#H1g{u:N•&Ia7?)SN?X:p)SV? ySK_nOaXֵGnm a#>ܾfv>w2/߅doszۇ{NMD6")d---ꂷ:^15ə2XhI5+UJzJi*ݵt>o֚Je{:X:11lwۮIe 8^ovb%n w͸V'%W"1 Uۜ z5S !u UYF) 2a>g" ? mDS X6mwQ9 fG( (:T^^jJٳgwqy 7/^ :޽q/L@apiBb(MRY3 %vg'/@ *^2NҨ)w 2A$^U]p[[!B-p"FY!W -F^,{A8$- #L PT`K'@,-9pR+MS^jSZk\TV?ƫ@2o/]0l -հYU5P+wGP4]{âG>>}a׫{`Y4=JCcN>R\.o"P&z  0%.h8*|yb4 +_7~fO38ϯMl,˥Xi A*,.D_F{o8y[GM1ⰫоВZVuXvQH|@𨹹`\q9+9MMM .ؼ:BR`viYWWw0oL☠ .GcB{HcF ~~kiuLu(cbF kLFN;-cڧ}zء_MJLT6P(6<@WF3kڬ% ޮVPI?|>hcKjjk0CDIMJl3Cy?Ub@VP+N4Edj{ڒp ó!q~RQQQQj/+ Ya" Yew.j R &߬i0p-61r`BMJXΞ9mfg=vWr~J|檺@T܊`0Xl47ZVC G`i}NMG7+04fhc2xBѸ Ykm88Rc KCb̙9gmXp> 'r fbq:54?t]! v]$ޮ Sab2[Ƈ铏oXyhOuI9_6LP H&@ v߾}ʏW̍ȈH{S) 9yW nϝ5oKhA ݛƵku:<Ӳc}*A$ ; 3Ok ꜄V R rHrR2." c'873DD⿕;Lf/c gM1 G-MY&"6B1E= pR{8S))m=HiL t 32 z CT@' ͕k t}%P@v9J"%H&C4()Md8$@Js $H&C4()Md8$@Js $H&C4()Md8$ -CD` p({ $xޣ=O&qҬ|OHD L(HO&=SHHib&C' oYj:/m[Gڪ^E9{x9h%quvɓ'_¡Z=jlB8AxUPLLLFFZ{u-/J-&PVV_Bc3f̘?!C4.syfLss3W;w.'QbbbkKzp@[8;޿0~xĂ?bA=/N42 4>qn22~[Ouڛ+gU_|nlE0xd-[CC|<~@T*ۥOs %n#dNZ2FDXuf\l77{$5FX_oМBKkS_Knٷ6VYʌA!W^e PoyrT!r +r/eqFOWCsK3fbnԧu͈>  ",, 9 8B1Dx87xbxǏeL\t?5h9 |z_3nPy`F:"ƪ|X~"Ň~w)/I0_?\g>Q|\Y þ7~58f{O/ơivB=67A|2IMsс?'bZ1գ1Onֱ9[Oc̘rPBJ- yys)roh(cr?kXƑ7+=;WĬUyMuշ%+}\hr'68!1G0]#7L.a @+&+4 46m*Ok~3+ԼһK6&:5 my!C)͔Lϧ2p1,'5.X&2U)32Ѿ-1QC:G4gIQ:#ČS@ O+\V&.eرMA59e&ę2[dLry:/5NG EJ.{qET/kTu?o>? Py | ^ \ \E9hs`ЅE-Z6bn?cpbF\7fCo|b8--=juK.? =]dDŽVJ5#6TO:>բ/^/ E=% lS#B/7uf>Qӧ񙞞!L u5U3bض:YkvbS/gxsȠYXKjqa̙3-٠ ;;枩(ӬЮchjN'NTVVnw[GC"!a]7>m'Ĺrą2㯪_k2[cHiP|W 脄/}\Z]e'ǰ+**JJJFc=~nI8cԨQft' BCCC)vHi*ďqIpZ74GllRt8;88lp*&Jdѣe .jH [ON6rO$ eak\`o-Mqhh5n4LzCp9K(n8.uHi]N@sDDφ#9#K;uVC:$CtDEf  Ҥ&J-4[T(HM&5QGl ٢BqD@j4="`)#R IM[HiPp%="0 tȃ|&CFÕHiyJV@gt:R2wgUWt_x~R+ٕ{bZ\S\#nPR/]sfݭ wݍGo٤|%C#чOnzzY}m//^9+gvuv_Oz&;w >d|٫kf|/J_㿹|w="o;?' DTx8^,Н UpSӡKR?|!Tx0EL3bۂ B{}eqM|sTot\brHte.HD&{$Nz(-Z抬,KvĔGs;#?^>NB"AXd=rGe)+W,WwjjccގM7kK}5p zOJ"[4'OܬRBWAٔҩVh PN˝mHӘdo8dYjsT玞nIҝohmnco n}CņINM.Y437}w+OW+5KW#J"&-8D'`SG[D>{- g.]?zōZm}ᎊ I%)λTK8iuV}#+&[.'+ci'';)*yAIzɭKkuQSnKÚϨmv/i:ޚ [mُ1K%t;)"˳](*nBI8Q[g qi^I_L0&a6fH !ͪ!M sXaNM(oGO%@`@ [~_cA%m;#[I!/b1S&FFoT* pHYs  zIDATx \TeǟaEV}Lm͖ʒf^-Ӻ]OakWOַ4\_2[2R#$EeS``w80039ӌ~syy~fFxFt"@x$9DHr.M7#$9DHr.M7#$9DHr.M7#v"`@rr.$kbcc^ID8"PZZ5,t" $X(pD$ I$JF#$9Gd(HB$' V2J 9"CD@$9IQ"IJ' IGHrP:INd8"@sD҉$Hr`%D#2N$!@+%t" $X(pD$ I-9#ju$vygͽn,#.% u8co^3[}=S{uLP8i.' $\`k:5vUyXrdkq()5_,ݚ'#Q7Tcٗ[EoN35QIQW}//}<^̇qfΜo`l\g'.يly>{Nƺe'!gl|kqoƛy\xeKR빻ValPY3^~ F܌8}9cƶC ^+'Moxo̕r h[lH`1oye0>+漴ފYtHjc+֭JO,|7UrC”V"ĉr**dLe#Gʌ=Mjͦ^H_=ˏ''%Ňf^`#~؝<;qԠKz>Gp9>*IػA45@%A1]z%nF@E Ȧog3qlv~m=6kM71=qN 0Pn< _V|DCܖ8 Ku0YA?ogU/~]7 gU7O|̃$f XUӌ[yvڵ"}đ<'YjFLΕ\!AD"vŔsBg2p7?bܥZcSg2.kZ+/>Slo:Ig2г c+6i#nFs\Y^'3L߻xػʵ-`ęe}vv.s|eIse]peO+Vl]}:dlhڶP_o\{[͜zOur{DOI@g6"^d---ѓwLNkl3ouF&gNgRk8tB6ĚtFZݞ/YLaNB47阂,.R ;U'Wk": z@ ~k:&,e}>Q59ih#M_jz$E6E@eggԭ^ӧOw^}8[G}dK'OĴ{ˬDܭ QW3Jyߏr>N$+j$9Wq$>^}WY皚~ R)ɜ񲲪R[YX#j.4$4,$,,4t-Ȓknn\|ȱ#?kAP4:i1c4A^^V+9K]J뀅ݍȒ/sM&_Ψ^y|a~A G ل+7͎J"nL@di?CjQ#GIq\~Q?##"J5W zCD63[ai>"Ė\6 ˹MMjDxoCc#6luMA"Nv:I&uHC"Dc#"r974NR SST` ?]`L`HpH``kZloKC/L(E""K@h  U ]^r>DGEwrڰu4#8`ۧLHXj6hŜCC/f#5%p1k,4 g544@u|_+*.&:`8/}ďrIzX;uԓN])Q{l6OuرN!ȒCjjK ˄ ܺsG~H^r ?'pGsn**$(zSl(joSȒGlA3/xL XN UP|,β]%'{4UU` Ɔ  ,9L `˾2G9LXI9~ U7_EwQQ(!t/1|b6:H'PD1^F-,¢,jĄDL[ 4\wىuC Cr!@ccF^ߚ.$Yr].Eƾ 3 RbI ZB.:jij 1ώD<1,\B,9O=ȆٳظQ~= _AG^ =:lVij/,nni 2ZWQ p"K1 C翢U *b:ZR<DDDCDN5sFtH$" PJ(ʯuÊǞD8eO܄@￝&P1g yEx$9 "@JHrE$Y <-$<Iγ/*m*c=4kt{H~/=!@ K$@$@.&6Hr6H(HI$'%]MllPINJd " %t6!@AB D@J$9)m"`C$gđ\ii) ID/pR2d'&v‡Nѓl8QήiJ$DIΖ  $K--J![L{Nk655u>2nx0ᄧ ۾V+W|7W^t%w 7n &bIr"컦JJJ>mԩf8p $'y"<';v|п?x//4/'ɾkٳ۶mKHH{cJ G}tԨQwy9rH9;@@bM6͝;wƌ _KZ z9FJ Ehh(^@)=}WG9fW+|afN祌_p3K{5ԩ׏;tSotڶ7wc-;9hju ;5V Ɗcf+;ziFG _؝09R1$tЊ.i ~78q f&xO/)gI:!5 ' `BP*7/^VfM>bف_hgWx赦IW|Gi#[^disGȽ!£uB9y"'yayNfrq3S8IQ*N'i<7Px 蠚v䜡wEC1*emU]6L^P䀡wk;_(/|?B *XF;݀'4RN^NQwG§FƬ!/|H'4,gw?1p5|w捧_ע}"@AD@j]/p A@!o)p jX3݅ QU .%@s)n Q .%@s)n Q .%CN/IENDB`django-simple-captcha-0.5.6/docs/_static/random_chars.png000066400000000000000000000177101321370405700234100ustar00rootroot00000000000000PNG  IHDR0ˮs[oiCCPICC Profilex{4T{9 yRI5(Ly"QifIwHN#)BB/ \&w/{~s6R6 l^Ȥf e[SNH 빏c_c`R&km+$[(ȡ<0byH"fF=q,b ǝf(bA.s ׈9, @TfHo[2 X 8q}xxx*Ask f~|EEc[t Jh?vdj" Hԥ п[$H=ƈD"5vR(9D`Ȁ&l%B0&ȼDਯs֌MT_a5c&Ӟ0 ) ǚdP60{EO-IV]cmN~mfecS’BLjkmZwG=2i̧'~(3N1:BB)+ Wi{X-q B R%_SS[q6l۲mv,wi`LLՙҴ$5zE)Izފ}W?e(geVPK8pYeGB86X L ΢uV**>t:R2wgUWt_x~R+ٕ{bZ\S\#nPR/]sfݭ wݍGo٤|%C#чOnzzY}m//^9+gvuv_Oz&;w >d|٫kf|/J_㿹|w="o;?' DTx8^,Н UpSӡKR?|!Tx0EL3bۂ B{}eqM|sTot\brHte.HD&{$Nz(-Z抬,KvĔGs;#?^>NB"AXd=rGe)+W,WwjjccގM7kK}5p zOJ"[4'OܬRBWAٔҩVh PN˝mHӘdo8dYjsT玞nIҝohmnco n}CņINM.Y437}w+OW+5KW#J"&-8D'`SG[D>{- g.]?zōZm}ᎊ I%)λTK8iuV}#+&[.'+ci'';)*yAIzɭKkuQSnKÚϨmv/i:ޚ [mُ1K%t;)"˳](*nBI8Q[g qi^I_L0&a6fH !ͪ!M sXaNM(oGO%@`@ [~_cA%m;#[I!/b1S&FFoT* pHYs  IDATx XTǿaW b,ŲrviLtt?N;zxzZ2+V3,/03X00 :katؕ Ү0"` 2:KJiWTLi%v%@+n*X&@̇ A7F, AZCg] 튛 # -DHvMHY"`W$Hˆe$H|,+UɯrJAړ{w_:[ʏ8@'~*w?&+{T{ӟ^\865LrQr"\^_"zkHUݨ,+"T1/`ƕ+8\] ;Շ')8T[~p} ˘|jj.OǞ6oӊUrnS0'3myOffnx{ciY _-1=zKV? +?rU\~YK&0Oo߱䃜SФ̅ [/a,&kNMbLgɜ#o4g `>q)j~[K]'*pR:LJ[) snȗbe%y6wp`U9!YK>Xμ!fW-)U>@F^,+<} uGEta6W W6駡Aebc"}f8+g?y C%LoΫS9G4',t[kB2}{'> O׫BWA2]z'@Ƃrv.a2SOC޾-=E7n35! SUd2 T_Fdo"oU\HsqUOS`BAylܚl(q0tSn{^Px0m청[.ΊiitL$ R9$V}r߯p榬b[z*MBj=44!eerIRTWlʓT%'KM?r2U9Q*}= \g `h:ڪ>aZxNK SťLLbKW6ɒ&eת #>ټfob&e-cތjK&-<\~KK2$;!y;jق==,ѴеZ&ev~/k&_vQFɚjqtz^k]/iQVe8R)TdE?/ٸ2^Њex\}0eC|^/}lZI*Qb)؁~%:U{?d(Zo/BMS2V3D6qZ45ۭDϟ`6"z{W_eƇv l,}uҒ&Cۡ* Mpm۶׹5N:bp,l "~Nam+1?f貹xe9pHd8 Aڇ3B"@ E"!@g*XE@AFF7eRY``KfВDQN- `8Ijy5l 1k4v %gh6 $! uAiY鑼#gTVUj5ZD?qԈQqAXhٴZORTRTyRxzz 7p䰑}@x^C+>\ ^]Ю =w/#"080x@€ c&$I1ZOF@@Atk~:m]En"7N{>5)h,"<굫jW%kbbK_tryiN?z|td4 fMpqCx?jVל?3g̙='%)%?$J5Ǐ~ ګb{+:u݅ ,XpMG6&Cn\m~2b{|zEE 2~ /ڿo u(>WK绸8o>*-j.^uBvYOΊ 'LIN24{scA'eevnZ=8O !IcS#|ሀ֬ !P#2 +FX)Y(ZHJ%țn=V\L}||lB13s+Wu11MM؁'wy{>cg8-ǢmC:N"`ȝ81U464>lU#$L b">T ҇GEDO'&^>J(?f-&CW+ 1(Y[")y*&$}[$m'-loL=^l]wyxz Il/{JP /, &<SA~>~0P'6 GW$!7ʚt: 5 }XClId:$! rZh/!de\059IXl`8K;D$`0]`#>bF#WźP*tLܼy$t@I~@: ק&Q.W\F{BɾILbN9P" 4)"{Db͹si)iMA8 y &/bzuR)$+w;(F^se#˜RjA>zlJ%h1r""b">^ѥD ciĐw rޠ {1D\ǜ)9wB #F^Ն>!֚s"h:b1 /7.<)JIоł;̎`͆,Liy!g!U\PMVFfMrQ덖!X:9?fD#X'?Z֬B3 byRaRDT$zðKOwEKӤh!董kw>3 f!\ۖ[ʯY!@8XX\qCXCG0CLNnݱK$ڪJ}}|C9ih WsNxz ml[PL;8jnn.4k`;662,ӈWJoyMuao5j 1t!+)>0 ܣjcn@b^]&:frFY]|,Y_5k r5\}HRツM&+k,!HF!Wd2EAf4;A@Rݺu =(bwU:~VN|>c7+kS5{oN-?_fvI BNmY0gm?gKf&~L#|Z,=O"¡a?oޡF؂+.JSw&!mѕ] wt9npD{HҤXa7 lg m>Eo3zݱ~K] =<'4D0DW1-M{sIM Xx27`j_z͑V5ѡBK:J/qaMB+< ^QUHp-9H1BpZ/):s܂os1==?zˉ|^o pܗgv?0"¬jy5F ^X m~i͑VhAǏ{ZZZhh3 VYS37 ԖMQjb,h h?P-fA#k^PW$4UÆᢪ'Nc}}} ֵSo;6mPH'D ȏ9RQQCNogh|ܼO_qsF^v Xݡa CDP`=[\\v`uAJg8T_P^^^TTԻwo  QQʳG~й’~uu)4V`)=:.q*nÇc w-ht)TL6%%%pbhnSHBPu