./0000755000175000017500000000000011670412542006771 5ustar jdjd./README.markdown0000644000175000017500000000623411670412422011474 0ustar jdjd Note: This fork tries to separate the general purpose logic from django related code so that it can be used with other template engines like Jinja2. typogrify: Filters to make web typography easier ================================================================ This application provides a set of custom filters for the Django template system which automatically apply various transformations to plain text in order to yield typographically-improved HTML. Requirements ============ ``typogrify`` is designed to work with `Django`_, and so requires a functioning installation of Django 0.96 or later. Also requires `the Python port of John Gruber's SmartyPants`_ for tokenization. .._ Django: http://www.djangoproject.com/ .._ The Python port of John Gruber's SmartyPants: http://web.chad.org/projects/smartypants.py/ Installation ============ To install a packaged version of ``typogrify``, download `the latest package from Google Code`_, and -- in the directory in which you downloaded it -- open a command line and do the following:: tar zxvf typogrify-0.2.tar.gz cd typogrify-0.2 python setup.py install This will perform a standard installation of ``typogrify``. Alternately, you can perform a Subversion checkout of the latest code; execute the following in a directory that's on your Python path:: svn checkout http://typogrify.googlecode.com/svn/trunk/typogrify/ Once ``typogrify`` is installed on your system, you can add it to the ``INSTALLED_APPS`` setting of any Django project in which you wish to use it, and then use ``{% load typogrify %}`` in your templates to load the filters it provides. .._ the latest package from Google Code: http://typogrify.googlecode.com/files/typogrify-0.1.tar.gz Included filters ================ ``amp`` ------- Wraps ampersands in HTML with ```` so they can be styled with CSS. Ampersands are also normalized to ``&``. Requires ampersands to have whitespace or an `` `` on both sides. Will not change any ampersand which has already been wrapped in this fashion. ``caps`` -------- Wraps multiple capital letters in ```` so they can be styled with CSS. ``initial_quotes`` ------------------ Wraps initial quotes in ```` for double quotes or ```` for single quotes. Works inside these block elements: * ``h1``, ``h2``, ``h3``, ``h4``, ``h5``, ``h6`` * ``p`` * ``li`` * ``dt`` * ``dd`` Also accounts for potential opening inline elements: ``a``, ``em``, ``strong``, ``span``, ``b``, ``i``. ``smartypants`` --------------- Applies ``SmartyPants``. ``typogrify`` ------------- Applies all of the following filters, in order: * ``amp`` * ``widont`` * ``smartypants`` * ``caps`` * ``initial_quotes`` ``widont`` ---------- Based on Shaun Inman's PHP utility of the same name, replaces the space between the last two words in a string with `` `` to avoid a final line of text with only one word. Works inside these block elements: * ``h1``, ``h2``, ``h3``, ``h4``, ``h5``, ``h6`` * ``p`` * ``li`` * ``dt`` * ``dd`` Also accounts for potential closing inline elements: ``a``, ``em``, ``strong``, ``span``, ``b``, ``i``. ./typogrify/0000755000175000017500000000000011670412422011022 5ustar jdjd./typogrify/templatetags/0000755000175000017500000000000011670412422013514 5ustar jdjd./typogrify/templatetags/django_filters.py0000644000175000017500000001563011670412422017065 0ustar jdjdfrom typogrify import Typogrify, TypogrifyError from functools import wraps from django.conf import settings from django import template from django.utils.html import conditional_escape from django.utils.safestring import mark_safe from django.utils.encoding import force_unicode register = template.Library() def make_safe(f): @wraps(f) def wrapper(text): text = force_unicode(text) f.is_safe = True out = text try: out = f(text) except TypogrifyError, e: if settings.DEBUG: raise template.TemplateError(e.message) return text return mark_safe(out) wrapper.is_safe = True return wrapper @make_safe def amp(text): """Wraps apersands in HTML with ```` so they can be styled with CSS. Apersands are also normalized to ``&``. Requires ampersands to have whitespace or an `` `` on both sides. >>> amp('One & two') u'One & two' >>> amp('One & two') u'One & two' >>> amp('One & two') u'One & two' >>> amp('One & two') u'One & two' It won't mess up & that are already wrapped, in entities or URLs >>> amp('One & two') u'One & two' >>> amp('“this” & that') u'“this” & that' It should ignore standalone amps that are in attributes >>> amp('xyz') u'xyz' """ return Typogrify.amp(text) @make_safe def caps(text): """Wraps multiple capital letters in ```` so they can be styled with CSS. >>> caps("A message from KU") u'A message from KU' Uses the smartypants tokenizer to not screw with HTML or with tags it shouldn't. >>> caps("
CAPS
more CAPS") u'
CAPS
more CAPS' >>> caps("A message from 2KU2 with digits") u'A message from 2KU2 with digits' >>> caps("Dotted caps followed by spaces should never include them in the wrap D.O.T. like so.") u'Dotted caps followed by spaces should never include them in the wrap D.O.T. like so.' All caps with with apostrophes in them shouldn't break. Only handles dump apostrophes though. >>> caps("JIMMY'S") u'JIMMY\\'S' >>> caps("D.O.T.HE34TRFID") u'D.O.T.HE34TRFID' """ return Typogrify.caps(text) @make_safe def initial_quotes(text): """Wraps initial quotes in ``class="dquo"`` for double quotes or ``class="quo"`` for single quotes. Works in these block tags ``(h1-h6, p, li, dt, dd)`` and also accounts for potential opening inline elements ``a, em, strong, span, b, i`` >>> initial_quotes('"With primes"') u'"With primes"' >>> initial_quotes("'With single primes'") u'\\'With single primes\\'' >>> initial_quotes('"With primes and a link"') u'"With primes and a link"' >>> initial_quotes('“With smartypanted quotes”') u'With smartypanted quotes”' """ return Typogrify.initial_quotes(text) @make_safe def smartypants(text): """Applies smarty pants to curl quotes. >>> smartypants('The "Green" man') u'The “Green” man' """ return Typogrify.smartypants(text) @make_safe def titlecase(text): """Support for titlecase.py's titlecasing >>> titlecase("this V that") u'This v That' >>> titlecase("this is just an example.com") u'This Is Just an example.com' """ return Typogrify.titlecase(text) @make_safe def typogrify(text): """The super typography filter Applies the following filters: widont, smartypants, caps, amp, initial_quotes >>> typogrify('

"Jayhawks" & KU fans act extremely obnoxiously

') u'

Jayhawks” & KU fans act extremely obnoxiously

' Each filters properly handles autoescaping. >>> conditional_escape(typogrify('

"Jayhawks" & KU fans act extremely obnoxiously

')) u'

Jayhawks” & KU fans act extremely obnoxiously

' """ text = force_unicode(text) return Typogrify.typogrify(text) @make_safe def widont(text): """Replaces the space between the last two words in a string with `` `` Works in these block tags ``(h1-h6, p, li, dd, dt)`` and also accounts for potential closing inline elements ``a, em, strong, span, b, i`` >>> widont('A very simple test') u'A very simple test' Single word items shouldn't be changed >>> widont('Test') u'Test' >>> widont(' Test') u' Test' >>> widont('
  • Test

    • ') u'
      • Test

        • ' >>> widont('
          • Test

            • ') u'
              • Test

                • ' >>> widont('

                  In a couple of paragraphs

                  paragraph two

                  ') u'

                  In a couple of paragraphs

                  paragraph two

                  ' >>> widont('

                  In a link inside a heading

                  ') u'

                  In a link inside a heading

                  ' >>> widont('

                  In a link followed by other text

                  ') u'

                  In a link followed by other text

                  ' Empty HTMLs shouldn't error >>> widont('

                  ') u'

                  ' >>> widont('
                  Divs get no love!
                  ') u'
                  Divs get no love!
                  ' >>> widont('
                  Neither do PREs
                  ') u'
                  Neither do PREs
                  ' >>> widont('

                  But divs with paragraphs do!

                  ') u'

                  But divs with paragraphs do!

                  ' """ return Typogrify.widont(text) register.filter('amp', amp) register.filter('caps', caps) register.filter('initial_quotes', initial_quotes) register.filter('smartypants', smartypants) register.filter('titlecase', titlecase) register.filter('typogrify', typogrify) register.filter('widont', widont) def _test(): """ How to run this: go two levels up to the root typogrify directory. $ ls INSTALL.txt MANIFEST README.markdown typogrify LICENSE.txt MANIFEST.in setup.py $ python -m typogrify.templatetags.filters """ import doctest doctest.testmod(verbose=True) if __name__ == "__main__": _test() ./typogrify/templatetags/jinja2_filters.py0000644000175000017500000001572611670412422017006 0ustar jdjdfrom typogrify import Typogrify, TypogrifyError from functools import wraps import jinja2 from jinja2.exceptions import TemplateError def make_safe(f): @wraps(f) def wrapper(text): f.is_safe = True out = text try: out = f(text) except TypogrifyError, e: raise TemplateError(e.message) return jinja2.Markup(out) wrapper.is_safe = True return wrapper @make_safe def amp(text): """Wraps apersands in HTML with ```` so they can be styled with CSS. Apersands are also normalized to ``&``. Requires ampersands to have whitespace or an `` `` on both sides. >>> amp('One & two') Markup(u'One & two') >>> amp('One & two') Markup(u'One & two') >>> amp('One & two') Markup(u'One & two') >>> amp('One & two') Markup(u'One & two') It won't mess up & that are already wrapped, in entities or URLs >>> amp('One & two') Markup(u'One & two') >>> amp('“this” & that') Markup(u'“this” & that') It should ignore standalone amps that are in attributes >>> amp('xyz') Markup(u'xyz') """ return Typogrify.amp(text) @make_safe def caps(text): """Wraps multiple capital letters in ```` so they can be styled with CSS. >>> caps("A message from KU") Markup(u'A message from KU') Uses the smartypants tokenizer to not screw with HTML or with tags it shouldn't. >>> caps("
                  CAPS
                  more CAPS") Markup(u'
                  CAPS
                  more CAPS') >>> caps("A message from 2KU2 with digits") Markup(u'A message from 2KU2 with digits') >>> caps("Dotted caps followed by spaces should never include them in the wrap D.O.T. like so.") Markup(u'Dotted caps followed by spaces should never include them in the wrap D.O.T. like so.') All caps with with apostrophes in them shouldn't break. Only handles dump apostrophes though. >>> caps("JIMMY'S") Markup(u'JIMMY\\'S') >>> caps("D.O.T.HE34TRFID") Markup(u'D.O.T.HE34TRFID') """ return Typogrify.caps(text) @make_safe def initial_quotes(text): """Wraps initial quotes in ``class="dquo"`` for double quotes or ``class="quo"`` for single quotes. Works in these block tags ``(h1-h6, p, li, dt, dd)`` and also accounts for potential opening inline elements ``a, em, strong, span, b, i`` >>> initial_quotes('"With primes"') Markup(u'"With primes"') >>> initial_quotes("'With single primes'") Markup(u'\\'With single primes\\'') >>> initial_quotes('"With primes and a link"') Markup(u'"With primes and a link"') >>> initial_quotes('“With smartypanted quotes”') Markup(u'With smartypanted quotes”') """ return Typogrify.initial_quotes(text) @make_safe def smartypants(text): """Applies smarty pants to curl quotes. >>> smartypants('The "Green" man') Markup(u'The “Green” man') """ return Typogrify.smartypants(text) @make_safe def titlecase(text): """Support for titlecase.py's titlecasing >>> titlecase("this V that") Markup(u'This v That') >>> titlecase("this is just an example.com") Markup(u'This Is Just an example.com') """ return Typogrify.titlecase(text) @make_safe def typogrify(text): """The super typography filter Applies the following filters: widont, smartypants, caps, amp, initial_quotes >>> typogrify('

                  "Jayhawks" & KU fans act extremely obnoxiously

                  ') Markup(u'

                  Jayhawks” & KU fans act extremely obnoxiously

                  ') Each filters properly handles autoescaping. >>> jinja2.escape(typogrify('

                  "Jayhawks" & KU fans act extremely obnoxiously

                  ')) Markup(u'

                  Jayhawks” & KU fans act extremely obnoxiously

                  ') """ return Typogrify.typogrify(text) @make_safe def widont(text): """Replaces the space between the last two words in a string with `` `` Works in these block tags ``(h1-h6, p, li, dd, dt)`` and also accounts for potential closing inline elements ``a, em, strong, span, b, i`` >>> widont('A very simple test') Markup(u'A very simple test') Single word items shouldn't be changed >>> widont('Test') Markup(u'Test') >>> widont(' Test') Markup(u' Test') >>> widont('
                  • Test

                    • ') Markup(u'
                      • Test

                        • ') >>> widont('
                          • Test

                            • ') Markup(u'
                              • Test

                                • ') >>> widont('

                                  In a couple of paragraphs

                                  paragraph two

                                  ') Markup(u'

                                  In a couple of paragraphs

                                  paragraph two

                                  ') >>> widont('

                                  In a link inside a heading

                                  ') Markup(u'

                                  In a link inside a heading

                                  ') >>> widont('

                                  In a link followed by other text

                                  ') Markup(u'

                                  In a link followed by other text

                                  ') Empty HTMLs shouldn't error >>> widont('

                                  ') Markup(u'

                                  ') >>> widont('
                                  Divs get no love!
                                  ') Markup(u'
                                  Divs get no love!
                                  ') >>> widont('
                                  Neither do PREs
                                  ') Markup(u'
                                  Neither do PREs
                                  ') >>> widont('

                                  But divs with paragraphs do!

                                  ') Markup(u'

                                  But divs with paragraphs do!

                                  ') """ return Typogrify.widont(text) def register(env): """ Call this to register the template filters for jinj2. """ env.filters['amp'] = amp env.filters['caps'] = caps env.filters['initial_quotes'] = initial_quotes env.filters['smartypants'] = smartypants env.filters['titlecase'] = titlecase env.filters['typogrify'] = typogrify env.filters['widont'] = widont def _test(): """ How to run this: go two levels up to the root typogrify directory. $ ls INSTALL.txt MANIFEST README.markdown typogrify LICENSE.txt MANIFEST.in setup.py $ python -m typogrify.templatetags.filters """ import doctest doctest.testmod(verbose=True) if __name__ == "__main__": _test() ./typogrify/templatetags/__init__.py0000644000175000017500000000000011670412422015613 0ustar jdjd./typogrify/__init__.py0000644000175000017500000002753611670412422013150 0ustar jdjdimport re class TypogrifyError(Exception): pass class Typogrify(object): """ Wrapping the utilities in a class to avoid namespace clashes. """ @staticmethod def amp(text): """Wraps apersands in HTML with ```` so they can be styled with CSS. Apersands are also normalized to ``&``. Requires ampersands to have whitespace or an `` `` on both sides. >>> Typogrify.amp('One & two') 'One & two' >>> Typogrify.amp('One & two') 'One & two' >>> Typogrify.amp('One & two') 'One & two' >>> Typogrify.amp('One & two') 'One & two' It won't mess up & that are already wrapped, in entities or URLs >>> Typogrify.amp('One & two') 'One & two' >>> Typogrify.amp('“this” & that') '“this” & that' It should ignore standalone amps that are in attributes >>> Typogrify.amp('xyz') 'xyz' """ # tag_pattern from http://haacked.com/archive/2004/10/25/usingregularexpressionstomatchhtml.aspx # it kinda sucks but it fixes the standalone amps in attributes bug tag_pattern = '\s]+))?)+\s*|\s*)/?>' amp_finder = re.compile(r"(\s| )(&|&|&\#38;)(\s| )") intra_tag_finder = re.compile(r'(?P(%s)?)(?P([^<]*))(?P(%s)?)' % (tag_pattern, tag_pattern)) def _amp_process(groups): prefix = groups.group('prefix') or '' text = amp_finder.sub(r"""\1&\3""", groups.group('text')) suffix = groups.group('suffix') or '' return prefix + text + suffix output = intra_tag_finder.sub(_amp_process, text) return output @staticmethod def caps(text): """Wraps multiple capital letters in ```` so they can be styled with CSS. >>> Typogrify.caps("A message from KU") 'A message from KU' Uses the smartypants tokenizer to not screw with HTML or with tags it shouldn't. >>> Typogrify.caps("
                                  CAPS
                                  more CAPS") '
                                  CAPS
                                  more CAPS' >>> Typogrify.caps("A message from 2KU2 with digits") 'A message from 2KU2 with digits' >>> Typogrify.caps("Dotted caps followed by spaces should never include them in the wrap D.O.T. like so.") 'Dotted caps followed by spaces should never include them in the wrap D.O.T. like so.' All caps with with apostrophes in them shouldn't break. Only handles dump apostrophes though. >>> Typogrify.caps("JIMMY'S") 'JIMMY\\'S' >>> Typogrify.caps("D.O.T.HE34TRFID") 'D.O.T.HE34TRFID' """ try: import smartypants except ImportError: raise TypogrifyError, "Error in {% caps %} filter: The Python SmartyPants library isn't installed." tokens = smartypants._tokenize(text) result = [] in_skipped_tag = False cap_finder = re.compile(r"""( (\b[A-Z\d]* # Group 2: Any amount of caps and digits [A-Z]\d*[A-Z] # A cap string much at least include two caps (but they can have digits between them) [A-Z\d']*\b) # Any amount of caps and digits or dumb apostsrophes | (\b[A-Z]+\.\s? # OR: Group 3: Some caps, followed by a '.' and an optional space (?:[A-Z]+\.\s?)+) # Followed by the same thing at least once more (?:\s|\b|$)) """, re.VERBOSE) def _cap_wrapper(matchobj): """This is necessary to keep dotted cap strings to pick up extra spaces""" if matchobj.group(2): return """%s""" % matchobj.group(2) else: if matchobj.group(3)[-1] == " ": caps = matchobj.group(3)[:-1] tail = ' ' else: caps = matchobj.group(3) tail = '' return """%s%s""" % (caps, tail) tags_to_skip_regex = re.compile("<(/)?(?:pre|code|kbd|script|math)[^>]*>", re.IGNORECASE) for token in tokens: if token[0] == "tag": # Don't mess with tags. result.append(token[1]) close_match = tags_to_skip_regex.match(token[1]) if close_match and close_match.group(1) == None: in_skipped_tag = True else: in_skipped_tag = False else: if in_skipped_tag: result.append(token[1]) else: result.append(cap_finder.sub(_cap_wrapper, token[1])) output = "".join(result) return output @staticmethod def initial_quotes(text): """Wraps initial quotes in ``class="dquo"`` for double quotes or ``class="quo"`` for single quotes. Works in these block tags ``(h1-h6, p, li, dt, dd)`` and also accounts for potential opening inline elements ``a, em, strong, span, b, i`` >>> Typogrify.initial_quotes('"With primes"') '"With primes"' >>> Typogrify.initial_quotes("'With single primes'") '\\'With single primes\\'' >>> Typogrify.initial_quotes('"With primes and a link"') '"With primes and a link"' >>> Typogrify.initial_quotes('“With smartypanted quotes”') 'With smartypanted quotes”' """ quote_finder = re.compile(r"""((<(p|h[1-6]|li|dt|dd)[^>]*>|^) # start with an opening p, h1-6, li, dd, dt or the start of the string \s* # optional white space! (<(a|em|span|strong|i|b)[^>]*>\s*)*) # optional opening inline tags, with more optional white space for each. (("|“|&\#8220;)|('|‘|&\#8216;)) # Find me a quote! (only need to find the left quotes and the primes) # double quotes are in group 7, singles in group 8 """, re.VERBOSE) def _quote_wrapper(matchobj): if matchobj.group(7): classname = "dquo" quote = matchobj.group(7) else: classname = "quo" quote = matchobj.group(8) return """%s%s""" % (matchobj.group(1), classname, quote) output = quote_finder.sub(_quote_wrapper, text) return output @staticmethod def smartypants(text): """Applies smarty pants to curl quotes. >>> Typogrify.smartypants('The "Green" man') 'The “Green” man' """ try: import smartypants except ImportError: raise TypogrifyError, "Error in {% smartypants %} filter: The Python smartypants library isn't installed." else: output = smartypants.smartyPants(text) return output @staticmethod def titlecase(text): """Support for titlecase.py's titlecasing >>> Typogrify.titlecase("this V that") 'This v That' >>> Typogrify.titlecase("this is just an example.com") 'This Is Just an example.com' """ try: import titlecase except ImportError: raise TypogrifyError, "Error in {% titlecase %} filter: The titlecase.py library isn't installed." else: return titlecase.titlecase(text) @staticmethod def typogrify(text): """The super typography filter Applies the following filters: widont, smartypants, caps, amp, initial_quotes >>> Typogrify.typogrify('

                                  "Jayhawks" & KU fans act extremely obnoxiously

                                  ') '

                                  Jayhawks” & KU fans act extremely obnoxiously

                                  ' """ text = Typogrify.amp(text) text = Typogrify.widont(text) text = Typogrify.smartypants(text) text = Typogrify.caps(text) text = Typogrify.initial_quotes(text) return text @staticmethod def widont(text): """Replaces the space between the last two words in a string with `` `` Works in these block tags ``(h1-h6, p, li, dd, dt)`` and also accounts for potential closing inline elements ``a, em, strong, span, b, i`` >>> Typogrify.widont('A very simple test') 'A very simple test' Single word items shouldn't be changed >>> Typogrify.widont('Test') 'Test' >>> Typogrify.widont(' Test') ' Test' >>> Typogrify.widont('
                                  • Test

                                    • ') '
                                      • Test

                                        • ' >>> Typogrify.widont('
                                          • Test

                                            • ') '
                                              • Test

                                                • ' >>> Typogrify.widont('

                                                  In a couple of paragraphs

                                                  paragraph two

                                                  ') '

                                                  In a couple of paragraphs

                                                  paragraph two

                                                  ' >>> Typogrify.widont('

                                                  In a link inside a heading

                                                  ') '

                                                  In a link inside a heading

                                                  ' >>> Typogrify.widont('

                                                  In a link followed by other text

                                                  ') '

                                                  In a link followed by other text

                                                  ' Empty HTMLs shouldn't error >>> Typogrify.widont('

                                                  ') '

                                                  ' >>> Typogrify.widont('
                                                  Divs get no love!
                                                  ') '
                                                  Divs get no love!
                                                  ' >>> Typogrify.widont('
                                                  Neither do PREs
                                                  ') '
                                                  Neither do PREs
                                                  ' >>> Typogrify.widont('

                                                  But divs with paragraphs do!

                                                  ') '

                                                  But divs with paragraphs do!

                                                  ' """ widont_finder = re.compile(r"""((?:]*>)|[^<>\s]) # must be proceeded by an approved inline opening or closing tag or a nontag/nonspace \s+ # the space to replace ([^<>\s]+ # must be flollowed by non-tag non-space characters \s* # optional white space! (\s*)* # optional closing inline tags with optional white space after each (()|$)) # end with a closing p, h1-6, li or the end of the string """, re.VERBOSE) output = widont_finder.sub(r'\1 \2', text) return output def _test(): import doctest doctest.testmod(verbose=True) if __name__ == "__main__": _test() ./LICENSE.txt0000644000175000017500000000275711670412422010624 0ustar jdjdCopyright (c) 2007, Christian Metts All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE../INSTALL.txt0000644000175000017500000000114311670412422010634 0ustar jdjdThanks for downloading typogrify. To install it, run the following command inside this directory:: python setup.py install Or simply move the typogrify folder into your python path. Once ``typogrify`` is installed on your system, you can add it to the ``INSTALLED_APPS`` setting of any Django project in which you wish to use it, and then use ``{% load typogrify %}`` in your templates to load the filters it provides. Note that this application requires Python 2.3 or later, and Django 0.96 or later; you can obtain Python from http://www.python.org/ and Django from http://www.djangoproject.com/../MANIFEST.in0000644000175000017500000000010011670412422010513 0ustar jdjdinclude INSTALL.txt include LICENSE.txt recursive-include docs *./.git/0000755000175000017500000000000011670412527007635 5ustar jdjd./.git/refs/0000755000175000017500000000000011670412422010566 5ustar jdjd./.git/refs/remotes/0000755000175000017500000000000011670412422012244 5ustar jdjd./.git/refs/remotes/origin/0000755000175000017500000000000011670412422013533 5ustar jdjd./.git/refs/remotes/origin/HEAD0000644000175000017500000000004011670412422014151 0ustar jdjdref: refs/remotes/origin/master ./.git/refs/tags/0000755000175000017500000000000011670412415011526 5ustar jdjd./.git/refs/heads/0000755000175000017500000000000011670412517011657 5ustar jdjd./.git/refs/heads/master0000644000175000017500000000005111670412422013064 0ustar jdjd6937a8a6e60b305abe23a1be70a3c496e4d5b8ac ./.git/refs/heads/debian/0000755000175000017500000000000011670412524013077 5ustar jdjd./.git/refs/heads/debian/unstable0000644000175000017500000000005111670412524014633 0ustar jdjd6937a8a6e60b305abe23a1be70a3c496e4d5b8ac ./.git/packed-refs0000644000175000017500000000024611670412422011740 0ustar jdjd# pack-refs with: peeled 6937a8a6e60b305abe23a1be70a3c496e4d5b8ac refs/remotes/origin/master 5ff449b6fbc5a0f53afb0e664c9e90b4b1921472 refs/remotes/origin/hyde-setup ./.git/HEAD0000644000175000017500000000004011670412527010253 0ustar jdjdref: refs/heads/debian/unstable ./.git/branches/0000755000175000017500000000000011670412415011416 5ustar jdjd./.git/description0000644000175000017500000000011111670412415012070 0ustar jdjdUnnamed repository; edit this file 'description' to name the repository. ./.git/index0000644000175000017500000000161011670412527010665 0ustar jdjdDIRC NdNd O"`K1U,딗 D' .gitignoreNdNd Pc01o :øgotypogrify/__init__.pyNdNd X⛲CK)wZS"typogrify/templatetags/__init__.pyNdNd YpqEXKqxX8u(typogrify/templatetags/django_filters.pyNdNd ZՓ?6+HmV Y="(typogrify/templatetags/jinja2_filters.pyZh*٩9]~&./.git/info/0000755000175000017500000000000011670412415010564 5ustar jdjd./.git/info/exclude0000644000175000017500000000036011670412415012137 0ustar jdjd# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ ./.git/hooks/0000755000175000017500000000000011670412415010754 5ustar jdjd./.git/hooks/applypatch-msg.sample0000755000175000017500000000070411670412415015114 0ustar jdjd#!/bin/sh # # An example hook script to check the commit log message taken by # applypatch from an e-mail message. # # The hook should exit with non-zero status after issuing an # appropriate message if it wants to stop the commit. The hook is # allowed to edit the commit message file. # # To enable this hook, rename this file to "applypatch-msg". . git-sh-setup test -x "$GIT_DIR/hooks/commit-msg" && exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} : ./.git/hooks/pre-rebase.sample0000755000175000017500000001155311670412415014214 0ustar jdjd#!/bin/sh # # Copyright (c) 2006, 2008 Junio C Hamano # # The "pre-rebase" hook is run just before "git rebase" starts doing # its job, and can prevent the command from running by exiting with # non-zero status. # # The hook is called with the following parameters: # # $1 -- the upstream the series was forked from. # $2 -- the branch being rebased (or empty when rebasing the current branch). # # This sample shows how to prevent topic branches that are already # merged to 'next' branch from getting rebased, because allowing it # would result in rebasing already published history. publish=next basebranch="$1" if test "$#" = 2 then topic="refs/heads/$2" else topic=`git symbolic-ref HEAD` || exit 0 ;# we do not interrupt rebasing detached HEAD fi case "$topic" in refs/heads/??/*) ;; *) exit 0 ;# we do not interrupt others. ;; esac # Now we are dealing with a topic branch being rebased # on top of master. Is it OK to rebase it? # Does the topic really exist? git show-ref -q "$topic" || { echo >&2 "No such branch $topic" exit 1 } # Is topic fully merged to master? not_in_master=`git rev-list --pretty=oneline ^master "$topic"` if test -z "$not_in_master" then echo >&2 "$topic is fully merged to master; better remove it." exit 1 ;# we could allow it, but there is no point. fi # Is topic ever merged to next? If so you should not be rebasing it. only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` only_next_2=`git rev-list ^master ${publish} | sort` if test "$only_next_1" = "$only_next_2" then not_in_topic=`git rev-list "^$topic" master` if test -z "$not_in_topic" then echo >&2 "$topic is already up-to-date with master" exit 1 ;# we could allow it, but there is no point. else exit 0 fi else not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` /usr/bin/perl -e ' my $topic = $ARGV[0]; my $msg = "* $topic has commits already merged to public branch:\n"; my (%not_in_next) = map { /^([0-9a-f]+) /; ($1 => 1); } split(/\n/, $ARGV[1]); for my $elem (map { /^([0-9a-f]+) (.*)$/; [$1 => $2]; } split(/\n/, $ARGV[2])) { if (!exists $not_in_next{$elem->[0]}) { if ($msg) { print STDERR $msg; undef $msg; } print STDERR " $elem->[1]\n"; } } ' "$topic" "$not_in_next" "$not_in_master" exit 1 fi exit 0 <<\DOC_END ################################################################ This sample hook safeguards topic branches that have been published from being rewound. The workflow assumed here is: * Once a topic branch forks from "master", "master" is never merged into it again (either directly or indirectly). * Once a topic branch is fully cooked and merged into "master", it is deleted. If you need to build on top of it to correct earlier mistakes, a new topic branch is created by forking at the tip of the "master". This is not strictly necessary, but it makes it easier to keep your history simple. * Whenever you need to test or publish your changes to topic branches, merge them into "next" branch. The script, being an example, hardcodes the publish branch name to be "next", but it is trivial to make it configurable via $GIT_DIR/config mechanism. With this workflow, you would want to know: (1) ... if a topic branch has ever been merged to "next". Young topic branches can have stupid mistakes you would rather clean up before publishing, and things that have not been merged into other branches can be easily rebased without affecting other people. But once it is published, you would not want to rewind it. (2) ... if a topic branch has been fully merged to "master". Then you can delete it. More importantly, you should not build on top of it -- other people may already want to change things related to the topic as patches against your "master", so if you need further changes, it is better to fork the topic (perhaps with the same name) afresh from the tip of "master". Let's look at this example: o---o---o---o---o---o---o---o---o---o "next" / / / / / a---a---b A / / / / / / / / c---c---c---c B / / / / \ / / / / b---b C \ / / / / / \ / ---o---o---o---o---o---o---o---o---o---o---o "master" A, B and C are topic branches. * A has one fix since it was merged up to "next". * B has finished. It has been fully merged up to "master" and "next", and is ready to be deleted. * C has not merged to "next" at all. We would want to allow C to be rebased, refuse A, and encourage B to be deleted. To compute (1): git rev-list ^master ^topic next git rev-list ^master next if these match, topic has not merged in next at all. To compute (2): git rev-list master..topic if this is empty, it is fully merged to "master". DOC_END ./.git/hooks/update.sample0000755000175000017500000000703311670412415013447 0ustar jdjd#!/bin/sh # # An example hook script to blocks unannotated tags from entering. # Called by "git receive-pack" with arguments: refname sha1-old sha1-new # # To enable this hook, rename this file to "update". # # Config # ------ # hooks.allowunannotated # This boolean sets whether unannotated tags will be allowed into the # repository. By default they won't be. # hooks.allowdeletetag # This boolean sets whether deleting tags will be allowed in the # repository. By default they won't be. # hooks.allowmodifytag # This boolean sets whether a tag may be modified after creation. By default # it won't be. # hooks.allowdeletebranch # This boolean sets whether deleting branches will be allowed in the # repository. By default they won't be. # hooks.denycreatebranch # This boolean sets whether remotely creating branches will be denied # in the repository. By default this is allowed. # # --- Command line refname="$1" oldrev="$2" newrev="$3" # --- Safety check if [ -z "$GIT_DIR" ]; then echo "Don't run this script from the command line." >&2 echo " (if you want, you could supply GIT_DIR then run" >&2 echo " $0 )" >&2 exit 1 fi if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then echo "Usage: $0 " >&2 exit 1 fi # --- Config allowunannotated=$(git config --bool hooks.allowunannotated) allowdeletebranch=$(git config --bool hooks.allowdeletebranch) denycreatebranch=$(git config --bool hooks.denycreatebranch) allowdeletetag=$(git config --bool hooks.allowdeletetag) allowmodifytag=$(git config --bool hooks.allowmodifytag) # check for no description projectdesc=$(sed -e '1q' "$GIT_DIR/description") case "$projectdesc" in "Unnamed repository"* | "") echo "*** Project description file hasn't been set" >&2 exit 1 ;; esac # --- Check types # if $newrev is 0000...0000, it's a commit to delete a ref. zero="0000000000000000000000000000000000000000" if [ "$newrev" = "$zero" ]; then newrev_type=delete else newrev_type=$(git cat-file -t $newrev) fi case "$refname","$newrev_type" in refs/tags/*,commit) # un-annotated tag short_refname=${refname##refs/tags/} if [ "$allowunannotated" != "true" ]; then echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 exit 1 fi ;; refs/tags/*,delete) # delete tag if [ "$allowdeletetag" != "true" ]; then echo "*** Deleting a tag is not allowed in this repository" >&2 exit 1 fi ;; refs/tags/*,tag) # annotated tag if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 then echo "*** Tag '$refname' already exists." >&2 echo "*** Modifying a tag is not allowed in this repository." >&2 exit 1 fi ;; refs/heads/*,commit) # branch if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then echo "*** Creating a branch is not allowed in this repository" >&2 exit 1 fi ;; refs/heads/*,delete) # delete branch if [ "$allowdeletebranch" != "true" ]; then echo "*** Deleting a branch is not allowed in this repository" >&2 exit 1 fi ;; refs/remotes/*,commit) # tracking branch ;; refs/remotes/*,delete) # delete tracking branch if [ "$allowdeletebranch" != "true" ]; then echo "*** Deleting a tracking branch is not allowed in this repository" >&2 exit 1 fi ;; *) # Anything else (is there anything else?) echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 exit 1 ;; esac # --- Finished exit 0 ./.git/hooks/pre-commit.sample0000755000175000017500000000325011670412415014236 0ustar jdjd#!/bin/sh # # An example hook script to verify what is about to be committed. # Called by "git commit" with no arguments. The hook should # exit with non-zero status after issuing an appropriate message if # it wants to stop the commit. # # To enable this hook, rename this file to "pre-commit". if git rev-parse --verify HEAD >/dev/null 2>&1 then against=HEAD else # Initial commit: diff against an empty tree object against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 fi # If you want to allow non-ascii filenames set this variable to true. allownonascii=$(git config hooks.allownonascii) # Redirect output to stderr. exec 1>&2 # Cross platform projects tend to avoid non-ascii filenames; prevent # them from being added to the repository. We exploit the fact that the # printable range starts at the space character and ends with tilde. if [ "$allownonascii" != "true" ] && # Note that the use of brackets around a tr range is ok here, (it's # even required, for portability to Solaris 10's /usr/bin/tr), since # the square bracket bytes happen to fall in the designated range. test $(git diff --cached --name-only --diff-filter=A -z $against | LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 then echo "Error: Attempt to add a non-ascii file name." echo echo "This can cause problems if you want to work" echo "with people on other platforms." echo echo "To be portable it is advisable to rename the file ..." echo echo "If you know what you are doing you can disable this" echo "check using:" echo echo " git config hooks.allownonascii true" echo exit 1 fi # If there are whitespace errors, print the offending file names and fail. exec git diff-index --check --cached $against -- ./.git/hooks/post-update.sample0000755000175000017500000000027511670412415014433 0ustar jdjd#!/bin/sh # # An example hook script to prepare a packed repository for use over # dumb transports. # # To enable this hook, rename this file to "post-update". exec git update-server-info ./.git/hooks/commit-msg.sample0000755000175000017500000000160011670412415014233 0ustar jdjd#!/bin/sh # # An example hook script to check the commit log message. # Called by "git commit" with one argument, the name of the file # that has the commit message. The hook should exit with non-zero # status after issuing an appropriate message if it wants to stop the # commit. The hook is allowed to edit the commit message file. # # To enable this hook, rename this file to "commit-msg". # Uncomment the below to add a Signed-off-by line to the message. # Doing this in a hook is a bad idea in general, but the prepare-commit-msg # hook is more suited to it. # # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" # This example catches duplicate Signed-off-by lines. test "" = "$(grep '^Signed-off-by: ' "$1" | sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { echo >&2 Duplicate Signed-off-by lines. exit 1 } ./.git/hooks/prepare-commit-msg.sample0000755000175000017500000000232711670412415015676 0ustar jdjd#!/bin/sh # # An example hook script to prepare the commit log message. # Called by "git commit" with the name of the file that has the # commit message, followed by the description of the commit # message's source. The hook's purpose is to edit the commit # message file. If the hook fails with a non-zero status, # the commit is aborted. # # To enable this hook, rename this file to "prepare-commit-msg". # This hook includes three examples. The first comments out the # "Conflicts:" part of a merge commit. # # The second includes the output of "git diff --name-status -r" # into the message, just before the "git status" output. It is # commented because it doesn't cope with --amend or with squashed # commits. # # The third example adds a Signed-off-by line to the message, that can # still be edited. This is rarely a good idea. case "$2,$3" in merge,) /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; # ,|template,) # /usr/bin/perl -i.bak -pe ' # print "\n" . `git diff --cached --name-status -r` # if /^#/ && $first++ == 0' "$1" ;; *) ;; esac # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" ./.git/hooks/pre-applypatch.sample0000755000175000017500000000061611670412415015116 0ustar jdjd#!/bin/sh # # An example hook script to verify what is about to be committed # by applypatch from an e-mail message. # # The hook should exit with non-zero status after issuing an # appropriate message if it wants to stop the commit. # # To enable this hook, rename this file to "pre-applypatch". . git-sh-setup test -x "$GIT_DIR/hooks/pre-commit" && exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} : ./.git/logs/0000755000175000017500000000000011670412422010573 5ustar jdjd./.git/logs/refs/0000755000175000017500000000000011670412524011535 5ustar jdjd./.git/logs/refs/heads/0000755000175000017500000000000011670412517012623 5ustar jdjd./.git/logs/refs/heads/master0000644000175000017500000000027011670412422014033 0ustar jdjd0000000000000000000000000000000000000000 6937a8a6e60b305abe23a1be70a3c496e4d5b8ac Julien Danjou 1323439378 +0100 clone: from https://github.com/hyde/typogrify.git ./.git/logs/refs/heads/debian/0000755000175000017500000000000011670412524014043 5ustar jdjd./.git/logs/refs/heads/debian/unstable0000644000175000017500000000055411670412524015607 0ustar jdjd0000000000000000000000000000000000000000 6937a8a6e60b305abe23a1be70a3c496e4d5b8ac Julien Danjou 1323439439 +0100 branch: Created from master 6937a8a6e60b305abe23a1be70a3c496e4d5b8ac 6937a8a6e60b305abe23a1be70a3c496e4d5b8ac Julien Danjou 1323439444 +0100 Branch: renamed refs/heads/debian/uns to refs/heads/debian/unstable ./.git/logs/HEAD0000644000175000017500000000055611670412527011233 0ustar jdjd0000000000000000000000000000000000000000 6937a8a6e60b305abe23a1be70a3c496e4d5b8ac Julien Danjou 1323439378 +0100 clone: from https://github.com/hyde/typogrify.git 6937a8a6e60b305abe23a1be70a3c496e4d5b8ac 6937a8a6e60b305abe23a1be70a3c496e4d5b8ac Julien Danjou 1323439447 +0100 checkout: moving from master to debian/unstable ./.git/objects/0000755000175000017500000000000011670412415011262 5ustar jdjd./.git/objects/pack/0000755000175000017500000000000011670412422012176 5ustar jdjd./.git/objects/pack/pack-4417a02b4bd7815a6fd96728103780345edaa301.idx0000444000175000017500000001021411670412421020735 0ustar jdjdtOc  !!!!"""""""$$$%%&'())*+,,,-./01122245667899:;<<<==>>???@@@ABBCDEEFFFGGGHHIIIIKKLMMMMMMMOPPPPPPPPPQQQQQQRRRRRRRRRRRRRRSSTTTTTUUWWWXXXYZ[[\\^^^___``aaabbbbbbcefghhhiilnooopqqвTԁإP6+F.<A/N) |J*} R K m Y̧$c: pzVL:m/KO H|aѽ:Jm>B|tQמ8IF)K >$$:.)=\=ݯK+Xi\6s,iSTmd(x-mΦ5ßjQ01ECa_*|/ش>Y@aGJ!lL.M߰J#& kCE&h3VK]Bn`K֒IL`==J ˴78B%QYǹ ^swSӌ" Au`oPRTrO,A .Ǟa ɛ:1X գ$ \_0Do}d8GKo_IŠ:fLrb#*};rALd ̞|-F~KeYc|R0$Efx"fXDSz2] (Jz^g #l~FPmi7 0Z#pĖոj@bpTn$a]Tpk`[=x$6.\ naU?ה;e`=oo9.;4GV&pqEXKqxX8uq#uASzuk>rtK D9thL/RK^B,w~YDI'#wfg`ƂAF.?Ogx*w\Z20Gyy׽[ջ K2{ЦSM>o :øgo|2e#~c.i}8F‡rC 1Hw_kwP;X`0_85uϔABN~eǟӇ7e ~vФ\[(R۬Q;rP'e/]kZj{M< =,UC 2z莸,w]\W̻X(e,[!HvP.}g5VM9DsuCP6倭MâW\ȕq T\@߆Qozw9q9oF3;P~pbJZX{ZusI?=K 'h׭McnT"SUKZ+le|0e\*n.ӔV+srà, BSOQDGiB˞(۷,fJPd6B\e:ĵבlӬ.VkQnv)75O?*R{_?ܺ}\kFe.4f*o}H̐+b8 UT "KJIJw@iL'LqPVL I@8?NBM$UJSXvLIOU XIQiQ?UhWa<N Z8%fIVK%% V)3\QPIBTSJ9C?QO>MW98jS?KWRJWJScTJM}I[J #Q;]QS HV8 qS H<HK~XAH[jtR3Ӈĭ4 #hP Y5қ;s#5s񅉩22+{i\v31%^%n^xKj1:R`r{}KLbA$ V]D#:a)D6:ZÉXP@}p>lC.S%T.B1ϯ( ?-;# PsOmӯ޹&{4ޮroGml&EKN?!I63/mz},ﳪ~ ][x;0 =ȎT%iBLLN@?( nO%WCbs4փ i{61pY# y G,@}]M O,?u:%}ʙoR[\E^XdnMxM F h\yKҖV%KYfmX|! SfB0`N!!2G(DALbHd蒠[fy煶,//8^%Rk: 9棍_}ԶHxM 0F9\@d@ĭxI2ږ.#=x|7ES e.5LvhZ sbuB+ޛk$ l$xkR12\w~gcZІN !>XUVxIV(oFxK 0@9\@L>MAD P/f&Xm~{,|3fRJ;6lu5m#6!;5Y 356ڎLۑcGH41DW3\t80l(Lc Zo1aQ}꣯UU*axMpڞ/To;Gx T $])R@Nb[O;%43ҫEr.Zk6IHL8w.Lqˆܩ-Y*d`eم`Pҍ')'pa-o’QNy]3=}cБEETgZ寳e-c^)J/>B-xh^dݶ޼5m+#羗U]xNN0+:T|cS jGζп'B΁9FF3`5; ^hM)8et8.46I{ ̴X R\s \W?u9cBt[ҡ d) Q*өj5{w;^c,-k^x7B xN0 y KQ:!7n8moloO7d[o%3&7^#ru՛  E 3/͚#u3ڇcgR9.rwGD5]]e 荱ּi[z4QzC Ss 7)y|\ƕRS,p=!0 `H}F(" #!3^&|""eZ?8(M,M;DNe^X_)GyUZWp-_Q0x=o0wC dR_ H-n:$1HqdpD>=28"H-"U' U/D]'rd*}wF}Sa*E-)ohڄ7 <=k )S>JJT84d Qu+<L>!b]E{`|m3 z=m W0 6%;qǨQ{I|+eV.N+D@G'E  t`@`2x166뚎ʰՏ2_Doi^6]7@sxNpikpVRF^L/b曹Yڳ9P :դ0nwu)c'x$sOd {x 0PZ^sstuKP( '_[ySqHl@Ί#C FM hҖ"2&A 8YIභeϘ3SγLn#YN5B*¸-lxn Fw"&l}~,|So_Mg8t!r5tP1 K11.HcFpv߰"$ѹHSʠ QKP[_ow~ɪEHRx^Qݬw},mDrYQ7!t7|?58Dq:&ġWb?rxN0 } #m4m2!48^tdj\=ĝ>Y+t=iJ8ՉAb0aLuŕC0uVؑsAw=jC~8)U9ķ #Y%e.ԢF9`RY?#_@Jw2>?ի1MPBSagm.sLBQIKߗG[Ϙ.8v5BIpڡw-lbiPS Ymf6I|cD}XiʊVw4*ln3XUBœ74/m gXKkKuZb&Z:U̮>v%v)xn0 Ew}±AQP%Cf;%{5pKIi0V[NP43`լIb2:B*x3D544M!-8Y TR毄^TGPy+2lH7Pjv0jEl[b ڴR^-tyCJLr< 158ONk뽤頙>/Z@kxj0Dl),gq$V鲋jfC Ltj胰'WMxaXZ-~;| 䵔<[5qaA Y3H9:5|C,ǣ?P wȥavXmcs!^ D?ʴwsSQrH u&eqx340031QK,L/JeH[\A~&XN 8C*OGé}mB]M-6Oi2OgW`W.2Wq{6 NA:y0td57uվ lc~!1ޠn~PeA.zE)y < .=&UtoԒJ]4txgB8vf 41ʂ̴JoLQF~HwWxc&100644 .gitignore`K1U,딗 D'&].inQYǹ ^sw;Ҳ~:RGI.0$(xKMOK+NΏJ*IJ,. &x]N0DpRTR{'&vkM# ﬓ4B{vv%Fg w2J`Ω`\$i-Z@PyZ쳸¶NeQ/MeCZ~|DM/|Ywb -^`?'ȋ<@ pwe  X9LIt '&`S^'mw>Fe|Tv0}@CO4@&Ls0aI7EH:3jw!Hxƛt9QIˬ`:8)toXq0vA;)%M,=>3f&uTq gGq}Ћ= x㦠 9$od݇An}\.|jʹVy\dj$HT["(ԚB`5J*$Z h2 _^w@6J \4C0DVX]TmU5WY6Lay"%l(,X.-#ג@CbE[M+.)D[%EE؆Ȏ@oi@IU}tmME~n*FDd-Tt~*08WlhYPB.1%b$BkHGRndA jeYRq *Ce 4JH"FL x^Xmp[L5|ZpyP.v4fax/b))#XېTٻGb+Z4VyD2IpTLhq&qD*Kdz -,ʞqk"+s׿>gxK)MIU q+(ʄx:ŊRK3Rua) ZOxVao6_q( sY).XcDKĚ&U {GR؀ ?Xt{DDl+ju[ NIOp"H F鄦wmTEgwT\jl-[TJZK= *dQ742VFGo ,"mڌ+Y ][I\S,v$)x/EQD.DiUٽO@vCURdH .2Q1G5 Z=a%)#''] 9 ( YW3aF%u};y;U;v__ɏrr'Mr&, "3l[ Lɔ'$Lt'h(62 *pѣwO3}[Zf׺zt_z  u"nQ71R\,s!trEFAVaQ2Z^:4\/V ev>Zvl%>?bWvӉj+GdnUj;mEP}i^YhI/0bSmNOExC v`/Rۍ/&i гc=6XVE |oh{hd׋&ZToe#6(I}ϣ@^Cݢ?3F'^~=[>gg$>ۜ0&hdCwDh'j(Nn‱a 7ۃ WSI7l䐳c=C,۷?>8)/8Mf[-be հh)匑03Ir%Cf5#0NxTuoلmxjIJŽP캲,Nӯ(CR!o;4\Y=ƞ*-f~`#c> F=s/./|waX KV7It 8{榬۾8V% .ɺhg֞7rq${-cC2՟=檷}Zۤ`3fvC]]Ib]] )cqoM)E_b`>Ejۯ71>lc 9 Zj[HZ(W>f%I~~yݴjZa^ռ秨*#PD'B>fBHgMqiNՕ'}F|LJt{$bgayJON&3Mh\f6*h\k 7{8Ic/[:78!/J0NhI2;MzWAyLexASIF|shyr1boU]p`x~lpUx@FU# I/xURn0+T%cڃMp" 0himmWɕ[}(Hܙ@D=;#.2=vUdYe.yh?\uC,CG |M U=w..PdR~!s,"]br)3#MS6Xj16*59;}\VՁwHjzfT4ZH{!CUyaÊ%|+ 4`fw{l `R2זѶr% &8UL7vk;R(Tq+-${%˓2Чoȉ$~cF"$ kB.Em1%g] o$1zJ4ѵs)!M닳қ0tOh8`rDL /f-,;Ɉ 0H5)KA &49FƄNc'eAcY %I@tBz2T V[6##2Izgg9*0҄šH$S.{ 𽾺)3 D|)M-#w2dĈHPPj"T%}]}IL47uqW-hoB՗jҢPV=uP?IɝlG&%b0FՉYAaQ Gr}TLN'\n%'0ݣd=D Pץ~Ae<, +``.4OX$Kق(i az!n _XK+|u,F^oQӛ$׃gIDߚiN(ݰ|Kф߲vww$x3p[Y{Hp2S&ȥGe|opF=C6Z%_TX= v{ؿq>mZ _}{~o[~_^ sv` )0pC$krґV߭LYZ [!ZvAVKf=dy*!'\ R'(pށz'3Rǎ݂@y4 ȧ (z;oo4W0o٦ok{Ccٮ'LҊ}QTMڲ'ނ>uh2@}{x!t?M;KHF4 6M>.ɬySZb#D'H*KE9rJ9;%+ˊsl^K}>+'Gfpz9Sl}P" 5C!0Zt߸Ӻ(#A$mz8UG-ť y1uEW?By $[S/\nC-F(OEE):"@9/";{( L,AeZtLp*MBGzǘGA&}V ==PV<NCE}r&*VB83JlVa"ֵvrOpBq*):Es!bAA!oUǧ߿?;v7 Q[rc1\`9-`E1OA{XLEQuuG7Xׁ$DANW{KІ Z\SiLC@U`b`zuM/܋gXoPiAˢ}XՀN)1'vm*K_ R *cvMIuA c@ 9ZNp"nMdP|˸2\4ݞ&+ WzEClجIdznmj5G[֛)D@M^%n&˳LσtS}&6 UVT'(7K9%*aN/**0i<>4?޶KT,&zGKEuQh×cMxJ5ܹcà,w_vu aVn#@C6NsG͘)|6:HثuΫJ]H^w~23pN,kӊD3MnUYC.W%2<56_gͮ)w41ԃp9]ZȺ3lҕy!Dq:}=2ʒ΅70udzm@vdc_Ax23"'t㴆A^Ȏ1v){=&FZdH407JUub{.2z]XR&`}C+.RZ7 ]C 2HwJfPh+-ƛ(!=+x#xV'۾h[U\ >Uv] 7V$Į$6|Dysؼϓ6>X`kB,EF.^쟠)diBj}T8VR[\ſCBɮ_( h<2j(Wl0ݪ~f#…f( ^v "hƐyUf \YӃRJrR [r)aW pz,~EՖt{ȐFR5m MW,R_[9u/>5$)&Clca{"sj| .|=|Of>}T٬+֡ͮK8Xln5H ZoÏyj{mo|*Z 1Wq­M/:7[W ohX7!-^SQLwfw'G"_tؐ-ڪ>qsٺib}Ӳlڵ2p6 @w 15-$PGuOT:Tǃvu8L)sh0n#QDvxVoL[UϠß>hkKDd[dncѾ7i_yﲍ21&c,f4D.1&~0YBbE#Od4ZZ̛4{~ӛS, (a$fsbe4K¹!I%vr`ALzPFo>C=f, LFHGxGXHH# ⰐDi.. /U>sXHx<#&I?T`5 v]Wv {۳̱4_Ps[Gv5v-z{e-*ꏲn-Iw|݃gUpRRV qذZ!8b`x6c݊E B&+BW֪ެy)ye&e\MU~\(&jn{MMn4LAcU@rzjzӜ4mg,O\x+8H9z%~DJ]n+Y0l)hCa6 K Z~`?Bu$ xxBXSf9n30>[ 0i;A藶$ Q3Gh}д=D(S; ':.7rm+R:M(CT;Pnרë5N N48ԞY]p]Ա wAuP(Q\&u 8\ypVZJPh(Y5JT: A-kγu-VnKº+ܝJFT!]^X}_H8bmQjs+hVf}rqMTcGw7dS8=ǻlO"0x6}q-$y?)N .ۄMۉfg.6y5olY􉭆n`i<#EerG0chL9ft[Ǿ>Kfxn@0Emx~:>o2?^7a#G[>XʃPt*ϳx0!;6؁mJ rtV|:^~Bgi,0_ӽ~ Ėb41^La%e:zs2hA AQv+RA,75`u}_f41m~xui <wR-3𘵘6/l֐'B>!`5ZcWU0䇮pCqsߒ\ 5Y$xC c'܏vSYᢶ.E^ewLR,Cx340031Q,+dx6M9{wk+qIODCļ̜ԢbWϸ2=.fPYyYFȊN78+ m(I60xCxmSMhA&Y1mENb67HjҮFkb{&kww֙F7/ << 7'wg7?mM2o{3MM3@cUnub9@@9g\1[7<;$ ffF!rEgҍ 5#G tZ <8fOfI4: ABJ'>q0fSsBԃzk8x&9**QM%\bZm+[Nn(s×کf8^+ck,u\SeoK6[~qn,>|/5RZ`vπR;\|rCb #.vQ A{RWK_R}=m,1-XBsHճ}bu,|+sCN ao]bڧ BVvc6[WJe_+/ot.OZ.Y\~~iI'6}I`ƞi"xKyxYC^x!J $N.$jyxuF Lx+LJ*IJMO5&Z x q+(tv v}<\C2SKJ *J* Ӌ2*32KQEKRs rKRKӋQSZTGaVf^VBDfxK)MIU q+(ʄx::ye[ Mx&(?W!%$3X/9(U!3 D8 Li%ڪTeUp)(L x/jb% E9%%V)z9@3s ZzA 19;1=6`G$5 '$$1X=/9'83-3%,5'r;!h0шDdԐVRpI-LjCSdVgdS 2pm]i\Ux340031QK,L/Jexm(TӯL/8GpjEPgqr~/.t/Ǽ+̕nܳpSAPe~n! ި~h͵ݕ^CS iBjcAy5lM @!%?zeĎL.O0}´)ũ%z -ͷ/NĴ^]߅%b!FTeU2|ɟ~l,ѧe^kuOx;.inQYǹ ^sw/,' |jQܓ$;"Nx340031Q(,O/L+(ahw;vJ? =9VxVao6_A v[ˀ f1%b-*IYQ#)YNVl@L,>޽{w{Zj;,B ik%ߪK7{{\pJZ.c7r\m ѼJMfˋyLr_M}Gu=?L^rd4ocKi)Aɺ<0ʒ:Cˏ;v_O$9GL4}oW=ȰEQ68kHE^VZ{-–"TNz8x!Ϻی, >K;Ytғ71W£; BW#50g›B(`E/hM?Dj6FrrY> s}7^@8OZpN$|ƾWi#xC[N? fB6*^PhXG %myUSݽG6_ż힏-ICYu|Bf %M<>B4TIƞp ̞@$PdTpz ;cFBIkuE7ϿWhnt۱XT X tIUD9qtZdc{-m<| ՟>#dʣ.OLHi &cc㹭L wcKpL`06)L"|sRr_Mz/W8юZOVEa: Z!sR]A'88,b(TFeWRA]x=fPӈ.|~I3c8Ga)=>vqBòW- VѰ~@n0pQcו4Ҹ!w+yU+?hh$9× ƙHEi>|OERIJtQ%@Q )"}khK@ߍXW*(=OxuD=݉qfnV`i0 x340031Q,+dx6M9{wk+qIOD P(I-I,I-IL/fo~wZ]5%5M o/8d"?x340031Q,+dx6M9{wk+qIODCʂ̴JBߥWμSU*ͷn)" TxHw_kwP$FxuD=)au. (K-*ϳU738ydU;\ VV .řy1gExkbjbpJD5%6\-]^OJ koxzui&f.M.xkbjbpJ$D#y'g[-"`8  ~o/xeK46+JxkbjbpJrũ6sޫ+㻰\L{*]mx{zu'D׉s߰+*8$Nfd߼ёĺ .xzu'FC-B*\x8 ?(3R OmxxĴIDA/=$3=/(WaGM{_ZپbB܍j<6x+Lg7u?_ˤ;5dQ[?8n`=<َKyN7rN~ Mrl?y*wf}ߋNk|Nr3Y&ўӿyv́FLVPq? L &QVWw2JJUAXj~ɖj!B'T=GiZufVATixk`j`FVLv9yA x340031Q,+dx6M9{wk+qIOD P(I-I,I-IL/fq32| ?L#x340031Q,+dx6M9{wk+qIODCʂ̴J\O_]Ee 1[߳7K1"l"Ax[4dBvIjnANbI^JjZbiNIZfNIjQBfnA~QBqIQf^:DpRQvԒҢɇص$s lQh47KsW.ѦQZ KKY!9 f-Iv~4&{Kk++ded&旤bhGܼVz.ŹE%y%zvQZvu xk`8!vbH5 P9BʼnwTQCl;xzu7F L_ x340031Q q+(aX_%oJ;ZԬCe>ή~`e?]~?]et㞕l *uts c~!1ޠn~Peũ%z "'288Ck ?M @ ?(3ҭ )OΫ$Q?Mu_x{ryojnANbIj|iIfNDE! ũ !Ei y E )Yy : )) % %̼Ĝl1HX8$3/XrZm +4x340031Q,+dx6M9{wk+qIOD P(I-I,I-IL/f<\L~c+ߒf{Y @x340031Q,+dx6M9{wk+qIODCʂ̴J:ojy䲝]w.T˸x]X. oOx29dkܜU49Eux˸qJ;Y~YQXUb{ x340031Q,+dx6M9{wk+qIOD P(I-I,I-IL/fh=1.6'] )./.gitignore0000644000175000017500000000004211670412422010752 0ustar jdjd*.egg-info/ *.py[co] build/ dist/