diveintopython3-20110517-77958af.orig/0000755000000000000000000000000011773544727015610 5ustar rootrootdiveintopython3-20110517-77958af.orig/blank.html0000644000000000000000000000072611773544727017572 0ustar rootroot This page intentionally left blank - Dive Into Python 3

This page intentionally left blank. diveintopython3-20110517-77958af.orig/generators.html0000644000000000000000000011652211773544727020656 0ustar rootroot Closures & Generators - Dive Into Python 3

  

You are here: Home Dive Into Python 3

Difficulty level: ♦♦♦♢♢

Closures & Generators

My spelling is Wobbly. It’s good spelling but it Wobbles, and the letters get in the wrong places.
— Winnie-the-Pooh

 

Diving In

Having grown up the son of a librarian and an English major, I have always been fascinated by languages. Not programming languages. Well yes, programming languages, but also natural languages. Take English. English is a schizophrenic language that borrows words from German, French, Spanish, and Latin (to name a few). Actually, “borrows” is the wrong word; “pillages” is more like it. Or perhaps “assimilates” — like the Borg. Yes, I like that.

We are the Borg. Your linguistic and etymological distinctiveness will be added to our own. Resistance is futile.

In this chapter, you’re going to learn about plural nouns. Also, functions that return other functions, advanced regular expressions, and generators. But first, let’s talk about how to make plural nouns. (If you haven’t read the chapter on regular expressions, now would be a good time. This chapter assumes you understand the basics of regular expressions, and it quickly descends into more advanced uses.)

If you grew up in an English-speaking country or learned English in a formal school setting, you’re probably familiar with the basic rules:

(I know, there are a lot of exceptions. Man becomes men and woman becomes women, but human becomes humans. Mouse becomes mice and louse becomes lice, but house becomes houses. Knife becomes knives and wife becomes wives, but lowlife becomes lowlifes. And don’t even get me started on words that are their own plural, like sheep, deer, and haiku.)

Other languages, of course, are completely different.

Let’s design a Python library that automatically pluralizes English nouns. We’ll start with just these four rules, but keep in mind that you’ll inevitably need to add more.

I Know, Let’s Use Regular Expressions!

So you’re looking at words, which, at least in English, means you’re looking at strings of characters. You have rules that say you need to find different combinations of characters, then do different things to them. This sounds like a job for regular expressions!

[download plural1.py]

import re

def plural(noun):          
    if re.search('[sxz]$', noun):             
        return re.sub('$', 'es', noun)        
    elif re.search('[^aeioudgkprt]h$', noun):
        return re.sub('$', 'es', noun)       
    elif re.search('[^aeiou]y$', noun):      
        return re.sub('y$', 'ies', noun)     
    else:
        return noun + 's'
  1. This is a regular expression, but it uses a syntax you didn’t see in Regular Expressions. The square brackets mean “match exactly one of these characters.” So [sxz] means “s, or x, or z”, but only one of them. The $ should be familiar; it matches the end of string. Combined, this regular expression tests whether noun ends with s, x, or z.
  2. This re.sub() function performs regular expression-based string substitutions.

Let’s look at regular expression substitutions in more detail.

>>> import re
>>> re.search('[abc]', 'Mark')    
<_sre.SRE_Match object at 0x001C1FA8>
>>> re.sub('[abc]', 'o', 'Mark')  
'Mork'
>>> re.sub('[abc]', 'o', 'rock')  
'rook'
>>> re.sub('[abc]', 'o', 'caps')  
'oops'
  1. Does the string Mark contain a, b, or c? Yes, it contains a.
  2. OK, now find a, b, or c, and replace it with o. Mark becomes Mork.
  3. The same function turns rock into rook.
  4. You might think this would turn caps into oaps, but it doesn’t. re.sub replaces all of the matches, not just the first one. So this regular expression turns caps into oops, because both the c and the a get turned into o.

And now, back to the plural() function…

def plural(noun):          
    if re.search('[sxz]$', noun):            
        return re.sub('$', 'es', noun)         
    elif re.search('[^aeioudgkprt]h$', noun):  
        return re.sub('$', 'es', noun)
    elif re.search('[^aeiou]y$', noun):        
        return re.sub('y$', 'ies', noun)     
    else:
        return noun + 's'
  1. Here, you’re replacing the end of the string (matched by $) with the string es. In other words, adding es to the string. You could accomplish the same thing with string concatenation, for example noun + 'es', but I chose to use regular expressions for each rule, for reasons that will become clear later in the chapter.
  2. Look closely, this is another new variation. The ^ as the first character inside the square brackets means something special: negation. [^abc] means “any single character except a, b, or c”. So [^aeioudgkprt] means any character except a, e, i, o, u, d, g, k, p, r, or t. Then that character needs to be followed by h, followed by end of string. You’re looking for words that end in H where the H can be heard.
  3. Same pattern here: match words that end in Y, where the character before the Y is not a, e, i, o, or u. You’re looking for words that end in Y that sounds like I.

Let’s look at negation regular expressions in more detail.

>>> import re
>>> re.search('[^aeiou]y$', 'vacancy')  
<_sre.SRE_Match object at 0x001C1FA8>
>>> re.search('[^aeiou]y$', 'boy')      
>>> 
>>> re.search('[^aeiou]y$', 'day')
>>> 
>>> re.search('[^aeiou]y$', 'pita')     
>>> 
  1. vacancy matches this regular expression, because it ends in cy, and c is not a, e, i, o, or u.
  2. boy does not match, because it ends in oy, and you specifically said that the character before the y could not be o. day does not match, because it ends in ay.
  3. pita does not match, because it does not end in y.
>>> re.sub('y$', 'ies', 'vacancy')               
'vacancies'
>>> re.sub('y$', 'ies', 'agency')
'agencies'
>>> re.sub('([^aeiou])y$', r'\1ies', 'vacancy')  
'vacancies'
  1. This regular expression turns vacancy into vacancies and agency into agencies, which is what you wanted. Note that it would also turn boy into boies, but that will never happen in the function because you did that re.search first to find out whether you should do this re.sub.
  2. Just in passing, I want to point out that it is possible to combine these two regular expressions (one to find out if the rule applies, and another to actually apply it) into a single regular expression. Here’s what that would look like. Most of it should look familiar: you’re using a remembered group, which you learned in Case study: Parsing Phone Numbers. The group is used to remember the character before the letter y. Then in the substitution string, you use a new syntax, \1, which means “hey, that first group you remembered? put it right here.” In this case, you remember the c before the y; when you do the substitution, you substitute c in place of c, and ies in place of y. (If you have more than one remembered group, you can use \2 and \3 and so on.)

Regular expression substitutions are extremely powerful, and the \1 syntax makes them even more powerful. But combining the entire operation into one regular expression is also much harder to read, and it doesn’t directly map to the way you first described the pluralizing rules. You originally laid out rules like “if the word ends in S, X, or Z, then add ES”. If you look at this function, you have two lines of code that say “if the word ends in S, X, or Z, then add ES”. It doesn’t get much more direct than that.

A List Of Functions

Now you’re going to add a level of abstraction. You started by defining a list of rules: if this, do that, otherwise go to the next rule. Let’s temporarily complicate part of the program so you can simplify another part.

[download plural2.py]

import re

def match_sxz(noun):
    return re.search('[sxz]$', noun)

def apply_sxz(noun):
    return re.sub('$', 'es', noun)

def match_h(noun):
    return re.search('[^aeioudgkprt]h$', noun)

def apply_h(noun):
    return re.sub('$', 'es', noun)

def match_y(noun):                             
    return re.search('[^aeiou]y$', noun)
        
def apply_y(noun):                             
    return re.sub('y$', 'ies', noun)

def match_default(noun):
    return True

def apply_default(noun):
    return noun + 's'

rules = ((match_sxz, apply_sxz),               
         (match_h, apply_h),
         (match_y, apply_y),
         (match_default, apply_default)
         )

def plural(noun):           
    for matches_rule, apply_rule in rules:       
        if matches_rule(noun):
            return apply_rule(noun)
  1. Now, each match rule is its own function which returns the results of calling the re.search() function.
  2. Each apply rule is also its own function which calls the re.sub() function to apply the appropriate pluralization rule.
  3. Instead of having one function (plural()) with multiple rules, you have the rules data structure, which is a sequence of pairs of functions.
  4. Since the rules have been broken out into a separate data structure, the new plural() function can be reduced to a few lines of code. Using a for loop, you can pull out the match and apply rules two at a time (one match, one apply) from the rules structure. On the first iteration of the for loop, matches_rule will get match_sxz, and apply_rule will get apply_sxz. On the second iteration (assuming you get that far), matches_rule will be assigned match_h, and apply_rule will be assigned apply_h. The function is guaranteed to return something eventually, because the final match rule (match_default) simply returns True, meaning the corresponding apply rule (apply_default) will always be applied.

The reason this technique works is that everything in Python is an object, including functions. The rules data structure contains functions — not names of functions, but actual function objects. When they get assigned in the for loop, then matches_rule and apply_rule are actual functions that you can call. On the first iteration of the for loop, this is equivalent to calling matches_sxz(noun), and if it returns a match, calling apply_sxz(noun).

If this additional level of abstraction is confusing, try unrolling the function to see the equivalence. The entire for loop is equivalent to the following:


def plural(noun):
    if match_sxz(noun):
        return apply_sxz(noun)
    if match_h(noun):
        return apply_h(noun)
    if match_y(noun):
        return apply_y(noun)
    if match_default(noun):
        return apply_default(noun)

The benefit here is that the plural() function is now simplified. It takes a sequence of rules, defined elsewhere, and iterates through them in a generic fashion.

  1. Get a match rule
  2. Does it match? Then call the apply rule and return the result.
  3. No match? Go to step 1.

The rules could be defined anywhere, in any way. The plural() function doesn’t care.

Now, was adding this level of abstraction worth it? Well, not yet. Let’s consider what it would take to add a new rule to the function. In the first example, it would require adding an if statement to the plural() function. In this second example, it would require adding two functions, match_foo() and apply_foo(), and then updating the rules sequence to specify where in the order the new match and apply functions should be called relative to the other rules.

But this is really just a stepping stone to the next section. Let’s move on…

A List Of Patterns

Defining separate named functions for each match and apply rule isn’t really necessary. You never call them directly; you add them to the rules sequence and call them through there. Furthermore, each function follows one of two patterns. All the match functions call re.search(), and all the apply functions call re.sub(). Let’s factor out the patterns so that defining new rules can be easier.

[download plural3.py]

import re

def build_match_and_apply_functions(pattern, search, replace):
    def matches_rule(word):                                     
        return re.search(pattern, word)
    def apply_rule(word):                                       
        return re.sub(search, replace, word)
    return (matches_rule, apply_rule)                           
  1. build_match_and_apply_functions() is a function that builds other functions dynamically. It takes pattern, search and replace, then defines a matches_rule() function which calls re.search() with the pattern that was passed to the build_match_and_apply_functions() function, and the word that was passed to the matches_rule() function you’re building. Whoa.
  2. Building the apply function works the same way. The apply function is a function that takes one parameter, and calls re.sub() with the search and replace parameters that were passed to the build_match_and_apply_functions() function, and the word that was passed to the apply_rule() function you’re building. This technique of using the values of outside parameters within a dynamic function is called closures. You’re essentially defining constants within the apply function you’re building: it takes one parameter (word), but it then acts on that plus two other values (search and replace) which were set when you defined the apply function.
  3. Finally, the build_match_and_apply_functions() function returns a tuple of two values: the two functions you just created. The constants you defined within those functions (pattern within the matches_rule() function, and search and replace within the apply_rule() function) stay with those functions, even after you return from build_match_and_apply_functions(). That’s insanely cool.

If this is incredibly confusing (and it should be, this is weird stuff), it may become clearer when you see how to use it.

patterns = \                                                        
  (
    ('[sxz]$',           '$',  'es'),
    ('[^aeioudgkprt]h$', '$',  'es'),
    ('(qu|[^aeiou])y$',  'y$', 'ies'),
    ('$',                '$',  's')                                 
  )
rules = [build_match_and_apply_functions(pattern, search, replace)  
         for (pattern, search, replace) in patterns]
  1. Our pluralization “rules” are now defined as a tuple of tuples of strings (not functions). The first string in each group is the regular expression pattern that you would use in re.search() to see if this rule matches. The second and third strings in each group are the search and replace expressions you would use in re.sub() to actually apply the rule to turn a noun into its plural.
  2. There’s a slight change here, in the fallback rule. In the previous example, the match_default() function simply returned True, meaning that if none of the more specific rules matched, the code would simply add an s to the end of the given word. This example does something functionally equivalent. The final regular expression asks whether the word has an end ($ matches the end of a string). Of course, every string has an end, even an empty string, so this expression always matches. Thus, it serves the same purpose as the match_default() function that always returned True: it ensures that if no more specific rule matches, the code adds an s to the end of the given word.
  3. This line is magic. It takes the sequence of strings in patterns and turns them into a sequence of functions. How? By “mapping” the strings to the build_match_and_apply_functions() function. That is, it takes each triplet of strings and calls the build_match_and_apply_functions() function with those three strings as arguments. The build_match_and_apply_functions() function returns a tuple of two functions. This means that rules ends up being functionally equivalent to the previous example: a list of tuples, where each tuple is a pair of functions. The first function is the match function that calls re.search(), and the second function is the apply function that calls re.sub().

Rounding out this version of the script is the main entry point, the plural() function.

def plural(noun):
    for matches_rule, apply_rule in rules:  
        if matches_rule(noun):
            return apply_rule(noun)
  1. Since the rules list is the same as the previous example (really, it is), it should come as no surprise that the plural() function hasn’t changed at all. It’s completely generic; it takes a list of rule functions and calls them in order. It doesn’t care how the rules are defined. In the previous example, they were defined as separate named functions. Now they are built dynamically by mapping the output of the build_match_and_apply_functions() function onto a list of raw strings. It doesn’t matter; the plural() function still works the same way.

A File Of Patterns

You’ve factored out all the duplicate code and added enough abstractions so that the pluralization rules are defined in a list of strings. The next logical step is to take these strings and put them in a separate file, where they can be maintained separately from the code that uses them.

First, let’s create a text file that contains the rules you want. No fancy data structures, just whitespace-delimited strings in three columns. Let’s call it plural4-rules.txt.

[download plural4-rules.txt]

[sxz]$               $    es
[^aeioudgkprt]h$     $    es
[^aeiou]y$          y$    ies
$                    $    s

Now let’s see how you can use this rules file.

[download plural4.py]

import re

def build_match_and_apply_functions(pattern, search, replace):  
    def matches_rule(word):
        return re.search(pattern, word)
    def apply_rule(word):
        return re.sub(search, replace, word)
    return (matches_rule, apply_rule)

rules = []
with open('plural4-rules.txt', encoding='utf-8') as pattern_file:  
    for line in pattern_file:                                      
        pattern, search, replace = line.split(None, 3)             
        rules.append(build_match_and_apply_functions(              
                pattern, search, replace))
  1. The build_match_and_apply_functions() function has not changed. You’re still using closures to build two functions dynamically that use variables defined in the outer function.
  2. The global open() function opens a file and returns a file object. In this case, the file we’re opening contains the pattern strings for pluralizing nouns. The with statement creates what’s called a context: when the with block ends, Python will automatically close the file, even if an exception is raised inside the with block. You’ll learn more about with blocks and file objects in the Files chapter.
  3. The for line in <fileobject> idiom reads data from the open file, one line at a time, and assigns the text to the line variable. You’ll learn more about reading from files in the Files chapter.
  4. Each line in the file really has three values, but they’re separated by whitespace (tabs or spaces, it makes no difference). To split it out, use the split() string method. The first argument to the split() method is None, which means “split on any whitespace (tabs or spaces, it makes no difference).” The second argument is 3, which means “split on whitespace 3 times, then leave the rest of the line alone.” A line like [sxz]$ $ es will be broken up into the list ['[sxz]$', '$', 'es'], which means that pattern will get '[sxz]$', search will get '$', and replace will get 'es'. That’s a lot of power in one little line of code.
  5. Finally, you pass pattern, search, and replace to the build_match_and_apply_functions() function, which returns a tuple of functions. You append this tuple to the rules list, and rules ends up storing the list of match and apply functions that the plural() function expects.

The improvement here is that you’ve completely separated the pluralization rules into an external file, so it can be maintained separately from the code that uses it. Code is code, data is data, and life is good.

Generators

Wouldn’t it be grand to have a generic plural() function that parses the rules file? Get rules, check for a match, apply appropriate transformation, go to next rule. That’s all the plural() function has to do, and that’s all the plural() function should do.

[download plural5.py]

def rules(rules_filename):
    with open(rules_filename, encoding='utf-8') as pattern_file:
        for line in pattern_file:
            pattern, search, replace = line.split(None, 3)
            yield build_match_and_apply_functions(pattern, search, replace)

def plural(noun, rules_filename='plural5-rules.txt'):
    for matches_rule, apply_rule in rules(rules_filename):
        if matches_rule(noun):
            return apply_rule(noun)
    raise ValueError('no matching rule for {0}'.format(noun))

How the heck does that work? Let’s look at an interactive example first.

>>> def make_counter(x):
...     print('entering make_counter')
...     while True:
...         yield x                    
...         print('incrementing x')
...         x = x + 1
... 
>>> counter = make_counter(2)          
>>> counter                            
<generator object at 0x001C9C10>
>>> next(counter)                      
entering make_counter
2
>>> next(counter)                      
incrementing x
3
>>> next(counter)                      
incrementing x
4
  1. The presence of the yield keyword in make_counter means that this is not a normal function. It is a special kind of function which generates values one at a time. You can think of it as a resumable function. Calling it will return a generator that can be used to generate successive values of x.
  2. To create an instance of the make_counter generator, just call it like any other function. Note that this does not actually execute the function code. You can tell this because the first line of the make_counter() function calls print(), but nothing has been printed yet.
  3. The make_counter() function returns a generator object.
  4. The next() function takes a generator object and returns its next value. The first time you call next() with the counter generator, it executes the code in make_counter() up to the first yield statement, then returns the value that was yielded. In this case, that will be 2, because you originally created the generator by calling make_counter(2).
  5. Repeatedly calling next() with the same generator object resumes exactly where it left off and continues until it hits the next yield statement. All variables, local state, &c. are saved on yield and restored on next(). The next line of code waiting to be executed calls print(), which prints incrementing x. After that, the statement x = x + 1. Then it loops through the while loop again, and the first thing it hits is the statement yield x, which saves the state of everything and returns the current value of x (now 3).
  6. The second time you call next(counter), you do all the same things again, but this time x is now 4.

Since make_counter sets up an infinite loop, you could theoretically do this forever, and it would just keep incrementing x and spitting out values. But let’s look at more productive uses of generators instead.

A Fibonacci Generator

[download fibonacci.py]

def fib(max):
    a, b = 0, 1          
    while a < max:
        yield a          
        a, b = b, a + b  
  1. The Fibonacci sequence is a sequence of numbers where each number is the sum of the two numbers before it. It starts with 0 and 1, goes up slowly at first, then more and more rapidly. To start the sequence, you need two variables: a starts at 0, and b starts at 1.
  2. a is the current number in the sequence, so yield it.
  3. b is the next number in the sequence, so assign that to a, but also calculate the next value (a + b) and assign that to b for later use. Note that this happens in parallel; if a is 3 and b is 5, then a, b = b, a + b will set a to 5 (the previous value of b) and b to 8 (the sum of the previous values of a and b).

So you have a function that spits out successive Fibonacci numbers. Sure, you could do that with recursion, but this way is easier to read. Also, it works well with for loops.

>>> from fibonacci import fib
>>> for n in fib(1000):      
...     print(n, end=' ')    
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> list(fib(1000))          
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]
  1. You can use a generator like fib() in a for loop directly. The for loop will automatically call the next() function to get values from the fib() generator and assign them to the for loop index variable (n).
  2. Each time through the for loop, n gets a new value from the yield statement in fib(), and all you have to do is print it out. Once fib() runs out of numbers (a becomes bigger than max, which in this case is 1000), then the for loop exits gracefully.
  3. This is a useful idiom: pass a generator to the list() function, and it will iterate through the entire generator (just like the for loop in the previous example) and return a list of all the values.

A Plural Rule Generator

Let’s go back to plural5.py and see how this version of the plural() function works.

def rules(rules_filename):
    with open(rules_filename, encoding='utf-8') as pattern_file:
        for line in pattern_file:
            pattern, search, replace = line.split(None, 3)                   
            yield build_match_and_apply_functions(pattern, search, replace)  

def plural(noun, rules_filename='plural5-rules.txt'):
    for matches_rule, apply_rule in rules(rules_filename):                   
        if matches_rule(noun):
            return apply_rule(noun)
    raise ValueError('no matching rule for {0}'.format(noun))
  1. No magic here. Remember that the lines of the rules file have three values separated by whitespace, so you use line.split(None, 3) to get the three “columns” and assign them to three local variables.
  2. And then you yield. What do you yield? Two functions, built dynamically with your old friend, build_match_and_apply_functions(), which is identical to the previous examples. In other words, rules() is a generator that spits out match and apply functions on demand.
  3. Since rules() is a generator, you can use it directly in a for loop. The first time through the for loop, you will call the rules() function, which will open the pattern file, read the first line, dynamically build a match function and an apply function from the patterns on that line, and yield the dynamically built functions. The second time through the for loop, you will pick up exactly where you left off in rules() (which was in the middle of the for line in pattern_file loop). The first thing it will do is read the next line of the file (which is still open), dynamically build another match and apply function based on the patterns on that line in the file, and yield the two functions.

What have you gained over stage 4? Startup time. In stage 4, when you imported the plural4 module, it read the entire patterns file and built a list of all the possible rules, before you could even think about calling the plural() function. With generators, you can do everything lazily: you read the first rule and create functions and try them, and if that works you don’t ever read the rest of the file or create any other functions.

What have you lost? Performance! Every time you call the plural() function, the rules() generator starts over from the beginning — which means re-opening the patterns file and reading from the beginning, one line at a time.

What if you could have the best of both worlds: minimal startup cost (don’t execute any code on import), and maximum performance (don’t build the same functions over and over again). Oh, and you still want to keep the rules in a separate file (because code is code and data is data), just as long as you never have to read the same line twice.

To do that, you’ll need to build your own iterator. But before you do that, you need to learn about Python classes.

Further Reading

© 2001–11 Mark Pilgrim diveintopython3-20110517-77958af.orig/troubleshooting.html0000644000000000000000000001170411773544727021730 0ustar rootroot Troubleshooting - Dive Into Python 3

  

You are here: Home Dive Into Python 3

Troubleshooting

Where’s the ANY key?
variously attributed

 

Diving In

FIXME

Getting to the Command Line

Throughout this book, there are examples of executing Python programs from the command line. Where is the command line?

On Linux, look in your Applications menu for a program called Terminal. (It may be in a submenu like Accessories or System.)

On Mac OS X, there is an application called Terminal in your /Applications/Utilities/ folder. To get there, click on your desktop, open the Go menu, select Go to folder..., and type /Applications/Utilities/. Then double-click the Terminal program.

On Windows, click Start, select Run..., type cmd, and press ENTER.

Running Python on the command line

Once you get to the command line, you should be able to run the Python interactive shell. On the Linux or Mac OS X command line, type python3 and press ENTER. On the Windows command line, type c:\python31\python and press ENTER. If all goes well, you should see something like this:

you@localhost:~$ python3
Python 3.1 (r31:73572, Jul 28 2009, 06:52:23) 
[GCC 4.2.4 (Ubuntu 4.2.4-1ubuntu4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

(Type exit() and press ENTER to exit the Python interactive shell and go back to the command line. This works on all platforms.)

If you get a “command not found” error, it probably means you don’t have Python 3 installed.

you@localhost:~$ python3
bash: python3: command not found

On the other hand, if you get into a Python interactive shell but the version number is not what you expected, you may have more than one version of Python installed. This happens most often on Linux and Mac OS X systems, where an older version of Python is pre-installed. You can install the latest version without deleting the older version (they will live side-by-side in peace), but you will need to be more specific when you run Python from the command line.

For example, on my home Linux box, I have several versions of Python installed so I can test the Python software that I write. To run a specific version, I can type python3.0, python3.1, or python2.6.

mark@atlantis:~$ python3.0
Python 3.0.1+ (r301:69556, Apr 15 2009, 17:25:52)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
mark@atlantis:~$ python3.1
Python 3.1 (r31:73572, Jul 28 2009, 06:52:23) 
[GCC 4.2.4 (Ubuntu 4.2.4-1ubuntu4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
mark@atlantis:~$ python2.6
Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41) 
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()

© 2001–11 Mark Pilgrim diveintopython3-20110517-77958af.orig/porting-code-to-python-3-with-2to3.html0000644000000000000000000021543611773544727024740 0ustar rootroot Porting code to Python 3 with 2to3 - Dive Into Python 3

  

You are here: Home Dive Into Python 3

Difficulty level: ♦♦♦♦♦

Porting Code to Python 3 with 2to3

Life is pleasant. Death is peaceful. It’s the transition that’s troublesome.
— Isaac Asimov (attributed)

 

Diving In

So much has changed between Python 2 and Python 3, there are vanishingly few programs that will run unmodified under both. But don’t despair! To help with this transition, Python 3 comes with a utility script called 2to3, which takes your actual Python 2 source code as input and auto-converts as much as it can to Python 3. Case study: porting chardet to Python 3 describes how to run the 2to3 script, then shows some things it can’t fix automatically. This appendix documents what it can fix automatically.

print statement

In Python 2, print was a statement. Whatever you wanted to print simply followed the print keyword. In Python 3, print() is a function. Whatever you want to print, pass it to print() like any other function.
Notes Python 2 Python 3
print print()
print 1 print(1)
print 1, 2 print(1, 2)
print 1, 2, print(1, 2, end=' ')
print >>sys.stderr, 1, 2, 3 print(1, 2, 3, file=sys.stderr)

  1. To print a blank line, call print() without any arguments.
  2. To print a single value, call print() with one argument.
  3. To print two values separated by a space, call print() with two arguments.
  4. This one is a little tricky. In Python 2, if you ended a print statement with a comma, it would print the values separated by spaces, then print a trailing space, then stop without printing a carriage return. (Technically, it’s a little more complicated than that. The print statement in Python 2 used a now-deprecated attribute called softspace. Instead of printing a space, Python 2 would set sys.stdout.softspace to 1. The space character wasn’t really printed until something else got printed on the same line. If the next print statement printed a carriage return, sys.stdout.softspace would be set to 0 and the space would never be printed. You probably never noticed the difference unless your application was sensitive to the presence or absence of trailing whitespace in print-generated output.) In Python 3, the way to do this is to pass end=' ' as a keyword argument to the print() function. The end argument defaults to '\n' (a carriage return), so overriding it will suppress the carriage return after printing the other arguments.
  5. In Python 2, you could redirect the output to a pipe — like sys.stderr — by using the >>pipe_name syntax. In Python 3, the way to do this is to pass the pipe in the file keyword argument. The file argument defaults to sys.stdout (standard out), so overriding it will output to a different pipe instead.

Unicode string literals

Python 2 had two string types: Unicode strings and non-Unicode strings. Python 3 has one string type: Unicode strings.
Notes Python 2 Python 3
u'PapayaWhip' 'PapayaWhip'
ur'PapayaWhip\foo' r'PapayaWhip\foo'

  1. Unicode string literals are simply converted into string literals, which, in Python 3, are always Unicode.
  2. Unicode raw strings (in which Python does not auto-escape backslashes) are converted to raw strings. In Python 3, raw strings are always Unicode.

unicode() global function

Python 2 had two global functions to coerce objects into strings: unicode() to coerce them into Unicode strings, and str() to coerce them into non-Unicode strings. Python 3 has only one string type, Unicode strings, so the str() function is all you need. (The unicode() function no longer exists.)
Notes Python 2 Python 3
unicode(anything) str(anything)

long data type

Python 2 had separate int and long types for non-floating-point numbers. An int could not be any larger than sys.maxint, which varied by platform. Longs were defined by appending an L to the end of the number, and they could be, well, longer than ints. In Python 3, there is only one integer type, called int, which mostly behaves like the long type in Python 2. Since there are no longer two types, there is no need for special syntax to distinguish them.

Further reading: PEP 237: Unifying Long Integers and Integers.
Notes Python 2 Python 3
x = 1000000000000L x = 1000000000000
x = 0xFFFFFFFFFFFFL x = 0xFFFFFFFFFFFF
long(x) int(x)
type(x) is long type(x) is int
isinstance(x, long) isinstance(x, int)

  1. Base 10 long integer literals become base 10 integer literals.
  2. Base 16 long integer literals become base 16 integer literals.
  3. In Python 3, the old long() function no longer exists, since longs don’t exist. To coerce a variable to an integer, use the int() function.
  4. To check whether a variable is an integer, get its type and compare it to int, not long.
  5. You can also use the isinstance() function to check data types; again, use int, not long, to check for integers.

<> comparison

Python 2 supported <> as a synonym for !=, the not-equals comparison operator. Python 3 supports the != operator, but not <>.
Notes Python 2 Python 3
if x <> y: if x != y:
if x <> y <> z: if x != y != z:

  1. A simple comparison.
  2. A more complex comparison between three values.

has_key() dictionary method

In Python 2, dictionaries had a has_key() method to test whether the dictionary had a certain key. In Python 3, this method no longer exists. Instead, you need to use the in operator.
Notes Python 2 Python 3
a_dictionary.has_key('PapayaWhip') 'PapayaWhip' in a_dictionary
a_dictionary.has_key(x) or a_dictionary.has_key(y) x in a_dictionary or y in a_dictionary
a_dictionary.has_key(x or y) (x or y) in a_dictionary
a_dictionary.has_key(x + y) (x + y) in a_dictionary
x + a_dictionary.has_key(y) x + (y in a_dictionary)

  1. The simplest form.
  2. The in operator takes precedence over the or operator, so there is no need for parentheses around x in a_dictionary or around y in a_dictionary.
  3. On the other hand, you do need parentheses around x or y here, for the same reason — in takes precedence over or. (Note: this code is completely different from the previous line. Python interprets x or y first, which results in either x (if x is true in a boolean context) or y. Then it takes that singular value and checks whether it is a key in a_dictionary.)
  4. The + operator takes precedence over the in operator, so this form technically doesn’t need parentheses around x + y, but 2to3 includes them anyway.
  5. This form definitely needs parentheses around y in a_dictionary, since the + operator takes precedence over the in operator.

Dictionary methods that return lists

In Python 2, many dictionary methods returned lists. The most frequently used methods were keys(), items(), and values(). In Python 3, all of these methods return dynamic views. In some contexts, this is not a problem. If the method’s return value is immediately passed to another function that iterates through the entire sequence, it makes no difference whether the actual type is a list or a view. In other contexts, it matters a great deal. If you were expecting a complete list with individually addressable elements, your code will choke, because views do not support indexing.
Notes Python 2 Python 3
a_dictionary.keys() list(a_dictionary.keys())
a_dictionary.items() list(a_dictionary.items())
a_dictionary.iterkeys() iter(a_dictionary.keys())
[i for i in a_dictionary.iterkeys()] [i for i in a_dictionary.keys()]
min(a_dictionary.keys()) no change

  1. 2to3 errs on the side of safety, converting the return value from keys() to a static list with the list() function. This will always work, but it will be less efficient than using a view. You should examine the converted code to see if a list is absolutely necessary, or if a view would do.
  2. Another view-to-list conversion, with the items() method. 2to3 will do the same thing with the values() method.
  3. Python 3 does not support the iterkeys() method anymore. Use keys(), and if necessary, convert the view to an iterator with the iter() function.
  4. 2to3 recognizes when the iterkeys() method is used inside a list comprehension, and converts it to the keys() method (without wrapping it in an extra call to iter()). This works because views are iterable.
  5. 2to3 recognizes that the keys() method is immediately passed to a function which iterates through an entire sequence, so there is no need to convert the return value to a list first. The min() function will happily iterate through the view instead. This applies to min(), max(), sum(), list(), tuple(), set(), sorted(), any(), and all().

Modules that have been renamed or reorganized

Several modules in the Python Standard Library have been renamed. Several other modules which are related to each other have been combined or reorganized to make their association more logical.

http

In Python 3, several related HTTP modules have been combined into a single package, http.
Notes Python 2 Python 3
import httplib import http.client
import Cookie import http.cookies
import cookielib import http.cookiejar
import BaseHTTPServer
import SimpleHTTPServer
import CGIHttpServer
import http.server

  1. The http.client module implements a low-level library that can request HTTP resources and interpret HTTP responses.
  2. The http.cookies module provides a Pythonic interface to browser cookies that are sent in a Set-Cookie: HTTP header.
  3. The http.cookiejar module manipulates the actual files on disk that popular web browsers use to store cookies.
  4. The http.server module provides a basic HTTP server.

urllib

Python 2 had a rat’s nest of overlapping modules to parse, encode, and fetch URLs. In Python 3, these have all been refactored and combined in a single package, urllib.
Notes Python 2 Python 3
import urllib import urllib.request, urllib.parse, urllib.error
import urllib2 import urllib.request, urllib.error
import urlparse import urllib.parse
import robotparser import urllib.robotparser
from urllib import FancyURLopener
from urllib import urlencode
from urllib.request import FancyURLopener
from urllib.parse import urlencode
from urllib2 import Request
from urllib2 import HTTPError
from urllib.request import Request
from urllib.error import HTTPError

  1. The old urllib module in Python 2 had a variety of functions, including urlopen() for fetching data and splittype(), splithost(), and splituser() for splitting a URL into its constituent parts. These functions have been reorganized more logically within the new urllib package. 2to3 will also change all calls to these functions so they use the new naming scheme.
  2. The old urllib2 module in Python 2 has been folded into the urllib package in Python 3. All your urllib2 favorites — the build_opener() method, Request objects, and HTTPBasicAuthHandler and friends — are still available.
  3. The urllib.parse module in Python 3 contains all the parsing functions from the old urlparse module in Python 2.
  4. The urllib.robotparser module parses robots.txt files.
  5. The FancyURLopener class, which handles HTTP redirects and other status codes, is still available in the new urllib.request module. The urlencode() function has moved to urllib.parse.
  6. The Request object is still available in urllib.request, but constants like HTTPError have been moved to urllib.error.

Did I mention that 2to3 will rewrite your function calls too? For example, if your Python 2 code imports the urllib module and calls urllib.urlopen() to fetch data, 2to3 will fix both the import statement and the function call.
Notes Python 2 Python 3
import urllib
print urllib.urlopen('http://diveintopython3.org/').read()
import urllib.request, urllib.parse, urllib.error
print(urllib.request.urlopen('http://diveintopython3.org/').read())

dbm

All the various DBM clones are now in a single package, dbm. If you need a specific variant like GNU DBM, you can import the appropriate module within the dbm package.
Notes Python 2 Python 3
import dbm import dbm.ndbm
import gdbm import dbm.gnu
import dbhash import dbm.bsd
import dumbdbm import dbm.dumb
import anydbm
import whichdb
import dbm

xmlrpc

XML-RPC is a lightweight method of performing remote RPC calls over HTTP. The XML-RPC client library and several XML-RPC server implementations are now combined in a single package, xmlrpc.
Notes Python 2 Python 3
import xmlrpclib import xmlrpc.client
import DocXMLRPCServer
import SimpleXMLRPCServer
import xmlrpc.server

Other modules

Notes Python 2 Python 3
try:
    import cStringIO as StringIO
except ImportError:
    import StringIO
import io
try:
    import cPickle as pickle
except ImportError:
    import pickle
import pickle
import __builtin__ import builtins
import copy_reg import copyreg
import Queue import queue
import SocketServer import socketserver
import ConfigParser import configparser
import repr import reprlib
import commands import subprocess
  1. A common idiom in Python 2 was to try to import cStringIO as StringIO, and if that failed, to import StringIO instead. Do not do this in Python 3; the io module does it for you. It will find the fastest implementation available and use it automatically.
  2. A similar idiom was used to import the fastest pickle implementation. Do not do this in Python 3; the pickle module does it for you.
  3. The builtins module contains the global functions, classes, and constants used throughout the Python language. Redefining a function in the builtins module will redefine the global function everywhere. That is exactly as powerful and scary as it sounds.
  4. The copyreg module adds pickle support for custom types defined in C.
  5. The queue module implements a multi-producer, multi-consumer queue.
  6. The socketserver module provides generic base classes for implementing different kinds of socket servers.
  7. The configparser module parses INI-style configuration files.
  8. The reprlib module reimplements the built-in repr() function, with additional controls on how long the representations can be before they are truncated.
  9. The subprocess module allows you to spawn processes, connect to their pipes, and obtain their return codes.

Relative imports within a package

A package is a group of related modules that function as a single entity. In Python 2, when modules within a package need to reference each other, you use import foo or from foo import Bar. The Python 2 interpreter first searches within the current package to find foo.py, and then moves on to the other directories in the Python search path (sys.path). Python 3 works a bit differently. Instead of searching the current package, it goes directly to the Python search path. If you want one module within a package to import another module in the same package, you need to explicitly provide the relative path between the two modules.

Suppose you had this package, with multiple files in the same directory:

chardet/
|
+--__init__.py
|
+--constants.py
|
+--mbcharsetprober.py
|
+--universaldetector.py

Now suppose that universaldetector.py needs to import the entire constants.py file and one class from mbcharsetprober.py. How do you do it?
Notes Python 2 Python 3
import constants from . import constants
from mbcharsetprober import MultiByteCharSetProber from .mbcharsetprober import MultiByteCharsetProber

  1. When you need to import an entire module from elsewhere in your package, use the new from . import syntax. The period is actually a relative path from this file (universaldetector.py) to the file you want to import (constants.py). In this case, they are in the same directory, thus the single period. You can also import from the parent directory (from .. import anothermodule) or a subdirectory.
  2. To import a specific class or function from another module directly into your module’s namespace, prefix the target module with a relative path, minus the trailing slash. In this case, mbcharsetprober.py is in the same directory as universaldetector.py, so the path is a single period. You can also import form the parent directory (from ..anothermodule import AnotherClass) or a subdirectory.

next() iterator method

In Python 2, iterators had a next() method which returned the next item in the sequence. That’s still true in Python 3, but there is now also a global next() function that takes an iterator as an argument.
Notes Python 2 Python 3
anIterator.next() next(anIterator)
a_function_that_returns_an_iterator().next() next(a_function_that_returns_an_iterator())
class A:
    def next(self):
        pass
class A:
    def __next__(self):
        pass
class A:
    def next(self, x, y):
        pass
no change
next = 42
for an_iterator in a_sequence_of_iterators:
    an_iterator.next()
next = 42
for an_iterator in a_sequence_of_iterators:
    an_iterator.__next__()

  1. In the simplest case, instead of calling an iterator’s next() method, you now pass the iterator itself to the global next() function.
  2. If you have a function that returns an iterator, call the function and pass the result to the next() function. (The 2to3 script is smart enough to convert this properly.)
  3. If you define your own class and mean to use it as an iterator, define the __next__() special method.
  4. If you define your own class and just happen to have a method named next() that takes one or more arguments, 2to3 will not touch it. This class can not be used as an iterator, because its next() method takes arguments.
  5. This one is a bit tricky. If you have a local variable named next, then it takes precedence over the new global next() function. In this case, you need to call the iterator’s special __next__() method to get the next item in the sequence. (Alternatively, you could also refactor the code so the local variable wasn’t named next, but 2to3 will not do that for you automatically.)

filter() global function

In Python 2, the filter() function returned a list, the result of filtering a sequence through a function that returned True or False for each item in the sequence. In Python 3, the filter() function returns an iterator, not a list.
Notes Python 2 Python 3
filter(a_function, a_sequence) list(filter(a_function, a_sequence))
list(filter(a_function, a_sequence)) no change
filter(None, a_sequence) [i for i in a_sequence if i]
for i in filter(None, a_sequence): no change
[i for i in filter(a_function, a_sequence)] no change

  1. In the most basic case, 2to3 will wrap a call to filter() with a call to list(), which simply iterates through its argument and returns a real list.
  2. However, if the call to filter() is already wrapped in list(), 2to3 will do nothing, since the fact that filter() is returning an iterator is irrelevant.
  3. For the special syntax of filter(None, ...), 2to3 will transform the call into a semantically equivalent list comprehension.
  4. In contexts like for loops, which iterate through the entire sequence anyway, no changes are necessary.
  5. Again, no changes are necessary, because the list comprehension will iterate through the entire sequence, and it can do that just as well if filter() returns an iterator as if it returns a list.

map() global function

In much the same way as filter(), the map() function now returns an iterator. (In Python 2, it returned a list.)
Notes Python 2 Python 3
map(a_function, 'PapayaWhip') list(map(a_function, 'PapayaWhip'))
map(None, 'PapayaWhip') list('PapayaWhip')
map(lambda x: x+1, range(42)) [x+1 for x in range(42)]
for i in map(a_function, a_sequence): no change
[i for i in map(a_function, a_sequence)] no change

  1. As with filter(), in the most basic case, 2to3 will wrap a call to map() with a call to list().
  2. For the special syntax of map(None, ...), the identity function, 2to3 will convert it to an equivalent call to list().
  3. If the first argument to map() is a lambda function, 2to3 will convert it to an equivalent list comprehension.
  4. In contexts like for loops, which iterate through the entire sequence anyway, no changes are necessary.
  5. Again, no changes are necessary, because the list comprehension will iterate through the entire sequence, and it can do that just as well if map() returns an iterator as if it returns a list.

reduce() global function

In Python 3, the reduce() function has been removed from the global namespace and placed in the functools module.
Notes Python 2 Python 3
reduce(a, b, c)
from functools import reduce
reduce(a, b, c)

apply() global function

Python 2 had a global function called apply(), which took a function f and a list [a, b, c] and returned f(a, b, c). You can accomplish the same thing by calling the function directly and passing it the list of arguments preceded by an asterisk. In Python 3, the apply() function no longer exists; you must use the asterisk notation.
Notes Python 2 Python 3
apply(a_function, a_list_of_args) a_function(*a_list_of_args)
apply(a_function, a_list_of_args, a_dictionary_of_named_args) a_function(*a_list_of_args, **a_dictionary_of_named_args)
apply(a_function, a_list_of_args + z) a_function(*a_list_of_args + z)
apply(aModule.a_function, a_list_of_args) aModule.a_function(*a_list_of_args)

  1. In the simplest form, you can call a function with a list of arguments (an actual list like [a, b, c]) by prepending the list with an asterisk (*). This is exactly equivalent to the old apply() function in Python 2.
  2. In Python 2, the apply() function could actually take three parameters: a function, a list of arguments, and a dictionary of named arguments. In Python 3, you can accomplish the same thing by prepending the list of arguments with an asterisk (*) and the dictionary of named arguments with two asterisks (**).
  3. The + operator, used here for list concatenation, takes precedence over the * operator, so there is no need for extra parentheses around a_list_of_args + z.
  4. The 2to3 script is smart enough to convert complex apply() calls, including calling functions within imported modules.

intern() global function

In Python 2, you could call the intern() function on a string to intern it as a performance optimization. In Python 3, the intern() function has been moved to the sys module.
Notes Python 2 Python 3
intern(aString) sys.intern(aString)

exec statement

Just as the print statement became a function in Python 3, so too has the exec statement. The exec() function takes a string which contains arbitrary Python code and executes it as if it were just another statement or expression. exec() is like eval(), but even more powerful and evil. The eval() function can only evaluate a single expression, but exec() can execute multiple statements, imports, function declarations — essentially an entire Python program in a string.
Notes Python 2 Python 3
exec codeString exec(codeString)
exec codeString in a_global_namespace exec(codeString, a_global_namespace)
exec codeString in a_global_namespace, a_local_namespace exec(codeString, a_global_namespace, a_local_namespace)

  1. In the simplest form, the 2to3 script simply encloses the code-as-a-string in parentheses, since exec() is now a function instead of a statement.
  2. The old exec statement could take a namespace, a private environment of globals in which the code-as-a-string would be executed. Python 3 can also do this; just pass the namespace as the second argument to the exec() function.
  3. Even fancier, the old exec statement could also take a local namespace (like the variables defined within a function). In Python 3, the exec() function can do that too.

execfile statement

Like the old exec statement, the old execfile statement will execute strings as if they were Python code. Where exec took a string, execfile took a filename. In Python 3, the execfile statement has been eliminated. If you really need to take a file of Python code and execute it (but you’re not willing to simply import it), you can accomplish the same thing by opening the file, reading its contents, calling the global compile() function to force the Python interpreter to compile the code, and then call the new exec() function.
Notes Python 2 Python 3
execfile('a_filename') exec(compile(open('a_filename').read(), 'a_filename', 'exec'))

repr literals (backticks)

In Python 2, there was a special syntax of wrapping any object in backticks (like `x`) to get a representation of the object. In Python 3, this capability still exists, but you can no longer use backticks to get it. Instead, use the global repr() function.
Notes Python 2 Python 3
`x` repr(x)
`'PapayaWhip' + `2`` repr('PapayaWhip' + repr(2))

  1. Remember, x can be anything — a class, a function, a module, a primitive data type, &c. The repr() function works on everything.
  2. In Python 2, backticks could be nested, leading to this sort of confusing (but valid) expression. The 2to3 tool is smart enough to convert this into nested calls to repr().

try...except statement

The syntax for catching exceptions has changed slightly between Python 2 and Python 3.
Notes Python 2 Python 3
try:
    import mymodule
except ImportError, e
    pass
try:
    import mymodule
except ImportError as e:
    pass
try:
    import mymodule
except (RuntimeError, ImportError), e
    pass
try:
    import mymodule
except (RuntimeError, ImportError) as e:
    pass
try:
    import mymodule
except ImportError:
    pass
no change
try:
    import mymodule
except:
    pass
no change

  1. Instead of a comma after the exception type, Python 3 uses a new keyword, as.
  2. The as keyword also works for catching multiple types of exceptions at once.
  3. If you catch an exception but don’t actually care about accessing the exception object itself, the syntax is identical between Python 2 and Python 3.
  4. Similarly, if you use a fallback to catch all exceptions, the syntax is identical.

You should never use a fallback to catch all exceptions when importing modules (or most other times). Doing so will catch things like KeyboardInterrupt (if the user pressed Ctrl-C to interrupt the program) and can make it more difficult to debug errors.

raise statement

The syntax for raising your own exceptions has changed slightly between Python 2 and Python 3.
Notes Python 2 Python 3
raise MyException unchanged
raise MyException, 'error message' raise MyException('error message')
raise MyException, 'error message', a_traceback raise MyException('error message').with_traceback(a_traceback)
raise 'error message' unsupported

  1. In the simplest form, raising an exception without a custom error message, the syntax is unchanged.
  2. The change becomes noticeable when you want to raise an exception with a custom error message. Python 2 separated the exception class and the message with a comma; Python 3 passes the error message as a parameter.
  3. Python 2 supported a more complex syntax to raise an exception with a custom traceback (stack trace). You can do this in Python 3 as well, but the syntax is quite different.
  4. In Python 2, you could raise an exception with no exception class, just an error message. In Python 3, this is no longer possible. 2to3 will warn you that it was unable to fix this automatically.

throw method on generators

In Python 2, generators have a throw() method. Calling a_generator.throw() raises an exception at the point where the generator was paused, then returns the next value yielded by the generator function. In Python 3, this functionality is still available, but the syntax is slightly different.
Notes Python 2 Python 3
a_generator.throw(MyException) no change
a_generator.throw(MyException, 'error message') a_generator.throw(MyException('error message'))
a_generator.throw('error message') unsupported

  1. In the simplest form, a generator throws an exception without a custom error message. In this case, the syntax has not changed between Python 2 and Python 3.
  2. If the generator throws an exception with a custom error message, you need to pass the error string to the exception when you create it.
  3. Python 2 also supported throwing an exception with only a custom error message. Python 3 does not support this, and the 2to3 script will display a warning telling you that you will need to fix this code manually.

xrange() global function

In Python 2, there were two ways to get a range of numbers: range(), which returned a list, and xrange(), which returned an iterator. In Python 3, range() returns an iterator, and xrange() doesn’t exist.
Notes Python 2 Python 3
xrange(10) range(10)
a_list = range(10) a_list = list(range(10))
[i for i in xrange(10)] [i for i in range(10)]
for i in range(10): no change
sum(range(10)) no change

  1. In the simplest case, the 2to3 script will simply convert xrange() to range().
  2. If your Python 2 code used range(), the 2to3 script does not know whether you needed a list, or whether an iterator would do. It errs on the side of caution and coerces the return value into a list by calling the list() function.
  3. If the xrange() function was inside a list comprehension, the 2to3 script is clever enough not to wrap the range() function with a call to list(). The list comprehension will work just fine with the iterator that the range() function returns.
  4. Similarly, a for loop will work just fine with an iterator, so there is no need to change anything here.
  5. The sum() function will also work with an iterator, so 2to3 makes no changes here either. Like dictionary methods that return views instead of lists, this applies to min(), max(), sum(), list(), tuple(), set(), sorted(), any(), and all().

raw_input() and input() global functions

Python 2 had two global functions for asking the user for input on the command line. The first, called input(), expected the user to enter a Python expression (and returned the result). The second, called raw_input(), just returned whatever the user typed. This was wildly confusing for beginners and widely regarded as a “wart” in the language. Python 3 excises this wart by renaming raw_input() to input(), so it works the way everyone naively expects it to work.
Notes Python 2 Python 3
raw_input() input()
raw_input('prompt') input('prompt')
input() eval(input())

  1. In the simplest form, raw_input() becomes input().
  2. In Python 2, the raw_input() function could take a prompt as a parameter. This has been retained in Python 3.
  3. If you actually need to ask the user for a Python expression to evaluate, use the input() function and pass the result to eval().

func_* function attributes

In Python 2, code within functions can access special attributes about the function itself. In Python 3, these special function attributes have been renamed for consistency with other attributes.
Notes Python 2 Python 3
a_function.func_name a_function.__name__
a_function.func_doc a_function.__doc__
a_function.func_defaults a_function.__defaults__
a_function.func_dict a_function.__dict__
a_function.func_closure a_function.__closure__
a_function.func_globals a_function.__globals__
a_function.func_code a_function.__code__

  1. The __name__ attribute (previously func_name) contains the function’s name.
  2. The __doc__ attribute (previously func_doc) contains the docstring that you defined in the function’s source code.
  3. The __defaults__ attribute (previously func_defaults) is a tuple containing default argument values for those arguments that have default values.
  4. The __dict__ attribute (previously func_dict) is the namespace supporting arbitrary function attributes.
  5. The __closure__ attribute (previously func_closure) is a tuple of cells that contain bindings for the function’s free variables.
  6. The __globals__ attribute (previously func_globals) is a reference to the global namespace of the module in which the function was defined.
  7. The __code__ attribute (previously func_code) is a code object representing the compiled function body.

xreadlines() I/O method

In Python 2, file objects had an xreadlines() method which returned an iterator that would read the file one line at a time. This was useful in for loops, among other places. In fact, it was so useful, later versions of Python 2 added the capability to file objects themselves.

In Python 3, the xreadlines() method no longer exists. 2to3 can fix the simple cases, but some edge cases will require manual intervention.
Notes Python 2 Python 3
for line in a_file.xreadlines(): for line in a_file:
for line in a_file.xreadlines(5): no change (broken)

  1. If you used to call xreadlines() with no arguments, 2to3 will convert it to just the file object. In Python 3, this will accomplish the same thing: read the file one line at a time and execute the body of the for loop.
  2. If you used to call xreadlines() with an argument (the number of lines to read at a time), 2to3 will not fix it, and your code will fail with an AttributeError: '_io.TextIOWrapper' object has no attribute 'xreadlines'. You can manually change xreadlines() to readlines() to get it to work in Python 3. (The readlines() method now returns an iterator, so it is just as efficient as xreadlines() was in Python 2.)

lambda functions that take a tuple instead of multiple parameters

In Python 2, you could define anonymous lambda functions which took multiple parameters by defining the function as taking a tuple with a specific number of items. In effect, Python 2 would “unpack” the tuple into named arguments, which you could then reference (by name) within the lambda function. In Python 3, you can still pass a tuple to a lambda function, but the Python interpreter will not unpack the tuple into named arguments. Instead, you will need to reference each argument by its positional index.
Notes Python 2 Python 3
lambda (x,): x + f(x) lambda x1: x1[0] + f(x1[0])
lambda (x, y): x + f(y) lambda x_y: x_y[0] + f(x_y[1])
lambda (x, (y, z)): x + y + z lambda x_y_z: x_y_z[0] + x_y_z[1][0] + x_y_z[1][1]
lambda x, y, z: x + y + z unchanged

  1. If you had defined a lambda function that took a tuple of one item, in Python 3 that would become a lambda with references to x1[0]. The name x1 is autogenerated by the 2to3 script, based on the named arguments in the original tuple.
  2. A lambda function with a two-item tuple (x, y) gets converted to x_y with positional arguments x_y[0] and x_y[1].
  3. The 2to3 script can even handle lambda functions with nested tuples of named arguments. The resulting Python 3 code is a bit unreadable, but it works the same as the old code did in Python 2.
  4. You can define lambda functions that take multiple arguments. Without parentheses around the arguments, Python 2 just treats it as a lambda function with multiple arguments; within the lambda function, you simply reference the arguments by name, just like any other function. This syntax still works in Python 3.

Special method attributes

In Python 2, class methods can reference the class object in which they are defined, as well as the method object itself. im_self is the class instance object; im_func is the function object; im_class is the class of im_self. In Python 3, these special method attributes have been renamed to follow the naming conventions of other attributes.
Notes Python 2 Python 3
aClassInstance.aClassMethod.im_func aClassInstance.aClassMethod.__func__
aClassInstance.aClassMethod.im_self aClassInstance.aClassMethod.__self__
aClassInstance.aClassMethod.im_class aClassInstance.aClassMethod.__self__.__class__

__nonzero__ special method

In Python 2, you could build your own classes that could be used in a boolean context. For example, you could instantiate the class and then use the instance in an if statement. To do this, you defined a special __nonzero__() method which returned True or False, and it was called whenever the instance was used in a boolean context. In Python 3, you can still do this, but the name of the method has changed to __bool__().
Notes Python 2 Python 3
class A:
    def __nonzero__(self):
        pass
class A:
    def __bool__(self):
        pass
class A:
    def __nonzero__(self, x, y):
        pass
no change

  1. Instead of __nonzero__(), Python 3 calls the __bool__() method when evaluating an instance in a boolean context.
  2. However, if you have a __nonzero__() method that takes arguments, the 2to3 tool will assume that you were using it for some other purpose, and it will not make any changes.

Octal literals

The syntax for defining base 8 (octal) numbers has changed slightly between Python 2 and Python 3.
Notes Python 2 Python 3
x = 0755 x = 0o755

sys.maxint

Due to the integration of the long and int types, the sys.maxint constant is no longer accurate. Because the value may still be useful in determining platform-specific capabilities, it has been retained but renamed as sys.maxsize.
Notes Python 2 Python 3
from sys import maxint from sys import maxsize
a_function(sys.maxint) a_function(sys.maxsize)

  1. maxint becomes maxsize.
  2. Any usage of sys.maxint becomes sys.maxsize.

callable() global function

In Python 2, you could check whether an object was callable (like a function) with the global callable() function. In Python 3, this global function has been eliminated. To check whether an object is callable, check for the existence of the __call__() special method.
Notes Python 2 Python 3
callable(anything) hasattr(anything, '__call__')

zip() global function

In Python 2, the global zip() function took any number of sequences and returned a list of tuples. The first tuple contained the first item from each sequence; the second tuple contained the second item from each sequence; and so on. In Python 3, zip() returns an iterator instead of a list.
Notes Python 2 Python 3
zip(a, b, c) list(zip(a, b, c))
d.join(zip(a, b, c)) no change

  1. In the simplest form, you can get the old behavior of the zip() function by wrapping the return value in a call to list(), which will run through the iterator that zip() returns and return a real list of the results.
  2. In contexts that already iterate through all the items of a sequence (such as this call to the join() method), the iterator that zip() returns will work just fine. The 2to3 script is smart enough to detect these cases and make no change to your code.

StandardError exception

In Python 2, StandardError was the base class for all built-in exceptions other than StopIteration, GeneratorExit, KeyboardInterrupt, and SystemExit. In Python 3, StandardError has been eliminated; use Exception instead.
Notes Python 2 Python 3
x = StandardError() x = Exception()
x = StandardError(a, b, c) x = Exception(a, b, c)

types module constants

The types module contains a variety of constants to help you determine the type of an object. In Python 2, it contained constants for all primitive types like dict and int. In Python 3, these constants have been eliminated; just use the primitive type name instead.
Notes Python 2 Python 3
types.UnicodeType str
types.StringType bytes
types.DictType dict
types.IntType int
types.LongType int
types.ListType list
types.NoneType type(None)
types.BooleanType bool
types.BufferType memoryview
types.ClassType type
types.ComplexType complex
types.EllipsisType type(Ellipsis)
types.FloatType float
types.ObjectType object
types.NotImplementedType type(NotImplemented)
types.SliceType slice
types.TupleType tuple
types.TypeType type
types.XRangeType range

types.StringType gets mapped to bytes instead of str because a Python 2 “string” (not a Unicode string, just a regular string) is really just a sequence of bytes in a particular character encoding.

isinstance() global function

The isinstance() function checks whether an object is an instance of a particular class or type. In Python 2, you could pass a tuple of types, and isinstance() would return True if the object was any of those types. In Python 3, you can still do this, but passing the same type twice is deprecated.
Notes Python 2 Python 3
isinstance(x, (int, float, int)) isinstance(x, (int, float))

basestring datatype

Python 2 had two string types: Unicode and non-Unicode. But there was also another type, basestring. It was an abstract type, a superclass for both the str and unicode types. It couldn’t be called or instantiated directly, but you could pass it to the global isinstance() function to check whether an object was either a Unicode or non-Unicode string. In Python 3, there is only one string type, so basestring has no reason to exist.
Notes Python 2 Python 3
isinstance(x, basestring) isinstance(x, str)

itertools module

Python 2.3 introduced the itertools module, which defined variants of the global zip(), map(), and filter() functions that returned iterators instead of lists. In Python 3, those global functions return iterators, so those functions in the itertools module have been eliminated. (There are still lots of useful functions in the itertools module, just not these.)
Notes Python 2 Python 3
itertools.izip(a, b) zip(a, b)
itertools.imap(a, b) map(a, b)
itertools.ifilter(a, b) filter(a, b)
from itertools import imap, izip, foo from itertools import foo

  1. Instead of itertools.izip(), just use the global zip() function.
  2. Instead of itertools.imap(), just use map().
  3. itertools.ifilter() becomes filter().
  4. The itertools module still exists in Python 3, it just doesn’t have the functions that have migrated to the global namespace. The 2to3 script is smart enough to remove the specific imports that no longer exist, while leaving other imports intact.

sys.exc_type, sys.exc_value, sys.exc_traceback

Python 2 had three variables in the sys module that you could access while an exception was being handled: sys.exc_type, sys.exc_value, sys.exc_traceback. (Actually, these date all the way back to Python 1.) Ever since Python 1.5, these variables have been deprecated in favor of sys.exc_info(), which is a function that returns a tuple containing those three values. In Python 3, these individual variables have finally gone away; you must use the sys.exc_info() function.
Notes Python 2 Python 3
sys.exc_type sys.exc_info()[0]
sys.exc_value sys.exc_info()[1]
sys.exc_traceback sys.exc_info()[2]

List comprehensions over tuples

In Python 2, if you wanted to code a list comprehension that iterated over a tuple, you did not need to put parentheses around the tuple values. In Python 3, explicit parentheses are required.
Notes Python 2 Python 3
[i for i in 1, 2] [i for i in (1, 2)]

os.getcwdu() function

Python 2 had a function named os.getcwd(), which returned the current working directory as a (non-Unicode) string. Because modern file systems can handle directory names in any character encoding, Python 2.3 introduced os.getcwdu(). The os.getcwdu() function returned the current working directory as a Unicode string. In Python 3, there is only one string type (Unicode), so os.getcwd() is all you need.
Notes Python 2 Python 3
os.getcwdu() os.getcwd()

Metaclasses

In Python 2, you could create metaclasses either by defining the metaclass argument in the class declaration, or by defining a special class-level __metaclass__ attribute. In Python 3, the class-level attribute has been eliminated.
Notes Python 2 Python 3
class C(metaclass=PapayaMeta):
    pass
unchanged
class Whip:
    __metaclass__ = PapayaMeta
class Whip(metaclass=PapayaMeta):
    pass
class C(Whipper, Beater):
    __metaclass__ = PapayaMeta
class C(Whipper, Beater, metaclass=PapayaMeta):
    pass

  1. Declaring the metaclass in the class declaration worked in Python 2, and it still works the same in Python 3.
  2. Declaring the metaclass in a class attribute worked in Python 2, but doesn’t work in Python 3.
  3. The 2to3 script is smart enough to construct a valid class declaration, even if the class is inherited from one or more base classes.

Matters of style

The rest of the “fixes” listed here aren’t really fixes per se. That is, the things they change are matters of style, not substance. They work just as well in Python 3 as they do in Python 2, but the developers of Python have a vested interest in making Python code as uniform as possible. To that end, there is an official Python style guide which outlines — in excruciating detail — all sorts of nitpicky details that you almost certainly don’t care about. And given that 2to3 provides such a great infrastructure for converting Python code from one thing to another, the authors took it upon themselves to add a few optional features to improve the readability of your Python programs.

set() literals (explicit)

In Python 2, the only way to define a literal set in your code was to call set(a_sequence). This still works in Python 3, but a clearer way of doing it is to use the new set literal notation: curly braces. This works for everything except empty sets, because dictionaries also use curly braces, so {} is an empty dictionary, not an empty set.

The 2to3 script will not fix set() literals by default. To enable this fix, specify -f set_literal on the command line when you call 2to3.

Notes Before After
set([1, 2, 3]) {1, 2, 3}
set((1, 2, 3)) {1, 2, 3}
set([i for i in a_sequence]) {i for i in a_sequence}

buffer() global function (explicit)

Python objects implemented in C can export a “buffer interface,” which allows other Python code to directly read and write a block of memory. (That is exactly as powerful and scary as it sounds.) In Python 3, buffer() has been renamed to memoryview(). (It’s a little more complicated than that, but you can almost certainly ignore the differences.)

The 2to3 script will not fix the buffer() function by default. To enable this fix, specify -f buffer on the command line when you call 2to3.

Notes Before After
x = buffer(y) x = memoryview(y)

Whitespace around commas (explicit)

Despite being draconian about whitespace for indenting and outdenting, Python is actually quite liberal about whitespace in other areas. Within lists, tuples, sets, and dictionaries, whitespace can appear before and after commas with no ill effects. However, the Python style guide states that commas should be preceded by zero spaces and followed by one. Although this is purely an aesthetic issue (the code works either way, in both Python 2 and Python 3), the 2to3 script can optionally fix this for you.

The 2to3 script will not fix whitespace around commas by default. To enable this fix, specify -f wscomma on the command line when you call 2to3.

Notes Before After
a ,b a, b
{a :b} {a: b}

Common idioms (explicit)

There were a number of common idioms built up in the Python community. Some, like the while 1: loop, date back to Python 1. (Python didn’t have a true boolean type until version 2.3, so developers used 1 and 0 instead.) Modern Python programmers should train their brains to use modern versions of these idioms instead.

The 2to3 script will not fix common idioms by default. To enable this fix, specify -f idioms on the command line when you call 2to3.

Notes Before After
while 1:
    do_stuff()
while True:
    do_stuff()
type(x) == T isinstance(x, T)
type(x) is T isinstance(x, T)
a_list = list(a_sequence)
a_list.sort()
do_stuff(a_list)
a_list = sorted(a_sequence)
do_stuff(a_list)

© 2001–11 Mark Pilgrim diveintopython3-20110517-77958af.orig/regular-expressions.html0000644000000000000000000015657311773544727022540 0ustar rootroot Regular expressions - Dive Into Python 3

  

You are here: Home Dive Into Python 3

Difficulty level: ♦♦♦♢♢

Regular Expressions

Some people, when confronted with a problem, think “I know, I’ll use regular expressions.” Now they have two problems.
Jamie Zawinski

 

Diving In

Getting a small bit of text out of a large block of text is a challenge. In Python, strings have methods for searching and replacing: index(), find(), split(), count(), replace(), &c. But these methods are limited to the simplest of cases. For example, the index() method looks for a single, hard-coded substring, and the search is always case-sensitive. To do case-insensitive searches of a string s, you must call s.lower() or s.upper() and make sure your search strings are the appropriate case to match. The replace() and split() methods have the same limitations.

If your goal can be accomplished with string methods, you should use them. They’re fast and simple and easy to read, and there’s a lot to be said for fast, simple, readable code. But if you find yourself using a lot of different string functions with if statements to handle special cases, or if you’re chaining calls to split() and join() to slice-and-dice your strings, you may need to move up to regular expressions.

Regular expressions are a powerful and (mostly) standardized way of searching, replacing, and parsing text with complex patterns of characters. Although the regular expression syntax is tight and unlike normal code, the result can end up being more readable than a hand-rolled solution that uses a long chain of string functions. There are even ways of embedding comments within regular expressions, so you can include fine-grained documentation within them.

If you’ve used regular expressions in other languages (like Perl, JavaScript, or PHP), Python’s syntax will be very familiar. Read the summary of the re module to get an overview of the available functions and their arguments.

Case Study: Street Addresses

This series of examples was inspired by a real-life problem I had in my day job several years ago, when I needed to scrub and standardize street addresses exported from a legacy system before importing them into a newer system. (See, I don’t just make this stuff up; it’s actually useful.) This example shows how I approached the problem.

>>> s = '100 NORTH MAIN ROAD'
>>> s.replace('ROAD', 'RD.')                
'100 NORTH MAIN RD.'
>>> s = '100 NORTH BROAD ROAD'
>>> s.replace('ROAD', 'RD.')                
'100 NORTH BRD. RD.'
>>> s[:-4] + s[-4:].replace('ROAD', 'RD.')  
'100 NORTH BROAD RD.'
>>> import re                               
>>> re.sub('ROAD$', 'RD.', s)               
'100 NORTH BROAD RD.'
  1. My goal is to standardize a street address so that 'ROAD' is always abbreviated as 'RD.'. At first glance, I thought this was simple enough that I could just use the string method replace(). After all, all the data was already uppercase, so case mismatches would not be a problem. And the search string, 'ROAD', was a constant. And in this deceptively simple example, s.replace() does indeed work.
  2. Life, unfortunately, is full of counterexamples, and I quickly discovered this one. The problem here is that 'ROAD' appears twice in the address, once as part of the street name 'BROAD' and once as its own word. The replace() method sees these two occurrences and blindly replaces both of them; meanwhile, I see my addresses getting destroyed.
  3. To solve the problem of addresses with more than one 'ROAD' substring, you could resort to something like this: only search and replace 'ROAD' in the last four characters of the address (s[-4:]), and leave the string alone (s[:-4]). But you can see that this is already getting unwieldy. For example, the pattern is dependent on the length of the string you’re replacing. (If you were replacing 'STREET' with 'ST.', you would need to use s[:-6] and s[-6:].replace(...).) Would you like to come back in six months and debug this? I know I wouldn’t.
  4. It’s time to move up to regular expressions. In Python, all functionality related to regular expressions is contained in the re module.
  5. Take a look at the first parameter: 'ROAD$'. This is a simple regular expression that matches 'ROAD' only when it occurs at the end of a string. The $ means “end of the string.” (There is a corresponding character, the caret ^, which means “beginning of the string.”) Using the re.sub() function, you search the string s for the regular expression 'ROAD$' and replace it with 'RD.'. This matches the ROAD at the end of the string s, but does not match the ROAD that’s part of the word BROAD, because that’s in the middle of s.

Continuing with my story of scrubbing addresses, I soon discovered that the previous example, matching 'ROAD' at the end of the address, was not good enough, because not all addresses included a street designation at all. Some addresses simply ended with the street name. I got away with it most of the time, but if the street name was 'BROAD', then the regular expression would match 'ROAD' at the end of the string as part of the word 'BROAD', which is not what I wanted.

>>> s = '100 BROAD'
>>> re.sub('ROAD$', 'RD.', s)
'100 BRD.'
>>> re.sub('\\bROAD$', 'RD.', s)   
'100 BROAD'
>>> re.sub(r'\bROAD$', 'RD.', s)   
'100 BROAD'
>>> s = '100 BROAD ROAD APT. 3'
>>> re.sub(r'\bROAD$', 'RD.', s)   
'100 BROAD ROAD APT. 3'
>>> re.sub(r'\bROAD\b', 'RD.', s)  
'100 BROAD RD. APT 3'
  1. What I really wanted was to match 'ROAD' when it was at the end of the string and it was its own word (and not a part of some larger word). To express this in a regular expression, you use \b, which means “a word boundary must occur right here.” In Python, this is complicated by the fact that the '\' character in a string must itself be escaped. This is sometimes referred to as the backslash plague, and it is one reason why regular expressions are easier in Perl than in Python. On the down side, Perl mixes regular expressions with other syntax, so if you have a bug, it may be hard to tell whether it’s a bug in syntax or a bug in your regular expression.
  2. To work around the backslash plague, you can use what is called a raw string, by prefixing the string with the letter r. This tells Python that nothing in this string should be escaped; '\t' is a tab character, but r'\t' is really the backslash character \ followed by the letter t. I recommend always using raw strings when dealing with regular expressions; otherwise, things get too confusing too quickly (and regular expressions are confusing enough already).
  3. *sigh* Unfortunately, I soon found more cases that contradicted my logic. In this case, the street address contained the word 'ROAD' as a whole word by itself, but it wasn’t at the end, because the address had an apartment number after the street designation. Because 'ROAD' isn’t at the very end of the string, it doesn’t match, so the entire call to re.sub() ends up replacing nothing at all, and you get the original string back, which is not what you want.
  4. To solve this problem, I removed the $ character and added another \b. Now the regular expression reads “match 'ROAD' when it’s a whole word by itself anywhere in the string,” whether at the end, the beginning, or somewhere in the middle.

Case Study: Roman Numerals

You’ve most likely seen Roman numerals, even if you didn’t recognize them. You may have seen them in copyrights of old movies and television shows (“Copyright MCMXLVI” instead of “Copyright 1946”), or on the dedication walls of libraries or universities (“established MDCCCLXXXVIII” instead of “established 1888”). You may also have seen them in outlines and bibliographical references. It’s a system of representing numbers that really does date back to the ancient Roman empire (hence the name).

In Roman numerals, there are seven characters that are repeated and combined in various ways to represent numbers.

The following are some general rules for constructing Roman numerals:

Checking For Thousands

What would it take to validate that an arbitrary string is a valid Roman numeral? Let’s take it one digit at a time. Since Roman numerals are always written highest to lowest, let’s start with the highest: the thousands place. For numbers 1000 and higher, the thousands are represented by a series of M characters.

>>> import re
>>> pattern = '^M?M?M?$'        
>>> re.search(pattern, 'M')     
<_sre.SRE_Match object at 0106FB58>
>>> re.search(pattern, 'MM')    
<_sre.SRE_Match object at 0106C290>
>>> re.search(pattern, 'MMM')   
<_sre.SRE_Match object at 0106AA38>
>>> re.search(pattern, 'MMMM')  
>>> re.search(pattern, '')      
<_sre.SRE_Match object at 0106F4A8>
  1. This pattern has three parts. ^ matches what follows only at the beginning of the string. If this were not specified, the pattern would match no matter where the M characters were, which is not what you want. You want to make sure that the M characters, if they’re there, are at the beginning of the string. M? optionally matches a single M character. Since this is repeated three times, you’re matching anywhere from zero to three M characters in a row. And $ matches the end of the string. When combined with the ^ character at the beginning, this means that the pattern must match the entire string, with no other characters before or after the M characters.
  2. The essence of the re module is the search() function, that takes a regular expression (pattern) and a string ('M') to try to match against the regular expression. If a match is found, search() returns an object which has various methods to describe the match; if no match is found, search() returns None, the Python null value. All you care about at the moment is whether the pattern matches, which you can tell by just looking at the return value of search(). 'M' matches this regular expression, because the first optional M matches and the second and third optional M characters are ignored.
  3. 'MM' matches because the first and second optional M characters match and the third M is ignored.
  4. 'MMM' matches because all three M characters match.
  5. 'MMMM' does not match. All three M characters match, but then the regular expression insists on the string ending (because of the $ character), and the string doesn’t end yet (because of the fourth M). So search() returns None.
  6. Interestingly, an empty string also matches this regular expression, since all the M characters are optional.

Checking For Hundreds

The hundreds place is more difficult than the thousands, because there are several mutually exclusive ways it could be expressed, depending on its value.

So there are four possible patterns:

The last two patterns can be combined:

This example shows how to validate the hundreds place of a Roman numeral.

>>> import re
>>> pattern = '^M?M?M?(CM|CD|D?C?C?C?)$'  
>>> re.search(pattern, 'MCM')             
<_sre.SRE_Match object at 01070390>
>>> re.search(pattern, 'MD')              
<_sre.SRE_Match object at 01073A50>
>>> re.search(pattern, 'MMMCCC')          
<_sre.SRE_Match object at 010748A8>
>>> re.search(pattern, 'MCMC')            
>>> re.search(pattern, '')                
<_sre.SRE_Match object at 01071D98>
  1. This pattern starts out the same as the previous one, checking for the beginning of the string (^), then the thousands place (M?M?M?). Then it has the new part, in parentheses, which defines a set of three mutually exclusive patterns, separated by vertical bars: CM, CD, and D?C?C?C? (which is an optional D followed by zero to three optional C characters). The regular expression parser checks for each of these patterns in order (from left to right), takes the first one that matches, and ignores the rest.
  2. 'MCM' matches because the first M matches, the second and third M characters are ignored, and the CM matches (so the CD and D?C?C?C? patterns are never even considered). MCM is the Roman numeral representation of 1900.
  3. 'MD' matches because the first M matches, the second and third M characters are ignored, and the D?C?C?C? pattern matches D (each of the three C characters are optional and are ignored). MD is the Roman numeral representation of 1500.
  4. 'MMMCCC' matches because all three M characters match, and the D?C?C?C? pattern matches CCC (the D is optional and is ignored). MMMCCC is the Roman numeral representation of 3300.
  5. 'MCMC' does not match. The first M matches, the second and third M characters are ignored, and the CM matches, but then the $ does not match because you’re not at the end of the string yet (you still have an unmatched C character). The C does not match as part of the D?C?C?C? pattern, because the mutually exclusive CM pattern has already matched.
  6. Interestingly, an empty string still matches this pattern, because all the M characters are optional and ignored, and the empty string matches the D?C?C?C? pattern where all the characters are optional and ignored.

Whew! See how quickly regular expressions can get nasty? And you’ve only covered the thousands and hundreds places of Roman numerals. But if you followed all that, the tens and ones places are easy, because they’re exactly the same pattern. But let’s look at another way to express the pattern.

Using The {n,m} Syntax

In the previous section, you were dealing with a pattern where the same character could be repeated up to three times. There is another way to express this in regular expressions, which some people find more readable. First look at the method we already used in the previous example.

>>> import re
>>> pattern = '^M?M?M?$'
>>> re.search(pattern, 'M')     
<_sre.SRE_Match object at 0x008EE090>
>>> re.search(pattern, 'MM')    
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MMM')   
<_sre.SRE_Match object at 0x008EE090>
>>> re.search(pattern, 'MMMM')  
>>> 
  1. This matches the start of the string, and then the first optional M, but not the second and third M (but that’s okay because they’re optional), and then the end of the string.
  2. This matches the start of the string, and then the first and second optional M, but not the third M (but that’s okay because it’s optional), and then the end of the string.
  3. This matches the start of the string, and then all three optional M, and then the end of the string.
  4. This matches the start of the string, and then all three optional M, but then does not match the end of the string (because there is still one unmatched M), so the pattern does not match and returns None.
>>> pattern = '^M{0,3}$'        
>>> re.search(pattern, 'M')     
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MM')    
<_sre.SRE_Match object at 0x008EE090>
>>> re.search(pattern, 'MMM')   
<_sre.SRE_Match object at 0x008EEDA8>
>>> re.search(pattern, 'MMMM')  
>>> 
  1. This pattern says: “Match the start of the string, then anywhere from zero to three M characters, then the end of the string.” The 0 and 3 can be any numbers; if you want to match at least one but no more than three M characters, you could say M{1,3}.
  2. This matches the start of the string, then one M out of a possible three, then the end of the string.
  3. This matches the start of the string, then two M out of a possible three, then the end of the string.
  4. This matches the start of the string, then three M out of a possible three, then the end of the string.
  5. This matches the start of the string, then three M out of a possible three, but then does not match the end of the string. The regular expression allows for up to only three M characters before the end of the string, but you have four, so the pattern does not match and returns None.

Checking For Tens And Ones

Now let’s expand the Roman numeral regular expression to cover the tens and ones place. This example shows the check for tens.

>>> pattern = '^M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)$'
>>> re.search(pattern, 'MCMXL')     
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MCML')      
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MCMLX')     
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MCMLXXX')   
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MCMLXXXX')  
>>> 
  1. This matches the start of the string, then the first optional M, then CM, then XL, then the end of the string. Remember, the (A|B|C) syntax means “match exactly one of A, B, or C”. You match XL, so you ignore the XC and L?X?X?X? choices, and then move on to the end of the string. MCMXL is the Roman numeral representation of 1940.
  2. This matches the start of the string, then the first optional M, then CM, then L?X?X?X?. Of the L?X?X?X?, it matches the L and skips all three optional X characters. Then you move to the end of the string. MCML is the Roman numeral representation of 1950.
  3. This matches the start of the string, then the first optional M, then CM, then the optional L and the first optional X, skips the second and third optional X, then the end of the string. MCMLX is the Roman numeral representation of 1960.
  4. This matches the start of the string, then the first optional M, then CM, then the optional L and all three optional X characters, then the end of the string. MCMLXXX is the Roman numeral representation of 1980.
  5. This matches the start of the string, then the first optional M, then CM, then the optional L and all three optional X characters, then fails to match the end of the string because there is still one more X unaccounted for. So the entire pattern fails to match, and returns None. MCMLXXXX is not a valid Roman numeral.

The expression for the ones place follows the same pattern. I’ll spare you the details and show you the end result.

>>> pattern = '^M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$'

So what does that look like using this alternate {n,m} syntax? This example shows the new syntax.

>>> pattern = '^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$'
>>> re.search(pattern, 'MDLV')              
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MMDCLXVI')          
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MMMDCCCLXXXVIII')   
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'I')                 
<_sre.SRE_Match object at 0x008EEB48>
  1. This matches the start of the string, then one of a possible three M characters, then D?C{0,3}. Of that, it matches the optional D and zero of three possible C characters. Moving on, it matches L?X{0,3} by matching the optional L and zero of three possible X characters. Then it matches V?I{0,3} by matching the optional V and zero of three possible I characters, and finally the end of the string. MDLV is the Roman numeral representation of 1555.
  2. This matches the start of the string, then two of a possible three M characters, then the D?C{0,3} with a D and one of three possible C characters; then L?X{0,3} with an L and one of three possible X characters; then V?I{0,3} with a V and one of three possible I characters; then the end of the string. MMDCLXVI is the Roman numeral representation of 2666.
  3. This matches the start of the string, then three out of three M characters, then D?C{0,3} with a D and three out of three C characters; then L?X{0,3} with an L and three out of three X characters; then V?I{0,3} with a V and three out of three I characters; then the end of the string. MMMDCCCLXXXVIII is the Roman numeral representation of 3888, and it’s the longest Roman numeral you can write without extended syntax.
  4. Watch closely. (I feel like a magician. “Watch closely, kids, I’m going to pull a rabbit out of my hat.”) This matches the start of the string, then zero out of three M, then matches D?C{0,3} by skipping the optional D and matching zero out of three C, then matches L?X{0,3} by skipping the optional L and matching zero out of three X, then matches V?I{0,3} by skipping the optional V and matching one out of three I. Then the end of the string. Whoa.

If you followed all that and understood it on the first try, you’re doing better than I did. Now imagine trying to understand someone else’s regular expressions, in the middle of a critical function of a large program. Or even imagine coming back to your own regular expressions a few months later. I’ve done it, and it’s not a pretty sight.

Now let’s explore an alternate syntax that can help keep your expressions maintainable.

Verbose Regular Expressions

So far you’ve just been dealing with what I’ll call “compact” regular expressions. As you’ve seen, they are difficult to read, and even if you figure out what one does, that’s no guarantee that you’ll be able to understand it six months later. What you really need is inline documentation.

Python allows you to do this with something called verbose regular expressions. A verbose regular expression is different from a compact regular expression in two ways:

This will be more clear with an example. Let’s revisit the compact regular expression you’ve been working with, and make it a verbose regular expression. This example shows how.

>>> pattern = '''
    ^                   # beginning of string
    M{0,3}              # thousands - 0 to 3 Ms
    (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 Cs),
                        #            or 500-800 (D, followed by 0 to 3 Cs)
    (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 Xs),
                        #        or 50-80 (L, followed by 0 to 3 Xs)
    (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 Is),
                        #        or 5-8 (V, followed by 0 to 3 Is)
    $                   # end of string
    '''
>>> re.search(pattern, 'M', re.VERBOSE)                 
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MCMLXXXIX', re.VERBOSE)         
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MMMDCCCLXXXVIII', re.VERBOSE)   
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'M')                             
  1. The most important thing to remember when using verbose regular expressions is that you need to pass an extra argument when working with them: re.VERBOSE is a constant defined in the re module that signals that the pattern should be treated as a verbose regular expression. As you can see, this pattern has quite a bit of whitespace (all of which is ignored), and several comments (all of which are ignored). Once you ignore the whitespace and the comments, this is exactly the same regular expression as you saw in the previous section, but it’s a lot more readable.
  2. This matches the start of the string, then one of a possible three M, then CM, then L and three of a possible three X, then IX, then the end of the string.
  3. This matches the start of the string, then three of a possible three M, then D and three of a possible three C, then L and three of a possible three X, then V and three of a possible three I, then the end of the string.
  4. This does not match. Why? Because it doesn’t have the re.VERBOSE flag, so the re.search function is treating the pattern as a compact regular expression, with significant whitespace and literal hash marks. Python can’t auto-detect whether a regular expression is verbose or not. Python assumes every regular expression is compact unless you explicitly state that it is verbose.

Case study: Parsing Phone Numbers

So far you’ve concentrated on matching whole patterns. Either the pattern matches, or it doesn’t. But regular expressions are much more powerful than that. When a regular expression does match, you can pick out specific pieces of it. You can find out what matched where.

This example came from another real-world problem I encountered, again from a previous day job. The problem: parsing an American phone number. The client wanted to be able to enter the number free-form (in a single field), but then wanted to store the area code, trunk, number, and optionally an extension separately in the company’s database. I scoured the Web and found many examples of regular expressions that purported to do this, but none of them were permissive enough.

Here are the phone numbers I needed to be able to accept:

Quite a variety! In each of these cases, I need to know that the area code was 800, the trunk was 555, and the rest of the phone number was 1212. For those with an extension, I need to know that the extension was 1234.

Let’s work through developing a solution for phone number parsing. This example shows the first step.

>>> phonePattern = re.compile(r'^(\d{3})-(\d{3})-(\d{4})$')  
>>> phonePattern.search('800-555-1212').groups()             
('800', '555', '1212')
>>> phonePattern.search('800-555-1212-1234')                 
>>> phonePattern.search('800-555-1212-1234').groups()        
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'groups'
  1. Always read regular expressions from left to right. This one matches the beginning of the string, and then (\d{3}). What’s \d{3}? Well, \d means “any numeric digit” (0 through 9). The {3} means “match exactly three numeric digits”; it’s a variation on the {n,m} syntax you saw earlier. Putting it all in parentheses means “match exactly three numeric digits, and then remember them as a group that I can ask for later”. Then match a literal hyphen. Then match another group of exactly three digits. Then another literal hyphen. Then another group of exactly four digits. Then match the end of the string.
  2. To get access to the groups that the regular expression parser remembered along the way, use the groups() method on the object that the search() method returns. It will return a tuple of however many groups were defined in the regular expression. In this case, you defined three groups, one with three digits, one with three digits, and one with four digits.
  3. This regular expression is not the final answer, because it doesn’t handle a phone number with an extension on the end. For that, you’ll need to expand the regular expression.
  4. And this is why you should never “chain” the search() and groups() methods in production code. If the search() method returns no matches, it returns None, not a regular expression match object. Calling None.groups() raises a perfectly obvious exception: None doesn’t have a groups() method. (Of course, it’s slightly less obvious when you get this exception from deep within your code. Yes, I speak from experience here.)
>>> phonePattern = re.compile(r'^(\d{3})-(\d{3})-(\d{4})-(\d+)$')  
>>> phonePattern.search('800-555-1212-1234').groups()              
('800', '555', '1212', '1234')
>>> phonePattern.search('800 555 1212 1234')                       
>>> 
>>> phonePattern.search('800-555-1212')                            
>>> 
  1. This regular expression is almost identical to the previous one. Just as before, you match the beginning of the string, then a remembered group of three digits, then a hyphen, then a remembered group of three digits, then a hyphen, then a remembered group of four digits. What’s new is that you then match another hyphen, and a remembered group of one or more digits, then the end of the string.
  2. The groups() method now returns a tuple of four elements, since the regular expression now defines four groups to remember.
  3. Unfortunately, this regular expression is not the final answer either, because it assumes that the different parts of the phone number are separated by hyphens. What if they’re separated by spaces, or commas, or dots? You need a more general solution to match several different types of separators.
  4. Oops! Not only does this regular expression not do everything you want, it’s actually a step backwards, because now you can’t parse phone numbers without an extension. That’s not what you wanted at all; if the extension is there, you want to know what it is, but if it’s not there, you still want to know what the different parts of the main number are.

The next example shows the regular expression to handle separators between the different parts of the phone number.

>>> phonePattern = re.compile(r'^(\d{3})\D+(\d{3})\D+(\d{4})\D+(\d+)$')  
>>> phonePattern.search('800 555 1212 1234').groups()  
('800', '555', '1212', '1234')
>>> phonePattern.search('800-555-1212-1234').groups()  
('800', '555', '1212', '1234')
>>> phonePattern.search('80055512121234')              
>>> 
>>> phonePattern.search('800-555-1212')                
>>> 
  1. Hang on to your hat. You’re matching the beginning of the string, then a group of three digits, then \D+. What the heck is that? Well, \D matches any character except a numeric digit, and + means “1 or more”. So \D+ matches one or more characters that are not digits. This is what you’re using instead of a literal hyphen, to try to match different separators.
  2. Using \D+ instead of - means you can now match phone numbers where the parts are separated by spaces instead of hyphens.
  3. Of course, phone numbers separated by hyphens still work too.
  4. Unfortunately, this is still not the final answer, because it assumes that there is a separator at all. What if the phone number is entered without any spaces or hyphens at all?
  5. Oops! This still hasn’t fixed the problem of requiring extensions. Now you have two problems, but you can solve both of them with the same technique.

The next example shows the regular expression for handling phone numbers without separators.

>>> phonePattern = re.compile(r'^(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$')  
>>> phonePattern.search('80055512121234').groups()      
('800', '555', '1212', '1234')
>>> phonePattern.search('800.555.1212 x1234').groups()  
('800', '555', '1212', '1234')
>>> phonePattern.search('800-555-1212').groups()        
('800', '555', '1212', '')
>>> phonePattern.search('(800)5551212 x1234')           
>>> 
  1. The only change you’ve made since that last step is changing all the + to *. Instead of \D+ between the parts of the phone number, you now match on \D*. Remember that + means “1 or more”? Well, * means “zero or more”. So now you should be able to parse phone numbers even when there is no separator character at all.
  2. Lo and behold, it actually works. Why? You matched the beginning of the string, then a remembered group of three digits (800), then zero non-numeric characters, then a remembered group of three digits (555), then zero non-numeric characters, then a remembered group of four digits (1212), then zero non-numeric characters, then a remembered group of an arbitrary number of digits (1234), then the end of the string.
  3. Other variations work now too: dots instead of hyphens, and both a space and an x before the extension.
  4. Finally, you’ve solved the other long-standing problem: extensions are optional again. If no extension is found, the groups() method still returns a tuple of four elements, but the fourth element is just an empty string.
  5. I hate to be the bearer of bad news, but you’re not finished yet. What’s the problem here? There’s an extra character before the area code, but the regular expression assumes that the area code is the first thing at the beginning of the string. No problem, you can use the same technique of “zero or more non-numeric characters” to skip over the leading characters before the area code.

The next example shows how to handle leading characters in phone numbers.

>>> phonePattern = re.compile(r'^\D*(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$')  
>>> phonePattern.search('(800)5551212 ext. 1234').groups()                  
('800', '555', '1212', '1234')
>>> phonePattern.search('800-555-1212').groups()                            
('800', '555', '1212', '')
>>> phonePattern.search('work 1-(800) 555.1212 #1234')                      
>>> 
  1. This is the same as in the previous example, except now you’re matching \D*, zero or more non-numeric characters, before the first remembered group (the area code). Notice that you’re not remembering these non-numeric characters (they’re not in parentheses). If you find them, you’ll just skip over them and then start remembering the area code whenever you get to it.
  2. You can successfully parse the phone number, even with the leading left parenthesis before the area code. (The right parenthesis after the area code is already handled; it’s treated as a non-numeric separator and matched by the \D* after the first remembered group.)
  3. Just a sanity check to make sure you haven’t broken anything that used to work. Since the leading characters are entirely optional, this matches the beginning of the string, then zero non-numeric characters, then a remembered group of three digits (800), then one non-numeric character (the hyphen), then a remembered group of three digits (555), then one non-numeric character (the hyphen), then a remembered group of four digits (1212), then zero non-numeric characters, then a remembered group of zero digits, then the end of the string.
  4. This is where regular expressions make me want to gouge my eyes out with a blunt object. Why doesn’t this phone number match? Because there’s a 1 before the area code, but you assumed that all the leading characters before the area code were non-numeric characters (\D*). Aargh.

Let’s back up for a second. So far the regular expressions have all matched from the beginning of the string. But now you see that there may be an indeterminate amount of stuff at the beginning of the string that you want to ignore. Rather than trying to match it all just so you can skip over it, let’s take a different approach: don’t explicitly match the beginning of the string at all. This approach is shown in the next example.

>>> phonePattern = re.compile(r'(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$')  
>>> phonePattern.search('work 1-(800) 555.1212 #1234').groups()         
('800', '555', '1212', '1234')
>>> phonePattern.search('800-555-1212').groups()                        
('800', '555', '1212', '')
>>> phonePattern.search('80055512121234').groups()                      
('800', '555', '1212', '1234')
  1. Note the lack of ^ in this regular expression. You are not matching the beginning of the string anymore. There’s nothing that says you need to match the entire input with your regular expression. The regular expression engine will do the hard work of figuring out where the input string starts to match, and go from there.
  2. Now you can successfully parse a phone number that includes leading characters and a leading digit, plus any number of any kind of separators around each part of the phone number.
  3. Sanity check. This still works.
  4. That still works too.

See how quickly a regular expression can get out of control? Take a quick glance at any of the previous iterations. Can you tell the difference between one and the next?

While you still understand the final answer (and it is the final answer; if you’ve discovered a case it doesn’t handle, I don’t want to know about it), let’s write it out as a verbose regular expression, before you forget why you made the choices you made.

>>> phonePattern = re.compile(r'''
                # don't match beginning of string, number can start anywhere
    (\d{3})     # area code is 3 digits (e.g. '800')
    \D*         # optional separator is any number of non-digits
    (\d{3})     # trunk is 3 digits (e.g. '555')
    \D*         # optional separator
    (\d{4})     # rest of number is 4 digits (e.g. '1212')
    \D*         # optional separator
    (\d*)       # extension is optional and can be any number of digits
    $           # end of string
    ''', re.VERBOSE)
>>> phonePattern.search('work 1-(800) 555.1212 #1234').groups()  
('800', '555', '1212', '1234')
>>> phonePattern.search('800-555-1212')                          
('800', '555', '1212', '')
  1. Other than being spread out over multiple lines, this is exactly the same regular expression as the last step, so it’s no surprise that it parses the same inputs.
  2. Final sanity check. Yes, this still works. You’re done.

Summary

This is just the tiniest tip of the iceberg of what regular expressions can do. In other words, even though you’re completely overwhelmed by them now, believe me, you ain’t seen nothing yet.

You should now be familiar with the following techniques:

Regular expressions are extremely powerful, but they are not the correct solution for every problem. You should learn enough about them to know when they are appropriate, when they will solve your problems, and when they will cause more problems than they solve.

© 2001–11 Mark Pilgrim diveintopython3-20110517-77958af.orig/refactoring.html0000644000000000000000000007440511773544727021013 0ustar rootroot Refactoring - Dive Into Python 3

  

You are here: Home Dive Into Python 3

Difficulty level: ♦♦♦♦♢

Refactoring

After one has played a vast quantity of notes and more notes, it is simplicity that emerges as the crowning reward of art.
Frédéric Chopin

 

Diving In

Like it or not, bugs happen. Despite your best efforts to write comprehensive unit tests, bugs happen. What do I mean by “bug”? A bug is a test case you haven’t written yet.

>>> import roman7
>>> roman7.from_roman('') 
0
  1. This is a bug. An empty string should raise an InvalidRomanNumeralError exception, just like any other sequence of characters that don’t represent a valid Roman numeral.

After reproducing the bug, and before fixing it, you should write a test case that fails, thus illustrating the bug.

class FromRomanBadInput(unittest.TestCase):  
    .
    .
    .
    def testBlank(self):
        '''from_roman should fail with blank string'''
        self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, '') 
  1. Pretty simple stuff here. Call from_roman() with an empty string and make sure it raises an InvalidRomanNumeralError exception. The hard part was finding the bug; now that you know about it, testing for it is the easy part.

Since your code has a bug, and you now have a test case that tests this bug, the test case will fail:

you@localhost:~/diveintopython3/examples$ python3 romantest8.py -v
from_roman should fail with blank string ... FAIL
from_roman should fail with malformed antecedents ... ok
from_roman should fail with repeated pairs of numerals ... ok
from_roman should fail with too many repeated numerals ... ok
from_roman should give known result with known input ... ok
to_roman should give known result with known input ... ok
from_roman(to_roman(n))==n for all n ... ok
to_roman should fail with negative input ... ok
to_roman should fail with non-integer input ... ok
to_roman should fail with large input ... ok
to_roman should fail with 0 input ... ok

======================================================================
FAIL: from_roman should fail with blank string
----------------------------------------------------------------------
Traceback (most recent call last):
  File "romantest8.py", line 117, in test_blank
    self.assertRaises(roman8.InvalidRomanNumeralError, roman8.from_roman, '')
AssertionError: InvalidRomanNumeralError not raised by from_roman

----------------------------------------------------------------------
Ran 11 tests in 0.171s

FAILED (failures=1)

Now you can fix the bug.

def from_roman(s):
    '''convert Roman numeral to integer'''
    if not s:                                                                  
        raise InvalidRomanNumeralError('Input can not be blank')
    if not re.search(romanNumeralPattern, s):
        raise InvalidRomanNumeralError('Invalid Roman numeral: {}'.format(s))  

    result = 0
    index = 0
    for numeral, integer in romanNumeralMap:
        while s[index:index+len(numeral)] == numeral:
            result += integer
            index += len(numeral)
    return result
  1. Only two lines of code are required: an explicit check for an empty string, and a raise statement.
  2. I don’t think I’ve mentioned this yet anywhere in this book, so let this serve as your final lesson in string formatting. Starting in Python 3.1, you can skip the numbers when using positional indexes in a format specifier. That is, instead of using the format specifier {0} to refer to the first parameter to the format() method, you can simply use {} and Python will fill in the proper positional index for you. This works for any number of arguments; the first {} is {0}, the second {} is {1}, and so forth.
you@localhost:~/diveintopython3/examples$ python3 romantest8.py -v
from_roman should fail with blank string ... ok  
from_roman should fail with malformed antecedents ... ok
from_roman should fail with repeated pairs of numerals ... ok
from_roman should fail with too many repeated numerals ... ok
from_roman should give known result with known input ... ok
to_roman should give known result with known input ... ok
from_roman(to_roman(n))==n for all n ... ok
to_roman should fail with negative input ... ok
to_roman should fail with non-integer input ... ok
to_roman should fail with large input ... ok
to_roman should fail with 0 input ... ok

----------------------------------------------------------------------
Ran 11 tests in 0.156s

OK  
  1. The blank string test case now passes, so the bug is fixed.
  2. All the other test cases still pass, which means that this bug fix didn’t break anything else. Stop coding.

Coding this way does not make fixing bugs any easier. Simple bugs (like this one) require simple test cases; complex bugs will require complex test cases. In a testing-centric environment, it may seem like it takes longer to fix a bug, since you need to articulate in code exactly what the bug is (to write the test case), then fix the bug itself. Then if the test case doesn’t pass right away, you need to figure out whether the fix was wrong, or whether the test case itself has a bug in it. However, in the long run, this back-and-forth between test code and code tested pays for itself, because it makes it more likely that bugs are fixed correctly the first time. Also, since you can easily re-run all the test cases along with your new one, you are much less likely to break old code when fixing new code. Today’s unit test is tomorrow’s regression test.

Handling Changing Requirements

Despite your best efforts to pin your customers to the ground and extract exact requirements from them on pain of horrible nasty things involving scissors and hot wax, requirements will change. Most customers don’t know what they want until they see it, and even if they do, they aren’t that good at articulating what they want precisely enough to be useful. And even if they do, they’ll want more in the next release anyway. So be prepared to update your test cases as requirements change.

Suppose, for instance, that you wanted to expand the range of the Roman numeral conversion functions. Normally, no character in a Roman numeral can be repeated more than three times in a row. But the Romans were willing to make an exception to that rule by having 4 M characters in a row to represent 4000. If you make this change, you’ll be able to expand the range of convertible numbers from 1..3999 to 1..4999. But first, you need to make some changes to your test cases.

[download roman8.py]

class KnownValues(unittest.TestCase):
    known_values = ( (1, 'I'),
                      .
                      .
                      .
                     (3999, 'MMMCMXCIX'),
                     (4000, 'MMMM'),                                      
                     (4500, 'MMMMD'),
                     (4888, 'MMMMDCCCLXXXVIII'),
                     (4999, 'MMMMCMXCIX') )

class ToRomanBadInput(unittest.TestCase):
    def test_too_large(self):
        '''to_roman should fail with large input'''
        self.assertRaises(roman8.OutOfRangeError, roman8.to_roman, 5000)  

    .
    .
    .

class FromRomanBadInput(unittest.TestCase):
    def test_too_many_repeated_numerals(self):
        '''from_roman should fail with too many repeated numerals'''
        for s in ('MMMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):     
            self.assertRaises(roman8.InvalidRomanNumeralError, roman8.from_roman, s)

    .
    .
    .

class RoundtripCheck(unittest.TestCase):
    def test_roundtrip(self):
        '''from_roman(to_roman(n))==n for all n'''
        for integer in range(1, 5000):                                    
            numeral = roman8.to_roman(integer)
            result = roman8.from_roman(numeral)
            self.assertEqual(integer, result)
  1. The existing known values don’t change (they’re all still reasonable values to test), but you need to add a few more in the 4000 range. Here I’ve included 4000 (the shortest), 4500 (the second shortest), 4888 (the longest), and 4999 (the largest).
  2. The definition of “large input” has changed. This test used to call to_roman() with 4000 and expect an error; now that 4000-4999 are good values, you need to bump this up to 5000.
  3. The definition of “too many repeated numerals” has also changed. This test used to call from_roman() with 'MMMM' and expect an error; now that MMMM is considered a valid Roman numeral, you need to bump this up to 'MMMMM'.
  4. The sanity check loops through every number in the range, from 1 to 3999. Since the range has now expanded, this for loop need to be updated as well to go up to 4999.

Now your test cases are up to date with the new requirements, but your code is not, so you expect several of the test cases to fail.

you@localhost:~/diveintopython3/examples$ python3 romantest9.py -v
from_roman should fail with blank string ... ok
from_roman should fail with malformed antecedents ... ok
from_roman should fail with non-string input ... ok
from_roman should fail with repeated pairs of numerals ... ok
from_roman should fail with too many repeated numerals ... ok
from_roman should give known result with known input ... ERROR          
to_roman should give known result with known input ... ERROR            
from_roman(to_roman(n))==n for all n ... ERROR                          
to_roman should fail with negative input ... ok
to_roman should fail with non-integer input ... ok
to_roman should fail with large input ... ok
to_roman should fail with 0 input ... ok

======================================================================
ERROR: from_roman should give known result with known input
----------------------------------------------------------------------
Traceback (most recent call last):
  File "romantest9.py", line 82, in test_from_roman_known_values
    result = roman9.from_roman(numeral)
  File "C:\home\diveintopython3\examples\roman9.py", line 60, in from_roman
    raise InvalidRomanNumeralError('Invalid Roman numeral: {0}'.format(s))
roman9.InvalidRomanNumeralError: Invalid Roman numeral: MMMM

======================================================================
ERROR: to_roman should give known result with known input
----------------------------------------------------------------------
Traceback (most recent call last):
  File "romantest9.py", line 76, in test_to_roman_known_values
    result = roman9.to_roman(integer)
  File "C:\home\diveintopython3\examples\roman9.py", line 42, in to_roman
    raise OutOfRangeError('number out of range (must be 0..3999)')
roman9.OutOfRangeError: number out of range (must be 0..3999)

======================================================================
ERROR: from_roman(to_roman(n))==n for all n
----------------------------------------------------------------------
Traceback (most recent call last):
  File "romantest9.py", line 131, in testSanity
    numeral = roman9.to_roman(integer)
  File "C:\home\diveintopython3\examples\roman9.py", line 42, in to_roman
    raise OutOfRangeError('number out of range (must be 0..3999)')
roman9.OutOfRangeError: number out of range (must be 0..3999)

----------------------------------------------------------------------
Ran 12 tests in 0.171s

FAILED (errors=3)
  1. The from_roman() known values test will fail as soon as it hits 'MMMM', because from_roman() still thinks this is an invalid Roman numeral.
  2. The to_roman() known values test will fail as soon as it hits 4000, because to_roman() still thinks this is out of range.
  3. The roundtrip check will also fail as soon as it hits 4000, because to_roman() still thinks this is out of range.

Now that you have test cases that fail due to the new requirements, you can think about fixing the code to bring it in line with the test cases. (When you first start coding unit tests, it might feel strange that the code being tested is never “ahead” of the test cases. While it’s behind, you still have some work to do, and as soon as it catches up to the test cases, you stop coding. After you get used to it, you’ll wonder how you ever programmed without tests.)

[download roman9.py]

roman_numeral_pattern = re.compile('''
    ^                   # beginning of string
    M{0,4}              # thousands - 0 to 4 Ms  
    (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 Cs),
                        #            or 500-800 (D, followed by 0 to 3 Cs)
    (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 Xs),
                        #        or 50-80 (L, followed by 0 to 3 Xs)
    (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 Is),
                        #        or 5-8 (V, followed by 0 to 3 Is)
    $                   # end of string
    ''', re.VERBOSE)

def to_roman(n):
    '''convert integer to Roman numeral'''
    if not isinstance(n, int):
        raise NotIntegerError('non-integers can not be converted')
    if not (0 < n < 5000):                        
        raise OutOfRangeError('number out of range (must be 1..4999)')

    result = ''
    for numeral, integer in roman_numeral_map:
        while n >= integer:
            result += numeral
            n -= integer
    return result

def from_roman(s):
    .
    .
    .
  1. You don’t need to make any changes to the from_roman() function at all. The only change is to roman_numeral_pattern. If you look closely, you’ll notice that I changed the maximum number of optional M characters from 3 to 4 in the first section of the regular expression. This will allow the Roman numeral equivalents of 4999 instead of 3999. The actual from_roman() function is completely generic; it just looks for repeated Roman numeral characters and adds them up, without caring how many times they repeat. The only reason it didn’t handle 'MMMM' before is that you explicitly stopped it with the regular expression pattern matching.
  2. The to_roman() function only needs one small change, in the range check. Where you used to check 0 < n < 4000, you now check 0 < n < 5000. And you change the error message that you raise to reflect the new acceptable range (1..4999 instead of 1..3999). You don’t need to make any changes to the rest of the function; it handles the new cases already. (It merrily adds 'M' for each thousand that it finds; given 4000, it will spit out 'MMMM'. The only reason it didn’t do this before is that you explicitly stopped it with the range check.)

You may be skeptical that these two small changes are all that you need. Hey, don’t take my word for it; see for yourself.

you@localhost:~/diveintopython3/examples$ python3 romantest9.py -v
from_roman should fail with blank string ... ok
from_roman should fail with malformed antecedents ... ok
from_roman should fail with non-string input ... ok
from_roman should fail with repeated pairs of numerals ... ok
from_roman should fail with too many repeated numerals ... ok
from_roman should give known result with known input ... ok
to_roman should give known result with known input ... ok
from_roman(to_roman(n))==n for all n ... ok
to_roman should fail with negative input ... ok
to_roman should fail with non-integer input ... ok
to_roman should fail with large input ... ok
to_roman should fail with 0 input ... ok

----------------------------------------------------------------------
Ran 12 tests in 0.203s

OK  
  1. All the test cases pass. Stop coding.

Comprehensive unit testing means never having to rely on a programmer who says “Trust me.”

Refactoring

The best thing about comprehensive unit testing is not the feeling you get when all your test cases finally pass, or even the feeling you get when someone else blames you for breaking their code and you can actually prove that you didn’t. The best thing about unit testing is that it gives you the freedom to refactor mercilessly.

Refactoring is the process of taking working code and making it work better. Usually, “better” means “faster”, although it can also mean “using less memory”, or “using less disk space”, or simply “more elegantly”. Whatever it means to you, to your project, in your environment, refactoring is important to the long-term health of any program.

Here, “better” means both “faster” and “easier to maintain.” Specifically, the from_roman() function is slower and more complex than I’d like, because of that big nasty regular expression that you use to validate Roman numerals. Now, you might think, “Sure, the regular expression is big and hairy, but how else am I supposed to validate that an arbitrary string is a valid a Roman numeral?”

Answer: there’s only 5000 of them; why don’t you just build a lookup table? This idea gets even better when you realize that you don’t need to use regular expressions at all. As you build the lookup table for converting integers to Roman numerals, you can build the reverse lookup table to convert Roman numerals to integers. By the time you need to check whether an arbitrary string is a valid Roman numeral, you will have collected all the valid Roman numerals. “Validating” is reduced to a single dictionary lookup.

And best of all, you already have a complete set of unit tests. You can change over half the code in the module, but the unit tests will stay the same. That means you can prove — to yourself and to others — that the new code works just as well as the original.

[download roman10.py]

class OutOfRangeError(ValueError): pass
class NotIntegerError(ValueError): pass
class InvalidRomanNumeralError(ValueError): pass

roman_numeral_map = (('M',  1000),
                     ('CM', 900),
                     ('D',  500),
                     ('CD', 400),
                     ('C',  100),
                     ('XC', 90),
                     ('L',  50),
                     ('XL', 40),
                     ('X',  10),
                     ('IX', 9),
                     ('V',  5),
                     ('IV', 4),
                     ('I',  1))

to_roman_table = [ None ]
from_roman_table = {}

def to_roman(n):
    '''convert integer to Roman numeral'''
    if not (0 < n < 5000):
        raise OutOfRangeError('number out of range (must be 1..4999)')
    if int(n) != n:
        raise NotIntegerError('non-integers can not be converted')
    return to_roman_table[n]

def from_roman(s):
    '''convert Roman numeral to integer'''
    if not isinstance(s, str):
        raise InvalidRomanNumeralError('Input must be a string')
    if not s:
        raise InvalidRomanNumeralError('Input can not be blank')
    if s not in from_roman_table:
        raise InvalidRomanNumeralError('Invalid Roman numeral: {0}'.format(s))
    return from_roman_table[s]

def build_lookup_tables():
    def to_roman(n):
        result = ''
        for numeral, integer in roman_numeral_map:
            if n >= integer:
                result = numeral
                n -= integer
                break
        if n > 0:
            result += to_roman_table[n]
        return result

    for integer in range(1, 5000):
        roman_numeral = to_roman(integer)
        to_roman_table.append(roman_numeral)
        from_roman_table[roman_numeral] = integer

build_lookup_tables()

Let’s break that down into digestable pieces. Arguably, the most important line is the last one:

build_lookup_tables()

You will note that is a function call, but there’s no if statement around it. This is not an if __name__ == '__main__' block; it gets called when the module is imported. (It is important to understand that modules are only imported once, then cached. If you import an already-imported module, it does nothing. So this code will only get called the first time you import this module.)

So what does the build_lookup_tables() function do? I’m glad you asked.

to_roman_table = [ None ]
from_roman_table = {}
.
.
.
def build_lookup_tables():
    def to_roman(n):                                
        result = ''
        for numeral, integer in roman_numeral_map:
            if n >= integer:
                result = numeral
                n -= integer
                break
        if n > 0:
            result += to_roman_table[n]
        return result

    for integer in range(1, 5000):
        roman_numeral = to_roman(integer)          
        to_roman_table.append(roman_numeral)       
        from_roman_table[roman_numeral] = integer
  1. This is a clever bit of programming… perhaps too clever. The to_roman() function is defined above; it looks up values in the lookup table and returns them. But the build_lookup_tables() function redefines the to_roman() function to actually do work (like the previous examples did, before you added a lookup table). Within the build_lookup_tables() function, calling to_roman() will call this redefined version. Once the build_lookup_tables() function exits, the redefined version disappears — it is only defined in the local scope of the build_lookup_tables() function.
  2. This line of code will call the redefined to_roman() function, which actually calculates the Roman numeral.
  3. Once you have the result (from the redefined to_roman() function), you add the integer and its Roman numeral equivalent to both lookup tables.

Once the lookup tables are built, the rest of the code is both easy and fast.

def to_roman(n):
    '''convert integer to Roman numeral'''
    if not (0 < n < 5000):
        raise OutOfRangeError('number out of range (must be 1..4999)')
    if int(n) != n:
        raise NotIntegerError('non-integers can not be converted')
    return to_roman_table[n]                                            

def from_roman(s):
    '''convert Roman numeral to integer'''
    if not isinstance(s, str):
        raise InvalidRomanNumeralError('Input must be a string')
    if not s:
        raise InvalidRomanNumeralError('Input can not be blank')
    if s not in from_roman_table:
        raise InvalidRomanNumeralError('Invalid Roman numeral: {0}'.format(s))
    return from_roman_table[s]                                          
  1. After doing the same bounds checking as before, the to_roman() function simply finds the appropriate value in the lookup table and returns it.
  2. Similarly, the from_roman() function is reduced to some bounds checking and one line of code. No more regular expressions. No more looping. O(1) conversion to and from Roman numerals.

But does it work? Why yes, yes it does. And I can prove it.

you@localhost:~/diveintopython3/examples$ python3 romantest10.py -v
from_roman should fail with blank string ... ok
from_roman should fail with malformed antecedents ... ok
from_roman should fail with non-string input ... ok
from_roman should fail with repeated pairs of numerals ... ok
from_roman should fail with too many repeated numerals ... ok
from_roman should give known result with known input ... ok
to_roman should give known result with known input ... ok
from_roman(to_roman(n))==n for all n ... ok
to_roman should fail with negative input ... ok
to_roman should fail with non-integer input ... ok
to_roman should fail with large input ... ok
to_roman should fail with 0 input ... ok

----------------------------------------------------------------------
Ran 12 tests in 0.031s                                                  

OK
  1. Not that you asked, but it’s fast, too! Like, almost 10× as fast. Of course, it’s not entirely a fair comparison, because this version takes longer to import (when it builds the lookup tables). But since the import is only done once, the startup cost is amortized over all the calls to the to_roman() and from_roman() functions. Since the tests make several thousand function calls (the roundtrip test alone makes 10,000), this savings adds up in a hurry!

The moral of the story?

Summary

Unit testing is a powerful concept which, if properly implemented, can both reduce maintenance costs and increase flexibility in any long-term project. It is also important to understand that unit testing is not a panacea, a Magic Problem Solver, or a silver bullet. Writing good test cases is hard, and keeping them up to date takes discipline (especially when customers are screaming for critical bug fixes). Unit testing is not a replacement for other forms of testing, including functional testing, integration testing, and user acceptance testing. But it is feasible, and it does work, and once you’ve seen it work, you’ll wonder how you ever got along without it.

These few chapters have covered a lot of ground, and much of it wasn’t even Python-specific. There are unit testing frameworks for many languages, all of which require you to understand the same basic concepts:

© 2001–11 Mark Pilgrim diveintopython3-20110517-77958af.orig/files.html0000644000000000000000000014363611773544727017615 0ustar rootroot Files - Dive Into Python 3

  

You are here: Home Dive Into Python 3

Difficulty level: ♦♦♦♢♢

Files

A nine mile walk is no joke, especially in the rain.
— Harry Kemelman, The Nine Mile Walk

 

Diving In

My Windows laptop had 38,493 files before I installed a single application. Installing Python 3 added almost 3,000 files to that total. Files are the primary storage paradigm of every major operating system; the concept is so ingrained that most people would have trouble imagining an alternative. Your computer is, metaphorically speaking, drowning in files.

Reading From Text Files

Before you can read from a file, you need to open it. Opening a file in Python couldn’t be easier:

a_file = open('examples/chinese.txt', encoding='utf-8')

Python has a built-in open() function, which takes a filename as an argument. Here the filename is 'examples/chinese.txt'. There are five interesting things about this filename:

  1. It’s not just the name of a file; it’s a combination of a directory path and a filename. A hypothetical file-opening function could have taken two arguments — a directory path and a filename — but the open() function only takes one. In Python, whenever you need a “filename,” you can include some or all of a directory path as well.
  2. The directory path uses a forward slash, but I didn’t say what operating system I was using. Windows uses backward slashes to denote subdirectories, while Mac OS X and Linux use forward slashes. But in Python, forward slashes always Just Work, even on Windows.
  3. The directory path does not begin with a slash or a drive letter, so it is called a relative path. Relative to what, you might ask? Patience, grasshopper.
  4. It’s a string. All modern operating systems (even Windows!) use Unicode to store the names of files and directories. Python 3 fully supports non-ASCII pathnames.
  5. It doesn’t need to be on your local disk. You might have a network drive mounted. That “file” might be a figment of an entirely virtual filesystem. If your computer considers it a file and can access it as a file, Python can open it.

But that call to the open() function didn’t stop at the filename. There’s another argument, called encoding. Oh dear, that sounds dreadfully familiar.

Character Encoding Rears Its Ugly Head

Bytes are bytes; characters are an abstraction. A string is a sequence of Unicode characters. But a file on disk is not a sequence of Unicode characters; a file on disk is a sequence of bytes. So if you read a “text file” from disk, how does Python convert that sequence of bytes into a sequence of characters? It decodes the bytes according to a specific character encoding algorithm and returns a sequence of Unicode characters (otherwise known as a string).

# This example was created on Windows. Other platforms may
# behave differently, for reasons outlined below.
>>> file = open('examples/chinese.txt')
>>> a_string = file.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python31\lib\encodings\cp1252.py", line 23, in decode
    return codecs.charmap_decode(input,self.errors,decoding_table)[0]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x8f in position 28: character maps to <undefined>
>>> 

What just happened? You didn’t specify a character encoding, so Python is forced to use the default encoding. What’s the default encoding? If you look closely at the traceback, you can see that it’s dying in cp1252.py, meaning that Python is using CP-1252 as the default encoding here. (CP-1252 is a common encoding on computers running Microsoft Windows.) The CP-1252 character set doesn’t support the characters that are in this file, so the read fails with an ugly UnicodeDecodeError.

But wait, it’s worse than that! The default encoding is platform-dependent, so this code might work on your computer (if your default encoding is UTF-8), but then it will fail when you distribute it to someone else (whose default encoding is different, like CP-1252).

If you need to get the default character encoding, import the locale module and call locale.getpreferredencoding(). On my Windows laptop, it returns 'cp1252', but on my Linux box upstairs, it returns 'UTF8'. I can’t even maintain consistency in my own house! Your results may be different (even on Windows) depending on which version of your operating system you have installed and how your regional/language settings are configured. This is why it’s so important to specify the encoding every time you open a file.

Stream Objects

So far, all we know is that Python has a built-in function called open(). The open() function returns a stream object, which has methods and attributes for getting information about and manipulating a stream of characters.

>>> a_file = open('examples/chinese.txt', encoding='utf-8')
>>> a_file.name                                              
'examples/chinese.txt'
>>> a_file.encoding                                          
'utf-8'
>>> a_file.mode                                              
'r'
  1. The name attribute reflects the name you passed in to the open() function when you opened the file. It is not normalized to an absolute pathname.
  2. Likewise, encoding attribute reflects the encoding you passed in to the open() function. If you didn’t specify the encoding when you opened the file (bad developer!) then the encoding attribute will reflect locale.getpreferredencoding().
  3. The mode attribute tells you in which mode the file was opened. You can pass an optional mode parameter to the open() function. You didn’t specify a mode when you opened this file, so Python defaults to 'r', which means “open for reading only, in text mode.” As you’ll see later in this chapter, the file mode serves several purposes; different modes let you write to a file, append to a file, or open a file in binary mode (in which you deal with bytes instead of strings).

The documentation for the open() function lists all the possible file modes.

Reading Data From A Text File

After you open a file for reading, you’ll probably want to read from it at some point.

>>> a_file = open('examples/chinese.txt', encoding='utf-8')
>>> a_file.read()                                            
'Dive Into Python 是为有经验的程序员编写的一本 Python 书。\n'
>>> a_file.read()                                            
''
  1. Once you open a file (with the correct encoding), reading from it is just a matter of calling the stream object’s read() method. The result is a string.
  2. Perhaps somewhat surprisingly, reading the file again does not raise an exception. Python does not consider reading past end-of-file to be an error; it simply returns an empty string.

What if you want to re-read a file?

# continued from the previous example
>>> a_file.read()                      
''
>>> a_file.seek(0)                     
0
>>> a_file.read(16)                    
'Dive Into Python'
>>> a_file.read(1)                     
' '
>>> a_file.read(1)
'是'
>>> a_file.tell()                      
20
  1. Since you’re still at the end of the file, further calls to the stream object’s read() method simply return an empty string.
  2. The seek() method moves to a specific byte position in a file.
  3. The read() method can take an optional parameter, the number of characters to read.
  4. If you like, you can even read one character at a time.
  5. 16 + 1 + 1 = … 20?

Let’s try that again.

# continued from the previous example
>>> a_file.seek(17)                    
17
>>> a_file.read(1)                     
'是'
>>> a_file.tell()                      
20
  1. Move to the 17th byte.
  2. Read one character.
  3. Now you’re on the 20th byte.

Do you see it yet? The seek() and tell() methods always count bytes, but since you opened this file as text, the read() method counts characters. Chinese characters require multiple bytes to encode in UTF-8. The English characters in the file only require one byte each, so you might be misled into thinking that the seek() and read() methods are counting the same thing. But that’s only true for some characters.

But wait, it gets worse!

>>> a_file.seek(18)                         
18
>>> a_file.read(1)                          
Traceback (most recent call last):
  File "<pyshell#12>", line 1, in <module>
    a_file.read(1)
  File "C:\Python31\lib\codecs.py", line 300, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf8' codec can't decode byte 0x98 in position 0: unexpected code byte
  1. Move to the 18th byte and try to read one character.
  2. Why does this fail? Because there isn’t a character at the 18th byte. The nearest character starts at the 17th byte (and goes for three bytes). Trying to read a character from the middle will fail with a UnicodeDecodeError.

Closing Files

Open files consume system resources, and depending on the file mode, other programs may not be able to access them. It’s important to close files as soon as you’re finished with them.

# continued from the previous example
>>> a_file.close()

Well that was anticlimactic.

The stream object a_file still exists; calling its close() method doesn’t destroy the object itself. But it’s not terribly useful.

# continued from the previous example
>>> a_file.read()                           
Traceback (most recent call last):
  File "<pyshell#24>", line 1, in <module>
    a_file.read()
ValueError: I/O operation on closed file.
>>> a_file.seek(0)                          
Traceback (most recent call last):
  File "<pyshell#25>", line 1, in <module>
    a_file.seek(0)
ValueError: I/O operation on closed file.
>>> a_file.tell()                           
Traceback (most recent call last):
  File "<pyshell#26>", line 1, in <module>
    a_file.tell()
ValueError: I/O operation on closed file.
>>> a_file.close()                          
>>> a_file.closed                           
True
  1. You can’t read from a closed file; that raises an IOError exception.
  2. You can’t seek in a closed file either.
  3. There’s no current position in a closed file, so the tell() method also fails.
  4. Perhaps surprisingly, calling the close() method on a stream object whose file has been closed does not raise an exception. It’s just a no-op.
  5. Closed stream objects do have one useful attribute: the closed attribute will confirm that the file is closed.

Closing Files Automatically

Stream objects have an explicit close() method, but what happens if your code has a bug and crashes before you call close()? That file could theoretically stay open for much longer than necessary. While you’re debugging on your local computer, that’s not a big deal. On a production server, maybe it is.

Python 2 had a solution for this: the try..finally block. That still works in Python 3, and you may see it in other people’s code or in older code that was ported to Python 3. But Python 2.6 introduced a cleaner solution, which is now the preferred solution in Python 3: the with statement.

with open('examples/chinese.txt', encoding='utf-8') as a_file:
    a_file.seek(17)
    a_character = a_file.read(1)
    print(a_character)

This code calls open(), but it never calls a_file.close(). The with statement starts a code block, like an if statement or a for loop. Inside this code block, you can use the variable a_file as the stream object returned from the call to open(). All the regular stream object methods are available — seek(), read(), whatever you need. When the with block ends, Python calls a_file.close() automatically.

Here’s the kicker: no matter how or when you exit the with block, Python will close that file… even if you “exit” it via an unhandled exception. That’s right, even if your code raises an exception and your entire program comes to a screeching halt, that file will get closed. Guaranteed.

In technical terms, the with statement creates a runtime context. In these examples, the stream object acts as a context manager. Python creates the stream object a_file and tells it that it is entering a runtime context. When the with code block is completed, Python tells the stream object that it is exiting the runtime context, and the stream object calls its own close() method. See Appendix B, “Classes That Can Be Used in a with Block” for details.

There’s nothing file-specific about the with statement; it’s just a generic framework for creating runtime contexts and telling objects that they’re entering and exiting a runtime context. If the object in question is a stream object, then it does useful file-like things (like closing the file automatically). But that behavior is defined in the stream object, not in the with statement. There are lots of other ways to use context managers that have nothing to do with files. You can even create your own, as you’ll see later in this chapter.

Reading Data One Line At A Time

A “line” of a text file is just what you think it is — you type a few words and press ENTER, and now you’re on a new line. A line of text is a sequence of characters delimited by… what exactly? Well, it’s complicated, because text files can use several different characters to mark the end of a line. Every operating system has its own convention. Some use a carriage return character, others use a line feed character, and some use both characters at the end of every line.

Now breathe a sigh of relief, because Python handles line endings automatically by default. If you say, “I want to read this text file one line at a time,” Python will figure out which kind of line ending the text file uses and and it will all Just Work.

If you need fine-grained control over what’s considered a line ending, you can pass the optional newline parameter to the open() function. See the open() function documentation for all the gory details.

So, how do you actually do it? Read a file one line at a time, that is. It’s so simple, it’s beautiful.

[download oneline.py]

line_number = 0
with open('examples/favorite-people.txt', encoding='utf-8') as a_file:  
    for a_line in a_file:                                               
        line_number += 1
        print('{:>4} {}'.format(line_number, a_line.rstrip()))          
  1. Using the with pattern, you safely open the file and let Python close it for you.
  2. To read a file one line at a time, use a for loop. That’s it. Besides having explicit methods like read(), the stream object is also an iterator which spits out a single line every time you ask for a value.
  3. Using the format() string method, you can print out the line number and the line itself. The format specifier {:>4} means “print this argument right-justified within 4 spaces.” The a_line variable contains the complete line, carriage returns and all. The rstrip() string method removes the trailing whitespace, including the carriage return characters.
you@localhost:~/diveintopython3$ python3 examples/oneline.py
   1 Dora
   2 Ethan
   3 Wesley
   4 John
   5 Anne
   6 Mike
   7 Chris
   8 Sarah
   9 Alex
  10 Lizzie

Did you get this error?

you@localhost:~/diveintopython3$ python3 examples/oneline.py
Traceback (most recent call last):
  File "examples/oneline.py", line 4, in <module>
    print('{:>4} {}'.format(line_number, a_line.rstrip()))
ValueError: zero length field name in format

If so, you’re probably using Python 3.0. You should really upgrade to Python 3.1.

Python 3.0 supported string formatting, but only with explicitly numbered format specifiers. Python 3.1 allows you to omit the argument indexes in your format specifiers. Here is the Python 3.0-compatible version for comparison:

print('{0:>4} {1}'.format(line_number, a_line.rstrip()))

Writing to Text Files

You can write to files in much the same way that you read from them. First you open a file and get a stream object, then you use methods on the stream object to write data to the file, then you close the file.

To open a file for writing, use the open() function and specify the write mode. There are two file modes for writing:

Either mode will create the file automatically if it doesn’t already exist, so there’s never a need for any sort of fiddly “if the file doesn’t exist yet, create a new empty file just so you can open it for the first time” function. Just open a file and start writing.

You should always close a file as soon as you’re done writing to it, to release the file handle and ensure that the data is actually written to disk. As with reading data from a file, you can call the stream object’s close() method, or you can use the with statement and let Python close the file for you. I bet you can guess which technique I recommend.

>>> with open('test.log', mode='w', encoding='utf-8') as a_file:  
...     a_file.write('test succeeded')                            
>>> with open('test.log', encoding='utf-8') as a_file:
...     print(a_file.read())                              
test succeeded
>>> with open('test.log', mode='a', encoding='utf-8') as a_file:  
...     a_file.write('and again')
>>> with open('test.log', encoding='utf-8') as a_file:
...     print(a_file.read())                              
test succeededand again                                           
  1. You start boldly by creating the new file test.log (or overwriting the existing file), and opening the file for writing. The mode='w' parameter means open the file for writing. Yes, that’s all as dangerous as it sounds. I hope you didn’t care about the previous contents of that file (if any), because that data is gone now.
  2. You can add data to the newly opened file with the write() method of the stream object returned by the open() function. After the with block ends, Python automatically closes the file.
  3. That was so fun, let’s do it again. But this time, with mode='a' to append to the file instead of overwriting it. Appending will never harm the existing contents of the file.
  4. Both the original line you wrote and the second line you appended are now in the file test.log. Also note that neither carriage returns nor line feeds are included. Since you didn’t write them explicitly to the file either time, the file doesn’t include them. You can write a carriage return with the '\r' character, and/or a line feed with the '\n' character. Since you didn’t do either, everything you wrote to the file ended up on one line.

Character Encoding Again

Did you notice the encoding parameter that got passed in to the open() function while you were opening a file for writing? It’s important; don’t ever leave it out! As you saw in the beginning of this chapter, files don’t contain strings, they contain bytes. Reading a “string” from a text file only works because you told Python what encoding to use to read a stream of bytes and convert it to a string. Writing text to a file presents the same problem in reverse. You can’t write characters to a file; characters are an abstraction. In order to write to the file, Python needs to know how to convert your string into a sequence of bytes. The only way to be sure it’s performing the correct conversion is to specify the encoding parameter when you open the file for writing.

Binary Files

my dog Beauregard

Not all files contain text. Some of them contain pictures of my dog.

>>> an_image = open('examples/beauregard.jpg', mode='rb')                
>>> an_image.mode                                                        
'rb'
>>> an_image.name                                                        
'examples/beauregard.jpg'
>>> an_image.encoding                                                    
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: '_io.BufferedReader' object has no attribute 'encoding'
  1. Opening a file in binary mode is simple but subtle. The only difference from opening it in text mode is that the mode parameter contains a 'b' character.
  2. The stream object you get from opening a file in binary mode has many of the same attributes, including mode, which reflects the mode parameter you passed into the open() function.
  3. Binary stream objects also have a name attribute, just like text stream objects.
  4. Here’s one difference, though: a binary stream object has no encoding attribute. That makes sense, right? You’re reading (or writing) bytes, not strings, so there’s no conversion for Python to do. What you get out of a binary file is exactly what you put into it, no conversion necessary.

Did I mention you’re reading bytes? Oh yes you are.

# continued from the previous example
>>> an_image.tell()
0
>>> data = an_image.read(3)  
>>> data
b'\xff\xd8\xff'
>>> type(data)               
<class 'bytes'>
>>> an_image.tell()          
3
>>> an_image.seek(0)
0
>>> data = an_image.read()
>>> len(data)
3150
  1. Like text files, you can read binary files a little bit at a time. But there’s a crucial difference…
  2. …you’re reading bytes, not strings. Since you opened the file in binary mode, the read() method takes the number of bytes to read, not the number of characters.
  3. That means that there’s never an unexpected mismatch between the number you passed into the read() method and the position index you get out of the tell() method. The read() method reads bytes, and the seek() and tell() methods track the number of bytes read. For binary files, they’ll always agree.

Stream Objects From Non-File Sources

Imagine you’re writing a library, and one of your library functions is going to read some data from a file. The function could simply take a filename as a string, go open the file for reading, read it, and close it before exiting. But you shouldn’t do that. Instead, your API should take an arbitrary stream object.

In the simplest case, a stream object is anything with a read() method which takes an optional size parameter and returns a string. When called with no size parameter, the read() method should read everything there is to read from the input source and return all the data as a single value. When called with a size parameter, it reads that much from the input source and returns that much data. When called again, it picks up where it left off and returns the next chunk of data.

That sounds exactly like the stream object you get from opening a real file. The difference is that you’re not limiting yourself to real files. The input source that’s being “read” could be anything: a web page, a string in memory, even the output of another program. As long as your functions take a stream object and simply call the object’s read() method, you can handle any input source that acts like a file, without specific code to handle each kind of input.

>>> a_string = 'PapayaWhip is the new black.'
>>> import io                                  
>>> a_file = io.StringIO(a_string)             
>>> a_file.read()                              
'PapayaWhip is the new black.'
>>> a_file.read()                              
''
>>> a_file.seek(0)                             
0
>>> a_file.read(10)                            
'PapayaWhip'
>>> a_file.tell()                       
10
>>> a_file.seek(18)
18
>>> a_file.read()
'new black.'
  1. The io module defines the StringIO class that you can use to treat a string in memory as a file.
  2. To create a stream object out of a string, create an instance of the io.StringIO() class and pass it the string you want to use as your “file” data. Now you have a stream object, and you can do all sorts of stream-like things with it.
  3. Calling the read() method “reads” the entire “file,” which in the case of a StringIO object simply returns the original string.
  4. Just like a real file, calling the read() method again returns an empty string.
  5. You can explicitly seek to the beginning of the string, just like seeking through a real file, by using the seek() method of the StringIO object.
  6. You can also read the string in chunks, by passing a size parameter to the read() method.

io.StringIO lets you treat a string as a text file. There’s also a io.BytesIO class, which lets you treat a byte array as a binary file.

Handling Compressed Files

The Python standard library contains modules that support reading and writing compressed files. There are a number of different compression schemes; the two most popular on non-Windows systems are gzip and bzip2. (You may have also encountered PKZIP archives and GNU Tar archives. Python has modules for those, too.)

The gzip module lets you create a stream object for reading or writing a gzip-compressed file. The stream object it gives you supports the read() method (if you opened it for reading) or the write() method (if you opened it for writing). That means you can use the methods you’ve already learned for regular files to directly read or write a gzip-compressed file, without creating a temporary file to store the decompressed data.

As an added bonus, it supports the with statement too, so you can let Python automatically close your gzip-compressed file when you’re done with it.

you@localhost:~$ python3

>>> import gzip
>>> with gzip.open('out.log.gz', mode='wb') as z_file:                                      
...   z_file.write('A nine mile walk is no joke, especially in the rain.'.encode('utf-8'))
... 
>>> exit()

you@localhost:~$ ls -l out.log.gz                                                           
-rw-r--r--  1 mark mark    79 2009-07-19 14:29 out.log.gz
you@localhost:~$ gunzip out.log.gz                                                          
you@localhost:~$ cat out.log                                                                
A nine mile walk is no joke, especially in the rain.
  1. You should always open gzipped files in binary mode. (Note the 'b' character in the mode argument.)
  2. I constructed this example on Linux. If you’re not familiar with the command line, this command is showing the “long listing” of the gzip-compressed file you just created in the Python Shell. This listing shows that the file exists (good), and that it is 79 bytes long. That’s actually larger than the string you started with! The gzip file format includes a fixed-length header that contains some metadata about the file, so it’s inefficient for extremely small files.
  3. The gunzip command (pronounced “gee-unzip”) decompresses the file and stores the contents in a new file named the same as the compressed file but without the .gz file extension.
  4. The cat command displays the contents of a file. This file contains the string you originally wrote directly to the compressed file out.log.gz from within the Python Shell.

Did you get this error?

>>> with gzip.open('out.log.gz', mode='wb') as z_file:
...         z_file.write('A nine mile walk is no joke, especially in the rain.'.encode('utf-8'))
... 
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
AttributeError: 'GzipFile' object has no attribute '__exit__'

If so, you’re probably using Python 3.0. You should really upgrade to Python 3.1.

Python 3.0 had a gzip module, but it did not support using a gzipped-file object as a context manager. Python 3.1 added the ability to use gzipped-file objects in a with statement.

Standard Input, Output, and Error

Command-line gurus are already familiar with the concept of standard input, standard output, and standard error. This section is for the rest of you.

Standard output and standard error (commonly abbreviated stdout and stderr) are pipes that are built into every UNIX-like system, including Mac OS X and Linux. When you call the print() function, the thing you’re printing is sent to the stdout pipe. When your program crashes and prints out a traceback, it goes to the stderr pipe. By default, both of these pipes are just connected to the terminal window where you are working; when your program prints something, you see the output in your terminal window, and when a program crashes, you see the traceback in your terminal window too. In the graphical Python Shell, the stdout and stderr pipes default to your “Interactive Window”.

>>> for i in range(3):
...     print('PapayaWhip')                
PapayaWhip
PapayaWhip
PapayaWhip
>>> import sys
>>> for i in range(3):
...     l = sys.stdout.write('is the')     
is theis theis the
>>> for i in range(3):
...     l = sys.stderr.write('new black')  
new blacknew blacknew black
  1. The print() function, in a loop. Nothing surprising here.
  2. stdout is defined in the sys module, and it is a stream object. Calling its write() function will print out whatever string you give it, then return the length of the output. In fact, this is what the print function really does; it adds a carriage return to the end of the string you’re printing, and calls sys.stdout.write.
  3. In the simplest case, sys.stdout and sys.stderr send their output to the same place: the Python IDE (if you’re in one), or the terminal (if you’re running Python from the command line). Like standard output, standard error does not add carriage returns for you. If you want carriage returns, you’ll need to write carriage return characters.

sys.stdout and sys.stderr are stream objects, but they are write-only. Attempting to call their read() method will always raise an IOError.

>>> import sys
>>> sys.stdout.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: not readable

Redirecting Standard Output

sys.stdout and sys.stderr are stream objects, albeit ones that only support writing. But they’re not constants; they’re variables. That means you can assign them a new value — any other stream object — to redirect their output.

[download stdout.py]

import sys

class RedirectStdoutTo:
    def __init__(self, out_new):
        self.out_new = out_new

    def __enter__(self):
        self.out_old = sys.stdout
        sys.stdout = self.out_new

    def __exit__(self, *args):
        sys.stdout = self.out_old

print('A')
with open('out.log', mode='w', encoding='utf-8') as a_file, RedirectStdoutTo(a_file):
    print('B')
print('C')

Check this out:

you@localhost:~/diveintopython3/examples$ python3 stdout.py
A
C
you@localhost:~/diveintopython3/examples$ cat out.log
B

Did you get this error?

you@localhost:~/diveintopython3/examples$ python3 stdout.py
  File "stdout.py", line 15
    with open('out.log', mode='w', encoding='utf-8') as a_file, RedirectStdoutTo(a_file):
                                                              ^
SyntaxError: invalid syntax

If so, you’re probably using Python 3.0. You should really upgrade to Python 3.1.

Python 3.0 supported the with statement, but each statement can only use one context manager. Python 3.1 allows you to chain multiple context managers in a single with statement.

Let’s take the last part first.

print('A')
with open('out.log', mode='w', encoding='utf-8') as a_file, RedirectStdoutTo(a_file):
    print('B')
print('C')

That’s a complicated with statement. Let me rewrite it as something more recognizable.

with open('out.log', mode='w', encoding='utf-8') as a_file:
    with RedirectStdoutTo(a_file):
        print('B')

As the rewrite shows, you actually have two with statements, one nested within the scope of the other. The “outer” with statement should be familiar by now: it opens a UTF-8-encoded text file named out.log for writing and assigns the stream object to a variable named a_file. But that’s not the only thing odd here.

with RedirectStdoutTo(a_file):

Where’s the as clause? The with statement doesn’t actually require one. Just like you can call a function and ignore its return value, you can have a with statement that doesn’t assign the with context to a variable. In this case, you’re only interested in the side effects of the RedirectStdoutTo context.

What are those side effects? Take a look inside the RedirectStdoutTo class. This class is a custom context manager. Any class can be a context manager by defining two special methods: __enter__() and __exit__().

class RedirectStdoutTo:
    def __init__(self, out_new):    
        self.out_new = out_new

    def __enter__(self):            
        self.out_old = sys.stdout
        sys.stdout = self.out_new

    def __exit__(self, *args):      
        sys.stdout = self.out_old
  1. The __init__() method is called immediately after an instance is created. It takes one parameter, the stream object that you want to use as standard output for the life of the context. This method just saves the stream object in an instance variable so other methods can use it later.
  2. The __enter__() method is a special class method; Python calls it when entering a context (i.e. at the beginning of the with statement). This method saves the current value of sys.stdout in self.out_old, then redirects standard output by assigning self.out_new to sys.stdout.
  3. The __exit__() method is another special class method; Python calls it when exiting the context (i.e. at the end of the with statement). This method restores standard output to its original value by assigning the saved self.out_old value to sys.stdout.

Putting it all together:


print('A')                                                                             
with open('out.log', mode='w', encoding='utf-8') as a_file, RedirectStdoutTo(a_file):  
    print('B')                                                                         
print('C')                                                                             
  1. This will print to the IDE “Interactive Window” (or the terminal, if running the script from the command line).
  2. This with statement takes a comma-separated list of contexts. The comma-separated list acts like a series of nested with blocks. The first context listed is the “outer” block; the last one listed is the “inner” block. The first context opens a file; the second context redirects sys.stdout to the stream object that was created in the first context.
  3. Because this print() function is executed with the context created by the with statement, it will not print to the screen; it will write to the file out.log.
  4. The with code block is over. Python has told each context manager to do whatever it is they do upon exiting a context. The context managers form a last-in-first-out stack. Upon exiting, the second context changed sys.stdout back to its original value, then the first context closed the file named out.log. Since standard output has been restored to its original value, calling the print() function will once again print to the screen.

Redirecting standard error works exactly the same way, using sys.stderr instead of sys.stdout.

Further Reading

© 2001–11 Mark Pilgrim diveintopython3-20110517-77958af.orig/table-of-contents.html0000644000000000000000000006630711773544727022036 0ustar rootroot Table of contents - Dive Into Python 3

 

You are here: Home Dive Into Python 3

Table of Contents

  1. What’s New in “Dive Into Python 3”
    1. a.k.a. “the minus level”
  2. Installing Python
    1. Diving In
    2. Which Python Is Right For You?
    3. Installing on Microsoft Windows
    4. Installing on Mac OS X
    5. Installing on Ubuntu Linux
    6. Installing on Other Platforms
    7. Using The Python Shell
    8. Python Editors and IDEs
  3. Your First Python Program
    1. Diving In
    2. Declaring Functions
      1. Optional and Named Arguments
    3. Writing Readable Code
      1. Documentation Strings
    4. The import Search Path
    5. Everything Is An Object
      1. What’s An Object?
    6. Indenting Code
    7. Exceptions
      1. Catching Import Errors
    8. Unbound Variables
    9. Everything is Case-Sensitive
    10. Running Scripts
    11. Further Reading
  4. Native Datatypes
    1. Diving In
    2. Booleans
    3. Numbers
      1. Coercing Integers To Floats And Vice-Versa
      2. Common Numerical Operations
      3. Fractions
      4. Trigonometry
      5. Numbers In A Boolean Context
    4. Lists
      1. Creating A List
      2. Slicing A List
      3. Adding Items To A List
      4. Searching For Values In A List
      5. Removing Items From A List
      6. Removing Items From A List: Bonus Round
      7. Lists In A Boolean Context
    5. Tuples
      1. Tuples In A Boolean Context
      2. Assigning Multiple Values At Once
    6. Sets
      1. Creating A Set
      2. Modifying A Set
      3. Removing Items From A Set
      4. Common Set Operations
      5. Sets In A Boolean Context
    7. Dictionaries
      1. Creating A Dictionary
      2. Modifying A Dictionary
      3. Mixed-Value Dictionaries
      4. Dictionaries In A Boolean Context
    8. None
      1. None In A Boolean Context
    9. Further Reading
  5. Comprehensions
    1. Diving In
    2. Working With Files And Directories
      1. The Current Working Directory
      2. Working With Filenames and Directory Names
      3. Listing Directories
      4. Getting File Metadata
      5. Constructing Absolute Pathnames
    3. List Comprehensions
    4. Dictionary Comprehensions
      1. Other Fun Stuff To Do With Dictionary Comprehensions
    5. Set Comprehensions
    6. Further Reading
  6. Strings
    1. Some Boring Stuff You Need To Understand Before You Can Dive In
    2. Unicode
    3. Diving In
    4. Formatting Strings
      1. Compound Field Names
      2. Format Specifiers
    5. Other Common String Methods
      1. Slicing A String
    6. Strings vs. Bytes
    7. Postscript: Character Encoding Of Python Source Code
    8. Further Reading
  7. Regular Expressions
    1. Diving In
    2. Case Study: Street Addresses
    3. Case Study: Roman Numerals
      1. Checking For Thousands
      2. Checking For Hundreds
    4. Using The {n,m} Syntax
      1. Checking For Tens And Ones
    5. Verbose Regular Expressions
    6. Case study: Parsing Phone Numbers
    7. Summary
  8. Closures & Generators
    1. Diving In
    2. I Know, Let’s Use Regular Expressions!
    3. A List Of Functions
    4. A List Of Patterns
    5. A File Of Patterns
    6. Generators
      1. A Fibonacci Generator
      2. A Plural Rule Generator
    7. Further Reading
  9. Classes & Iterators
    1. Diving In
    2. Defining Classes
      1. The __init__() Method
    3. Instantiating Classes
    4. Instance Variables
    5. A Fibonacci Iterator
    6. A Plural Rule Iterator
    7. Further Reading
  10. Advanced Iterators
    1. Diving In
    2. Finding all occurrences of a pattern
    3. Finding the unique items in a sequence
    4. Making assertions
    5. Generator expressions
    6. Calculating Permutations… The Lazy Way!
    7. Other Fun Stuff in the itertools Module
    8. A New Kind Of String Manipulation
    9. Evaluating Arbitrary Strings As Python Expressions
    10. Putting It All Together
    11. Further Reading
  11. Unit Testing
    1. (Not) Diving In
    2. A Single Question
    3. “Halt And Catch Fire”
    4. More Halting, More Fire
    5. And One More Thing…
    6. A Pleasing Symmetry
    7. More Bad Input
  12. Refactoring
    1. Diving In
    2. Handling Changing Requirements
    3. Refactoring
    4. Summary
  13. Files
    1. Diving In
    2. Reading From Text Files
      1. Character Encoding Rears Its Ugly Head
      2. Stream Objects
      3. Reading Data From A Text File
      4. Closing Files
      5. Closing Files Automatically
      6. Reading Data One Line At A Time
    3. Writing to Text Files
      1. Character Encoding Again
    4. Binary Files
    5. Stream Objects From Non-File Sources
      1. Handling Compressed Files
    6. Standard Input, Output, and Error
      1. Redirecting Standard Output
    7. Further Reading
  14. XML
    1. Diving In
    2. A 5-Minute Crash Course in XML
    3. The Structure Of An Atom Feed
    4. Parsing XML
      1. Elements Are Lists
      2. Attributes Are Dictonaries
    5. Searching For Nodes Within An XML Document
    6. Going Further With lxml
    7. Generating XML
    8. Parsing Broken XML
    9. Further Reading
  15. Serializing Python Objects
    1. Diving In
      1. A Quick Note About The Examples in This Chapter
    2. Saving Data to a Pickle File
    3. Loading Data from a Pickle File
    4. Pickling Without a File
    5. Bytes and Strings Rear Their Ugly Heads Again
    6. Debugging Pickle Files
    7. Serializing Python Objects to be Read by Other Languages
    8. Saving Data to a JSON File
    9. Mapping of Python Datatypes to JSON
    10. Serializing Datatypes Unsupported by JSON
    11. Loading Data from a JSON File
    12. Further Reading
  16. HTTP Web Services
    1. Diving In
    2. Features of HTTP
      1. Caching
      2. Last-Modified Checking
      3. ETag Checking
      4. Compression
      5. Redirects
    3. How Not To Fetch Data Over HTTP
    4. What’s On The Wire?
    5. Introducing httplib2
      1. A Short Digression To Explain Why httplib2 Returns Bytes Instead of Strings
      2. How httplib2 Handles Caching
      3. How httplib2 Handles Last-Modified and ETag Headers
      4. How http2lib Handles Compression
      5. How httplib2 Handles Redirects
    6. Beyond HTTP GET
    7. Beyond HTTP POST
    8. Further Reading
  17. Case Study: Porting chardet to Python 3
    1. Diving In
    2. What is Character Encoding Auto-Detection?
      1. Isn’t That Impossible?
      2. Does Such An Algorithm Exist?
    3. Introducing The chardet Module
      1. UTF-n With A BOM
      2. Escaped Encodings
      3. Multi-Byte Encodings
      4. Single-Byte Encodings
      5. windows-1252
    4. Running 2to3
    5. A Short Digression Into Multi-File Modules
    6. Fixing What 2to3 Can’t
      1. False is invalid syntax
      2. No module named constants
      3. Name 'file' is not defined
      4. Can’t use a string pattern on a bytes-like object
      5. Can't convert 'bytes' object to str implicitly
      6. Unsupported operand type(s) for +: 'int' and 'bytes'
      7. ord() expected string of length 1, but int found
      8. Unorderable types: int() >= str()
      9. Global name 'reduce' is not defined
    7. Summary
  18. Packaging Python Libraries
    1. Diving In
    2. Things Distutils Can’t Do For You
    3. Directory Structure
    4. Writing Your Setup Script
    5. Classifying Your Package
      1. Examples of Good Package Classifiers
    6. Specifying Additional Files With A Manifest
    7. Checking Your Setup Script for Errors
    8. Creating a Source Distribution
    9. Creating a Graphical Installer
      1. Building Installable Packages for Other Operating Systems
    10. Adding Your Software to The Python Package Index
    11. The Many Possible Futures of Python Packaging
    12. Further Reading
  19. Porting Code to Python 3 with 2to3
    1. Diving In
    2. print statement
    3. Unicode string literals
    4. unicode() global function
    5. long data type
    6. <> comparison
    7. has_key() dictionary method
    8. Dictionary methods that return lists
    9. Modules that have been renamed or reorganized
      1. http
      2. urllib
      3. dbm
      4. xmlrpc
      5. Other modules
    10. Relative imports within a package
    11. next() iterator method
    12. filter() global function
    13. map() global function
    14. reduce() global function
    15. apply() global function
    16. intern() global function
    17. exec statement
    18. execfile statement
    19. repr literals (backticks)
    20. try...except statement
    21. raise statement
    22. throw method on generators
    23. xrange() global function
    24. raw_input() and input() global functions
    25. func_* function attributes
    26. xreadlines() I/O method
    27. lambda functions that take a tuple instead of multiple parameters
    28. Special method attributes
    29. __nonzero__ special method
    30. Octal literals
    31. sys.maxint
    32. callable() global function
    33. zip() global function
    34. StandardError exception
    35. types module constants
    36. isinstance() global function
    37. basestring datatype
    38. itertools module
    39. sys.exc_type, sys.exc_value, sys.exc_traceback
    40. List comprehensions over tuples
    41. os.getcwdu() function
    42. Metaclasses
    43. Matters of style
      1. set() literals (explicit)
      2. buffer() global function (explicit)
      3. Whitespace around commas (explicit)
      4. Common idioms (explicit)
  20. Special Method Names
    1. Diving In
    2. Basics
    3. Classes That Act Like Iterators
    4. Computed Attributes
    5. Classes That Act Like Functions
    6. Classes That Act Like Sets
    7. Classes That Act Like Dictionaries
    8. Classes That Act Like Numbers
    9. Classes That Can Be Compared
    10. Classes That Can Be Serialized
    11. Classes That Can Be Used in a with Block
    12. Really Esoteric Stuff
    13. Further Reading
  21. Where to Go From Here
    1. Things to Read
    2. Where To Look For Python 3-Compatible Code
  22. Troubleshooting
    1. Diving In
    2. Getting to the Command Line
    3. Running Python on the command line

© 2001–11 Mark Pilgrim diveintopython3-20110517-77958af.orig/index.html0000644000000000000000000001052611773544727017611 0ustar rootroot Dive Into Python 3

 

You are here:  

Dive Into Python 3

Dive Into Python 3 covers Python 3 and its differences from Python 2. Compared to Dive Into Python, it’s about 20% revised and 80% new material. The book is now complete, but feedback is always welcome.

Table of Contents (expand)

Also available on dead trees!
Dive Into Python 3

  1. What’s New in “Dive Into Python 3”
  2. Installing Python
  3. Your First Python Program
  4. Native Datatypes
  5. Comprehensions
  6. Strings
  7. Regular Expressions
  8. Closures & Generators
  9. Classes & Iterators
  10. Advanced Iterators
  11. Unit Testing
  12. Refactoring
  13. Files
  14. XML
  15. Serializing Python Objects
  16. HTTP Web Services
  17. Case Study: Porting chardet to Python 3
  18. Packaging Python Libraries
  19. Porting Code to Python 3 with 2to3
  20. Special Method Names
  21. Where to Go From Here
  22. Troubleshooting

The book is freely licensed under the Creative Commons Attribution Share-Alike license. You can download it as HTML or PDF. Über-geeks can also clone the Git repository:

you@localhost:~$ git clone git://github.com/diveintomark/diveintopython3.git

© 2001–11 Mark Pilgrim

Translations: en español, in italiano, на русском языке, به پارسی, česky diveintopython3-20110517-77958af.orig/serializing.html0000644000000000000000000014761111773544727021030 0ustar rootroot Serializing Python Objects - Dive Into Python 3

  

You are here: Home Dive Into Python 3

Difficulty level: ♦♦♦♦♢

Serializing Python Objects

Every Saturday since we’ve lived in this apartment, I have awakened at 6:15, poured myself a bowl of cereal, added
a quarter-cup of 2% milk, sat on this end of this couch, turned on BBC America, and watched Doctor Who.
— Sheldon, The Big Bang Theory

 

Diving In

On the surface, the concept of serialization is simple. You have a data structure in memory that you want to save, reuse, or send to someone else. How would you do that? Well, that depends on how you want to save it, how you want to reuse it, and to whom you want to send it. Many games allow you to save your progress when you quit the game and pick up where you left off when you relaunch the game. (Actually, many non-gaming applications do this as well.) In this case, a data structure that captures “your progress so far” needs to be stored on disk when you quit, then loaded from disk when you relaunch. The data is only meant to be used by the same program that created it, never sent over a network, and never read by anything other than the program that created it. Therefore, the interoperability issues are limited to ensuring that later versions of the program can read data written by earlier versions.

For cases like this, the pickle module is ideal. It’s part of the Python standard library, so it’s always available. It’s fast; the bulk of it is written in C, like the Python interpreter itself. It can store arbitrarily complex Python data structures.

What can the pickle module store?

If this isn’t enough for you, the pickle module is also extensible. If you’re interested in extensibility, check out the links in the Further Reading section at the end of the chapter.

A Quick Note About The Examples in This Chapter

This chapter tells a tale with two Python Shells. All of the examples in this chapter are part of a single story arc. You will be asked to switch back and forth between the two Python Shells as I demonstrate the pickle and json modules.

To help keep things straight, open the Python Shell and define the following variable:

>>> shell = 1

Keep that window open. Now open another Python Shell and define the following variable:

>>> shell = 2

Throughout this chapter, I will use the shell variable to indicate which Python Shell is being used in each example.

Saving Data to a Pickle File

The pickle module works with data structures. Let’s build one.

>>> shell                                                                                              
1
>>> entry = {}                                                                                         
>>> entry['title'] = 'Dive into history, 2009 edition'
>>> entry['article_link'] = 'http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition'
>>> entry['comments_link'] = None
>>> entry['internal_id'] = b'\xDE\xD5\xB4\xF8'
>>> entry['tags'] = ('diveintopython', 'docbook', 'html')
>>> entry['published'] = True
>>> import time
>>> entry['published_date'] = time.strptime('Fri Mar 27 22:20:42 2009')                                
>>> entry['published_date']
time.struct_time(tm_year=2009, tm_mon=3, tm_mday=27, tm_hour=22, tm_min=20, tm_sec=42, tm_wday=4, tm_yday=86, tm_isdst=-1)
  1. Follow along in Python Shell #1.
  2. The idea here is to build a Python dictionary that could represent something useful, like an entry in an Atom feed. But I also want to ensure that it contains several different types of data, to show off the pickle module. Don’t read too much into these values.
  3. The time module contains a data structure (struct_time) to represent a point in time (accurate to one millisecond) and functions to manipulate time structs. The strptime() function takes a formatted string an converts it to a struct_time. This string is in the default format, but you can control that with format codes. See the time module for more details.

That’s a handsome-looking Python dictionary. Let’s save it to a file.

>>> shell                                    
1
>>> import pickle
>>> with open('entry.pickle', 'wb') as f:    
...     pickle.dump(entry, f)                
... 
  1. This is still in Python Shell #1.
  2. Use the open() function to open a file. Set the file mode to 'wb' to open the file for writing in binary mode. Wrap it in a with statement to ensure the file is closed automatically when you’re done with it.
  3. The dump() function in the pickle module takes a serializable Python data structure, serializes it into a binary, Python-specific format using the latest version of the pickle protocol, and saves it to an open file.

That last sentence was pretty important.

Loading Data from a Pickle File

Now switch to your second Python Shell — i.e. not the one where you created the entry dictionary.

>>> shell                                    
2
>>> entry                                    
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'entry' is not defined
>>> import pickle
>>> with open('entry.pickle', 'rb') as f:    
...     entry = pickle.load(f)               
... 
>>> entry                                    
{'comments_link': None,
 'internal_id': b'\xDE\xD5\xB4\xF8',
 'title': 'Dive into history, 2009 edition',
 'tags': ('diveintopython', 'docbook', 'html'),
 'article_link':
 'http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition',
 'published_date': time.struct_time(tm_year=2009, tm_mon=3, tm_mday=27, tm_hour=22, tm_min=20, tm_sec=42, tm_wday=4, tm_yday=86, tm_isdst=-1),
 'published': True}
  1. This is Python Shell #2.
  2. There is no entry variable defined here. You defined an entry variable in Python Shell #1, but that’s a completely different environment with its own state.
  3. Open the entry.pickle file you created in Python Shell #1. The pickle module uses a binary data format, so you should always open pickle files in binary mode.
  4. The pickle.load() function takes a stream object, reads the serialized data from the stream, creates a new Python object, recreates the serialized data in the new Python object, and returns the new Python object.
  5. Now the entry variable is a dictionary with familiar-looking keys and values.

The pickle.dump() / pickle.load() cycle results in a new data structure that is equal to the original data structure.

>>> shell                                    
1
>>> with open('entry.pickle', 'rb') as f:    
...     entry2 = pickle.load(f)              
... 
>>> entry2 == entry                          
True
>>> entry2 is entry                          
False
>>> entry2['tags']                           
('diveintopython', 'docbook', 'html')
>>> entry2['internal_id']
b'\xDE\xD5\xB4\xF8'
  1. Switch back to Python Shell #1.
  2. Open the entry.pickle file.
  3. Load the serialized data into a new variable, entry2.
  4. Python confirms that the two dictionaries, entry and entry2, are equal. In this shell, you built entry from the ground up, starting with an empty dictionary and manually assigning values to specific keys. You serialized this dictionary and stored it in the entry.pickle file. Now you’ve read the serialized data from that file and created a perfect replica of the original data structure.
  5. Equality is not the same as identity. I said you’ve created a perfect replica of the original data structure, which is true. But it’s still a copy.
  6. For reasons that will become clear later in this chapter, I want to point out that the value of the 'tags' key is a tuple, and the value of the 'internal_id' key is a bytes object.

Pickling Without a File

The examples in the previous section showed how to serialize a Python object directly to a file on disk. But what if you don’t want or need a file? You can also serialize to a bytes object in memory.

>>> shell
1
>>> b = pickle.dumps(entry)     
>>> type(b)                     
<class 'bytes'>
>>> entry3 = pickle.loads(b)    
>>> entry3 == entry             
True
  1. The pickle.dumps() function (note the 's' at the end of the function name) performs the same serialization as the pickle.dump() function. Instead of taking a stream object and writing the serialized data to a file on disk, it simply returns the serialized data.
  2. Since the pickle protocol uses a binary data format, the pickle.dumps() function returns a bytes object.
  3. The pickle.loads() function (again, note the 's' at the end of the function name) performs the same deserialization as the pickle.load() function. Instead of taking a stream object and reading the serialized data from a file, it takes a bytes object containing serialized data, such as the one returned by the pickle.dumps() function.
  4. The end result is the same: a perfect replica of the original dictionary.

Bytes and Strings Rear Their Ugly Heads Again

The pickle protocol has been around for many years, and it has matured as Python itself has matured. There are now four different versions of the pickle protocol.

Oh look, the difference between bytes and strings rears its ugly head again. (If you’re surprised, you haven’t been paying attention.) What this means in practice is that, while Python 3 can read data pickled with protocol version 2, Python 2 can not read data pickled with protocol version 3.

Debugging Pickle Files

What does the pickle protocol look like? Let’s jump out of the Python Shell for a moment and take a look at that entry.pickle file we created. To the naked eye, it’s mostly gibberish.

you@localhost:~/diveintopython3/examples$ ls -l entry.pickle
-rw-r--r-- 1 you  you  358 Aug  3 13:34 entry.pickle
you@localhost:~/diveintopython3/examples$ cat entry.pickle
comments_linkqNXtagsqXdiveintopythonqXdocbookqXhtmlq?qX publishedq?
XlinkXJhttp://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition
q   Xpublished_dateq
ctime
struct_time
?qRqXtitleqXDive into history, 2009 editionqu.

That wasn’t terribly helpful. You can see the strings, but other datatypes end up as unprintable (or at least unreadable) characters. Fields are not obviously delimited by tabs or spaces. This is not a format you would want to debug by yourself.

>>> shell
1
>>> import pickletools
>>> with open('entry.pickle', 'rb') as f:
...     pickletools.dis(f)
    0: \x80 PROTO      3
    2: }    EMPTY_DICT
    3: q    BINPUT     0
    5: (    MARK
    6: X        BINUNICODE 'published_date'
   25: q        BINPUT     1
   27: c        GLOBAL     'time struct_time'
   45: q        BINPUT     2
   47: (        MARK
   48: M            BININT2    2009
   51: K            BININT1    3
   53: K            BININT1    27
   55: K            BININT1    22
   57: K            BININT1    20
   59: K            BININT1    42
   61: K            BININT1    4
   63: K            BININT1    86
   65: J            BININT     -1
   70: t            TUPLE      (MARK at 47)
   71: q        BINPUT     3
   73: }        EMPTY_DICT
   74: q        BINPUT     4
   76: \x86     TUPLE2
   77: q        BINPUT     5
   79: R        REDUCE
   80: q        BINPUT     6
   82: X        BINUNICODE 'comments_link'
  100: q        BINPUT     7
  102: N        NONE
  103: X        BINUNICODE 'internal_id'
  119: q        BINPUT     8
  121: C        SHORT_BINBYTES 'ÞÕ´ø'
  127: q        BINPUT     9
  129: X        BINUNICODE 'tags'
  138: q        BINPUT     10
  140: X        BINUNICODE 'diveintopython'
  159: q        BINPUT     11
  161: X        BINUNICODE 'docbook'
  173: q        BINPUT     12
  175: X        BINUNICODE 'html'
  184: q        BINPUT     13
  186: \x87     TUPLE3
  187: q        BINPUT     14
  189: X        BINUNICODE 'title'
  199: q        BINPUT     15
  201: X        BINUNICODE 'Dive into history, 2009 edition'
  237: q        BINPUT     16
  239: X        BINUNICODE 'article_link'
  256: q        BINPUT     17
  258: X        BINUNICODE 'http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition'
  337: q        BINPUT     18
  339: X        BINUNICODE 'published'
  353: q        BINPUT     19
  355: \x88     NEWTRUE
  356: u        SETITEMS   (MARK at 5)
  357: .    STOP
highest protocol among opcodes = 3

The most interesting piece of information in that disassembly is on the last line, because it includes the version of the pickle protocol with which this file was saved. There is no explicit version marker in the pickle protocol. To determine which protocol version was used to store a pickle file, you need to look at the markers (“opcodes”) within the pickled data and use hard-coded knowledge of which opcodes were introduced with each version of the pickle protocol. The pickletools.dis() function does exactly that, and it prints the result in the last line of the disassembly output. Here is a function that returns just the version number, without printing anything:

[download pickleversion.py]

import pickletools

def protocol_version(file_object):
    maxproto = -1
    for opcode, arg, pos in pickletools.genops(file_object):
        maxproto = max(maxproto, opcode.proto)
    return maxproto

And here it is in action:

>>> import pickleversion
>>> with open('entry.pickle', 'rb') as f:
...     v = pickleversion.protocol_version(f)
>>> v
3

Serializing Python Objects to be Read by Other Languages

The data format used by the pickle module is Python-specific. It makes no attempt to be compatible with other programming languages. If cross-language compatibility is one of your requirements, you need to look at other serialization formats. One such format is JSON. “JSON” stands for “JavaScript Object Notation,” but don’t let the name fool you — JSON is explicitly designed to be usable across multiple programming languages.

Python 3 includes a json module in the standard library. Like the pickle module, the json module has functions for serializing data structures, storing the serialized data on disk, loading serialized data from disk, and unserializing the data back into a new Python object. But there are some important differences, too. First of all, the JSON data format is text-based, not binary. RFC 4627 defines the JSON format and how different types of data must be encoded as text. For example, a boolean value is stored as either the five-character string 'false' or the four-character string 'true'. All JSON values are case-sensitive.

Second, as with any text-based format, there is the issue of whitespace. JSON allows arbitrary amounts of whitespace (spaces, tabs, carriage returns, and line feeds) between values. This whitespace is “insignificant,” which means that JSON encoders can add as much or as little whitespace as they like, and JSON decoders are required to ignore the whitespace between values. This allows you to “pretty-print” your JSON data, nicely nesting values within values at different indentation levels so you can read it in a standard browser or text editor. Python’s json module has options for pretty-printing during encoding.

Third, there’s the perennial problem of character encoding. JSON encodes values as plain text, but as you know, there ain’t no such thing as “plain text.” JSON must be stored in a Unicode encoding (UTF-32, UTF-16, or the default, UTF-8), and section 3 of RFC 4627 defines how to tell which encoding is being used.

Saving Data to a JSON File

JSON looks remarkably like a data structure you might define manually in JavaScript. This is no accident; you can actually use the JavaScript eval() function to “decode” JSON-serialized data. (The usual caveats about untrusted input apply, but the point is that JSON is valid JavaScript.) As such, JSON may already look familiar to you.

>>> shell
1
>>> basic_entry = {}                                           
>>> basic_entry['id'] = 256
>>> basic_entry['title'] = 'Dive into history, 2009 edition'
>>> basic_entry['tags'] = ('diveintopython', 'docbook', 'html')
>>> basic_entry['published'] = True
>>> basic_entry['comments_link'] = None
>>> import json
>>> with open('basic.json', mode='w', encoding='utf-8') as f:  
...     json.dump(basic_entry, f)                              
  1. We’re going to create a new data structure instead of re-using the existing entry data structure. Later in this chapter, we’ll see what happens when we try to encode the more complex data structure in JSON.
  2. JSON is a text-based format, which means you need to open this file in text mode and specify a character encoding. You can never go wrong with UTF-8.
  3. Like the pickle module, the json module defines a dump() function which takes a Python data structure and a writeable stream object. The dump() function serializes the Python data structure and writes it to the stream object. Doing this inside a with statement will ensure that the file is closed properly when we’re done.

So what does the resulting JSON serialization look like?

you@localhost:~/diveintopython3/examples$ cat basic.json
{"published": true, "tags": ["diveintopython", "docbook", "html"], "comments_link": null,
"id": 256, "title": "Dive into history, 2009 edition"}

That’s certainly more readable than a pickle file. But JSON can contain arbitrary whitespace between values, and the json module provides an easy way to take advantage of this to create even more readable JSON files.

>>> shell
1
>>> with open('basic-pretty.json', mode='w', encoding='utf-8') as f:
...     json.dump(basic_entry, f, indent=2)                            
  1. If you pass an indent parameter to the json.dump() function, it will make the resulting JSON file more readable, at the expense of larger file size. The indent parameter is an integer. 0 means “put each value on its own line.” A number greater than 0 means “put each value on its own line, and use this number of spaces to indent nested data structures.”

And this is the result:

you@localhost:~/diveintopython3/examples$ cat basic-pretty.json
{
  "published": true, 
  "tags": [
    "diveintopython", 
    "docbook", 
    "html"
  ], 
  "comments_link": null, 
  "id": 256, 
  "title": "Dive into history, 2009 edition"
}

Mapping of Python Datatypes to JSON

Since JSON is not Python-specific, there are some mismatches in its coverage of Python datatypes. Some of them are simply naming differences, but there is two important Python datatypes that are completely missing. See if you can spot them:
Notes JSON Python 3
object dictionary
array list
string string
integer integer
real number float
* true True
* false False
* null None
* All JSON values are case-sensitive.

Did you notice what was missing? Tuples & bytes! JSON has an array type, which the json module maps to a Python list, but it does not have a separate type for “frozen arrays” (tuples). And while JSON supports strings quite nicely, it has no support for bytes objects or byte arrays.

Serializing Datatypes Unsupported by JSON

Even if JSON has no built-in support for bytes, that doesn’t mean you can’t serialize bytes objects. The json module provides extensibility hooks for encoding and decoding unknown datatypes. (By “unknown,” I mean “not defined in JSON.” Obviously the json module knows about byte arrays, but it’s constrained by the limitations of the JSON specification.) If you want to encode bytes or other datatypes that JSON doesn’t support natively, you need to provide custom encoders and decoders for those types.

>>> shell
1
>>> entry                                                 
{'comments_link': None,
 'internal_id': b'\xDE\xD5\xB4\xF8',
 'title': 'Dive into history, 2009 edition',
 'tags': ('diveintopython', 'docbook', 'html'),
 'article_link': 'http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition',
 'published_date': time.struct_time(tm_year=2009, tm_mon=3, tm_mday=27, tm_hour=22, tm_min=20, tm_sec=42, tm_wday=4, tm_yday=86, tm_isdst=-1),
 'published': True}
>>> import json
>>> with open('entry.json', 'w', encoding='utf-8') as f:  
...     json.dump(entry, f)                               
... 
Traceback (most recent call last):
  File "<stdin>", line 5, in <module>
  File "C:\Python31\lib\json\__init__.py", line 178, in dump
    for chunk in iterable:
  File "C:\Python31\lib\json\encoder.py", line 408, in _iterencode
    for chunk in _iterencode_dict(o, _current_indent_level):
  File "C:\Python31\lib\json\encoder.py", line 382, in _iterencode_dict
    for chunk in chunks:
  File "C:\Python31\lib\json\encoder.py", line 416, in _iterencode
    o = _default(o)
  File "C:\Python31\lib\json\encoder.py", line 170, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: b'\xDE\xD5\xB4\xF8' is not JSON serializable
  1. OK, it’s time to revisit the entry data structure. This has it all: a boolean value, a None value, a string, a tuple of strings, a bytes object, and a time structure.
  2. I know I’ve said it before, but it’s worth repeating: JSON is a text-based format. Always open JSON files in text mode with a UTF-8 character encoding.
  3. Well that’s not good. What happened?

Here’s what happened: the json.dump() function tried to serialize the bytes object b'\xDE\xD5\xB4\xF8', but it failed, because JSON has no support for bytes objects. However, if storing bytes is important to you, you can define your own “mini-serialization format.”

[download customserializer.py]


def to_json(python_object):                                             
    if isinstance(python_object, bytes):                                
        return {'__class__': 'bytes',
                '__value__': list(python_object)}                       
    raise TypeError(repr(python_object) + ' is not JSON serializable')  
  1. To define your own “mini-serialization format” for a datatype that JSON doesn’t support natively, just define a function that takes a Python object as a parameter. This Python object will be the actual object that the json.dump() function is unable to serialize by itself — in this case, the bytes object b'\xDE\xD5\xB4\xF8'.
  2. Your custom serialization function should check the type of the Python object that the json.dump() function passed to it. This is not strictly necessary if your function only serializes one datatype, but it makes it crystal clear what case your function is covering, and it makes it easier to extend if you need to add serializations for more datatypes later.
  3. In this case, I’ve chosen to convert a bytes object into a dictionary. The __class__ key will hold the original datatype (as a string, 'bytes'), and the __value__ key will hold the actual value. Of course this can’t be a bytes object; the entire point is to convert it into something that can be serialized in JSON! A bytes object is just a sequence of integers; each integer is somewhere in the range 0–255. We can use the list() function to convert the bytes object into a list of integers. So b'\xDE\xD5\xB4\xF8' becomes [222, 213, 180, 248]. (Do the math! It works! The byte \xDE in hexadecimal is 222 in decimal, \xD5 is 213, and so on.)
  4. This line is important. The data structure you’re serializing may contain types that neither the built-in JSON serializer nor your custom serializer can handle. In this case, your custom serializer must raise a TypeError so that the json.dump() function knows that your custom serializer did not recognize the type.

That’s it; you don’t need to do anything else. In particular, this custom serialization function returns a Python dictionary, not a string. You’re not doing the entire serializing-to-JSON yourself; you’re only doing the converting-to-a-supported-datatype part. The json.dump() function will do the rest.

>>> shell
1
>>> import customserializer                                                             
>>> with open('entry.json', 'w', encoding='utf-8') as f:                                
...     json.dump(entry, f, default=customserializer.to_json)                           
... 
Traceback (most recent call last):
  File "<stdin>", line 9, in <module>
    json.dump(entry, f, default=customserializer.to_json)
  File "C:\Python31\lib\json\__init__.py", line 178, in dump
    for chunk in iterable:
  File "C:\Python31\lib\json\encoder.py", line 408, in _iterencode
    for chunk in _iterencode_dict(o, _current_indent_level):
  File "C:\Python31\lib\json\encoder.py", line 382, in _iterencode_dict
    for chunk in chunks:
  File "C:\Python31\lib\json\encoder.py", line 416, in _iterencode
    o = _default(o)
  File "/Users/pilgrim/diveintopython3/examples/customserializer.py", line 12, in to_json
    raise TypeError(repr(python_object) + ' is not JSON serializable')                     
TypeError: time.struct_time(tm_year=2009, tm_mon=3, tm_mday=27, tm_hour=22, tm_min=20, tm_sec=42, tm_wday=4, tm_yday=86, tm_isdst=-1) is not JSON serializable
  1. The customserializer module is where you just defined the to_json() function in the previous example.
  2. Text mode, UTF-8 encoding, yadda yadda. (You’ll forget! I forget sometimes! And everything will work right up until the moment that it fails, and then it will fail most spectacularly.)
  3. This is the important bit: to hook your custom conversion function into the json.dump() function, pass your function into the json.dump() function in the default parameter. (Hooray, everything in Python is an object!)
  4. OK, so it didn’t actually work. But take a look at the exception. The json.dump() function is no longer complaining about being unable to serialize the bytes object. Now it’s complaining about a completely different object: the time.struct_time object.

While getting a different exception might not seem like progress, it really is! It’ll just take one more tweak to get past this.


import time

def to_json(python_object):
    if isinstance(python_object, time.struct_time):          
        return {'__class__': 'time.asctime',
                '__value__': time.asctime(python_object)}    
    if isinstance(python_object, bytes):
        return {'__class__': 'bytes',
                '__value__': list(python_object)}
    raise TypeError(repr(python_object) + ' is not JSON serializable')
  1. Adding to our existing customserializer.to_json() function, we need to check whether the Python object (that the json.dump() function is having trouble with) is a time.struct_time.
  2. If so, we’ll do something similar to the conversion we did with the bytes object: convert the time.struct_time object to a dictionary that only contains JSON-serializable values. In this case, the easiest way to convert a datetime into a JSON-serializable value is to convert it to a string with the time.asctime() function. The time.asctime() function will convert that nasty-looking time.struct_time into the string 'Fri Mar 27 22:20:42 2009'.

With these two custom conversions, the entire entry data structure should serialize to JSON without any further problems.

>>> shell
1
>>> with open('entry.json', 'w', encoding='utf-8') as f:
...     json.dump(entry, f, default=customserializer.to_json)
... 
you@localhost:~/diveintopython3/examples$ ls -l example.json
-rw-r--r-- 1 you  you  391 Aug  3 13:34 entry.json
you@localhost:~/diveintopython3/examples$ cat example.json
{"published_date": {"__class__": "time.asctime", "__value__": "Fri Mar 27 22:20:42 2009"},
"comments_link": null, "internal_id": {"__class__": "bytes", "__value__": [222, 213, 180, 248]},
"tags": ["diveintopython", "docbook", "html"], "title": "Dive into history, 2009 edition",
"article_link": "http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition",
"published": true}

Loading Data from a JSON File

Like the pickle module, the json module has a load() function which takes a stream object, reads JSON-encoded data from it, and creates a new Python object that mirrors the JSON data structure.

>>> shell
2
>>> del entry                                             
>>> entry
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'entry' is not defined
>>> import json
>>> with open('entry.json', 'r', encoding='utf-8') as f:
...     entry = json.load(f)                              
... 
>>> entry                                                 
{'comments_link': None,
 'internal_id': {'__class__': 'bytes', '__value__': [222, 213, 180, 248]},
 'title': 'Dive into history, 2009 edition',
 'tags': ['diveintopython', 'docbook', 'html'],
 'article_link': 'http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition',
 'published_date': {'__class__': 'time.asctime', '__value__': 'Fri Mar 27 22:20:42 2009'},
 'published': True}
  1. For demonstration purposes, switch to Python Shell #2 and delete the entry data structure that you created earlier in this chapter with the pickle module.
  2. In the simplest case, the json.load() function works the same as the pickle.load() function. You pass in a stream object and it returns a new Python object.
  3. I have good news and bad news. Good news first: the json.load() function successfully read the entry.json file you created in Python Shell #1 and created a new Python object that contained the data. Now the bad news: it didn’t recreate the original entry data structure. The two values 'internal_id' and 'published_date' were recreated as dictionaries — specifically, the dictionaries with JSON-compatible values that you created in the to_json() conversion function.

json.load() doesn’t know anything about any conversion function you may have passed to json.dump(). What you need is the opposite of the to_json() function — a function that will take a custom-converted JSON object and convert it back to the original Python datatype.

# add this to customserializer.py
def from_json(json_object):                                   
    if '__class__' in json_object:                            
        if json_object['__class__'] == 'time.asctime':
            return time.strptime(json_object['__value__'])    
        if json_object['__class__'] == 'bytes':
            return bytes(json_object['__value__'])            
    return json_object
  1. This conversion function also takes one parameter and returns one value. But the parameter it takes is not a string, it’s a Python object — the result of deserializing a JSON-encoded string into Python.
  2. All you need to do is check whether this object contains the '__class__' key that the to_json() function created. If so, the value of the '__class__' key will tell you how to decode the value back into the original Python datatype.
  3. To decode the time string returned by the time.asctime() function, you use the time.strptime() function. This function takes a formatted datetime string (in a customizable format, but it defaults to the same format that time.asctime() defaults to) and returns a time.struct_time.
  4. To convert a list of integers back into a bytes object, you can use the bytes() function.

That was it; there were only two datatypes handled in the to_json() function, and now those two datatypes are handled in the from_json() function. This is the result:

>>> shell
2
>>> import customserializer
>>> with open('entry.json', 'r', encoding='utf-8') as f:
...     entry = json.load(f, object_hook=customserializer.from_json)  
... 
>>> entry                                                             
{'comments_link': None,
 'internal_id': b'\xDE\xD5\xB4\xF8',
 'title': 'Dive into history, 2009 edition',
 'tags': ['diveintopython', 'docbook', 'html'],
 'article_link': 'http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition',
 'published_date': time.struct_time(tm_year=2009, tm_mon=3, tm_mday=27, tm_hour=22, tm_min=20, tm_sec=42, tm_wday=4, tm_yday=86, tm_isdst=-1),
 'published': True}
  1. To hook the from_json() function into the deserialization process, pass it as the object_hook parameter to the json.load() function. Functions that take functions; it’s so handy!
  2. The entry data structure now contains an 'internal_id' key whose value is a bytes object. It also contains a 'published_date' key whose value is a time.struct_time object.

There is one final glitch, though.

>>> shell
1
>>> import customserializer
>>> with open('entry.json', 'r', encoding='utf-8') as f:
...     entry2 = json.load(f, object_hook=customserializer.from_json)
... 
>>> entry2 == entry                                                    
False
>>> entry['tags']                                                      
('diveintopython', 'docbook', 'html')
>>> entry2['tags']                                                     
['diveintopython', 'docbook', 'html']
  1. Even after hooking the to_json() function into the serialization, and hooking the from_json() function into the deserialization, we still haven’t recreated a perfect replica of the original data structure. Why not?
  2. In the original entry data structure, the value of the 'tags' key was a tuple of three strings.
  3. But in the round-tripped entry2 data structure, the value of the 'tags' key is a list of three strings. JSON doesn’t distinguish between tuples and lists; it only has a single list-like datatype, the array, and the json module silently converts both tuples and lists into JSON arrays during serialization. For most uses, you can ignore the difference between tuples and lists, but it’s something to keep in mind as you work with the json module.

Further Reading

Many articles about the pickle module make references to cPickle. In Python 2, there were two implementations of the pickle module, one written in pure Python and another written in C (but still callable from Python). In Python 3, these two modules have been consolidated, so you should always just import pickle. You may find these articles useful, but you should ignore the now-obsolete information about cPickle.

On pickling with the pickle module:

On JSON and the json module:

On pickle extensibility:

© 2001–11 Mark Pilgrim diveintopython3-20110517-77958af.orig/where-to-go-from-here.html0000644000000000000000000001407011773544727022517 0ustar rootroot Where to Go From Here - Dive Into Python 3

  

You are here: Home Dive Into Python 3

Where To Go From Here

Go forth on your path, as it exists only through your walking.
— St. Augustine of Hippo (attributed)

 

Things to Read

Unfortunately, I can not write cover every facet of Python 3 in this book. Fortunately, there are many wonderful, freely available tutorials available elsewhere.

Decorators:

Properties:

Descriptors:

Threading & multiprocessing:

Metaclasses:

In addition, Doug Hellman’s Python Module of the Week is a fantastic guide to many of the modules in the Python standard library.

Where To Look For Python 3-Compatible Code

As Python 3 is relatively new, there is a dearth of compatible libraries. Here are some of the places to look for code that works with Python 3.

© 2001–11 Mark Pilgrim diveintopython3-20110517-77958af.orig/http-web-services.html0000644000000000000000000024760411773544727022066 0ustar rootroot HTTP Web Services - Dive Into Python 3

  

You are here: Home Dive Into Python 3

Difficulty level: ♦♦♦♦♢

HTTP Web Services

A ruffled mind makes a restless pillow.
— Charlotte Brontë

 

Diving In

Philosophically, I can describe HTTP web services in 12 words: exchanging data with remote servers using nothing but the operations of HTTP. If you want to get data from the server, use HTTP GET. If you want to send new data to the server, use HTTP POST. Some more advanced HTTP web service APIs also allow creating, modifying, and deleting data, using HTTP PUT and HTTP DELETE. That’s it. No registries, no envelopes, no wrappers, no tunneling. The “verbs” built into the HTTP protocol (GET, POST, PUT, and DELETE) map directly to application-level operations for retrieving, creating, modifying, and deleting data.

The main advantage of this approach is simplicity, and its simplicity has proven popular. Data — usually XML or JSON — can be built and stored statically, or generated dynamically by a server-side script, and all major programming languages (including Python, of course!) include an HTTP library for downloading it. Debugging is also easier; because each resource in an HTTP web service has a unique address (in the form of a URL), you can load it in your web browser and immediately see the raw data.

Examples of HTTP web services:

Python 3 comes with two different libraries for interacting with HTTP web services:

So which one should you use? Neither of them. Instead, you should use httplib2, an open source third-party library that implements HTTP more fully than http.client but provides a better abstraction than urllib.request.

To understand why httplib2 is the right choice, you first need to understand HTTP.

Features of HTTP

There are five important features which all HTTP clients should support.

Caching

The most important thing to understand about any type of web service is that network access is incredibly expensive. I don’t mean “dollars and cents” expensive (although bandwidth ain’t free). I mean that it takes an extraordinary long time to open a connection, send a request, and retrieve a response from a remote server. Even on the fastest broadband connection, latency (the time it takes to send a request and start retrieving data in a response) can still be higher than you anticipated. A router misbehaves, a packet is dropped, an intermediate proxy is under attack — there’s never a dull moment on the public internet, and there may be nothing you can do about it.

HTTP is designed with caching in mind. There is an entire class of devices (called “caching proxies”) whose only job is to sit between you and the rest of the world and minimize network access. Your company or ISP almost certainly maintains caching proxies, even if you’re unaware of them. They work because caching is built into the HTTP protocol.

Here’s a concrete example of how caching works. You visit diveintomark.org in your browser. That page includes a background image, wearehugh.com/m.jpg. When your browser downloads that image, the server includes the following HTTP headers:

HTTP/1.1 200 OK
Date: Sun, 31 May 2009 17:14:04 GMT
Server: Apache
Last-Modified: Fri, 22 Aug 2008 04:28:16 GMT
ETag: "3075-ddc8d800"
Accept-Ranges: bytes
Content-Length: 12405
Cache-Control: max-age=31536000, public
Expires: Mon, 31 May 2010 17:14:04 GMT
Connection: close
Content-Type: image/jpeg

The Cache-Control and Expires headers tell your browser (and any caching proxies between you and the server) that this image can be cached for up to a year. A year! And if, in the next year, you visit another page which also includes a link to this image, your browser will load the image from its cache without generating any network activity whatsoever.

But wait, it gets better. Let’s say your browser purges the image from your local cache for some reason. Maybe it ran out of disk space; maybe you manually cleared the cache. Whatever. But the HTTP headers said that this data could be cached by public caching proxies. (Technically, the important thing is what the headers don’t say; the Cache-Control header doesn’t have the private keyword, so this data is cacheable by default.) Caching proxies are designed to have tons of storage space, probably far more than your local browser has allocated.

If your company or ISP maintain a caching proxy, the proxy may still have the image cached. When you visit diveintomark.org again, your browser will look in its local cache for the image, but it won’t find it, so it will make a network request to try to download it from the remote server. But if the caching proxy still has a copy of the image, it will intercept that request and serve the image from its cache. That means that your request will never reach the remote server; in fact, it will never leave your company’s network. That makes for a faster download (fewer network hops) and saves your company money (less data being downloaded from the outside world).

HTTP caching only works when everybody does their part. On one side, servers need to send the correct headers in their response. On the other side, clients need to understand and respect those headers before they request the same data twice. The proxies in the middle are not a panacea; they can only be as smart as the servers and clients allow them to be.

Python’s HTTP libraries do not support caching, but httplib2 does.

Last-Modified Checking

Some data never changes, while other data changes all the time. In between, there is a vast field of data that might have changed, but hasn’t. CNN.com’s feed is updated every few minutes, but my weblog’s feed may not change for days or weeks at a time. In the latter case, I don’t want to tell clients to cache my feed for weeks at a time, because then when I do actually post something, people may not read it for weeks (because they’re respecting my cache headers which said “don’t bother checking this feed for weeks”). On the other hand, I don’t want clients downloading my entire feed once an hour if it hasn’t changed!

HTTP has a solution to this, too. When you request data for the first time, the server can send back a Last-Modified header. This is exactly what it sounds like: the date that the data was changed. That background image referenced from diveintomark.org included a Last-Modified header.

HTTP/1.1 200 OK
Date: Sun, 31 May 2009 17:14:04 GMT
Server: Apache
Last-Modified: Fri, 22 Aug 2008 04:28:16 GMT
ETag: "3075-ddc8d800"
Accept-Ranges: bytes
Content-Length: 12405
Cache-Control: max-age=31536000, public
Expires: Mon, 31 May 2010 17:14:04 GMT
Connection: close
Content-Type: image/jpeg

When you request the same data a second (or third or fourth) time, you can send an If-Modified-Since header with your request, with the date you got back from the server last time. If the data has changed since then, then the server gives you the new data with a 200 status code. But if the data hasn’t changed since then, the server sends back a special HTTP 304 status code, which means “this data hasn’t changed since the last time you asked for it.” You can test this on the command line, using curl:

you@localhost:~$ curl -I -H "If-Modified-Since: Fri, 22 Aug 2008 04:28:16 GMT" http://wearehugh.com/m.jpg
HTTP/1.1 304 Not Modified
Date: Sun, 31 May 2009 18:04:39 GMT
Server: Apache
Connection: close
ETag: "3075-ddc8d800"
Expires: Mon, 31 May 2010 18:04:39 GMT
Cache-Control: max-age=31536000, public

Why is this an improvement? Because when the server sends a 304, it doesn’t re-send the data. All you get is the status code. Even after your cached copy has expired, last-modified checking ensures that you won’t download the same data twice if it hasn’t changed. (As an extra bonus, this 304 response also includes caching headers. Proxies will keep a copy of data even after it officially “expires,” in the hopes that the data hasn’t really changed and the next request responds with a 304 status code and updated cache information.)

Python’s HTTP libraries do not support last-modified date checking, but httplib2 does.

ETag Checking

ETags are an alternate way to accomplish the same thing as the last-modified checking. With Etags, the server sends a hash code in an ETag header along with the data you requested. (Exactly how this hash is determined is entirely up to the server. The only requirement is that it changes when the data changes.) That background image referenced from diveintomark.org had an ETag header.

HTTP/1.1 200 OK
Date: Sun, 31 May 2009 17:14:04 GMT
Server: Apache
Last-Modified: Fri, 22 Aug 2008 04:28:16 GMT
ETag: "3075-ddc8d800"
Accept-Ranges: bytes
Content-Length: 12405
Cache-Control: max-age=31536000, public
Expires: Mon, 31 May 2010 17:14:04 GMT
Connection: close
Content-Type: image/jpeg

The second time you request the same data, you include the ETag hash in an If-None-Match header of your request. If the data hasn’t changed, the server will send you back a 304 status code. As with the last-modified date checking, the server sends back only the 304 status code; it doesn’t send you the same data a second time. By including the ETag hash in your second request, you’re telling the server that there’s no need to re-send the same data if it still matches this hash, since you still have the data from the last time.

Again with the curl:

you@localhost:~$ curl -I -H "If-None-Match: \"3075-ddc8d800\"" http://wearehugh.com/m.jpg  
HTTP/1.1 304 Not Modified
Date: Sun, 31 May 2009 18:04:39 GMT
Server: Apache
Connection: close
ETag: "3075-ddc8d800"
Expires: Mon, 31 May 2010 18:04:39 GMT
Cache-Control: max-age=31536000, public
  1. ETags are commonly enclosed in quotation marks, but the quotation marks are part of the value. That means you need to send the quotation marks back to the server in the If-None-Match header.

Python’s HTTP libraries do not support ETags, but httplib2 does.

Compression

When you talk about HTTP web services, you’re almost always talking about moving text-based data back and forth over the wire. Maybe it’s XML, maybe it’s JSON, maybe it’s just plain text. Regardless of the format, text compresses well. The example feed in the XML chapter is 3070 bytes uncompressed, but would be 941 bytes after gzip compression. That’s just 30% of the original size!

HTTP supports several compression algorithms. The two most common types are gzip and deflate. When you request a resource over HTTP, you can ask the server to send it in compressed format. You include an Accept-encoding header in your request that lists which compression algorithms you support. If the server supports any of the same algorithms, it will send you back compressed data (with a Content-encoding header that tells you which algorithm it used). Then it’s up to you to decompress the data.

Important tip for server-side developers: make sure that the compressed version of a resource has a different Etag than the uncompressed version. Otherwise, caching proxies will get confused and may serve the compressed version to clients that can’t handle it. Read the discussion of Apache bug 39727 for more details on this subtle issue.

Python’s HTTP libraries do not support compression, but httplib2 does.

Redirects

Cool URIs don’t change, but many URIs are seriously uncool. Web sites get reorganized, pages move to new addresses. Even web services can reorganize. A syndicated feed at http://example.com/index.xml might be moved to http://example.com/xml/atom.xml. Or an entire domain might move, as an organization expands and reorganizes; http://www.example.com/index.xml becomes http://server-farm-1.example.com/index.xml.

Every time you request any kind of resource from an HTTP server, the server includes a status code in its response. Status code 200 means “everything’s normal, here’s the page you asked for”. Status code 404 means “page not found”. (You’ve probably seen 404 errors while browsing the web.) Status codes in the 300’s indicate some form of redirection.

HTTP has several different ways of signifying that a resource has moved. The two most common techiques are status codes 302 and 301. Status code 302 is a temporary redirect; it means “oops, that got moved over here temporarily” (and then gives the temporary address in a Location header). Status code 301 is a permanent redirect; it means “oops, that got moved permanently” (and then gives the new address in a Location header). If you get a 302 status code and a new address, the HTTP specification says you should use the new address to get what you asked for, but the next time you want to access the same resource, you should retry the old address. But if you get a 301 status code and a new address, you’re supposed to use the new address from then on.

The urllib.request module automatically “follow” redirects when it receives the appropriate status code from the HTTP server, but it doesn’t tell you that it did so. You’ll end up getting data you asked for, but you’ll never know that the underlying library “helpfully” followed a redirect for you. So you’ll continue pounding away at the old address, and each time you’ll get redirected to the new address, and each time the urllib.request module will “helpfully” follow the redirect. In other words, it treats permanent redirects the same as temporary redirects. That means two round trips instead of one, which is bad for the server and bad for you.

httplib2 handles permanent redirects for you. Not only will it tell you that a permanent redirect occurred, it will keep track of them locally and automatically rewrite redirected URLs before requesting them.

How Not To Fetch Data Over HTTP

Let’s say you want to download a resource over HTTP, such as an Atom feed. Being a feed, you’re not just going to download it once; you’re going to download it over and over again. (Most feed readers will check for changes once an hour.) Let’s do it the quick-and-dirty way first, and then see how you can do better.

>>> import urllib.request
>>> a_url = 'http://diveintopython3.org/examples/feed.xml'
>>> data = urllib.request.urlopen(a_url).read()  
>>> type(data)                                   
<class 'bytes'>
>>> print(data)
<?xml version='1.0' encoding='utf-8'?>
<feed xmlns='http://www.w3.org/2005/Atom' xml:lang='en'>
  <title>dive into mark</title>
  <subtitle>currently between addictions</subtitle>
  <id>tag:diveintomark.org,2001-07-29:/</id>
  <updated>2009-03-27T21:56:07Z</updated>
  <link rel='alternate' type='text/html' href='http://diveintomark.org/'/>
  …
  1. Downloading anything over HTTP is incredibly easy in Python; in fact, it’s a one-liner. The urllib.request module has a handy urlopen() function that takes the address of the page you want, and returns a file-like object that you can just read() from to get the full contents of the page. It just can’t get any easier.
  2. The urlopen().read() method always returns a bytes object, not a string. Remember, bytes are bytes; characters are an abstraction. HTTP servers don’t deal in abstractions. If you request a resource, you get bytes. If you want it as a string, you’ll need to determine the character encoding and explicitly convert it to a string.

So what’s wrong with this? For a quick one-off during testing or development, there’s nothing wrong with it. I do it all the time. I wanted the contents of the feed, and I got the contents of the feed. The same technique works for any web page. But once you start thinking in terms of a web service that you want to access on a regular basis (e.g. requesting this feed once an hour), then you’re being inefficient, and you’re being rude.

What’s On The Wire?

To see why this is inefficient and rude, let’s turn on the debugging features of Python’s HTTP library and see what’s being sent “on the wire” (i.e. over the network).

>>> from http.client import HTTPConnection
>>> HTTPConnection.debuglevel = 1                                       
>>> from urllib.request import urlopen
>>> response = urlopen('http://diveintopython3.org/examples/feed.xml')  
send: b'GET /examples/feed.xml HTTP/1.1                                 
Host: diveintopython3.org                                               
Accept-Encoding: identity                                               
User-Agent: Python-urllib/3.1'                                          
Connection: close
reply: 'HTTP/1.1 200 OK'
…further debugging information omitted…
  1. As I mentioned at the beginning of the chapter, urllib.request relies on another standard Python library, http.client. Normally you don’t need to touch http.client directly. (The urllib.request module imports it automatically.) But we import it here so we can toggle the debugging flag on the HTTPConnection class that urllib.request uses to connect to the HTTP server.
  2. Now that the debugging flag is set, information on the HTTP request and response is printed out in real time. As you can see, when you request the Atom feed, the urllib.request module sends five lines to the server.
  3. The first line specifies the HTTP verb you’re using, and the path of the resource (minus the domain name).
  4. The second line specifies the domain name from which we’re requesting this feed.
  5. The third line specifies the compression algorithms that the client supports. As I mentioned earlier, urllib.request does not support compression by default.
  6. The fourth line specifies the name of the library that is making the request. By default, this is Python-urllib plus a version number. Both urllib.request and httplib2 support changing the user agent, simply by adding a User-Agent header to the request (which will override the default value).

Now let’s look at what the server sent back in its response.

# continued from previous example
>>> print(response.headers.as_string())        
Date: Sun, 31 May 2009 19:23:06 GMT            
Server: Apache
Last-Modified: Sun, 31 May 2009 06:39:55 GMT   
ETag: "bfe-93d9c4c0"                           
Accept-Ranges: bytes
Content-Length: 3070                           
Cache-Control: max-age=86400                   
Expires: Mon, 01 Jun 2009 19:23:06 GMT
Vary: Accept-Encoding
Connection: close
Content-Type: application/xml
>>> data = response.read()                     
>>> len(data)
3070
  1. The response returned from the urllib.request.urlopen() function contains all the HTTP headers the server sent back. It also contains methods to download the actual data; we’ll get to that in a minute.
  2. The server tells you when it handled your request.
  3. This response includes a Last-Modified header.
  4. This response includes an ETag header.
  5. The data is 3070 bytes long. Notice what isn’t here: a Content-encoding header. Your request stated that you only accept uncompressed data (Accept-encoding: identity), and sure enough, this response contains uncompressed data.
  6. This response includes caching headers that state that this feed can be cached for up to 24 hours (86400 seconds).
  7. And finally, download the actual data by calling response.read(). As you can tell from the len() function, this fetched a total of 3070 bytes.

As you can see, this code is already inefficient: it asked for (and received) uncompressed data. I know for a fact that this server supports gzip compression, but HTTP compression is opt-in. We didn’t ask for it, so we didn’t get it. That means we’re fetching 3070 bytes when we could have fetched 941. Bad dog, no biscuit.

But wait, it gets worse! To see just how inefficient this code is, let’s request the same feed a second time.

# continued from the previous example
>>> response2 = urlopen('http://diveintopython3.org/examples/feed.xml')
send: b'GET /examples/feed.xml HTTP/1.1
Host: diveintopython3.org
Accept-Encoding: identity
User-Agent: Python-urllib/3.1'
Connection: close
reply: 'HTTP/1.1 200 OK'
…further debugging information omitted…

Notice anything peculiar about this request? It hasn’t changed! It’s exactly the same as the first request. No sign of If-Modified-Since headers. No sign of If-None-Match headers. No respect for the caching headers. Still no compression.

And what happens when you do the same thing twice? You get the same response. Twice.

# continued from the previous example
>>> print(response2.headers.as_string())     
Date: Mon, 01 Jun 2009 03:58:00 GMT
Server: Apache
Last-Modified: Sun, 31 May 2009 22:51:11 GMT
ETag: "bfe-255ef5c0"
Accept-Ranges: bytes
Content-Length: 3070
Cache-Control: max-age=86400
Expires: Tue, 02 Jun 2009 03:58:00 GMT
Vary: Accept-Encoding
Connection: close
Content-Type: application/xml
>>> data2 = response2.read()
>>> len(data2)                               
3070
>>> data2 == data                            
True
  1. The server is still sending the same array of “smart” headers: Cache-Control and Expires to allow caching, Last-Modified and ETag to enable “not-modified” tracking. Even the Vary: Accept-Encoding header hints that the server would support compression, if only you would ask for it. But you didn’t.
  2. Once again, this request fetches the whole 3070 bytes…
  3. …the exact same 3070 bytes you got last time.

HTTP is designed to work better than this. urllib speaks HTTP like I speak Spanish — enough to get by in a jam, but not enough to hold a conversation. HTTP is a conversation. It’s time to upgrade to a library that speaks HTTP fluently.

Introducing httplib2

Before you can use httplib2, you’ll need to install it. Visit code.google.com/p/httplib2/ and download the latest version. httplib2 is available for Python 2.x and Python 3.x; make sure you get the Python 3 version, named something like httplib2-python3-0.5.0.zip.

Unzip the archive, open a terminal window, and go to the newly created httplib2 directory. On Windows, open the Start menu, select Run..., type cmd.exe and press ENTER.

c:\Users\pilgrim\Downloads> dir
 Volume in drive C has no label.
 Volume Serial Number is DED5-B4F8

 Directory of c:\Users\pilgrim\Downloads

07/28/2009  12:36 PM    <DIR>          .
07/28/2009  12:36 PM    <DIR>          ..
07/28/2009  12:36 PM    <DIR>          httplib2-python3-0.5.0
07/28/2009  12:33 PM            18,997 httplib2-python3-0.5.0.zip
               1 File(s)         18,997 bytes
               3 Dir(s)  61,496,684,544 bytes free

c:\Users\pilgrim\Downloads> cd httplib2-python3-0.5.0
c:\Users\pilgrim\Downloads\httplib2-python3-0.5.0> c:\python31\python.exe setup.py install
running install
running build
running build_py
running install_lib
creating c:\python31\Lib\site-packages\httplib2
copying build\lib\httplib2\iri2uri.py -> c:\python31\Lib\site-packages\httplib2
copying build\lib\httplib2\__init__.py -> c:\python31\Lib\site-packages\httplib2
byte-compiling c:\python31\Lib\site-packages\httplib2\iri2uri.py to iri2uri.pyc
byte-compiling c:\python31\Lib\site-packages\httplib2\__init__.py to __init__.pyc
running install_egg_info
Writing c:\python31\Lib\site-packages\httplib2-python3_0.5.0-py3.1.egg-info

On Mac OS X, run the Terminal.app application in your /Applications/Utilities/ folder. On Linux, run the Terminal application, which is usually in your Applications menu under Accessories or System.

you@localhost:~/Desktop$ unzip httplib2-python3-0.5.0.zip
Archive:  httplib2-python3-0.5.0.zip
  inflating: httplib2-python3-0.5.0/README
  inflating: httplib2-python3-0.5.0/setup.py
  inflating: httplib2-python3-0.5.0/PKG-INFO
  inflating: httplib2-python3-0.5.0/httplib2/__init__.py
  inflating: httplib2-python3-0.5.0/httplib2/iri2uri.py
you@localhost:~/Desktop$ cd httplib2-python3-0.5.0/
you@localhost:~/Desktop/httplib2-python3-0.5.0$ sudo python3 setup.py install
running install
running build
running build_py
creating build
creating build/lib.linux-x86_64-3.1
creating build/lib.linux-x86_64-3.1/httplib2
copying httplib2/iri2uri.py -> build/lib.linux-x86_64-3.1/httplib2
copying httplib2/__init__.py -> build/lib.linux-x86_64-3.1/httplib2
running install_lib
creating /usr/local/lib/python3.1/dist-packages/httplib2
copying build/lib.linux-x86_64-3.1/httplib2/iri2uri.py -> /usr/local/lib/python3.1/dist-packages/httplib2
copying build/lib.linux-x86_64-3.1/httplib2/__init__.py -> /usr/local/lib/python3.1/dist-packages/httplib2
byte-compiling /usr/local/lib/python3.1/dist-packages/httplib2/iri2uri.py to iri2uri.pyc
byte-compiling /usr/local/lib/python3.1/dist-packages/httplib2/__init__.py to __init__.pyc
running install_egg_info
Writing /usr/local/lib/python3.1/dist-packages/httplib2-python3_0.5.0.egg-info

To use httplib2, create an instance of the httplib2.Http class.

>>> import httplib2
>>> h = httplib2.Http('.cache')                                                    
>>> response, content = h.request('http://diveintopython3.org/examples/feed.xml')  
>>> response.status                                                                
200
>>> content[:52]                                                                   
b"<?xml version='1.0' encoding='utf-8'?>\r\n<feed xmlns="
>>> len(content)
3070
  1. The primary interface to httplib2 is the Http object. For reasons you’ll see in the next section, you should always pass a directory name when you create an Http object. The directory does not need to exist; httplib2 will create it if necessary.
  2. Once you have an Http object, retrieving data is as simple as calling the request() method with the address of the data you want. This will issue an HTTP GET request for that URL. (Later in this chapter, you’ll see how to issue other HTTP requests, like POST.)
  3. The request() method returns two values. The first is an httplib2.Response object, which contains all the HTTP headers the server returned. For example, a status code of 200 indicates that the request was successful.
  4. The content variable contains the actual data that was returned by the HTTP server. The data is returned as a bytes object, not a string. If you want it as a string, you’ll need to determine the character encoding and convert it yourself.

You probably only need one httplib2.Http object. There are valid reasons for creating more than one, but you should only do so if you know why you need them. “I need to request data from two different URLs” is not a valid reason. Re-use the Http object and just call the request() method twice.

A Short Digression To Explain Why httplib2 Returns Bytes Instead of Strings

Bytes. Strings. What a pain. Why can’t httplib2 “just” do the conversion for you? Well, it’s complicated, because the rules for determining the character encoding are specific to what kind of resource you’re requesting. How could httplib2 know what kind of resource you’re requesting? It’s usually listed in the Content-Type HTTP header, but that’s an optional feature of HTTP and not all HTTP servers include it. If that header is not included in the HTTP response, it’s left up to the client to guess. (This is commonly called “content sniffing,” and it’s never perfect.)

If you know what sort of resource you’re expecting (an XML document in this case), perhaps you could “just” pass the returned bytes object to the xml.etree.ElementTree.parse() function. That’ll work as long as the XML document includes information on its own character encoding (as this one does), but that’s an optional feature and not all XML documents do that. If an XML document doesn’t include encoding information, the client is supposed to look at the enclosing transport — i.e. the Content-Type HTTP header, which can include a charset parameter.

[I support RFC 3023 t-shirt]

But it’s worse than that. Now character encoding information can be in two places: within the XML document itself, and within the Content-Type HTTP header. If the information is in both places, which one wins? According to RFC 3023 (I swear I am not making this up), if the media type given in the Content-Type HTTP header is application/xml, application/xml-dtd, application/xml-external-parsed-entity, or any one of the subtypes of application/xml such as application/atom+xml or application/rss+xml or even application/rdf+xml, then the encoding is

  1. the encoding given in the charset parameter of the Content-Type HTTP header, or
  2. the encoding given in the encoding attribute of the XML declaration within the document, or
  3. UTF-8

On the other hand, if the media type given in the Content-Type HTTP header is text/xml, text/xml-external-parsed-entity, or a subtype like text/AnythingAtAll+xml, then the encoding attribute of the XML declaration within the document is ignored completely, and the encoding is

  1. the encoding given in the charset parameter of the Content-Type HTTP header, or
  2. us-ascii

And that’s just for XML documents. For HTML documents, web browsers have constructed such byzantine rules for content-sniffing [PDF] that we’re still trying to figure them all out.

Patches welcome.”

How httplib2 Handles Caching

Remember in the previous section when I said you should always create an httplib2.Http object with a directory name? Caching is the reason.

# continued from the previous example
>>> response2, content2 = h.request('http://diveintopython3.org/examples/feed.xml')  
>>> response2.status                                                                 
200
>>> content2[:52]                                                                    
b"<?xml version='1.0' encoding='utf-8'?>\r\n<feed xmlns="
>>> len(content2)
3070
  1. This shouldn’t be terribly surprising. It’s the same thing you did last time, except you’re putting the result into two new variables.
  2. The HTTP status is once again 200, just like last time.
  3. The downloaded content is the same as last time, too.

So… who cares? Quit your Python interactive shell and relaunch it with a new session, and I’ll show you.

# NOT continued from previous example!
# Please exit out of the interactive shell
# and launch a new one.
>>> import httplib2
>>> httplib2.debuglevel = 1                                                        
>>> h = httplib2.Http('.cache')                                                    
>>> response, content = h.request('http://diveintopython3.org/examples/feed.xml')  
>>> len(content)                                                                   
3070
>>> response.status                                                                
200
>>> response.fromcache                                                             
True
  1. Let’s turn on debugging and see what’s on the wire. This is the httplib2 equivalent of turning on debugging in http.client. httplib2 will print all the data being sent to the server and some key information being sent back.
  2. Create an httplib2.Http object with the same directory name as before.
  3. Request the same URL as before. Nothing appears to happen. More precisely, nothing gets sent to the server, and nothing gets returned from the server. There is absolutely no network activity whatsoever.
  4. Yet we did “receive” some data — in fact, we received all of it.
  5. We also “received” an HTTP status code indicating that the “request” was successful.
  6. Here’s the rub: this “response” was generated from httplib2’s local cache. That directory name you passed in when you created the httplib2.Http object — that directory holds httplib2’s cache of all the operations it’s ever performed.

If you want to turn on httplib2 debugging, you need to set a module-level constant (httplib2.debuglevel), then create a new httplib2.Http object. If you want to turn off debugging, you need to change the same module-level constant, then create a new httplib2.Http object.

You previously requested the data at this URL. That request was successful (status: 200). That response included not only the feed data, but also a set of caching headers that told anyone who was listening that they could cache this resource for up to 24 hours (Cache-Control: max-age=86400, which is 24 hours measured in seconds). httplib2 understand and respects those caching headers, and it stored the previous response in the .cache directory (which you passed in when you create the Http object). That cache hasn’t expired yet, so the second time you request the data at this URL, httplib2 simply returns the cached result without ever hitting the network.

I say “simply,” but obviously there is a lot of complexity hidden behind that simplicity. httplib2 handles HTTP caching automatically and by default. If for some reason you need to know whether a response came from the cache, you can check response.fromcache. Otherwise, it Just Works.

Now, suppose you have data cached, but you want to bypass the cache and re-request it from the remote server. Browsers sometimes do this if the user specifically requests it. For example, pressing F5 refreshes the current page, but pressing Ctrl+F5 bypasses the cache and re-requests the current page from the remote server. You might think “oh, I’ll just delete the data from my local cache, then request it again.” You could do that, but remember that there may be more parties involved than just you and the remote server. What about those intermediate proxy servers? They’re completely beyond your control, and they may still have that data cached, and will happily return it to you because (as far as they are concerned) their cache is still valid.

Instead of manipulating your local cache and hoping for the best, you should use the features of HTTP to ensure that your request actually reaches the remote server.

# continued from the previous example
>>> response2, content2 = h.request('http://diveintopython3.org/examples/feed.xml',
...     headers={'cache-control':'no-cache'})  
connect: (diveintopython3.org, 80)             
send: b'GET /examples/feed.xml HTTP/1.1
Host: diveintopython3.org
user-agent: Python-httplib2/$Rev: 259 $
accept-encoding: deflate, gzip
cache-control: no-cache'
reply: 'HTTP/1.1 200 OK'
…further debugging information omitted…
>>> response2.status
200
>>> response2.fromcache                        
False
>>> print(dict(response2.items()))             
{'status': '200',
 'content-length': '3070',
 'content-location': 'http://diveintopython3.org/examples/feed.xml',
 'accept-ranges': 'bytes',
 'expires': 'Wed, 03 Jun 2009 00:40:26 GMT',
 'vary': 'Accept-Encoding',
 'server': 'Apache',
 'last-modified': 'Sun, 31 May 2009 22:51:11 GMT',
 'connection': 'close',
 '-content-encoding': 'gzip',
 'etag': '"bfe-255ef5c0"',
 'cache-control': 'max-age=86400',
 'date': 'Tue, 02 Jun 2009 00:40:26 GMT',
 'content-type': 'application/xml'}
  1. httplib2 allows you to add arbitrary HTTP headers to any outgoing request. In order to bypass all caches (not just your local disk cache, but also any caching proxies between you and the remote server), add a no-cache header in the headers dictionary.
  2. Now you see httplib2 initiating a network request. httplib2 understands and respects caching headers in both directions — as part of the incoming response and as part of the outgoing request. It noticed that you added the no-cache header, so it bypassed its local cache altogether and then had no choice but to hit the network to request the data.
  3. This response was not generated from your local cache. You knew that, of course, because you saw the debugging information on the outgoing request. But it’s nice to have that programmatically verified.
  4. The request succeeded; you downloaded the entire feed again from the remote server. Of course, the server also sent back a full complement of HTTP headers along with the feed data. That includes caching headers, which httplib2 uses to update its local cache, in the hopes of avoiding network access the next time you request this feed. Everything about HTTP caching is designed to maximize cache hits and minimize network access. Even though you bypassed the cache this time, the remote server would really appreciate it if you would cache the result for next time.

How httplib2 Handles Last-Modified and ETag Headers

The Cache-Control and Expires caching headers are called freshness indicators. They tell caches in no uncertain terms that you can completely avoid all network access until the cache expires. And that’s exactly the behavior you saw in the previous section: given a freshness indicator, httplib2 does not generate a single byte of network activity to serve up cached data (unless you explicitly bypass the cache, of course).

But what about the case where the data might have changed, but hasn’t? HTTP defines Last-Modified and Etag headers for this purpose. These headers are called validators. If the local cache is no longer fresh, a client can send the validators with the next request to see if the data has actually changed. If the data hasn’t changed, the server sends back a 304 status code and no data. So there’s still a round-trip over the network, but you end up downloading fewer bytes.

>>> import httplib2
>>> httplib2.debuglevel = 1
>>> h = httplib2.Http('.cache')
>>> response, content = h.request('http://diveintopython3.org/')  
connect: (diveintopython3.org, 80)
send: b'GET / HTTP/1.1
Host: diveintopython3.org
accept-encoding: deflate, gzip
user-agent: Python-httplib2/$Rev: 259 $'
reply: 'HTTP/1.1 200 OK'
>>> print(dict(response.items()))                                 
{'-content-encoding': 'gzip',
 'accept-ranges': 'bytes',
 'connection': 'close',
 'content-length': '6657',
 'content-location': 'http://diveintopython3.org/',
 'content-type': 'text/html',
 'date': 'Tue, 02 Jun 2009 03:26:54 GMT',
 'etag': '"7f806d-1a01-9fb97900"',
 'last-modified': 'Tue, 02 Jun 2009 02:51:48 GMT',
 'server': 'Apache',
 'status': '200',
 'vary': 'Accept-Encoding,User-Agent'}
>>> len(content)                                                  
6657
  1. Instead of the feed, this time we’re going to download the site’s home page, which is HTML. Since this is the first time you’ve ever requested this page, httplib2 has little to work with, and it sends out a minimum of headers with the request.
  2. The response contains a multitude of HTTP headers… but no caching information. However, it does include both an ETag and Last-Modified header.
  3. At the time I constructed this example, this page was 6657 bytes. It’s probably changed since then, but don’t worry about it.
# continued from the previous example
>>> response, content = h.request('http://diveintopython3.org/')  
connect: (diveintopython3.org, 80)
send: b'GET / HTTP/1.1
Host: diveintopython3.org
if-none-match: "7f806d-1a01-9fb97900"                             
if-modified-since: Tue, 02 Jun 2009 02:51:48 GMT                  
accept-encoding: deflate, gzip
user-agent: Python-httplib2/$Rev: 259 $'
reply: 'HTTP/1.1 304 Not Modified'                                
>>> response.fromcache                                            
True
>>> response.status                                               
200
>>> response.dict['status']                                       
'304'
>>> len(content)                                                  
6657
  1. You request the same page again, with the same Http object (and the same local cache).
  2. httplib2 sends the ETag validator back to the server in the If-None-Match header.
  3. httplib2 also sends the Last-Modified validator back to the server in the If-Modified-Since header.
  4. The server looked at these validators, looked at the page you requested, and determined that the page has not changed since you last requested it, so it sends back a 304 status code and no data.
  5. Back on the client, httplib2 notices the 304 status code and loads the content of the page from its cache.
  6. This might be a bit confusing. There are really two status codes — 304 (returned from the server this time, which caused httplib2 to look in its cache), and 200 (returned from the server last time, and stored in httplib2’s cache along with the page data). response.status returns the status from the cache.
  7. If you want the raw status code returned from the server, you can get that by looking in response.dict, which is a dictionary of the actual headers returned from the server.
  8. However, you still get the data in the content variable. Generally, you don’t need to know why a response was served from the cache. (You may not even care that it was served from the cache at all, and that’s fine too. httplib2 is smart enough to let you act dumb.) By the time the request() method returns to the caller, httplib2 has already updated its cache and returned the data to you.

How http2lib Handles Compression

HTTP supports several types of compression; the two most common types are gzip and deflate. httplib2 supports both of these.

>>> response, content = h.request('http://diveintopython3.org/')
connect: (diveintopython3.org, 80)
send: b'GET / HTTP/1.1
Host: diveintopython3.org
accept-encoding: deflate, gzip                          
user-agent: Python-httplib2/$Rev: 259 $'
reply: 'HTTP/1.1 200 OK'
>>> print(dict(response.items()))
{'-content-encoding': 'gzip',                           
 'accept-ranges': 'bytes',
 'connection': 'close',
 'content-length': '6657',
 'content-location': 'http://diveintopython3.org/',
 'content-type': 'text/html',
 'date': 'Tue, 02 Jun 2009 03:26:54 GMT',
 'etag': '"7f806d-1a01-9fb97900"',
 'last-modified': 'Tue, 02 Jun 2009 02:51:48 GMT',
 'server': 'Apache',
 'status': '304',
 'vary': 'Accept-Encoding,User-Agent'}
  1. Every time httplib2 sends a request, it includes an Accept-Encoding header to tell the server that it can handle either deflate or gzip compression.
  2. In this case, the server has responded with a gzip-compressed payload. By the time the request() method returns, httplib2 has already decompressed the body of the response and placed it in the content variable. If you’re curious about whether or not the response was compressed, you can check response['-content-encoding']; otherwise, don’t worry about it.

How httplib2 Handles Redirects

HTTP defines two kinds of redirects: temporary and permanent. There’s nothing special to do with temporary redirects except follow them, which httplib2 does automatically.

>>> import httplib2
>>> httplib2.debuglevel = 1
>>> h = httplib2.Http('.cache')
>>> response, content = h.request('http://diveintopython3.org/examples/feed-302.xml')  
connect: (diveintopython3.org, 80)
send: b'GET /examples/feed-302.xml HTTP/1.1                                            
Host: diveintopython3.org
accept-encoding: deflate, gzip
user-agent: Python-httplib2/$Rev: 259 $'
reply: 'HTTP/1.1 302 Found'                                                            
send: b'GET /examples/feed.xml HTTP/1.1                                                
Host: diveintopython3.org
accept-encoding: deflate, gzip
user-agent: Python-httplib2/$Rev: 259 $'
reply: 'HTTP/1.1 200 OK'
  1. There is no feed at this URL. I’ve set up my server to issue a temporary redirect to the correct address.
  2. There’s the request.
  3. And there’s the response: 302 Found. Not shown here, this response also includes a Location header that points to the real URL.
  4. httplib2 immediately turns around and “follows” the redirect by issuing another request for the URL given in the Location header: http://diveintopython3.org/examples/feed.xml

“Following” a redirect is nothing more than this example shows. httplib2 sends a request for the URL you asked for. The server comes back with a response that says “No no, look over there instead.” httplib2 sends another request for the new URL.

# continued from the previous example
>>> response                                                          
{'status': '200',
 'content-length': '3070',
 'content-location': 'http://diveintopython3.org/examples/feed.xml',  
 'accept-ranges': 'bytes',
 'expires': 'Thu, 04 Jun 2009 02:21:41 GMT',
 'vary': 'Accept-Encoding',
 'server': 'Apache',
 'last-modified': 'Wed, 03 Jun 2009 02:20:15 GMT',
 'connection': 'close',
 '-content-encoding': 'gzip',                                         
 'etag': '"bfe-4cbbf5c0"',
 'cache-control': 'max-age=86400',                                    
 'date': 'Wed, 03 Jun 2009 02:21:41 GMT',
 'content-type': 'application/xml'}
  1. The response you get back from this single call to the request() method is the response from the final URL.
  2. httplib2 adds the final URL to the response dictionary, as content-location. This is not a header that came from the server; it’s specific to httplib2.
  3. Apropos of nothing, this feed is compressed.
  4. And cacheable. (This is important, as you’ll see in a minute.)

The response you get back gives you information about the final URL. What if you want more information about the intermediate URLs, the ones that eventually redirected to the final URL? httplib2 lets you do that, too.

# continued from the previous example
>>> response.previous                                                     
{'status': '302',
 'content-length': '228',
 'content-location': 'http://diveintopython3.org/examples/feed-302.xml',
 'expires': 'Thu, 04 Jun 2009 02:21:41 GMT',
 'server': 'Apache',
 'connection': 'close',
 'location': 'http://diveintopython3.org/examples/feed.xml',
 'cache-control': 'max-age=86400',
 'date': 'Wed, 03 Jun 2009 02:21:41 GMT',
 'content-type': 'text/html; charset=iso-8859-1'}
>>> type(response)                                                        
<class 'httplib2.Response'>
>>> type(response.previous)
<class 'httplib2.Response'>
>>> response.previous.previous                                            
>>>
  1. The response.previous attribute holds a reference to the previous response object that httplib2 followed to get to the current response object.
  2. Both response and response.previous are httplib2.Response objects.
  3. That means you can check response.previous.previous to follow the redirect chain backwards even further. (Scenario: one URL redirects to a second URL which redirects to a third URL. It could happen!) In this case, we’ve already reached the beginning of the redirect chain, so the attribute is None.

What happens if you request the same URL again?

# continued from the previous example
>>> response2, content2 = h.request('http://diveintopython3.org/examples/feed-302.xml')  
connect: (diveintopython3.org, 80)
send: b'GET /examples/feed-302.xml HTTP/1.1                                              
Host: diveintopython3.org
accept-encoding: deflate, gzip
user-agent: Python-httplib2/$Rev: 259 $'
reply: 'HTTP/1.1 302 Found'                                                              
>>> content2 == content                                                                  
True
  1. Same URL, same httplib2.Http object (and therefore the same cache).
  2. The 302 response was not cached, so httplib2 sends another request for the same URL.
  3. Once again, the server responds with a 302. But notice what didn’t happen: there wasn’t ever a second request for the final URL, http://diveintopython3.org/examples/feed.xml. That response was cached (remember the Cache-Control header that you saw in the previous example). Once httplib2 received the 302 Found code, it checked its cache before issuing another request. The cache contained a fresh copy of http://diveintopython3.org/examples/feed.xml, so there was no need to re-request it.
  4. By the time the request() method returns, it has read the feed data from the cache and returned it. Of course, it’s the same as the data you received last time.

In other words, you don’t have to do anything special for temporary redirects. httplib2 will follow them automatically, and the fact that one URL redirects to another has no bearing on httplib2’s support for compression, caching, ETags, or any of the other features of HTTP.

Permanent redirects are just as simple.

# continued from the previous example
>>> response, content = h.request('http://diveintopython3.org/examples/feed-301.xml')  
connect: (diveintopython3.org, 80)
send: b'GET /examples/feed-301.xml HTTP/1.1
Host: diveintopython3.org
accept-encoding: deflate, gzip
user-agent: Python-httplib2/$Rev: 259 $'
reply: 'HTTP/1.1 301 Moved Permanently'                                                
>>> response.fromcache                                                                 
True
  1. Once again, this URL doesn’t really exist. I’ve set up my server to issue a permanent redirect to http://diveintopython3.org/examples/feed.xml.
  2. And here it is: status code 301. But again, notice what didn’t happen: there was no request to the redirect URL. Why not? Because it’s already cached locally.
  3. httplib2 “followed” the redirect right into its cache.

But wait! There’s more!

# continued from the previous example
>>> response2, content2 = h.request('http://diveintopython3.org/examples/feed-301.xml')  
>>> response2.fromcache                                                                  
True
>>> content2 == content                                                                  
True
  1. Here’s the difference between temporary and permanent redirects: once httplib2 follows a permanent redirect, all further requests for that URL will transparently be rewritten to the target URL without hitting the network for the original URL. Remember, debugging is still turned on, yet there is no output of network activity whatsoever.
  2. Yep, this response was retrieved from the local cache.
  3. Yep, you got the entire feed (from the cache).

HTTP. It works.

Beyond HTTP GET

HTTP web services are not limited to GET requests. What if you want to create something new? Whenever you post a comment on a discussion forum, update your weblog, publish your status on a microblogging service like Twitter or Identi.ca, you’re probably already using HTTP POST.

Both Twitter and Identi.ca both offer a simple HTTP-based API for publishing and updating your status in 140 characters or less. Let’s look at Identi.ca’s API documentation for updating your status:

Identi.ca REST API Method: statuses/update
Updates the authenticating user’s status. Requires the status parameter specified below. Request must be a POST.

URL
https://identi.ca/api/statuses/update.format
Formats
xml, json, rss, atom
HTTP Method(s)
POST
Requires Authentication
true
Parameters
status. Required. The text of your status update. URL-encode as necessary.

How does this work? To publish a new message on Identi.ca, you need to issue an HTTP POST request to http://identi.ca/api/statuses/update.format. (The format bit is not part of the URL; you replace it with the data format you want the server to return in response to your request. So if you want a response in XML, you would post the request to https://identi.ca/api/statuses/update.xml.) The request needs to include a parameter called status, which contains the text of your status update. And the request needs to be authenticated.

Authenticated? Sure. To update your status on Identi.ca, you need to prove who you are. Identi.ca is not a wiki; only you can update your own status. Identi.ca uses HTTP Basic Authentication (a.k.a. RFC 2617) over SSL to provide secure but easy-to-use authentication. httplib2 supports both SSL and HTTP Basic Authentication, so this part is easy.

A POST request is different from a GET request, because it includes a payload. The payload is the data you want to send to the server. The one piece of data that this API method requires is status, and it should be URL-encoded. This is a very simple serialization format that takes a set of key-value pairs (i.e. a dictionary) and transforms it into a string.

>>> from urllib.parse import urlencode              
>>> data = {'status': 'Test update from Python 3'}  
>>> urlencode(data)                                 
'status=Test+update+from+Python+3'
  1. Python comes with a utility function to URL-encode a dictionary: urllib.parse.urlencode().
  2. This is the sort of dictionary that the Identi.ca API is looking for. It contains one key, status, whose value is the text of a single status update.
  3. This is what the URL-encoded string looks like. This is the payload that will be sent “on the wire” to the Identi.ca API server in your HTTP POST request.

>>> from urllib.parse import urlencode
>>> import httplib2
>>> httplib2.debuglevel = 1
>>> h = httplib2.Http('.cache')
>>> data = {'status': 'Test update from Python 3'}
>>> h.add_credentials('diveintomark', 'MY_SECRET_PASSWORD', 'identi.ca')    
>>> resp, content = h.request('https://identi.ca/api/statuses/update.xml',
...     'POST',                                                             
...     urlencode(data),                                                    
...     headers={'Content-Type': 'application/x-www-form-urlencoded'})      
  1. This is how httplib2 handles authentication. Store your username and password with the add_credentials() method. When httplib2 tries to issue the request, the server will respond with a 401 Unauthorized status code, and it will list which authentication methods it supports (in the WWW-Authenticate header). httplib2 will automatically construct an Authorization header and re-request the URL.
  2. The second parameter is the type of HTTP request, in this case POST.
  3. The third parameter is the payload to send to the server. We’re sending the URL-encoded dictionary with a status message.
  4. Finally, we need to tell the server that the payload is URL-encoded data.

The third parameter to the add_credentials() method is the domain in which the credentials are valid. You should always specify this! If you leave out the domain and later reuse the httplib2.Http object on a different authenticated site, httplib2 might end up leaking one site’s username and password to the other site.

This is what goes over the wire:

# continued from the previous example
send: b'POST /api/statuses/update.xml HTTP/1.1
Host: identi.ca
Accept-Encoding: identity
Content-Length: 32
content-type: application/x-www-form-urlencoded
user-agent: Python-httplib2/$Rev: 259 $

status=Test+update+from+Python+3'
reply: 'HTTP/1.1 401 Unauthorized'                        
send: b'POST /api/statuses/update.xml HTTP/1.1            
Host: identi.ca
Accept-Encoding: identity
Content-Length: 32
content-type: application/x-www-form-urlencoded
authorization: Basic SECRET_HASH_CONSTRUCTED_BY_HTTPLIB2  
user-agent: Python-httplib2/$Rev: 259 $

status=Test+update+from+Python+3'
reply: 'HTTP/1.1 200 OK'                                  
  1. After the first request, the server responds with a 401 Unauthorized status code. httplib2 will never send authentication headers unless the server explicitly asks for them. This is how the server asks for them.
  2. httplib2 immediately turns around and requests the same URL a second time.
  3. This time, it includes the username and password that you added with the add_credentials() method.
  4. It worked!

What does the server send back after a successful request? That depends entirely on the web service API. In some protocols (like the Atom Publishing Protocol), the server sends back a 201 Created status code and the location of the newly created resource in the Location header. Identi.ca sends back a 200 OK and an XML document containing information about the newly created resource.

# continued from the previous example
>>> print(content.decode('utf-8'))                             
<?xml version="1.0" encoding="UTF-8"?>
<status>
 <text>Test update from Python 3</text>                        
 <truncated>false</truncated>
 <created_at>Wed Jun 10 03:53:46 +0000 2009</created_at>
 <in_reply_to_status_id></in_reply_to_status_id>
 <source>api</source>
 <id>5131472</id>                                              
 <in_reply_to_user_id></in_reply_to_user_id>
 <in_reply_to_screen_name></in_reply_to_screen_name>
 <favorited>false</favorited>
 <user>
  <id>3212</id>
  <name>Mark Pilgrim</name>
  <screen_name>diveintomark</screen_name>
  <location>27502, US</location>
  <description>tech writer, husband, father</description>
  <profile_image_url>http://avatar.identi.ca/3212-48-20081216000626.png</profile_image_url>
  <url>http://diveintomark.org/</url>
  <protected>false</protected>
  <followers_count>329</followers_count>
  <profile_background_color></profile_background_color>
  <profile_text_color></profile_text_color>
  <profile_link_color></profile_link_color>
  <profile_sidebar_fill_color></profile_sidebar_fill_color>
  <profile_sidebar_border_color></profile_sidebar_border_color>
  <friends_count>2</friends_count>
  <created_at>Wed Jul 02 22:03:58 +0000 2008</created_at>
  <favourites_count>30768</favourites_count>
  <utc_offset>0</utc_offset>
  <time_zone>UTC</time_zone>
  <profile_background_image_url></profile_background_image_url>
  <profile_background_tile>false</profile_background_tile>
  <statuses_count>122</statuses_count>
  <following>false</following>
  <notifications>false</notifications>
</user>
</status>
  1. Remember, the data returned by httplib2 is always bytes, not a string. To convert it to a string, you need to decode it using the proper character encoding. Identi.ca’s API always returns results in UTF-8, so that part is easy.
  2. There’s the text of the status message we just published.
  3. There’s the unique identifier for the new status message. Identi.ca uses this to construct a URL for viewing the message on the web.

And here it is:

screenshot showing published status message on Identi.ca

Beyond HTTP POST

HTTP isn’t limited to GET and POST. Those are certainly the most common types of requests, especially in web browsers. But web service APIs can go beyond GET and POST, and httplib2 is ready.

# continued from the previous example
>>> from xml.etree import ElementTree as etree
>>> tree = etree.fromstring(content)                                          
>>> status_id = tree.findtext('id')                                           
>>> status_id
'5131472'
>>> url = 'https://identi.ca/api/statuses/destroy/{0}.xml'.format(status_id)  
>>> resp, deleted_content = h.request(url, 'DELETE')                          
  1. The server returned XML, right? You know how to parse XML.
  2. The findtext() method finds the first instance of the given expression and extracts its text content. In this case, we’re just looking for an <id> element.
  3. Based on the text content of the <id> element, we can construct a URL to delete the status message we just published.
  4. To delete a message, you simply issue an HTTP DELETE request to that URL.

This is what goes over the wire:

send: b'DELETE /api/statuses/destroy/5131472.xml HTTP/1.1      
Host: identi.ca
Accept-Encoding: identity
user-agent: Python-httplib2/$Rev: 259 $

'
reply: 'HTTP/1.1 401 Unauthorized'                             
send: b'DELETE /api/statuses/destroy/5131472.xml HTTP/1.1      
Host: identi.ca
Accept-Encoding: identity
authorization: Basic SECRET_HASH_CONSTRUCTED_BY_HTTPLIB2       
user-agent: Python-httplib2/$Rev: 259 $

'
reply: 'HTTP/1.1 200 OK'                                       
>>> resp.status
200
  1. “Delete this status message.”
  2. “I’m sorry, Dave, I’m afraid I can’t do that.”
  3. “Unauthorized Hmmph. Delete this status message, please
  4. …and here’s my username and password.”
  5. “Consider it done!”

And just like that, poof, it’s gone.

screenshot showing deleted message on Identi.ca

Further Reading

httplib2:

HTTP caching:

RFCs:

© 2001–11 Mark Pilgrim diveintopython3-20110517-77958af.orig/xml.html0000644000000000000000000017110711773544727017305 0ustar rootroot XML - Dive Into Python 3

  

You are here: Home Dive Into Python 3

Difficulty level: ♦♦♦♦♢

XML

In the archonship of Aristaechmus, Draco enacted his ordinances.
Aristotle

 

Diving In

Nearly all the chapters in this book revolve around a piece of sample code. But XML isn’t about code; it’s about data. One common use of XML is “syndication feeds” that list the latest articles on a blog, forum, or other frequently-updated website. Most popular blogging software can produce a feed and update it whenever new articles, discussion threads, or blog posts are published. You can follow a blog by “subscribing” to its feed, and you can follow multiple blogs with a dedicated “feed aggregator” like Google Reader.

Here, then, is the XML data we’ll be working with in this chapter. It’s a feed — specifically, an Atom syndication feed.

[download feed.xml]

<?xml version='1.0' encoding='utf-8'?>
<feed xmlns='http://www.w3.org/2005/Atom' xml:lang='en'>
  <title>dive into mark</title>
  <subtitle>currently between addictions</subtitle>
  <id>tag:diveintomark.org,2001-07-29:/</id>
  <updated>2009-03-27T21:56:07Z</updated>
  <link rel='alternate' type='text/html' href='http://diveintomark.org/'/>
  <link rel='self' type='application/atom+xml' href='http://diveintomark.org/feed/'/>
  <entry>
    <author>
      <name>Mark</name>
      <uri>http://diveintomark.org/</uri>
    </author>
    <title>Dive into history, 2009 edition</title>
    <link rel='alternate' type='text/html'
      href='http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition'/>
    <id>tag:diveintomark.org,2009-03-27:/archives/20090327172042</id>
    <updated>2009-03-27T21:56:07Z</updated>
    <published>2009-03-27T17:20:42Z</published>
    <category scheme='http://diveintomark.org' term='diveintopython'/>
    <category scheme='http://diveintomark.org' term='docbook'/>
    <category scheme='http://diveintomark.org' term='html'/>
  <summary type='html'>Putting an entire chapter on one page sounds
    bloated, but consider this &amp;mdash; my longest chapter so far
    would be 75 printed pages, and it loads in under 5 seconds&amp;hellip;
    On dialup.</summary>
  </entry>
  <entry>
    <author>
      <name>Mark</name>
      <uri>http://diveintomark.org/</uri>
    </author>
    <title>Accessibility is a harsh mistress</title>
    <link rel='alternate' type='text/html'
      href='http://diveintomark.org/archives/2009/03/21/accessibility-is-a-harsh-mistress'/>
    <id>tag:diveintomark.org,2009-03-21:/archives/20090321200928</id>
    <updated>2009-03-22T01:05:37Z</updated>
    <published>2009-03-21T20:09:28Z</published>
    <category scheme='http://diveintomark.org' term='accessibility'/>
    <summary type='html'>The accessibility orthodoxy does not permit people to
      question the value of features that are rarely useful and rarely used.</summary>
  </entry>
  <entry>
    <author>
      <name>Mark</name>
    </author>
    <title>A gentle introduction to video encoding, part 1: container formats</title>
    <link rel='alternate' type='text/html'
      href='http://diveintomark.org/archives/2008/12/18/give-part-1-container-formats'/>
    <id>tag:diveintomark.org,2008-12-18:/archives/20081218155422</id>
    <updated>2009-01-11T19:39:22Z</updated>
    <published>2008-12-18T15:54:22Z</published>
    <category scheme='http://diveintomark.org' term='asf'/>
    <category scheme='http://diveintomark.org' term='avi'/>
    <category scheme='http://diveintomark.org' term='encoding'/>
    <category scheme='http://diveintomark.org' term='flv'/>
    <category scheme='http://diveintomark.org' term='GIVE'/>
    <category scheme='http://diveintomark.org' term='mp4'/>
    <category scheme='http://diveintomark.org' term='ogg'/>
    <category scheme='http://diveintomark.org' term='video'/>
    <summary type='html'>These notes will eventually become part of a
      tech talk on video encoding.</summary>
  </entry>
</feed>

A 5-Minute Crash Course in XML

If you already know about XML, you can skip this section.

XML is a generalized way of describing hierarchical structured data. An XML document contains one or more elements, which are delimited by start and end tags. This is a complete (albeit boring) XML document:

<foo>   
</foo>  
  1. This is the start tag of the foo element.
  2. This is the matching end tag of the foo element. Like balancing parentheses in writing or mathematics or code, every start tag must be closed (matched) by a corresponding end tag.

Elements can be nested to any depth. An element bar inside an element foo is said to be a subelement or child of foo.

<foo>
  <bar></bar>
</foo>

The first element in every XML document is called the root element. An XML document can only have one root element. The following is not an XML document, because it has two root elements:

<foo></foo>
<bar></bar>

Elements can have attributes, which are name-value pairs. Attributes are listed within the start tag of an element and separated by whitespace. Attribute names can not be repeated within an element. Attribute values must be quoted. You may use either single or double quotes.

<foo lang='en'>                          
  <bar id='papayawhip' lang="fr"></bar>  
</foo>
  1. The foo element has one attribute, named lang. The value of its lang attribute is en.
  2. The bar element has two attributes, named id and lang. The value of its lang attribute is fr. This doesn’t conflict with the foo element in any way. Each element has its own set of attributes.

If an element has more than one attribute, the ordering of the attributes is not significant. An element’s attributes form an unordered set of keys and values, like a Python dictionary. There is no limit to the number of attributes you can define on each element.

Elements can have text content.

<foo lang='en'>
  <bar lang='fr'>PapayaWhip</bar>
</foo>

Elements that contain no text and no children are empty.

<foo></foo>

There is a shorthand for writing empty elements. By putting a / character in the start tag, you can skip the end tag altogther. The XML document in the previous example could be written like this instead:

<foo/>

Like Python functions can be declared in different modules, XML elements can be declared in different namespaces. Namespaces usually look like URLs. You use an xmlns declaration to define a default namespace. A namespace declaration looks similar to an attribute, but it has a different purpose.

<feed xmlns='http://www.w3.org/2005/Atom'>  
  <title>dive into mark</title>             
</feed>
  1. The feed element is in the http://www.w3.org/2005/Atom namespace.
  2. The title element is also in the http://www.w3.org/2005/Atom namespace. The namespace declaration affects the element where it’s declared, plus all child elements.

You can also use an xmlns:prefix declaration to define a namespace and associate it with a prefix. Then each element in that namespace must be explicitly declared with the prefix.

<atom:feed xmlns:atom='http://www.w3.org/2005/Atom'>  
  <atom:title>dive into mark</atom:title>             
</atom:feed>
  1. The feed element is in the http://www.w3.org/2005/Atom namespace.
  2. The title element is also in the http://www.w3.org/2005/Atom namespace.

As far as an XML parser is concerned, the previous two XML documents are identical. Namespace + element name = XML identity. Prefixes only exist to refer to namespaces, so the actual prefix name (atom:) is irrelevant. The namespaces match, the element names match, the attributes (or lack of attributes) match, and each element’s text content matches, therefore the XML documents are the same.

Finally, XML documents can contain character encoding information on the first line, before the root element. (If you’re curious how a document can contain information which needs to be known before the document can be parsed, Section F of the XML specification details how to resolve this Catch-22.)

<?xml version='1.0' encoding='utf-8'?>

And now you know just enough XML to be dangerous!

The Structure Of An Atom Feed

Think of a weblog, or in fact any website with frequently updated content, like CNN.com. The site itself has a title (“CNN.com”), a subtitle (“Breaking News, U.S., World, Weather, Entertainment & Video News”), a last-updated date (“updated 12:43 p.m. EDT, Sat May 16, 2009”), and a list of articles posted at different times. Each article also has a title, a first-published date (and maybe also a last-updated date, if they published a correction or fixed a typo), and a unique URL.

The Atom syndication format is designed to capture all of this information in a standard format. My weblog and CNN.com are wildly different in design, scope, and audience, but they both have the same basic structure. CNN.com has a title; my blog has a title. CNN.com publishes articles; I publish articles.

At the top level is the root element, which every Atom feed shares: the feed element in the http://www.w3.org/2005/Atom namespace.

<feed xmlns='http://www.w3.org/2005/Atom'  
      xml:lang='en'>                       
  1. http://www.w3.org/2005/Atom is the Atom namespace.
  2. Any element can contain an xml:lang attribute, which declares the language of the element and its children. In this case, the xml:lang attribute is declared once on the root element, which means the entire feed is in English.

An Atom feed contains several pieces of information about the feed itself. These are declared as children of the root-level feed element.

<feed xmlns='http://www.w3.org/2005/Atom' xml:lang='en'>
  <title>dive into mark</title>                                             
  <subtitle>currently between addictions</subtitle>                         
  <id>tag:diveintomark.org,2001-07-29:/</id>                                
  <updated>2009-03-27T21:56:07Z</updated>                                   
  <link rel='alternate' type='text/html' href='http://diveintomark.org/'/>  
  1. The title of this feed is dive into mark.
  2. The subtitle of this feed is currently between addictions.
  3. Every feed needs a globally unique identifier. See RFC 4151 for how to create one.
  4. This feed was last updated on March 27, 2009, at 21:56 GMT. This is usually equivalent to the last-modified date of the most recent article.
  5. Now things start to get interesting. This link element has no text content, but it has three attributes: rel, type, and href. The rel value tells you what kind of link this is; rel='alternate' means that this is a link to an alternate representation of this feed. The type='text/html' attribute means that this is a link to an HTML page. And the link target is given in the href attribute.

Now we know that this is a feed for a site named “dive into mark“ which is available at http://diveintomark.org/ and was last updated on March 27, 2009.

Although the order of elements can be relevant in some XML documents, it is not relevant in an Atom feed.

After the feed-level metadata is the list of the most recent articles. An article looks like this:

<entry>
  <author>                                                                 
    <name>Mark</name>
    <uri>http://diveintomark.org/</uri>
  </author>
  <title>Dive into history, 2009 edition</title>                           
  <link rel='alternate' type='text/html'                                   
    href='http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition'/>
  <id>tag:diveintomark.org,2009-03-27:/archives/20090327172042</id>        
  <updated>2009-03-27T21:56:07Z</updated>                                  
  <published>2009-03-27T17:20:42Z</published>        
  <category scheme='http://diveintomark.org' term='diveintopython'/>       
  <category scheme='http://diveintomark.org' term='docbook'/>
  <category scheme='http://diveintomark.org' term='html'/>
  <summary type='html'>Putting an entire chapter on one page sounds        
    bloated, but consider this &amp;mdash; my longest chapter so far
    would be 75 printed pages, and it loads in under 5 seconds&amp;hellip;
    On dialup.</summary>
</entry>                                                                   
  1. The author element tells who wrote this article: some guy named Mark, whom you can find loafing at http://diveintomark.org/. (This is the same as the alternate link in the feed metadata, but it doesn’t have to be. Many weblogs have multiple authors, each with their own personal website.)
  2. The title element gives the title of the article, “Dive into history, 2009 edition”.
  3. As with the feed-level alternate link, this link element gives the address of the HTML version of this article.
  4. Entries, like feeds, need a unique identifier.
  5. Entries have two dates: a first-published date (published) and a last-modified date (updated).
  6. Entries can have an arbitrary number of categories. This article is filed under diveintopython, docbook, and html.
  7. The summary element gives a brief summary of the article. (There is also a content element, not shown here, if you want to include the complete article text in your feed.) This summary element has the Atom-specific type='html' attribute, which specifies that this summary is a snippet of HTML, not plain text. This is important, since it has HTML-specific entities in it (&mdash; and &hellip;) which should be rendered as “—” and “…” rather than displayed directly.
  8. Finally, the end tag for the entry element, signaling the end of the metadata for this article.

Parsing XML

Python can parse XML documents in several ways. It has traditional DOM and SAX parsers, but I will focus on a different library called ElementTree.

[download feed.xml]

>>> import xml.etree.ElementTree as etree    
>>> tree = etree.parse('examples/feed.xml')  
>>> root = tree.getroot()                    
>>> root                                     
<Element {http://www.w3.org/2005/Atom}feed at cd1eb0>
  1. The ElementTree library is part of the Python standard library, in xml.etree.ElementTree.
  2. The primary entry point for the ElementTree library is the parse() function, which can take a filename or a file-like object. This function parses the entire document at once. If memory is tight, there are ways to parse an XML document incrementally instead.
  3. The parse() function returns an object which represents the entire document. This is not the root element. To get a reference to the root element, call the getroot() method.
  4. As expected, the root element is the feed element in the http://www.w3.org/2005/Atom namespace. The string representation of this object reinforces an important point: an XML element is a combination of its namespace and its tag name (also called the local name). Every element in this document is in the Atom namespace, so the root element is represented as {http://www.w3.org/2005/Atom}feed.

ElementTree represents XML elements as {namespace}localname. You’ll see and use this format in multiple places in the ElementTree API.

Elements Are Lists

In the ElementTree API, an element acts like a list. The items of the list are the element’s children.

# continued from the previous example
>>> root.tag                        
'{http://www.w3.org/2005/Atom}feed'
>>> len(root)                       
8
>>> for child in root:              
...   print(child)                  
... 
<Element {http://www.w3.org/2005/Atom}title at e2b5d0>
<Element {http://www.w3.org/2005/Atom}subtitle at e2b4e0>
<Element {http://www.w3.org/2005/Atom}id at e2b6c0>
<Element {http://www.w3.org/2005/Atom}updated at e2b6f0>
<Element {http://www.w3.org/2005/Atom}link at e2b4b0>
<Element {http://www.w3.org/2005/Atom}entry at e2b720>
<Element {http://www.w3.org/2005/Atom}entry at e2b510>
<Element {http://www.w3.org/2005/Atom}entry at e2b750>
  1. Continuing from the previous example, the root element is {http://www.w3.org/2005/Atom}feed.
  2. The “length” of the root element is the number of child elements.
  3. You can use the element itself as an iterator to loop through all of its child elements.
  4. As you can see from the output, there are indeed 8 child elements: all of the feed-level metadata (title, subtitle, id, updated, and link) followed by the three entry elements.

You may have guessed this already, but I want to point it out explicitly: the list of child elements only includes direct children. Each of the entry elements contain their own children, but those are not included in the list. They would be included in the list of each entry’s children, but they are not included in the list of the feed’s children. There are ways to find elements no matter how deeply nested they are; we’ll look at two such ways later in this chapter.

Attributes Are Dictonaries

XML isn’t just a collection of elements; each element can also have its own set of attributes. Once you have a reference to a specific element, you can easily get its attributes as a Python dictionary.

# continuing from the previous example
>>> root.attrib                           
{'{http://www.w3.org/XML/1998/namespace}lang': 'en'}
>>> root[4]                               
<Element {http://www.w3.org/2005/Atom}link at e181b0>
>>> root[4].attrib                        
{'href': 'http://diveintomark.org/',
 'type': 'text/html',
 'rel': 'alternate'}
>>> root[3]                               
<Element {http://www.w3.org/2005/Atom}updated at e2b4e0>
>>> root[3].attrib                        
{}
  1. The attrib property is a dictionary of the element’s attributes. The original markup here was <feed xmlns='http://www.w3.org/2005/Atom' xml:lang='en'>. The xml: prefix refers to a built-in namespace that every XML document can use without declaring it.
  2. The fifth child — [4] in a 0-based list — is the link element.
  3. The link element has three attributes: href, type, and rel.
  4. The fourth child — [3] in a 0-based list — is the updated element.
  5. The updated element has no attributes, so its .attrib is just an empty dictionary.

Searching For Nodes Within An XML Document

So far, we’ve worked with this XML document “from the top down,” starting with the root element, getting its child elements, and so on throughout the document. But many uses of XML require you to find specific elements. Etree can do that, too.

>>> import xml.etree.ElementTree as etree
>>> tree = etree.parse('examples/feed.xml')
>>> root = tree.getroot()
>>> root.findall('{http://www.w3.org/2005/Atom}entry')    
[<Element {http://www.w3.org/2005/Atom}entry at e2b4e0>,
 <Element {http://www.w3.org/2005/Atom}entry at e2b510>,
 <Element {http://www.w3.org/2005/Atom}entry at e2b540>]
>>> root.tag
'{http://www.w3.org/2005/Atom}feed'
>>> root.findall('{http://www.w3.org/2005/Atom}feed')     
[]
>>> root.findall('{http://www.w3.org/2005/Atom}author')   
[]
  1. The findall() method finds child elements that match a specific query. (More on the query format in a minute.)
  2. Each element — including the root element, but also child elements — has a findall() method. It finds all matching elements among the element’s children. But why aren’t there any results? Although it may not be obvious, this particular query only searches the element’s children. Since the root feed element has no child named feed, this query returns an empty list.
  3. This result may also surprise you. There is an author element in this document; in fact, there are three (one in each entry). But those author elements are not direct children of the root element; they are “grandchildren” (literally, a child element of a child element). If you want to look for author elements at any nesting level, you can do that, but the query format is slightly different.
>>> tree.findall('{http://www.w3.org/2005/Atom}entry')    
[<Element {http://www.w3.org/2005/Atom}entry at e2b4e0>,
 <Element {http://www.w3.org/2005/Atom}entry at e2b510>,
 <Element {http://www.w3.org/2005/Atom}entry at e2b540>]
>>> tree.findall('{http://www.w3.org/2005/Atom}author')   
[]
  1. For convenience, the tree object (returned from the etree.parse() function) has several methods that mirror the methods on the root element. The results are the same as if you had called the tree.getroot().findall() method.
  2. Perhaps surprisingly, this query does not find the author elements in this document. Why not? Because this is just a shortcut for tree.getroot().findall('{http://www.w3.org/2005/Atom}author'), which means “find all the author elements that are children of the root element.” The author elements are not children of the root element; they’re children of the entry elements. Thus the query doesn’t return any matches.

There is also a find() method which returns the first matching element. This is useful for situations where you are only expecting one match, or if there are multiple matches, you only care about the first one.

>>> entries = tree.findall('{http://www.w3.org/2005/Atom}entry')           
>>> len(entries)
3
>>> title_element = entries[0].find('{http://www.w3.org/2005/Atom}title')  
>>> title_element.text
'Dive into history, 2009 edition'
>>> foo_element = entries[0].find('{http://www.w3.org/2005/Atom}foo')      
>>> foo_element
>>> type(foo_element)
<class 'NoneType'>
  1. You saw this in the previous example. It finds all the atom:entry elements.
  2. The find() method takes an ElementTree query and returns the first matching element.
  3. There are no elements in this entry named foo, so this returns None.

There is a “gotcha” with the find() method that will eventually bite you. In a boolean context, ElementTree element objects will evaluate to False if they contain no children (i.e. if len(element) is 0). This means that if element.find('...') is not testing whether the find() method found a matching element; it’s testing whether that matching element has any child elements! To test whether the find() method returned an element, use if element.find('...') is not None.

There is a way to search for descendant elements, i.e. children, grandchildren, and any element at any nesting level.

>>> all_links = tree.findall('//{http://www.w3.org/2005/Atom}link')  
>>> all_links
[<Element {http://www.w3.org/2005/Atom}link at e181b0>,
 <Element {http://www.w3.org/2005/Atom}link at e2b570>,
 <Element {http://www.w3.org/2005/Atom}link at e2b480>,
 <Element {http://www.w3.org/2005/Atom}link at e2b5a0>]
>>> all_links[0].attrib                                              
{'href': 'http://diveintomark.org/',
 'type': 'text/html',
 'rel': 'alternate'}
>>> all_links[1].attrib                                              
{'href': 'http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition',
 'type': 'text/html',
 'rel': 'alternate'}
>>> all_links[2].attrib
{'href': 'http://diveintomark.org/archives/2009/03/21/accessibility-is-a-harsh-mistress',
 'type': 'text/html',
 'rel': 'alternate'}
>>> all_links[3].attrib
{'href': 'http://diveintomark.org/archives/2008/12/18/give-part-1-container-formats',
 'type': 'text/html',
 'rel': 'alternate'}
  1. This query — //{http://www.w3.org/2005/Atom}link — is very similar to the previous examples, except for the two slashes at the beginning of the query. Those two slashes mean “don’t just look for direct children; I want any elements, regardless of nesting level.” So the result is a list of four link elements, not just one.
  2. The first result is a direct child of the root element. As you can see from its attributes, this is the feed-level alternate link that points to the HTML version of the website that the feed describes.
  3. The other three results are each entry-level alternate links. Each entry has a single link child element, and because of the double slash at the beginning of the query, this query finds all of them.

Overall, ElementTree’s findall() method is a very powerful feature, but the query language can be a bit surprising. It is officially described as “limited support for XPath expressions.” XPath is a W3C standard for querying XML documents. ElementTree’s query language is similar enough to XPath to do basic searching, but dissimilar enough that it may annoy you if you already know XPath. Now let’s look at a third-party XML library that extends the ElementTree API with full XPath support.

Going Further With lxml

lxml is an open source third-party library that builds on the popular libxml2 parser. It provides a 100% compatible ElementTree API, then extends it with full XPath 1.0 support and a few other niceties. There are installers available for Windows; Linux users should always try to use distribution-specific tools like yum or apt-get to install precompiled binaries from their repositories. Otherwise you’ll need to install lxml manually.

>>> from lxml import etree                   
>>> tree = etree.parse('examples/feed.xml')  
>>> root = tree.getroot()                    
>>> root.findall('{http://www.w3.org/2005/Atom}entry')  
[<Element {http://www.w3.org/2005/Atom}entry at e2b4e0>,
 <Element {http://www.w3.org/2005/Atom}entry at e2b510>,
 <Element {http://www.w3.org/2005/Atom}entry at e2b540>]
  1. Once imported, lxml provides the same API as the built-in ElementTree library.
  2. parse() function: same as ElementTree.
  3. getroot() method: also the same.
  4. findall() method: exactly the same.

For large XML documents, lxml is significantly faster than the built-in ElementTree library. If you’re only using the ElementTree API and want to use the fastest available implementation, you can try to import lxml and fall back to the built-in ElementTree.

try:
    from lxml import etree
except ImportError:
    import xml.etree.ElementTree as etree

But lxml is more than just a faster ElementTree. Its findall() method includes support for more complicated expressions.

>>> import lxml.etree                                                                   
>>> tree = lxml.etree.parse('examples/feed.xml')
>>> tree.findall('//{http://www.w3.org/2005/Atom}*[@href]')                             
[<Element {http://www.w3.org/2005/Atom}link at eeb8a0>,
 <Element {http://www.w3.org/2005/Atom}link at eeb990>,
 <Element {http://www.w3.org/2005/Atom}link at eeb960>,
 <Element {http://www.w3.org/2005/Atom}link at eeb9c0>]
>>> tree.findall("//{http://www.w3.org/2005/Atom}*[@href='http://diveintomark.org/']")  
[<Element {http://www.w3.org/2005/Atom}link at eeb930>]
>>> NS = '{http://www.w3.org/2005/Atom}'
>>> tree.findall('//{NS}author[{NS}uri]'.format(NS=NS))                                 
[<Element {http://www.w3.org/2005/Atom}author at eeba80>,
 <Element {http://www.w3.org/2005/Atom}author at eebba0>]
  1. In this example, I’m going to import lxml.etree (instead of, say, from lxml import etree), to emphasize that these features are specific to lxml.
  2. This query finds all elements in the Atom namespace, anywhere in the document, that have an href attribute. The // at the beginning of the query means “elements anywhere (not just as children of the root element).” {http://www.w3.org/2005/Atom} means “only elements in the Atom namespace.” * means “elements with any local name.” And [@href] means “has an href attribute.”
  3. The query finds all Atom elements with an href whose value is http://diveintomark.org/.
  4. After doing some quick string formatting (because otherwise these compound queries get ridiculously long), this query searches for Atom author elements that have an Atom uri element as a child. This only returns two author elements, the ones in the first and second entry. The author in the last entry contains only a name, not a uri.

Not enough for you? lxml also integrates support for arbitrary XPath 1.0 expressions. I’m not going to go into depth about XPath syntax; that could be a whole book unto itself! But I will show you how it integrates into lxml.

>>> import lxml.etree
>>> tree = lxml.etree.parse('examples/feed.xml')
>>> NSMAP = {'atom': 'http://www.w3.org/2005/Atom'}                    
>>> entries = tree.xpath("//atom:category[@term='accessibility']/..",  
...     namespaces=NSMAP)
>>> entries                                                            
[<Element {http://www.w3.org/2005/Atom}entry at e2b630>]
>>> entry = entries[0]
>>> entry.xpath('./atom:title/text()', namespaces=NSMAP)               
['Accessibility is a harsh mistress']
  1. To perform XPath queries on namespaced elements, you need to define a namespace prefix mapping. This is just a Python dictionary.
  2. Here is an XPath query. The XPath expression searches for category elements (in the Atom namespace) that contain a term attribute with the value accessibility. But that’s not actually the query result. Look at the very end of the query string; did you notice the /.. bit? That means “and then return the parent element of the category element you just found.” So this single XPath query will find all entries with a child element of <category term='accessibility'>.
  3. The xpath() function returns a list of ElementTree objects. In this document, there is only one entry with a category whose term is accessibility.
  4. XPath expressions don’t always return a list of elements. Technically, the DOM of a parsed XML document doesn’t contain elements; it contains nodes. Depending on their type, nodes can be elements, attributes, or even text content. The result of an XPath query is a list of nodes. This query returns a list of text nodes: the text content (text()) of the title element (atom:title) that is a child of the current element (./).

Generating XML

Python’s support for XML is not limited to parsing existing documents. You can also create XML documents from scratch.

>>> import xml.etree.ElementTree as etree
>>> new_feed = etree.Element('{http://www.w3.org/2005/Atom}feed',     
...     attrib={'{http://www.w3.org/XML/1998/namespace}lang': 'en'})  
>>> print(etree.tostring(new_feed))                                   
<ns0:feed xmlns:ns0='http://www.w3.org/2005/Atom' xml:lang='en'/>
  1. To create a new element, instantiate the Element class. You pass the element name (namespace + local name) as the first argument. This statement creates a feed element in the Atom namespace. This will be our new document’s root element.
  2. To add attributes to the newly created element, pass a dictionary of attribute names and values in the attrib argument. Note that the attribute name should be in the standard ElementTree format, {namespace}localname.
  3. At any time, you can serialize any element (and its children) with the ElementTree tostring() function.

Was that serialization surprising to you? The way ElementTree serializes namespaced XML elements is technically accurate but not optimal. The sample XML document at the beginning of this chapter defined a default namespace (xmlns='http://www.w3.org/2005/Atom'). Defining a default namespace is useful for documents — like Atom feeds — where every element is in the same namespace, because you can declare the namespace once and declare each element with just its local name (<feed>, <link>, <entry>). There is no need to use any prefixes unless you want to declare elements from another namespace.

An XML parser won’t “see” any difference between an XML document with a default namespace and an XML document with a prefixed namespace. The resulting DOM of this serialization:

<ns0:feed xmlns:ns0='http://www.w3.org/2005/Atom' xml:lang='en'/>

is identical to the DOM of this serialization:

<feed xmlns='http://www.w3.org/2005/Atom' xml:lang='en'/>

The only practical difference is that the second serialization is several characters shorter. If we were to recast our entire sample feed with a ns0: prefix in every start and end tag, it would add 4 characters per start tag × 79 tags + 4 characters for the namespace declaration itself, for a total of 320 characters. Assuming UTF-8 encoding, that’s 320 extra bytes. (After gzipping, the difference drops to 21 bytes, but still, 21 bytes is 21 bytes.) Maybe that doesn’t matter to you, but for something like an Atom feed, which may be downloaded several thousand times whenever it changes, saving a few bytes per request can quickly add up.

The built-in ElementTree library does not offer this fine-grained control over serializing namespaced elements, but lxml does.

>>> import lxml.etree
>>> NSMAP = {None: 'http://www.w3.org/2005/Atom'}                     
>>> new_feed = lxml.etree.Element('feed', nsmap=NSMAP)                
>>> print(lxml.etree.tounicode(new_feed))                             
<feed xmlns='http://www.w3.org/2005/Atom'/>
>>> new_feed.set('{http://www.w3.org/XML/1998/namespace}lang', 'en')  
>>> print(lxml.etree.tounicode(new_feed))
<feed xmlns='http://www.w3.org/2005/Atom' xml:lang='en'/>
  1. To start, define a namespace mapping as a dictionary. Dictionary values are namespaces; dictionary keys are the desired prefix. Using None as a prefix effectively declares a default namespace.
  2. Now you can pass the lxml-specific nsmap argument when you create an element, and lxml will respect the namespace prefixes you’ve defined.
  3. As expected, this serialization defines the Atom namespace as the default namespace and declares the feed element without a namespace prefix.
  4. Oops, we forgot to add the xml:lang attribute. You can always add attributes to any element with the set() method. It takes two arguments: the attribute name in standard ElementTree format, then the attribute value. (This method is not lxml-specific. The only lxml-specific part of this example was the nsmap argument to control the namespace prefixes in the serialized output.)

Are XML documents limited to one element per document? No, of course not. You can easily create child elements, too.

>>> title = lxml.etree.SubElement(new_feed, 'title',          
...     attrib={'type':'html'})                               
>>> print(lxml.etree.tounicode(new_feed))                     
<feed xmlns='http://www.w3.org/2005/Atom' xml:lang='en'><title type='html'/></feed>
>>> title.text = 'dive into &hellip;'                         
>>> print(lxml.etree.tounicode(new_feed))                     
<feed xmlns='http://www.w3.org/2005/Atom' xml:lang='en'><title type='html'>dive into &amp;hellip;</title></feed>
>>> print(lxml.etree.tounicode(new_feed, pretty_print=True))  
<feed xmlns='http://www.w3.org/2005/Atom' xml:lang='en'>
<title type='html'>dive into&amp;hellip;</title>
</feed>
  1. To create a child element of an existing element, instantiate the SubElement class. The only required arguments are the parent element (new_feed in this case) and the new element’s name. Since this child element will inherit the namespace mapping of its parent, there is no need to redeclare the namespace or prefix here.
  2. You can also pass in an attribute dictionary. Keys are attribute names; values are attribute values.
  3. As expected, the new title element was created in the Atom namespace, and it was inserted as a child of the feed element. Since the title element has no text content and no children of its own, lxml serializes it as an empty element (with the /> shortcut).
  4. To set the text content of an element, simply set its .text property.
  5. Now the title element is serialized with its text content. Any text content that contains less-than signs or ampersands needs to be escaped when serialized. lxml handles this escaping automatically.
  6. You can also apply “pretty printing” to the serialization, which inserts line breaks after end tags, and after start tags of elements that contain child elements but no text content. In technical terms, lxml adds “insignificant whitespace” to make the output more readable.

You might also want to check out xmlwitch, another third-party library for generating XML. It makes extensive use of the with statement to make XML generation code more readable.

Parsing Broken XML

The XML specification mandates that all conforming XML parsers employ “draconian error handling.” That is, they must halt and catch fire as soon as they detect any sort of wellformedness error in the XML document. Wellformedness errors include mismatched start and end tags, undefined entities, illegal Unicode characters, and a number of other esoteric rules. This is in stark contrast to other common formats like HTML — your browser doesn’t stop rendering a web page if you forget to close an HTML tag or escape an ampersand in an attribute value. (It is a common misconception that HTML has no defined error handling. HTML error handling is actually quite well-defined, but it’s significantly more complicated than “halt and catch fire on first error.”)

Some people (myself included) believe that it was a mistake for the inventors of XML to mandate draconian error handling. Don’t get me wrong; I can certainly see the allure of simplifying the error handling rules. But in practice, the concept of “wellformedness” is trickier than it sounds, especially for XML documents (like Atom feeds) that are published on the web and served over HTTP. Despite the maturity of XML, which standardized on draconian error handling in 1997, surveys continually show a significant fraction of Atom feeds on the web are plagued with wellformedness errors.

So, I have both theoretical and practical reasons to parse XML documents “at any cost,” that is, not to halt and catch fire at the first wellformedness error. If you find yourself wanting to do this too, lxml can help.

Here is a fragment of a broken XML document. I’ve highlighted the wellformedness error.

<?xml version='1.0' encoding='utf-8'?>
<feed xmlns='http://www.w3.org/2005/Atom' xml:lang='en'>
  <title>dive into &hellip;</title>
...
</feed>

That’s an error, because the &hellip; entity is not defined in XML. (It is defined in HTML.) If you try to parse this broken feed with the default settings, lxml will choke on the undefined entity.

>>> import lxml.etree
>>> tree = lxml.etree.parse('examples/feed-broken.xml')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "lxml.etree.pyx", line 2693, in lxml.etree.parse (src/lxml/lxml.etree.c:52591)
  File "parser.pxi", line 1478, in lxml.etree._parseDocument (src/lxml/lxml.etree.c:75665)
  File "parser.pxi", line 1507, in lxml.etree._parseDocumentFromURL (src/lxml/lxml.etree.c:75993)
  File "parser.pxi", line 1407, in lxml.etree._parseDocFromFile (src/lxml/lxml.etree.c:75002)
  File "parser.pxi", line 965, in lxml.etree._BaseParser._parseDocFromFile (src/lxml/lxml.etree.c:72023)
  File "parser.pxi", line 539, in lxml.etree._ParserContext._handleParseResultDoc (src/lxml/lxml.etree.c:67830)
  File "parser.pxi", line 625, in lxml.etree._handleParseResult (src/lxml/lxml.etree.c:68877)
  File "parser.pxi", line 565, in lxml.etree._raiseParseError (src/lxml/lxml.etree.c:68125)
lxml.etree.XMLSyntaxError: Entity 'hellip' not defined, line 3, column 28

To parse this broken XML document, despite its wellformedness error, you need to create a custom XML parser.

>>> parser = lxml.etree.XMLParser(recover=True)                  
>>> tree = lxml.etree.parse('examples/feed-broken.xml', parser)  
>>> parser.error_log                                             
examples/feed-broken.xml:3:28:FATAL:PARSER:ERR_UNDECLARED_ENTITY: Entity 'hellip' not defined
>>> tree.findall('{http://www.w3.org/2005/Atom}title')
[<Element {http://www.w3.org/2005/Atom}title at ead510>]
>>> title = tree.findall('{http://www.w3.org/2005/Atom}title')[0]
>>> title.text                                                   
'dive into '
>>> print(lxml.etree.tounicode(tree.getroot()))                  
<feed xmlns='http://www.w3.org/2005/Atom' xml:lang='en'>
  <title>dive into </title>
.
. [rest of serialization snipped for brevity]
.
  1. To create a custom parser, instantiate the lxml.etree.XMLParser class. It can take a number of different named arguments. The one we’re interested in here is the recover argument. When set to True, the XML parser will try its best to “recover” from wellformedness errors.
  2. To parse an XML document with your custom parser, pass the parser object as the second argument to the parse() function. Note that lxml does not raise an exception about the undefined &hellip; entity.
  3. The parser keeps a log of the wellformedness errors that it has encountered. (This is actually true regardless of whether it is set to recover from those errors or not.)
  4. Since it didn’t know what to do with the undefined &hellip; entity, the parser just silently dropped it. The text content of the title element becomes 'dive into '.
  5. As you can see from the serialization, the &hellip; entity didn’t get moved; it was simply dropped.

It is important to reiterate that there is no guarantee of interoperability with “recovering” XML parsers. A different parser might decide that it recognized the &hellip; entity from HTML, and replace it with &amp;hellip; instead. Is that “better”? Maybe. Is it “more correct”? No, they are both equally incorrect. The correct behavior (according to the XML specification) is to halt and catch fire. If you’ve decided not to do that, you’re on your own.

Further Reading

© 2001–11 Mark Pilgrim diveintopython3-20110517-77958af.orig/comprehensions.html0000644000000000000000000007635611773544727021553 0ustar rootroot Comprehensions - Dive Into Python 3

  

You are here: Home Dive Into Python 3

Difficulty level: ♦♦♢♢♢

Comprehensions

Our imagination is stretched to the utmost, not, as in fiction, to imagine things which are not really there, but just to comprehend those things which are.
Richard Feynman

 

Diving In

Every programming language has that one feature, a complicated thing intentionally made simple. If you’re coming from another language, you could easily miss it, because your old language didn’t make that thing simple (because it was busy making something else simple instead). This chapter will teach you about list comprehensions, dictionary comprehensions, and set comprehensions: three related concepts centered around one very powerful technique. But first, I want to take a little detour into two modules that will help you navigate your local file system.

Working With Files And Directories

Python 3 comes with a module called os, which stands for “operating system.” The os module contains a plethora of functions to get information on — and in some cases, to manipulate — local directories, files, processes, and environment variables. Python does its best to offer a unified API across all supported operating systems so your programs can run on any computer with as little platform-specific code as possible.

The Current Working Directory

When you’re just getting started with Python, you’re going to spend a lot of time in the Python Shell. Throughout this book, you will see examples that go like this:

  1. Import one of the modules in the examples folder
  2. Call a function in that module
  3. Explain the result

If you don’t know about the current working directory, step 1 will probably fail with an ImportError. Why? Because Python will look for the example module in the import search path, but it won’t find it because the examples folder isn’t one of the directories in the search path. To get past this, you can do one of two things:

  1. Add the examples folder to the import search path
  2. Change the current working directory to the examples folder

The current working directory is an invisible property that Python holds in memory at all times. There is always a current working directory, whether you’re in the Python Shell, running your own Python script from the command line, or running a Python CGI script on a web server somewhere.

The os module contains two functions to deal with the current working directory.

>>> import os                                            
>>> print(os.getcwd())                                   
C:\Python31
>>> os.chdir('/Users/pilgrim/diveintopython3/examples')  
>>> print(os.getcwd())                                   
C:\Users\pilgrim\diveintopython3\examples
  1. The os module comes with Python; you can import it anytime, anywhere.
  2. Use the os.getcwd() function to get the current working directory. When you run the graphical Python Shell, the current working directory starts as the directory where the Python Shell executable is. On Windows, this depends on where you installed Python; the default directory is c:\Python31. If you run the Python Shell from the command line, the current working directory starts as the directory you were in when you ran python3.
  3. Use the os.chdir() function to change the current working directory.
  4. When I called the os.chdir() function, I used a Linux-style pathname (forward slashes, no drive letter) even though I’m on Windows. This is one of the places where Python tries to paper over the differences between operating systems.

Working With Filenames and Directory Names

While we’re on the subject of directories, I want to point out the os.path module. os.path contains functions for manipulating filenames and directory names.

>>> import os
>>> print(os.path.join('/Users/pilgrim/diveintopython3/examples/', 'humansize.py'))              
/Users/pilgrim/diveintopython3/examples/humansize.py
>>> print(os.path.join('/Users/pilgrim/diveintopython3/examples', 'humansize.py'))               
/Users/pilgrim/diveintopython3/examples\humansize.py
>>> print(os.path.expanduser('~'))                                                               
c:\Users\pilgrim
>>> print(os.path.join(os.path.expanduser('~'), 'diveintopython3', 'examples', 'humansize.py'))  
c:\Users\pilgrim\diveintopython3\examples\humansize.py
  1. The os.path.join() function constructs a pathname out of one or more partial pathnames. In this case, it simply concatenates strings.
  2. In this slightly less trivial case, calling the os.path.join() function will add an extra slash to the pathname before joining it to the filename. It’s a backslash instead of a forward slash, because I constructed this example on Windows. If you replicate this example on Linux or Mac OS X, you’ll see a forward slash instead. Don’t fuss with slashes; always use os.path.join() and let Python do the right thing.
  3. The os.path.expanduser() function will expand a pathname that uses ~ to represent the current user’s home directory. This works on any platform where users have a home directory, including Linux, Mac OS X, and Windows. The returned path does not have a trailing slash, but the os.path.join() function doesn’t mind.
  4. Combining these techniques, you can easily construct pathnames for directories and files in the user’s home directory. The os.path.join() function can take any number of arguments. I was overjoyed when I discovered this, since addSlashIfNecessary() is one of the stupid little functions I always need to write when building up my toolbox in a new language. Do not write this stupid little function in Python; smart people have already taken care of it for you.

os.path also contains functions to split full pathnames, directory names, and filenames into their constituent parts.

>>> pathname = '/Users/pilgrim/diveintopython3/examples/humansize.py'
>>> os.path.split(pathname)                                        
('/Users/pilgrim/diveintopython3/examples', 'humansize.py')
>>> (dirname, filename) = os.path.split(pathname)                  
>>> dirname                                                        
'/Users/pilgrim/diveintopython3/examples'
>>> filename                                                       
'humansize.py'
>>> (shortname, extension) = os.path.splitext(filename)            
>>> shortname
'humansize'
>>> extension
'.py'
  1. The split function splits a full pathname and returns a tuple containing the path and filename.
  2. Remember when I said you could use multi-variable assignment to return multiple values from a function? The os.path.split() function does exactly that. You assign the return value of the split function into a tuple of two variables. Each variable receives the value of the corresponding element of the returned tuple.
  3. The first variable, dirname, receives the value of the first element of the tuple returned from the os.path.split() function, the file path.
  4. The second variable, filename, receives the value of the second element of the tuple returned from the os.path.split() function, the filename.
  5. os.path also contains the os.path.splitext() function, which splits a filename and returns a tuple containing the filename and the file extension. You use the same technique to assign each of them to separate variables.

Listing Directories

The glob module is another tool in the Python standard library. It’s an easy way to get the contents of a directory programmatically, and it uses the sort of wildcards that you may already be familiar with from working on the command line.

>>> os.chdir('/Users/pilgrim/diveintopython3/')
>>> import glob
>>> glob.glob('examples/*.xml')                  
['examples\\feed-broken.xml',
 'examples\\feed-ns0.xml',
 'examples\\feed.xml']
>>> os.chdir('examples/')                        
>>> glob.glob('*test*.py')                       
['alphameticstest.py',
 'pluraltest1.py',
 'pluraltest2.py',
 'pluraltest3.py',
 'pluraltest4.py',
 'pluraltest5.py',
 'pluraltest6.py',
 'romantest1.py',
 'romantest10.py',
 'romantest2.py',
 'romantest3.py',
 'romantest4.py',
 'romantest5.py',
 'romantest6.py',
 'romantest7.py',
 'romantest8.py',
 'romantest9.py']
  1. The glob module takes a wildcard and returns the path of all files and directories matching the wildcard. In this example, the wildcard is a directory path plus “*.xml”, which will match all .xml files in the examples subdirectory.
  2. Now change the current working directory to the examples subdirectory. The os.chdir() function can take relative pathnames.
  3. You can include multiple wildcards in your glob pattern. This example finds all the files in the current working directory that end in a .py extension and contain the word test anywhere in their filename.

Getting File Metadata

Every modern file system stores metadata about each file: creation date, last-modified date, file size, and so on. Python provides a single API to access this metadata. You don’t need to open the file; all you need is the filename.

>>> import os
>>> print(os.getcwd())                 
c:\Users\pilgrim\diveintopython3\examples
>>> metadata = os.stat('feed.xml')     
>>> metadata.st_mtime                  
1247520344.9537716
>>> import time                        
>>> time.localtime(metadata.st_mtime)  
time.struct_time(tm_year=2009, tm_mon=7, tm_mday=13, tm_hour=17,
  tm_min=25, tm_sec=44, tm_wday=0, tm_yday=194, tm_isdst=1)
  1. The current working directory is the examples folder.
  2. feed.xml is a file in the examples folder. Calling the os.stat() function returns an object that contains several different types of metadata about the file.
  3. st_mtime is the modification time, but it’s in a format that isn’t terribly useful. (Technically, it’s the number of seconds since the Epoch, which is defined as the first second of January 1st, 1970. Seriously.)
  4. The time module is part of the Python standard library. It contains functions to convert between different time representations, format time values into strings, and fiddle with timezones.
  5. The time.localtime() function converts a time value from seconds-since-the-Epoch (from the st_mtime property returned from the os.stat() function) into a more useful structure of year, month, day, hour, minute, second, and so on. This file was last modified on July 13, 2009, at around 5:25 PM.
# continued from the previous example
>>> metadata.st_size                              
3070
>>> import humansize
>>> humansize.approximate_size(metadata.st_size)  
'3.0 KiB'
  1. The os.stat() function also returns the size of a file, in the st_size property. The file feed.xml is 3070 bytes.
  2. You can pass the st_size property to the approximate_size() function.

Constructing Absolute Pathnames

In the previous section, the glob.glob() function returned a list of relative pathnames. The first example had pathnames like 'examples\feed.xml', and the second example had even shorter relative pathnames like 'romantest1.py'. As long as you stay in the same current working directory, these relative pathnames will work for opening files or getting file metadata. But if you want to construct an absolute pathname — i.e. one that includes all the directory names back to the root directory or drive letter — then you’ll need the os.path.realpath() function.

>>> import os
>>> print(os.getcwd())
c:\Users\pilgrim\diveintopython3\examples
>>> print(os.path.realpath('feed.xml'))
c:\Users\pilgrim\diveintopython3\examples\feed.xml

List Comprehensions

A list comprehension provides a compact way of mapping a list into another list by applying a function to each of the elements of the list.

>>> a_list = [1, 9, 8, 4]
>>> [elem * 2 for elem in a_list]           
[2, 18, 16, 8]
>>> a_list                                  
[1, 9, 8, 4]
>>> a_list = [elem * 2 for elem in a_list]  
>>> a_list
[2, 18, 16, 8]
  1. To make sense of this, look at it from right to left. a_list is the list you’re mapping. The Python interpreter loops through a_list one element at a time, temporarily assigning the value of each element to the variable elem. Python then applies the function elem * 2 and appends that result to the returned list.
  2. A list comprehension creates a new list; it does not change the original list.
  3. It is safe to assign the result of a list comprehension to the variable that you’re mapping. Python constructs the new list in memory, and when the list comprehension is complete, it assigns the result to the original variable.

You can use any Python expression in a list comprehension, including the functions in the os module for manipulating files and directories.

>>> import os, glob
>>> glob.glob('*.xml')                                 
['feed-broken.xml', 'feed-ns0.xml', 'feed.xml']
>>> [os.path.realpath(f) for f in glob.glob('*.xml')]  
['c:\\Users\\pilgrim\\diveintopython3\\examples\\feed-broken.xml',
 'c:\\Users\\pilgrim\\diveintopython3\\examples\\feed-ns0.xml',
 'c:\\Users\\pilgrim\\diveintopython3\\examples\\feed.xml']
  1. This returns a list of all the .xml files in the current working directory.
  2. This list comprehension takes that list of .xml files and transforms it into a list of full pathnames.

List comprehensions can also filter items, producing a result that can be smaller than the original list.

>>> import os, glob
>>> [f for f in glob.glob('*.py') if os.stat(f).st_size > 6000]  
['pluraltest6.py',
 'romantest10.py',
 'romantest6.py',
 'romantest7.py',
 'romantest8.py',
 'romantest9.py']
  1. To filter a list, you can include an if clause at the end of the list comprehension. The expression after the if keyword will be evaluated for each item in the list. If the expression evaluates to True, the item will be included in the output. This list comprehension looks at the list of all .py files in the current directory, and the if expression filters that list by testing whether the size of each file is greater than 6000 bytes. There are six such files, so the list comprehension returns a list of six filenames.

All the examples of list comprehensions so far have featured simple expressions — multiply a number by a constant, call a single function, or simply return the original list item (after filtering). But there’s no limit to how complex a list comprehension can be.

>>> import os, glob
>>> [(os.stat(f).st_size, os.path.realpath(f)) for f in glob.glob('*.xml')]            
[(3074, 'c:\\Users\\pilgrim\\diveintopython3\\examples\\feed-broken.xml'),
 (3386, 'c:\\Users\\pilgrim\\diveintopython3\\examples\\feed-ns0.xml'),
 (3070, 'c:\\Users\\pilgrim\\diveintopython3\\examples\\feed.xml')]
>>> import humansize
>>> [(humansize.approximate_size(os.stat(f).st_size), f) for f in glob.glob('*.xml')]  
[('3.0 KiB', 'feed-broken.xml'),
 ('3.3 KiB', 'feed-ns0.xml'),
 ('3.0 KiB', 'feed.xml')]
  1. This list comprehension finds all the .xml files in the current working directory, gets the size of each file (by calling the os.stat() function), and constructs a tuple of the file size and the absolute path of each file (by calling the os.path.realpath() function).
  2. This comprehension builds on the previous one to call the approximate_size() function with the file size of each .xml file.

Dictionary Comprehensions

A dictionary comprehension is like a list comprehension, but it constructs a dictionary instead of a list.

>>> import os, glob
>>> metadata = [(f, os.stat(f)) for f in glob.glob('*test*.py')]    
>>> metadata[0]                                                     
('alphameticstest.py', nt.stat_result(st_mode=33206, st_ino=0, st_dev=0,
 st_nlink=0, st_uid=0, st_gid=0, st_size=2509, st_atime=1247520344,
 st_mtime=1247520344, st_ctime=1247520344))
>>> metadata_dict = {f:os.stat(f) for f in glob.glob('*test*.py')}  
>>> type(metadata_dict)                                             
<class 'dict'>
>>> list(metadata_dict.keys())                                      
['romantest8.py', 'pluraltest1.py', 'pluraltest2.py', 'pluraltest5.py',
 'pluraltest6.py', 'romantest7.py', 'romantest10.py', 'romantest4.py',
 'romantest9.py', 'pluraltest3.py', 'romantest1.py', 'romantest2.py',
 'romantest3.py', 'romantest5.py', 'romantest6.py', 'alphameticstest.py',
 'pluraltest4.py']
>>> metadata_dict['alphameticstest.py'].st_size                     
2509
  1. This is not a dictionary comprehension; it’s a list comprehension. It finds all .py files with test in their name, then constructs a tuple of the filename and the file metadata (from calling the os.stat() function).
  2. Each item of the resulting list is a tuple.
  3. This is a dictionary comprehension. The syntax is similar to a list comprehension, with two differences. First, it is enclosed in curly braces instead of square brackets. Second, instead of a single expression for each item, it contains two expressions separated by a colon. The expression before the colon (f in this example) is the dictionary key; the expression after the colon (os.stat(f) in this example) is the value.
  4. A dictionary comprehension returns a dictionary.
  5. The keys of this particular dictionary are simply the filenames returned from the call to glob.glob('*test*.py').
  6. The value associated with each key is the return value from the os.stat() function. That means we can “look up” a file by name in this dictionary to get its file metadata. One of the pieces of metadata is st_size, the file size. The file alphameticstest.py is 2509 bytes long.

Like list comprehensions, you can include an if clause in a dictionary comprehension to filter the input sequence based on an expression which is evaluated with each item.

>>> import os, glob, humansize
>>> metadata_dict = {f:os.stat(f) for f in glob.glob('*')}                                  
>>> humansize_dict = {os.path.splitext(f)[0]:humansize.approximate_size(meta.st_size) \     
...                   for f, meta in metadata_dict.items() if meta.st_size > 6000}          
>>> list(humansize_dict.keys())                                                             
['romantest9', 'romantest8', 'romantest7', 'romantest6', 'romantest10', 'pluraltest6']
>>> humansize_dict['romantest9']                                                            
'6.5 KiB'
  1. This dictionary comprehension constructs a list of all the files in the current working directory (glob.glob('*')), gets the file metadata for each file (os.stat(f)), and constructs a dictionary whose keys are filenames and whose values are the metadata for each file.
  2. This dictionary comprehension builds on the previous comprehension, filters out files smaller than 6000 bytes (if meta.st_size > 6000), and uses that filtered list to construct a dictionary whose keys are the filename minus the extension (os.path.splitext(f)[0]) and whose values are the approximate size of each file (humansize.approximate_size(meta.st_size)).
  3. As you saw in a previous example, there are six such files, thus there are six items in this dictionary.
  4. The value of each key is the string returned from the approximate_size() function.

Other Fun Stuff To Do With Dictionary Comprehensions

Here’s a trick with dictionary comprehensions that might be useful someday: swapping the keys and values of a dictionary.

>>> a_dict = {'a': 1, 'b': 2, 'c': 3}
>>> {value:key for key, value in a_dict.items()}
{1: 'a', 2: 'b', 3: 'c'}

Of course, this only works if the values of the dictionary are immutable, like strings or tuples. If you try this with a dictionary that contains lists, it will fail most spectacularly.

>>> a_dict = {'a': [1, 2, 3], 'b': 4, 'c': 5}
>>> {value:key for key, value in a_dict.items()}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <dictcomp>
TypeError: unhashable type: 'list'

Set Comprehensions

Not to be left out, sets have their own comprehension syntax as well. It is remarkably similar to the syntax for dictionary comprehensions. The only difference is that sets just have values instead of key:value pairs.

>>> a_set = set(range(10))
>>> a_set
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> {x ** 2 for x in a_set}           
{0, 1, 4, 81, 64, 9, 16, 49, 25, 36}
>>> {x for x in a_set if x % 2 == 0}  
{0, 8, 2, 4, 6}
>>> {2**x for x in range(10)}         
{32, 1, 2, 4, 8, 64, 128, 256, 16, 512}
  1. Set comprehensions can take a set as input. This set comprehension calculates the squares of the set of numbers from 0 to 9.
  2. Like list comprehensions and dictionary comprehensions, set comprehensions can contain an if clause to filter each item before returning it in the result set.
  3. Set comprehensions do not need to take a set as input; they can take any sequence.

Further Reading

© 2001–11 Mark Pilgrim diveintopython3-20110517-77958af.orig/your-first-python-program.html0000644000000000000000000011004711773544727023610 0ustar rootroot Your first Python program - Dive Into Python 3

  

You are here: Home Dive Into Python 3

Difficulty level: ♦♢♢♢♢

Your First Python Program

Don’t bury your burden in saintly silence. You have a problem? Great. Rejoice, dive in, and investigate.
Ven. Henepola Gunaratana

 

Diving In

Convention dictates that I should bore you with the fundamental building blocks of programming, so we can slowly work up to building something useful. Let’s skip all that. Here is a complete, working Python program. It probably makes absolutely no sense to you. Don’t worry about that, because you’re going to dissect it line by line. But read through it first and see what, if anything, you can make of it.

[download humansize.py]

SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
            1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}

def approximate_size(size, a_kilobyte_is_1024_bytes=True):
    '''Convert a file size to human-readable form.

    Keyword arguments:
    size -- file size in bytes
    a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
                                if False, use multiples of 1000

    Returns: string

    '''
    if size < 0:
        raise ValueError('number must be non-negative')

    multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
    for suffix in SUFFIXES[multiple]:
        size /= multiple
        if size < multiple:
            return '{0:.1f} {1}'.format(size, suffix)

    raise ValueError('number too large')

if __name__ == '__main__':
    print(approximate_size(1000000000000, False))
    print(approximate_size(1000000000000))

Now let’s run this program on the command line. On Windows, it will look something like this:

c:\home\diveintopython3\examples> c:\python31\python.exe humansize.py
1.0 TB
931.3 GiB

On Mac OS X or Linux, it would look something like this:

you@localhost:~/diveintopython3/examples$ python3 humansize.py
1.0 TB
931.3 GiB

What just happened? You executed your first Python program. You called the Python interpreter on the command line, and you passed the name of the script you wanted Python to execute. The script defines a single function, the approximate_size() function, which takes an exact file size in bytes and calculates a “pretty” (but approximate) size. (You’ve probably seen this in Windows Explorer, or the Mac OS X Finder, or Nautilus or Dolphin or Thunar on Linux. If you display a folder of documents as a multi-column list, it will display a table with the document icon, the document name, the size, type, last-modified date, and so on. If the folder contains a 1093-byte file named TODO, your file manager won’t display TODO 1093 bytes; it’ll say something like TODO 1 KB instead. That’s what the approximate_size() function does.)

Look at the bottom of the script, and you’ll see two calls to print(approximate_size(arguments)). These are function calls — first calling the approximate_size() function and passing a number of arguments, then taking the return value and passing it straight on to the print() function. The print() function is built-in; you’ll never see an explicit declaration of it. You can just use it, anytime, anywhere. (There are lots of built-in functions, and lots more functions that are separated into modules. Patience, grasshopper.)

So why does running the script on the command line give you the same output every time? We’ll get to that. First, let’s look at that approximate_size() function.

Declaring Functions

Python has functions like most other languages, but it does not have separate header files like C++ or interface/implementation sections like Pascal. When you need a function, just declare it, like this:

def approximate_size(size, a_kilobyte_is_1024_bytes=True):

The keyword def starts the function declaration, followed by the function name, followed by the arguments in parentheses. Multiple arguments are separated with commas.

Also note that the function doesn’t define a return datatype. Python functions do not specify the datatype of their return value; they don’t even specify whether or not they return a value. (In fact, every Python function returns a value; if the function ever executes a return statement, it will return that value, otherwise it will return None, the Python null value.)

In some languages, functions (that return a value) start with function, and subroutines (that do not return a value) start with sub. There are no subroutines in Python. Everything is a function, all functions return a value (even if it’s None), and all functions start with def.

The approximate_size() function takes the two arguments — size and a_kilobyte_is_1024_bytes — but neither argument specifies a datatype. In Python, variables are never explicitly typed. Python figures out what type a variable is and keeps track of it internally.

In Java and other statically-typed languages, you must specify the datatype of the function return value and each function argument. In Python, you never explicitly specify the datatype of anything. Based on what value you assign, Python keeps track of the datatype internally.

Optional and Named Arguments

Python allows function arguments to have default values; if the function is called without the argument, the argument gets its default value. Furthermore, arguments can be specified in any order by using named arguments.

Let’s take another look at that approximate_size() function declaration:

def approximate_size(size, a_kilobyte_is_1024_bytes=True):

The second argument, a_kilobyte_is_1024_bytes, specifies a default value of True. This means the argument is optional; you can call the function without it, and Python will act as if you had called it with True as a second parameter.

Now look at the bottom of the script:

if __name__ == '__main__':
    print(approximate_size(1000000000000, False))  
    print(approximate_size(1000000000000))         
  1. This calls the approximate_size() function with two arguments. Within the approximate_size() function, a_kilobyte_is_1024_bytes will be False, since you explicitly passed False as the second argument.
  2. This calls the approximate_size() function with only one argument. But that’s OK, because the second argument is optional! Since the caller doesn’t specify, the second argument defaults to True, as defined by the function declaration.

You can also pass values into a function by name.

>>> from humansize import approximate_size
>>> approximate_size(4000, a_kilobyte_is_1024_bytes=False)       
'4.0 KB'
>>> approximate_size(size=4000, a_kilobyte_is_1024_bytes=False)  
'4.0 KB'
>>> approximate_size(a_kilobyte_is_1024_bytes=False, size=4000)  
'4.0 KB'
>>> approximate_size(a_kilobyte_is_1024_bytes=False, 4000)       
  File "<stdin>", line 1
SyntaxError: non-keyword arg after keyword arg
>>> approximate_size(size=4000, False)                           
  File "<stdin>", line 1
SyntaxError: non-keyword arg after keyword arg
  1. This calls the approximate_size() function with 4000 for the first argument (size) and False for the argument named a_kilobyte_is_1024_bytes. (That happens to be the second argument, but doesn’t matter, as you’ll see in a minute.)
  2. This calls the approximate_size() function with 4000 for the argument named size and False for the argument named a_kilobyte_is_1024_bytes. (These named arguments happen to be in the same order as the arguments are listed in the function declaration, but that doesn’t matter either.)
  3. This calls the approximate_size() function with False for the argument named a_kilobyte_is_1024_bytes and 4000 for the argument named size. (See? I told you the order didn’t matter.)
  4. This call fails, because you have a named argument followed by an unnamed (positional) argument, and that never works. Reading the argument list from left to right, once you have a single named argument, the rest of the arguments must also be named.
  5. This call fails too, for the same reason as the previous call. Is that surprising? After all, you passed 4000 for the argument named size, then “obviously” that False value was meant for the a_kilobyte_is_1024_bytes argument. But Python doesn’t work that way. As soon as you have a named argument, all arguments to the right of that need to be named arguments, too.

Writing Readable Code

I won’t bore you with a long finger-wagging speech about the importance of documenting your code. Just know that code is written once but read many times, and the most important audience for your code is yourself, six months after writing it (i.e. after you’ve forgotten everything but need to fix something). Python makes it easy to write readable code, so take advantage of it. You’ll thank me in six months.

Documentation Strings

You can document a Python function by giving it a documentation string (docstring for short). In this program, the approximate_size() function has a docstring:

def approximate_size(size, a_kilobyte_is_1024_bytes=True):
    '''Convert a file size to human-readable form.

    Keyword arguments:
    size -- file size in bytes
    a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
                                if False, use multiples of 1000

    Returns: string

    '''

Triple quotes signify a multi-line string. Everything between the start and end quotes is part of a single string, including carriage returns, leading white space, and other quote characters. You can use them anywhere, but you’ll see them most often used when defining a docstring.

Triple quotes are also an easy way to define a string with both single and double quotes, like qq/.../ in Perl 5.

Everything between the triple quotes is the function’s docstring, which documents what the function does. A docstring, if it exists, must be the first thing defined in a function (that is, on the next line after the function declaration). You don’t technically need to give your function a docstring, but you always should. I know you’ve heard this in every programming class you’ve ever taken, but Python gives you an added incentive: the docstring is available at runtime as an attribute of the function.

Many Python IDEs use the docstring to provide context-sensitive documentation, so that when you type a function name, its docstring appears as a tooltip. This can be incredibly helpful, but it’s only as good as the docstrings you write.

The import Search Path

Before this goes any further, I want to briefly mention the library search path. Python looks in several places when you try to import a module. Specifically, it looks in all the directories defined in sys.path. This is just a list, and you can easily view it or modify it with standard list methods. (You’ll learn more about lists in Native Datatypes.)

>>> import sys                                                 
>>> sys.path                                                   
['', 
 '/usr/lib/python31.zip', 
 '/usr/lib/python3.1',
 '/usr/lib/python3.1/plat-linux2@EXTRAMACHDEPPATH@', 
 '/usr/lib/python3.1/lib-dynload', 
 '/usr/lib/python3.1/dist-packages', 
 '/usr/local/lib/python3.1/dist-packages']
>>> sys                                                        
<module 'sys' (built-in)>
>>> sys.path.insert(0, '/home/mark/diveintopython3/examples')  
>>> sys.path                                                   
['/home/mark/diveintopython3/examples', 
 '', 
 '/usr/lib/python31.zip', 
 '/usr/lib/python3.1', 
 '/usr/lib/python3.1/plat-linux2@EXTRAMACHDEPPATH@', 
 '/usr/lib/python3.1/lib-dynload', 
 '/usr/lib/python3.1/dist-packages', 
 '/usr/local/lib/python3.1/dist-packages']
  1. Importing the sys module makes all of its functions and attributes available.
  2. sys.path is a list of directory names that constitute the current search path. (Yours will look different, depending on your operating system, what version of Python you’re running, and where it was originally installed.) Python will look through these directories (in this order) for a .py file whose name matches what you’re trying to import.
  3. Actually, I lied; the truth is more complicated than that, because not all modules are stored as .py files. Some are built-in modules; they are actually baked right into Python itself. Built-in modules behave just like regular modules, but their Python source code is not available, because they are not written in Python! (Like Python itself, these built-in modules are written in C.)
  4. You can add a new directory to Python’s search path at runtime by adding the directory name to sys.path, and then Python will look in that directory as well, whenever you try to import a module. The effect lasts as long as Python is running.
  5. By using sys.path.insert(0, new_path), you inserted a new directory as the first item of the sys.path list, and therefore at the beginning of Python’s search path. This is almost always what you want. In case of naming conflicts (for example, if Python ships with version 2 of a particular library but you want to use version 3), this ensures that your modules will be found and used instead of the modules that came with Python.

Everything Is An Object

In case you missed it, I just said that Python functions have attributes, and that those attributes are available at runtime. A function, like everything else in Python, is an object.

Run the interactive Python shell and follow along:

>>> import humansize                               
>>> print(humansize.approximate_size(4096, True))  
4.0 KiB
>>> print(humansize.approximate_size.__doc__)      
Convert a file size to human-readable form.

    Keyword arguments:
    size -- file size in bytes
    a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
                                if False, use multiples of 1000

    Returns: string

  1. The first line imports the humansize program as a module — a chunk of code that you can use interactively, or from a larger Python program. Once you import a module, you can reference any of its public functions, classes, or attributes. Modules can do this to access functionality in other modules, and you can do it in the Python interactive shell too. This is an important concept, and you’ll see a lot more of it throughout this book.
  2. When you want to use functions defined in imported modules, you need to include the module name. So you can’t just say approximate_size; it must be humansize.approximate_size. If you’ve used classes in Java, this should feel vaguely familiar.
  3. Instead of calling the function as you would expect to, you asked for one of the function’s attributes, __doc__.

import in Python is like require in Perl. Once you import a Python module, you access its functions with module.function; once you require a Perl module, you access its functions with module::function.

What’s An Object?

Everything in Python is an object, and everything can have attributes and methods. All functions have a built-in attribute __doc__, which returns the docstring defined in the function’s source code. The sys module is an object which has (among other things) an attribute called path. And so forth.

Still, this doesn’t answer the more fundamental question: what is an object? Different programming languages define “object” in different ways. In some, it means that all objects must have attributes and methods; in others, it means that all objects are subclassable. In Python, the definition is looser. Some objects have neither attributes nor methods, but they could. Not all objects are subclassable. But everything is an object in the sense that it can be assigned to a variable or passed as an argument to a function.

You may have heard the term “first-class object” in other programming contexts. In Python, functions are first-class objects. You can pass a function as an argument to another function. Modules are first-class objects. You can pass an entire module as an argument to a function. Classes are first-class objects, and individual instances of a class are also first-class objects.

This is important, so I’m going to repeat it in case you missed it the first few times: everything in Python is an object. Strings are objects. Lists are objects. Functions are objects. Classes are objects. Class instances are objects. Even modules are objects.

Indenting Code

Python functions have no explicit begin or end, and no curly braces to mark where the function code starts and stops. The only delimiter is a colon (:) and the indentation of the code itself.

def approximate_size(size, a_kilobyte_is_1024_bytes=True):  
    if size < 0:                                            
        raise ValueError('number must be non-negative')     
                                                            
    multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
    for suffix in SUFFIXES[multiple]:                       
        size /= multiple
        if size < multiple:
            return '{0:.1f} {1}'.format(size, suffix)

    raise ValueError('number too large')
  1. Code blocks are defined by their indentation. By “code block,” I mean functions, if statements, for loops, while loops, and so forth. Indenting starts a block and unindenting ends it. There are no explicit braces, brackets, or keywords. This means that whitespace is significant, and must be consistent. In this example, the function code is indented four spaces. It doesn’t need to be four spaces, it just needs to be consistent. The first line that is not indented marks the end of the function.
  2. In Python, an if statement is followed by a code block. If the if expression evaluates to true, the indented block is executed, otherwise it falls to the else block (if any). Note the lack of parentheses around the expression.
  3. This line is inside the if code block. This raise statement will raise an exception (of type ValueError), but only if size < 0.
  4. This is not the end of the function. Completely blank lines don’t count. They can make the code more readable, but they don’t count as code block delimiters. The function continues on the next line.
  5. The for loop also marks the start of a code block. Code blocks can contain multiple lines, as long as they are all indented the same amount. This for loop has three lines of code in it. There is no other special syntax for multi-line code blocks. Just indent and get on with your life.

After some initial protests and several snide analogies to Fortran, you will make peace with this and start seeing its benefits. One major benefit is that all Python programs look similar, since indentation is a language requirement and not a matter of style. This makes it easier to read and understand other people’s Python code.

Python uses carriage returns to separate statements and a colon and indentation to separate code blocks. C++ and Java use semicolons to separate statements and curly braces to separate code blocks.

Exceptions

Exceptions are everywhere in Python. Virtually every module in the standard Python library uses them, and Python itself will raise them in a lot of different circumstances. You’ll see them repeatedly throughout this book.

What is an exception? Usually it’s an error, an indication that something went wrong. (Not all exceptions are errors, but never mind that for now.) Some programming languages encourage the use of error return codes, which you check. Python encourages the use of exceptions, which you handle.

When an error occurs in the Python Shell, it prints out some details about the exception and how it happened, and that’s that. This is called an unhandled exception. When the exception was raised, there was no code to explicitly notice it and deal with it, so it bubbled its way back up to the top level of the Python Shell, which spits out some debugging information and calls it a day. In the shell, that's no big deal, but if that happened while your actual Python program was running, the entire program would come to a screeching halt if nothing handles the exception. Maybe that’s what you want, maybe it isn’t.

Unlike Java, Python functions don’t declare which exceptions they might raise. It’s up to you to determine what possible exceptions you need to catch.

An exception doesn’t need to result in a complete program crash, though. Exceptions can be handled. Sometimes an exception is really because you have a bug in your code (like accessing a variable that doesn’t exist), but sometimes an exception is something you can anticipate. If you’re opening a file, it might not exist. If you’re importing a module, it might not be installed. If you’re connecting to a database, it might be unavailable, or you might not have the correct security credentials to access it. If you know a line of code may raise an exception, you should handle the exception using a try...except block.

Python uses try...except blocks to handle exceptions, and the raise statement to generate them. Java and C++ use try...catch blocks to handle exceptions, and the throw statement to generate them.

The approximate_size() function raises exceptions in two different cases: if the given size is larger than the function is designed to handle, or if it’s less than zero.

if size < 0:
    raise ValueError('number must be non-negative')

The syntax for raising an exception is simple enough. Use the raise statement, followed by the exception name, and an optional human-readable string for debugging purposes. The syntax is reminiscent of calling a function. (In reality, exceptions are implemented as classes, and this raise statement is actually creating an instance of the ValueError class and passing the string 'number must be non-negative' to its initialization method. But we’re getting ahead of ourselves!)

You don’t need to handle an exception in the function that raises it. If one function doesn’t handle it, the exception is passed to the calling function, then that function’s calling function, and so on “up the stack.” If the exception is never handled, your program will crash, Python will print a “traceback” to standard error, and that’s the end of that. Again, maybe that’s what you want; it depends on what your program does.

Catching Import Errors

One of Python’s built-in exceptions is ImportError, which is raised when you try to import a module and fail. This can happen for a variety of reasons, but the simplest case is when the module doesn’t exist in your import search path. You can use this to include optional features in your program. For example, the chardet library provides character encoding auto-detection. Perhaps your program wants to use this library if it exists, but continue gracefully if the user hasn’t installed it. You can do this with a try..except block.

try:
  import chardet
except ImportError:
  chardet = None

Later, you can check for the presence of the chardet module with a simple if statement:

if chardet:
  # do something
else:
  # continue anyway

Another common use of the ImportError exception is when two modules implement a common API, but one is more desirable than the other. (Maybe it’s faster, or it uses less memory.) You can try to import one module but fall back to a different module if the first import fails. For example, the XML chapter talks about two modules that implement a common API, called the ElementTree API. The first, lxml, is a third-party module that you need to download and install yourself. The second, xml.etree.ElementTree, is slower but is part of the Python 3 standard library.

try:
    from lxml import etree
except ImportError:
    import xml.etree.ElementTree as etree

By the end of this try..except block, you have imported some module and named it etree. Since both modules implement a common API, the rest of your code doesn’t need to keep checking which module got imported. And since the module that did get imported is always called etree, the rest of your code doesn’t need to be littered with if statements to call differently-named modules.

Unbound Variables

Take another look at this line of code from the approximate_size() function:

multiple = 1024 if a_kilobyte_is_1024_bytes else 1000

You never declare the variable multiple, you just assign a value to it. That’s OK, because Python lets you do that. What Python will not let you do is reference a variable that has never been assigned a value. Trying to do so will raise a NameError exception.

>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> x = 1
>>> x
1

You will thank Python for this one day.

Everything is Case-Sensitive

All names in Python are case-sensitive: variable names, function names, class names, module names, exception names. If you can get it, set it, call it, construct it, import it, or raise it, it’s case-sensitive.

>>> an_integer = 1
>>> an_integer
1
>>> AN_INTEGER
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'AN_INTEGER' is not defined
>>> An_Integer
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'An_Integer' is not defined
>>> an_inteGer
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'an_inteGer' is not defined

And so on.

Running Scripts

Python modules are objects and have several useful attributes. You can use this to easily test your modules as you write them, by including a special block of code that executes when you run the Python file on the command line. Take the last few lines of humansize.py:


if __name__ == '__main__':
    print(approximate_size(1000000000000, False))
    print(approximate_size(1000000000000))

Like C, Python uses == for comparison and = for assignment. Unlike C, Python does not support in-line assignment, so there’s no chance of accidentally assigning the value you thought you were comparing.

So what makes this if statement special? Well, modules are objects, and all modules have a built-in attribute __name__. A module’s __name__ depends on how you’re using the module. If you import the module, then __name__ is the module’s filename, without a directory path or file extension.

>>> import humansize
>>> humansize.__name__
'humansize'

But you can also run the module directly as a standalone program, in which case __name__ will be a special default value, __main__. Python will evaluate this if statement, find a true expression, and execute the if code block. In this case, to print two values.

c:\home\diveintopython3> c:\python31\python.exe humansize.py
1.0 TB
931.3 GiB

And that’s your first Python program!

Further Reading

© 2001–11 Mark Pilgrim diveintopython3-20110517-77958af.orig/colophon.html0000644000000000000000000001221311773544727020316 0ustar rootroot Colophon - Dive Into Python 3

  

You are here: Home Dive Into Python 3

Colophon

Je n’ai fait celle-ci plus longue que parce que je n’ai pas eu le loisir de la faire plus courte.
(I would have written a shorter letter, but I did not have the time.)
Blaise Pascal

 

Diving In

This book, like all books, was a labor of love. Oh sure, I got paid the medium-sized bucks for it, but nobody writes technical books for the money. And since this book is available on the web as well as on paper, I spent a lot of time fiddling with webby stuff when I should have been writing.

[typewriter]

The online edition loads as efficiently as possible. Efficiency never happens by accident; I spent many hours making it so. Perhaps too many hours. Yes, almost certainly too many hours. Never underestimate the depths to which a procrastinating writer will sink.

I won’t bore you with all the details. Wait, yes — I will bore you with all the details. But here’s the short version.

  1. HTML is minimized, then served compressed.
  2. Scripts and stylesheets are minimized by YUI Compressor (and also served compressed).
  3. Scripts are combined to reduce HTTP requests.
  4. Stylesheets are combined and inlined to reduce HTTP requests.
  5. Unused CSS selectors and properties are removed on a page-by-page basis with a little help from pyquery.
  6. HTTP caching and other server-side options are optimized based on advice from YSlow and Page Speed.
  7. Pages use Unicode characters in place of images wherever possible.
  8. Images are optimized with OptiPNG.
  9. The entire book was lovingly hand-authored in HTML 5 to avoid markup cruft.

Typography

vertical rhythm, best available ampersand, curly quotes/apostrophes, other stuff from webtypography.net

Graphics

Unicode, callouts, font-family issues on Windows

Performance

"Dive Into History 2009 edition", minimizing CSS + JS + HTML, inline CSS, optimizing images

Fun stuff

Quotes, constrained writing(?), PapayaWhip

Further Reading

© 2001–11 Mark Pilgrim diveintopython3-20110517-77958af.orig/j/0000755000000000000000000000000011773544727016041 5ustar rootrootdiveintopython3-20110517-77958af.orig/j/dip3.js0000644000000000000000000002175011773544727017243 0ustar rootroot/* The following three functions are taken from http://code.google.com/p/javascript-search-term-highlighter/ Copyright 2004 Dave Lemen Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ function parseTerms(query) { var s = query + ''; s = s.replace(/(^|\s)(site|related|link|info|cache):[^\s]*(\s|$)/ig, ' '); s = s.replace(/[^a-z0-9_\-]/ig, ' '); // word chars only. s = s.replace(/(^|\s)-/g, ' '); // +required -excluded ~synonyms s = s.replace(/\b(and|not|or)\b/ig, ' '); s = s.replace(/\b[a-z0-9]\b/ig, ' '); // one char terms return s.split(/\s+/); } function getParamValues(url, parameters) { var params = []; var p = parameters.replace(/,/, ' ').split(/\s+/); if (url.indexOf('?') > 0) { var qs = url.substr(url.indexOf('?') + 1); var qsa = qs.split('&'); for (i = 0; i < qsa.length; i++) { nameValue = qsa[i].split('='); if (nameValue.length != 2) { continue; } for (j = 0; j < p.length; j++) { if (nameValue[0] == p[j]) { params.push(unescape(nameValue[1]).toLowerCase().replace(/\+/g, ' ')); } } } } return params; } function getSearchTerms() { var highlighterParameters = 'q as_q as_epq as_oq query search'; var a = []; var params = getParamValues(document.referrer/*document.location.href*/, highlighterParameters); var terms; for (i = 0; i < params.length; i++) { terms = parseTerms(params[i]); for (j = 0; j < terms.length; j++) { if (terms[j] !== '') { a.push(terms[j].toLowerCase()); } } } return a; } /* The rest of this script is Copyright (c) 2009, Mark Pilgrim, 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. 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. */ var HS = {'visible': 'hide', 'hidden': 'show'}; function hideTOC() { var toc = ' show table of contents'; $("#toc").html(toc); } function showTOC() { var toc = ''; var old_level = 1; var level; $('h2,h3').each(function(i, h) { level = parseInt(h.tagName.substring(1), 10); if (level < old_level) { toc += ''; } else if (level > old_level) { toc += '

    '; } toc += '
  1. ' + h.innerHTML + ''; old_level = level; }); while (level > 1) { toc += '
'; level -= 1; } toc = ' hide table of contents
  1. Full table of contents
  2. ' + toc.substring(4); $("#toc").html(toc); } $(document).ready(function() { hideTOC(); prettyPrint(); /* on-hover permalink markers on each section header */ $('*:header[id]').each(function() { $('#'). attr('href', '#' + this.id). appendTo(this); }); /* "hide", "open in new window", and (optionally) "download" widgets on code & screen blocks */ $("pre > code").each(function(i) { var pre = $(this.parentNode); if (pre.parents("table").length === 0) { pre.addClass("code"); } }); $("pre.code:not(.nd), pre.screen:not(.nd)").each(function(i) { /* give each code block a unique ID */ this.id = "autopre" + i; /* wrap code block in a div and insert widget block */ $(this).wrapInner('
    '); var widgetHTML = '
    [' + HS.visible + '] [open in new window]'; if ($(this).hasClass('cmdline')) { widgetHTML += ' [command line help]'; } widgetHTML += '
    '; $(this).prepend(widgetHTML); /* move download link into widget block */ $(this).prev("p.d").each(function(i) { $(this).next("pre").find("div.w").append(" " + $(this).html()); this.parentNode.removeChild(this); }); /* create skip links */ var postelm = $(this).next().get(0); var postid = postelm.id || ("postautopre" + i); postelm.id = postid; $(this).before('

    skip over this code listing'); }); $("pre.screen.cmdline:not(.nd)").each(function(i) { /* add link to command-line help */ this.id = "autopre" + i; }); /* make skip links disappear until you tab to them */ $(".skip a").blur(function() { $(this).css({'position':'absolute','left':'0px','top':'-500px','width':'1px','height':'1px','overflow':'hidden'}); }); $(".skip a").blur(); $(".skip a").focus(function() { $(this).css({'position':'static','width':'auto','height':'auto'}); }); if (!$.browser.msie) { /* synchronized highlighting on callouts and their associated lines within code & screen blocks */ var hip = {'background-color':'#eee','cursor':'default'}; var unhip = {'background-color':'inherit','cursor':'inherit'}; $("pre.code, pre.screen").each(function() { var _this = $(this); window.setTimeout(function() { var s = ''; var ol = _this.next("ol"); var refs = _this.find("a:not([href])"); refs.each(function(i) { var li = ol.find("li:nth-child(" + (i+1) + ")"); s += "&#x" + (parseInt('2460', 16) + i).toString(16) + ";" + li.html() + ""; }); ol.replaceWith("" + s + "
    "); refs.each(function(i) { var a = $(this); var li = a.parents("pre").next("table").find("tr:nth-child(" + (i+1) + ") td:nth-child(2)"); li.add(a).hover(function() { a.css(hip); li.css(hip); }, function() { a.css(unhip); li.css(unhip); }); }); }, 0); }); /* synchronized highlighting on callouts and their associated table rows */ $("table").each(function() { $(this).find("tr:gt(0)").each(function(i) { var tr = $(this); window.setTimeout(function() { var li = tr.parents("table").next("ol").find("li:nth-child(" + (i+1) + ")"); if (li.length > 0) { li.add(tr).hover(function() { tr.css(hip); li.css(hip); }, function() { tr.css(unhip); li.css(unhip); }); } }, 0); }); }); } /* match terms with incoming search keywords and jump to the containing section */ var searchTerms = getSearchTerms(); $("dfn").each(function() { var dfn = $(this); var dfnTerm = dfn.text().toLowerCase(); if ($.inArray(dfnTerm, searchTerms) != -1) { var section = dfn.parents("p,table,ul,ol,blockquote").prevAll("*:header").get(0); if (section) { window.setTimeout(function() {document.location.hash = section.id;}, 0); return false; } } }); }); /* document.ready */ function toggleCodeBlock(id) { $("#" + id).find("div.b").toggle(); var a = $("#" + id).find("a.toggle"); a.text(a.text() == HS.visible ? HS.hidden : HS.visible); } function plainTextOnClick(id) { var clone = $("#" + id).clone(); clone.find("div.w, span.u").remove(); var win = window.open("about:blank", "plaintext", "toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0,resizable=1,width=600,height=400,left=35,top=75"); win.document.open(); win.document.write('

    ' + clone.html());
        win.document.close();
    }
    diveintopython3-20110517-77958af.orig/j/prettify.js0000644000000000000000000015345311773544727020260 0ustar  rootroot// Copyright (C) 2006 Google Inc.
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //      http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    
    /**
     * @fileoverview
     * some functions for browser-side pretty printing of code contained in html.
     *
     * The lexer should work on a number of languages including C and friends,
     * Java, Python, Bash, SQL, HTML, XML, CSS, Javascript, and Makefiles.
     * It works passably on Ruby, PHP and Awk and a decent subset of Perl, but,
     * because of commenting conventions, doesn't work on Smalltalk, Lisp-like, or
     * CAML-like languages.
     *
     * If there's a language not mentioned here, then I don't know it, and don't
     * know whether it works.  If it has a C-like, Bash-like, or XML-like syntax
     * then it should work passably.
     *
     * Usage:
     * 1) include this source file in an html page via
     * 
     * 2) define style rules.  See the example page for examples.
     * 3) mark the 
     and  tags in your source with class=pp.
     *    You can also use the (html deprecated)  tag, but the pretty printer
     *    needs to do more substantial DOM manipulations to support that, so some
     *    css styles may not be preserved.
     * That's it.  I wanted to keep the API as simple as possible, so there's no
     * need to specify which language the code is in.
     *
     * Change log:
     * cbeust, 2006/08/22
     *   Java annotations (start with "@") are now captured as literals ("lit")
     */
    
    // JSLint declarations
    /*global console, document, navigator, setTimeout, window */
    
    /**
     * Split {@code prettyPrint} into multiple timeouts so as not to interfere with
     * UI events.
     * If set to {@code false}, {@code prettyPrint()} is synchronous.
     */
    window['PR_SHOULD_USE_CONTINUATION'] = true;
    
    /** the number of characters between tab columns */
    window['PR_TAB_WIDTH'] = 8;
    
    /** Walks the DOM returning a properly escaped version of innerHTML.
      * @param {Node} node
      * @param {Array.<string>} out output buffer that receives chunks of HTML.
      */
    window['PR_normalizedHtml']
    
    /** Contains functions for creating and registering new language handlers.
      * @type {Object}
      */
      = window['PR']
    
    /** Pretty print a chunk of code.
      *
      * @param {string} sourceCodeHtml code as html
      * @return {string} code as html, but prettier
      */
      = window['prettyPrintOne']
    /** Find all the {@code <pre>} and {@code <code>} tags in the DOM with
      * {@code class=pp} and prettify them.
      * @param {Function?} opt_whenDone if specified, called when the last entry
      *     has been finished.
      */
      = window['prettyPrint'] = void 0;
    
    /** browser detection. @extern */
    window['_pr_isIE6'] = function () {
      var isIE6 = navigator && navigator.userAgent &&
          /\bMSIE 6\./.test(navigator.userAgent);
      window['_pr_isIE6'] = function () { return isIE6; };
      return isIE6;
    };
    
    
    (function () {
      // Keyword lists for various languages.
      var FLOW_CONTROL_KEYWORDS =
          "break continue do else for if return while ";
      var C_KEYWORDS = FLOW_CONTROL_KEYWORDS + "auto case char const default " +
          "double enum extern float goto int long register short signed sizeof " +
          "static struct switch typedef union unsigned void volatile ";
      var COMMON_KEYWORDS = C_KEYWORDS + "catch class delete false import " +
          "new operator private protected public this throw true try ";
      var CPP_KEYWORDS = COMMON_KEYWORDS + "alignof align_union asm axiom bool " +
          "concept concept_map const_cast constexpr decltype " +
          "dynamic_cast explicit export friend inline late_check " +
          "mutable namespace nullptr reinterpret_cast static_assert static_cast " +
          "template typeid typename typeof using virtual wchar_t where ";
      var JAVA_KEYWORDS = COMMON_KEYWORDS +
          "boolean byte extends final finally implements import instanceof null " +
          "native package strictfp super synchronized throws transient ";
      var CSHARP_KEYWORDS = JAVA_KEYWORDS +
          "as base by checked decimal delegate descending event " +
          "fixed foreach from group implicit in interface internal into is lock " +
          "object out override orderby params partial readonly ref sbyte sealed " +
          "stackalloc string select uint ulong unchecked unsafe ushort var ";
      var JSCRIPT_KEYWORDS = COMMON_KEYWORDS +
          "debugger eval export function get null set undefined var with " +
          "Infinity NaN ";
      var PERL_KEYWORDS = "caller delete die do dump elsif eval exit foreach for " +
          "goto if import last local my next no our print package redo require " +
          "sub undef unless until use wantarray while BEGIN END ";
      var PYTHON_KEYWORDS = FLOW_CONTROL_KEYWORDS + "and as assert class def del " +
          "elif except exec finally from global import in is lambda " +
          "nonlocal not or pass print raise try with yield " +
          "False True None ";
      var RUBY_KEYWORDS = FLOW_CONTROL_KEYWORDS + "alias and begin case class def" +
          " defined elsif end ensure false in module next nil not or redo rescue " +
          "retry self super then true undef unless until when yield BEGIN END ";
      var SH_KEYWORDS = FLOW_CONTROL_KEYWORDS + "case done elif esac eval fi " +
          "function in local set then until ";
      var ALL_KEYWORDS = (
          CPP_KEYWORDS + CSHARP_KEYWORDS + JSCRIPT_KEYWORDS + PERL_KEYWORDS +
          PYTHON_KEYWORDS + RUBY_KEYWORDS + SH_KEYWORDS);
    
      // token style names.  correspond to css classes
      /** token style for a string literal */
      var PR_STRING = 'str';
      /** token style for a keyword */
      var PR_KEYWORD = 'kwd';
      /** token style for a comment */
      var PR_COMMENT = 'com';
      /** token style for a type */
      var PR_TYPE = 'typ';
      /** token style for a literal value.  e.g. 1, null, true. */
      var PR_LITERAL = 'lit';
      /** token style for a punctuation string. */
      var PR_PUNCTUATION = 'pun';
      /** token style for a punctuation string. */
      var PR_PLAIN = 'pln';
    
      /** token style for an sgml tag. */
      var PR_TAG = 'tag';
      /** token style for a markup declaration such as a DOCTYPE. */
      var PR_DECLARATION = 'dec';
      /** token style for embedded source. */
      var PR_SOURCE = 'src';
      /** token style for an sgml attribute name. */
      var PR_ATTRIB_NAME = 'atn';
      /** token style for an sgml attribute value. */
      var PR_ATTRIB_VALUE = 'atv';
    
      /**
       * A class that indicates a section of markup that is not code, e.g. to allow
       * embedding of line numbers within code listings.
       */
      var PR_NOCODE = 'nocode';
    
      /** A set of tokens that can precede a regular expression literal in
        * javascript.
        * http://www.mozilla.org/js/language/js20/rationale/syntax.html has the full
        * list, but I've removed ones that might be problematic when seen in
        * languages that don't support regular expression literals.
        *
        * <p>Specifically, I've removed any keywords that can't precede a regexp
        * literal in a syntactically legal javascript program, and I've removed the
        * "in" keyword since it's not a keyword in many languages, and might be used
        * as a count of inches.
        *
        * <p>The link a above does not accurately describe EcmaScript rules since
        * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works
        * very well in practice.
        *
        * @private
        */
      var REGEXP_PRECEDER_PATTERN = function () {
          var preceders = [
              "!", "!=", "!==", "#", "%", "%=", "&", "&&", "&&=",
              "&=", "(", "*", "*=", /* "+", */ "+=", ",", /* "-", */ "-=",
              "->", /*".", "..", "...", handled below */ "/", "/=", ":", "::", ";",
              "<", "<<", "<<=", "<=", "=", "==", "===", ">",
              ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[",
              "^", "^=", "^^", "^^=", "{", "|", "|=", "||",
              "||=", "~" /* handles =~ and !~ */,
              "break", "case", "continue", "delete",
              "do", "else", "finally", "instanceof",
              "return", "throw", "try", "typeof"
              ];
          var pattern = '(?:^^|[+-]';
          for (var i = 0; i < preceders.length; ++i) {
            pattern += '|' + preceders[i].replace(/([^=<>:&a-z])/g, '\\$1');
          }
          pattern += ')\\s*';  // matches at end, and matches empty string
          return pattern;
          // CAVEAT: this does not properly handle the case where a regular
          // expression immediately follows another since a regular expression may
          // have flags for case-sensitivity and the like.  Having regexp tokens
          // adjacent is not valid in any language I'm aware of, so I'm punting.
          // TODO: maybe style special characters inside a regexp as punctuation.
        }();
    
      // Define regexps here so that the interpreter doesn't have to create an
      // object each time the function containing them is called.
      // The language spec requires a new object created even if you don't access
      // the $1 members.
      var pr_amp = /&/g;
      var pr_lt = /</g;
      var pr_gt = />/g;
      var pr_quot = /\"/g;
      /** like textToHtml but escapes double quotes to be attribute safe. */
      function attribToHtml(str) {
        return str.replace(pr_amp, '&amp;')
            .replace(pr_lt, '&lt;')
            .replace(pr_gt, '&gt;')
            .replace(pr_quot, '&quot;');
      }
    
      /** escapest html special characters to html. */
      function textToHtml(str) {
        return str.replace(pr_amp, '&amp;')
            .replace(pr_lt, '&lt;')
            .replace(pr_gt, '&gt;');
      }
    
    
      var pr_ltEnt = /&lt;/g;
      var pr_gtEnt = /&gt;/g;
      var pr_aposEnt = /&apos;/g;
      var pr_quotEnt = /&quot;/g;
      var pr_ampEnt = /&amp;/g;
      var pr_nbspEnt = /&nbsp;/g;
      /** unescapes html to plain text. */
      function htmlToText(html) {
        var pos = html.indexOf('&');
        if (pos < 0) { return html; }
        // Handle numeric entities specially.  We can't use functional substitution
        // since that doesn't work in older versions of Safari.
        // These should be rare since most browsers convert them to normal chars.
        for (--pos; (pos = html.indexOf('&#', pos + 1)) >= 0;) {
          var end = html.indexOf(';', pos);
          if (end >= 0) {
            var num = html.substring(pos + 3, end);
            var radix = 10;
            if (num && num.charAt(0) === 'x') {
              num = num.substring(1);
              radix = 16;
            }
            var codePoint = parseInt(num, radix);
            if (!isNaN(codePoint)) {
              html = (html.substring(0, pos) + String.fromCharCode(codePoint) +
                      html.substring(end + 1));
            }
          }
        }
    
        return html.replace(pr_ltEnt, '<')
            .replace(pr_gtEnt, '>')
            .replace(pr_aposEnt, "'")
            .replace(pr_quotEnt, '"')
            .replace(pr_ampEnt, '&')
            .replace(pr_nbspEnt, ' ');
      }
    
      /** is the given node's innerHTML normally unescaped? */
      function isRawContent(node) {
        return 'XMP' === node.tagName;
      }
    
      function normalizedHtml(node, out) {
        switch (node.nodeType) {
          case 1:  // an element
            var name = node.tagName.toLowerCase();
            out.push('<', name);
            for (var i = 0; i < node.attributes.length; ++i) {
              var attr = node.attributes[i];
              if (!attr.specified) { continue; }
              out.push(' ');
              normalizedHtml(attr, out);
            }
            out.push('>');
            for (var child = node.firstChild; child; child = child.nextSibling) {
              normalizedHtml(child, out);
            }
            if (node.firstChild || !/^(?:br|link|img)$/.test(name)) {
              out.push('<\/', name, '>');
            }
            break;
          case 2: // an attribute
            out.push(node.name.toLowerCase(), '="', attribToHtml(node.value), '"');
            break;
          case 3: case 4: // text
            out.push(textToHtml(node.nodeValue));
            break;
        }
      }
    
      /**
       * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally
       * matches the union o the sets o strings matched d by the input RegExp.
       * Since it matches globally, if the input strings have a start-of-input
       * anchor (/^.../), it is ignored for the purposes of unioning.
       * @param {Array.<RegExpr>} regexs non multiline, non-global regexs.
       * @return {RegExp} a global regex.
       */
      function combinePrefixPatterns(regexs) {
        var capturedGroupIndex = 0;
    
        var needToFoldCase = false;
        var ignoreCase = false;
        for (var i = 0, n = regexs.length; i < n; ++i) {
          var regex = regexs[i];
          if (regex.ignoreCase) {
            ignoreCase = true;
          } else if (/[a-z]/i.test(regex.source.replace(
                         /\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, ''))) {
            needToFoldCase = true;
            ignoreCase = false;
            break;
          }
        }
    
        function decodeEscape(charsetPart) {
          if (charsetPart.charAt(0) !== '\\') { return charsetPart.charCodeAt(0); }
          switch (charsetPart.charAt(1)) {
            case 'b': return 8;
            case 't': return 9;
            case 'n': return 0xa;
            case 'v': return 0xb;
            case 'f': return 0xc;
            case 'r': return 0xd;
            case 'u': case 'x':
              return parseInt(charsetPart.substring(2), 16)
                  || charsetPart.charCodeAt(1);
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7':
              return parseInt(charsetPart.substring(1), 8);
            default: return charsetPart.charCodeAt(1);
          }
        }
    
        function encodeEscape(charCode) {
          if (charCode < 0x20) {
            return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16);
          }
          var ch = String.fromCharCode(charCode);
          if (ch === '\\' || ch === '-' || ch === '[' || ch === ']') {
            ch = '\\' + ch;
          }
          return ch;
        }
    
        function caseFoldCharset(charSet) {
          var charsetParts = charSet.substring(1, charSet.length - 1).match(
              new RegExp(
                  '\\\\u[0-9A-Fa-f]{4}'
                  + '|\\\\x[0-9A-Fa-f]{2}'
                  + '|\\\\[0-3][0-7]{0,2}'
                  + '|\\\\[0-7]{1,2}'
                  + '|\\\\[\\s\\S]'
                  + '|-'
                  + '|[^-\\\\]',
                  'g'));
          var groups = [];
          var ranges = [];
          var inverse = charsetParts[0] === '^';
          for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {
            var p = charsetParts[i];
            switch (p) {
              case '\\B': case '\\b':
              case '\\D': case '\\d':
              case '\\S': case '\\s':
              case '\\W': case '\\w':
                groups.push(p);
                continue;
            }
            var start = decodeEscape(p);
            var end;
            if (i + 2 < n && '-' === charsetParts[i + 1]) {
              end = decodeEscape(charsetParts[i + 2]);
              i += 2;
            } else {
              end = start;
            }
            ranges.push([start, end]);
            // If the range might intersect letters, then expand it.
            if (!(end < 65 || start > 122)) {
              if (!(end < 65 || start > 90)) {
                ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);
              }
              if (!(end < 97 || start > 122)) {
                ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);
              }
            }
          }
    
          // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]
          // -> [[1, 12], [14, 14], [16, 17]]
          ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1]  - a[1]); });
          var consolidatedRanges = [];
          var lastRange = [NaN, NaN];
          for (var i = 0; i < ranges.length; ++i) {
            var range = ranges[i];
            if (range[0] <= lastRange[1] + 1) {
              lastRange[1] = Math.max(lastRange[1], range[1]);
            } else {
              consolidatedRanges.push(lastRange = range);
            }
          }
    
          var out = ['['];
          if (inverse) { out.push('^'); }
          out.push.apply(out, groups);
          for (var i = 0; i < consolidatedRanges.length; ++i) {
            var range = consolidatedRanges[i];
            out.push(encodeEscape(range[0]));
            if (range[1] > range[0]) {
              if (range[1] + 1 > range[0]) { out.push('-'); }
              out.push(encodeEscape(range[1]));
            }
          }
          out.push(']');
          return out.join('');
        }
    
        function allowAnywhereFoldCaseAndRenumberGroups(regex) {
          // Split into character sets, escape sequences, punctuation strings
          // like ('(', '(?:', ')', '^'), and runs of characters that do not
          // include any of the above.
          var parts = regex.source.match(
              new RegExp(
                  '(?:'
                  + '\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]'  // a character set
                  + '|\\\\u[A-Fa-f0-9]{4}'  // a unicode escape
                  + '|\\\\x[A-Fa-f0-9]{2}'  // a hex escape
                  + '|\\\\[0-9]+'  // a back-reference or octal escape
                  + '|\\\\[^ux0-9]'  // other escape sequence
                  + '|\\(\\?[:!=]'  // start of a non-capturing group
                  + '|[\\(\\)\\^]'  // start/emd of a group, or line start
                  + '|[^\\x5B\\x5C\\(\\)\\^]+'  // run of other characters
                  + ')',
                  'g'));
          var n = parts.length;
    
          // Maps captured group numbers to the number they will occupy in
          // the output or to -1 if that has not been determined, or to
          // undefined if they need not be capturing in the output.
          var capturedGroups = [];
    
          // Walk over and identify back references to build the capturedGroups
          // mapping.
          var groupIndex;
          for (var i = 0, groupIndex = 0; i < n; ++i) {
            var p = parts[i];
            if (p === '(') {
              // groups are 1-indexed, so max group index is count of '('
              ++groupIndex;
            } else if ('\\' === p.charAt(0)) {
              var decimalValue = +p.substring(1);
              if (decimalValue && decimalValue <= groupIndex) {
                capturedGroups[decimalValue] = -1;
              }
            }
          }
    
          // Renumber groups and reduce capturing groups to non-capturing groups
          // where possible.
          for (var i = 1; i < capturedGroups.length; ++i) {
            if (-1 === capturedGroups[i]) {
              capturedGroups[i] = ++capturedGroupIndex;
            }
          }
          for (var i = 0, groupIndex = 0; i < n; ++i) {
            var p = parts[i];
            if (p === '(') {
              ++groupIndex;
              if (capturedGroups[groupIndex] === undefined) {
                parts[i] = '(?:';
              }
            } else if ('\\' === p.charAt(0)) {
              var decimalValue = +p.substring(1);
              if (decimalValue && decimalValue <= groupIndex) {
                parts[i] = '\\' + capturedGroups[groupIndex];
              }
            }
          }
    
          // Remove any prefix anchors so that the output will match anywhere.
          // ^^ really does mean an anchored match though.
          for (var i = 0, groupIndex = 0; i < n; ++i) {
            if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }
          }
    
          // Expand letters to groupts to handle mixing of case-sensitive and
          // case-insensitive patterns if necessary.
          if (regex.ignoreCase && needToFoldCase) {
            for (var i = 0; i < n; ++i) {
              var p = parts[i];
              var ch0 = p.charAt(0);
              if (p.length >= 2 && ch0 === '[') {
                parts[i] = caseFoldCharset(p);
              } else if (ch0 !== '\\') {
                // TODO: handle letters in numeric escapes.
                parts[i] = p.replace(
                    /[a-zA-Z]/g,
                    function (ch) {
                      var cc = ch.charCodeAt(0);
                      return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';
                    });
              }
            }
          }
    
          return parts.join('');
        }
    
        var rewritten = [];
        for (var i = 0, n = regexs.length; i < n; ++i) {
          var regex = regexs[i];
          if (regex.global || regex.multiline) { throw new Error('' + regex); }
          rewritten.push(
              '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');
        }
    
        return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');
      }
    
      var PR_innerHtmlWorks = null;
      function getInnerHtml(node) {
        // inner html is hopelessly broken in Safari 2.0.4 when the content is
        // an html description of well formed XML and the containing tag is a PRE
        // tag, so we detect that case and emulate innerHTML.
        if (null === PR_innerHtmlWorks) {
          var testNode = document.createElement('PRE');
          testNode.appendChild(
              document.createTextNode('<!DOCTYPE foo PUBLIC "foo bar">\n<foo />'));
          PR_innerHtmlWorks = !/</.test(testNode.innerHTML);
        }
    
        if (PR_innerHtmlWorks) {
          var content = node.innerHTML;
          // XMP tags contain unescaped entities so require special handling.
          if (isRawContent(node)) {
            content = textToHtml(content);
          }
          return content;
        }
    
        var out = [];
        for (var child = node.firstChild; child; child = child.nextSibling) {
          normalizedHtml(child, out);
        }
        return out.join('');
      }
    
      /** returns a function that expand tabs to spaces.  This function can be fed
        * successive chunks of text, and will maintain its own internal state to
        * keep track of how tabs are expanded.
        * @return {function (string) : string} a function that takes
        *   plain text and return the text with tabs expanded.
        * @private
        */
      function makeTabExpander(tabWidth) {
        var SPACES = '                ';
        var charInLine = 0;
    
        return function (plainText) {
          // walk over each character looking for tabs and newlines.
          // On tabs, expand them.  On newlines, reset charInLine.
          // Otherwise increment charInLine
          var out = null;
          var pos = 0;
          for (var i = 0, n = plainText.length; i < n; ++i) {
            var ch = plainText.charAt(i);
    
            switch (ch) {
              case '\t':
                if (!out) { out = []; }
                out.push(plainText.substring(pos, i));
                // calculate how much space we need in front of this part
                // nSpaces is the amount of padding -- the number of spaces needed
                // to move us to the next column, where columns occur at factors of
                // tabWidth.
                var nSpaces = tabWidth - (charInLine % tabWidth);
                charInLine += nSpaces;
                for (; nSpaces >= 0; nSpaces -= SPACES.length) {
                  out.push(SPACES.substring(0, nSpaces));
                }
                pos = i + 1;
                break;
              case '\n':
                charInLine = 0;
                break;
              default:
                ++charInLine;
            }
          }
          if (!out) { return plainText; }
          out.push(plainText.substring(pos));
          return out.join('');
        };
      }
    
      var pr_chunkPattern = new RegExp(
          '[^<]+'  // A run of characters other than '<'
          + '|<\!--[\\s\\S]*?--\>'  // an HTML comment
          + '|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>'  // a CDATA section
          // a probable tag that should not be highlighted
          + '|<\/?[a-zA-Z](?:[^>\"\']|\'[^\']*\'|\"[^\"]*\")*>'
          + '|<',  // A '<' that does not begin a larger chunk
          'g');
      var pr_commentPrefix = /^<\!--/;
      var pr_cdataPrefix = /^<!\[CDATA\[/;
      var pr_brPrefix = /^<br\b/i;
      var pr_tagNameRe = /^<(\/?)([a-zA-Z][a-zA-Z0-9]*)/;
    
      /** split markup into chunks of html tags (style null) and
        * plain text (style {@link #PR_PLAIN}), converting tags which are
        * significant for tokenization (<br>) into their textual equivalent.
        *
        * @param {string} s html where whitespace is considered significant.
        * @return {Object} source code and extracted tags.
        * @private
        */
      function extractTags(s) {
        // since the pattern has the 'g' modifier and defines no capturing groups,
        // this will return a list of all chunks which we then classify and wrap as
        // PR_Tokens
        var matches = s.match(pr_chunkPattern);
        var sourceBuf = [];
        var sourceBufLen = 0;
        var extractedTags = [];
        if (matches) {
          for (var i = 0, n = matches.length; i < n; ++i) {
            var match = matches[i];
            if (match.length > 1 && match.charAt(0) === '<') {
              if (pr_commentPrefix.test(match)) { continue; }
              if (pr_cdataPrefix.test(match)) {
                // strip CDATA prefix and suffix.  Don't unescape since it's CDATA
                sourceBuf.push(match.substring(9, match.length - 3));
                sourceBufLen += match.length - 12;
              } else if (pr_brPrefix.test(match)) {
                // <br> tags are lexically significant so convert them to text.
                // This is undone later.
                sourceBuf.push('\n');
                ++sourceBufLen;
              } else {
                if (match.indexOf(PR_NOCODE) >= 0 && isNoCodeTag(match)) {
                  // A <span class="nocode"> will start a section that should be
                  // ignored.  Continue walking the list until we see a matching end
                  // tag.
                  var name = match.match(pr_tagNameRe)[2];
                  var depth = 1;
                  var j;
                  end_tag_loop:
                  for (j = i + 1; j < n; ++j) {
                    var name2 = matches[j].match(pr_tagNameRe);
                    if (name2 && name2[2] === name) {
                      if (name2[1] === '/') {
                        if (--depth === 0) { break end_tag_loop; }
                      } else {
                        ++depth;
                      }
                    }
                  }
                  if (j < n) {
                    extractedTags.push(
                        sourceBufLen, matches.slice(i, j + 1).join(''));
                    i = j;
                  } else {  // Ignore unclosed sections.
                    extractedTags.push(sourceBufLen, match);
                  }
                } else {
                  extractedTags.push(sourceBufLen, match);
                }
              }
            } else {
              var literalText = htmlToText(match);
              sourceBuf.push(literalText);
              sourceBufLen += literalText.length;
            }
          }
        }
        return { source: sourceBuf.join(''), tags: extractedTags };
      }
    
      /** True if the given tag contains a class attribute with the nocode class. */
      function isNoCodeTag(tag) {
        return !!tag
            // First canonicalize the representation of attributes
            .replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,
                     ' $1="$2$3$4"')
            // Then look for the attribute we want.
            .match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/);
      }
    
      /**
       * Apply the given language handler to sourceCode and add the resulting
       * decorations to out.
       * @param {number} basePos the index of sourceCode within the chunk of source
       *    whose decorations are already present on out.
       */
      function appendDecorations(basePos, sourceCode, langHandler, out) {
        if (!sourceCode) { return; }
        var job = {
          source: sourceCode,
          basePos: basePos
        };
        langHandler(job);
        out.push.apply(out, job.decorations);
      }
    
      /** Given triples of [style, pattern, context] returns a lexing function,
        * The lexing function interprets the patterns to find token boundaries and
        * returns a decoration list of the form
        * [index_0, style_0, index_1, style_1, ..., index_n, style_n]
        * where index_n is an index into the sourceCode, and style_n is a style
        * constant like PR_PLAIN.  index_n-1 <= index_n, and style_n-1 applies to
        * all characters in sourceCode[index_n-1:index_n].
        *
        * The stylePatterns is a list whose elements have the form
        * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].
        *
        * Style is a style constant like PR_PLAIN, or can be a string of the
        * form 'lang-FOO', where FOO is a language extension describing the
        * language of the portion of the token in $1 after pattern executes.
        * E.g., if style is 'lang-lisp', and group 1 contains the text
        * '(hello (world))', then that portion of the token will be passed to the
        * registered lisp handler for formatting.
        * The text before and after group 1 will be restyled using this decorator
        * so decorators should take care that this doesn't result in infinite
        * recursion.  For example, the HTML lexer rule for SCRIPT elements looks
        * something like ['lang-js', /<[s]cript>(.+?)<\/script>/].  This may match
        * '<script>foo()<\/script>', which would cause the current decorator to
        * be called with '<script>' which would not match the same rule since
        * group 1 must not be empty, so it would be instead styled as PR_TAG by
        * the generic tag rule.  The handler registered for the 'js' extension would
        * then be called with 'foo()', and finally, the current decorator would
        * be called with '<\/script>' which would not match the original rule and
        * so the generic tag rule would identify it as a tag.
        *
        * Pattern must only match prefixes, and if it matches a prefix, then that
        * match is considered a token with the same style.
        *
        * Context is applied to the last non-whitespace, non-comment token
        * recognized.
        *
        * Shortcut is an optional string of characters, any of which, if the first
        * character, gurantee that this pattern and only this pattern matches.
        *
        * @param {Array} shortcutStylePatterns patterns that always start with
        *   a known character.  Must have a shortcut string.
        * @param {Array} fallthroughStylePatterns patterns that will be tried in
        *   order if the shortcut ones fail.  May have shortcuts.
        *
        * @return {function (Object)} a
        *   function that takes source code and returns a list of decorations.
        */
      function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {
        var shortcuts = {};
        var tokenizer;
        (function () {
          var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);
          var allRegexs = [];
          var regexKeys = {};
          for (var i = 0, n = allPatterns.length; i < n; ++i) {
            var patternParts = allPatterns[i];
            var shortcutChars = patternParts[3];
            if (shortcutChars) {
              for (var c = shortcutChars.length; --c >= 0;) {
                shortcuts[shortcutChars.charAt(c)] = patternParts;
              }
            }
            var regex = patternParts[1];
            var k = '' + regex;
            if (!regexKeys.hasOwnProperty(k)) {
              allRegexs.push(regex);
              regexKeys[k] = null;
            }
          }
          allRegexs.push(/[\0-\uffff]/);
          tokenizer = combinePrefixPatterns(allRegexs);
        })();
    
        var nPatterns = fallthroughStylePatterns.length;
        var notWs = /\S/;
    
        /**
         * Lexes job.source and produces an output array job.decorations of style
         * classes preceded by the position at which they start in job.source in
         * order.
         *
         * @param {Object} job an object like {@code
         *    source: {string} sourceText plain text,
         *    basePos: {int} position of job.source in the larger chunk of
         *        sourceCode.
         * }
         */
        var decorate = function (job) {
          var sourceCode = job.source, basePos = job.basePos;
          /** Even entries are positions in source in ascending order.  Odd enties
            * are style markers (e.g., PR_COMMENT) that run from that position until
            * the end.
            * @type {Array.<number|string>}
            */
          var decorations = [basePos, PR_PLAIN];
          var pos = 0;  // index into sourceCode
          var tokens = sourceCode.match(tokenizer) || [];
          var styleCache = {};
    
          for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {
            var token = tokens[ti];
            var style = styleCache[token];
            var match;
    
            var isEmbedded;
            if (typeof style === 'string') {
              isEmbedded = false;
            } else {
              var patternParts = shortcuts[token.charAt(0)];
              if (patternParts) {
                match = token.match(patternParts[1]);
                style = patternParts[0];
              } else {
                for (var i = 0; i < nPatterns; ++i) {
                  patternParts = fallthroughStylePatterns[i];
                  match = token.match(patternParts[1]);
                  if (match) {
                    style = patternParts[0];
                    break;
                  }
                }
    
                if (!match) {  // make sure that we make progress
                  style = PR_PLAIN;
                }
              }
    
              isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5);
              if (isEmbedded && !(match && match[1])) {
                isEmbedded = false;
                style = PR_SOURCE;
              }
    
              if (!isEmbedded) { styleCache[token] = style; }
            }
    
            var tokenStart = pos;
            pos += token.length;
    
            if (!isEmbedded) {
              decorations.push(basePos + tokenStart, style);
            } else {  // Treat group 1 as an embedded block of source code.
              var embeddedSource = match[1];
              var embeddedSourceStart = token.indexOf(embeddedSource);
              var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;
              var lang = style.substring(5);
              var size = decorations.length - 10;
              // Decorate the left of the embedded source
              appendDecorations(
                  basePos + tokenStart,
                  token.substring(0, embeddedSourceStart),
                  decorate, decorations);
              // Decorate the embedded source
              appendDecorations(
                  basePos + tokenStart + embeddedSourceStart,
                  embeddedSource,
                  langHandlerForExtension(lang, embeddedSource),
                  decorations);
              // Decorate the right of the embedded section
              appendDecorations(
                  basePos + tokenStart + embeddedSourceEnd,
                  token.substring(embeddedSourceEnd),
                  decorate, decorations);
            }
          }
          job.decorations = decorations;
        };
        return decorate;
      }
    
      /** returns a function that produces a list of decorations from source text.
        *
        * This code treats ", ', and ` as string delimiters, and \ as a string
        * escape.  It does not recognize perl's qq() style strings.
        * It has no special handling for double delimiter escapes as in basic, or
        * the tripled delimiters used in python, but should work on those regardless
        * although in those cases a single string literal may be broken up into
        * multiple adjacent string literals.
        *
        * It recognizes C, C++, and shell style comments.
        *
        * @param {Object} options a set of optional parameters.
        * @return {function (Object)} a function that examines the source code
        *     in the input job and builds the decoration list.
        */
      function sourceDecorator(options) {
        var shortcutStylePatterns = [], fallthroughStylePatterns = [];
        if (options['tripleQuotedStrings']) {
          // '''multi-line-string''', 'single-line-string', and double-quoted
          shortcutStylePatterns.push(
              [PR_STRING,  /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
               null, '\'"']);
        } else if (options['multiLineStrings']) {
          // 'multi-line-string', "multi-line-string"
          shortcutStylePatterns.push(
              [PR_STRING,  /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,
               null, '\'"`']);
        } else {
          // 'single-line-string', "single-line-string"
          shortcutStylePatterns.push(
              [PR_STRING,
               /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,
               null, '"\'']);
        }
        if (options['hashComments']) {
          if (options['cStyleComments']) {
            // Stop C preprocessor declarations at an unclosed open comment
            shortcutStylePatterns.push(
                [PR_COMMENT, /^#(?:[^\r\n\/]|\/(?!\*)|\/\*[^\r\n]*?\*\/)*/,
                 null, '#']);
          } else {
            shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']);
          }
        }
        if (options['cStyleComments']) {
          fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]);
          fallthroughStylePatterns.push(
              [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]);
        }
        if (options['regexLiterals']) {
          var REGEX_LITERAL = (
              // A regular expression literal starts with a slash that is
              // not followed by * or / so that it is not confused with
              // comments.
              '/(?=[^/*])'
              // and then contains any number of raw characters,
              + '(?:[^/\\x5B\\x5C]'
              // escape sequences (\x5C),
              +    '|\\x5C[\\s\\S]'
              // or non-nesting character sets (\x5B\x5D);
              +    '|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+'
              // finally closed by a /.
              + '/');
          fallthroughStylePatterns.push(
              ['lang-regex',
               new RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')')
               ]);
        }
    
        var keywords = options['keywords'].replace(/^\s+|\s+$/g, '');
        if (keywords.length) {
          fallthroughStylePatterns.push(
              [PR_KEYWORD,
               new RegExp('^(?:' + keywords.replace(/\s+/g, '|') + ')\\b'), null]);
        }
    
        shortcutStylePatterns.push([PR_PLAIN,       /^\s+/, null, ' \r\n\t\xA0']);
        fallthroughStylePatterns.push(
            // TODO(mikesamuel): recognize non-latin letters and numerals in idents
            [PR_LITERAL,     /^@[a-z_$][a-z_$@0-9]*/i, null, '@'],
            [PR_TYPE,        /^@?[A-Z]+[a-z][A-Za-z_$@0-9]*/, null],
            [PR_PLAIN,       /^[a-z_$][a-z_$@0-9]*/i, null],
            [PR_LITERAL,
             new RegExp(
                 '^(?:'
                 // A hex number
                 + '0x[a-f0-9]+'
                 // or an octal or decimal number,
                 + '|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)'
                 // possibly in scientific notation
                 + '(?:e[+\\-]?\\d+)?'
                 + ')'
                 // with an optional modifier like UL for unsigned long
                 + '[a-z]*', 'i'),
             null, '0123456789'],
            [PR_PUNCTUATION, /^.[^\s\w\.$@\'\"\`\/\#]*/, null]);
    
        return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);
      }
    
      var decorateSource = sourceDecorator({
            'keywords': ALL_KEYWORDS,
            'hashComments': true,
            'cStyleComments': true,
            'multiLineStrings': true,
            'regexLiterals': true
          });
    
      /** Breaks {@code job.source} around style boundaries in
        * {@code job.decorations} while re-interleaving {@code job.extractedTags},
        * and leaves the result in {@code job.prettyPrintedHtml}.
        * @param {Object} job like {
        *    source: {string} source as plain text,
        *    extractedTags: {Array.<number|string>} extractedTags chunks of raw
        *                   html preceded by their position in {@code job.source}
        *                   in order
        *    decorations: {Array.<number|string} an array of style classes preceded
        *                 by the position at which they start in job.source in order
        * }
        * @private
        */
      function recombineTagsAndDecorations(job) {
        var sourceText = job.source;
        var extractedTags = job.extractedTags;
        var decorations = job.decorations;
    
        var html = [];
        // index past the last char in sourceText written to html
        var outputIdx = 0;
    
        var openDecoration = null;
        var currentDecoration = null;
        var tagPos = 0;  // index into extractedTags
        var decPos = 0;  // index into decorations
        var tabExpander = makeTabExpander(window['PR_TAB_WIDTH']);
    
        var adjacentSpaceRe = /([\r\n ]) /g;
        var startOrSpaceRe = /(^| ) /gm;
        var newlineRe = /\r\n?|\n/g;
        var trailingSpaceRe = /[ \r\n]$/;
        var lastWasSpace = true;  // the last text chunk emitted ended with a space.
    
        // A helper function that is responsible for opening sections of decoration
        // and outputing properly escaped chunks of source
        function emitTextUpTo(sourceIdx) {
          if (sourceIdx > outputIdx) {
            if (openDecoration && openDecoration !== currentDecoration) {
              // Close the current decoration
              html.push('</span>');
              openDecoration = null;
            }
            if (!openDecoration && currentDecoration) {
              openDecoration = currentDecoration;
              html.push('<span class="', openDecoration, '">');
            }
            // This interacts badly with some wikis which introduces paragraph tags
            // into pre blocks for some strange reason.
            // It's necessary for IE though which seems to lose the preformattedness
            // of <pre> tags when their innerHTML is assigned.
            // http://stud3.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
            // and it serves to undo the conversion of <br>s to newlines done in
            // chunkify.
            var htmlChunk = textToHtml(
                tabExpander(sourceText.substring(outputIdx, sourceIdx)))
                .replace(lastWasSpace
                         ? startOrSpaceRe
                         : adjacentSpaceRe, '$1&nbsp;');
            // Keep track of whether we need to escape space at the beginning of the
            // next chunk.
            lastWasSpace = trailingSpaceRe.test(htmlChunk);
            // IE collapses multiple adjacient <br>s into 1 line break.
            // Prefix every <br> with '&nbsp;' can prevent such IE's behavior.
            var lineBreakHtml = window['_pr_isIE6']() ? '&nbsp;<br />' : '<br />';
            html.push(htmlChunk.replace(newlineRe, lineBreakHtml));
            outputIdx = sourceIdx;
          }
        }
    
        while (true) {
          // Determine if we're going to consume a tag this time around.  Otherwise
          // we consume a decoration or exit.
          var outputTag;
          if (tagPos < extractedTags.length) {
            if (decPos < decorations.length) {
              // Pick one giving preference to extractedTags since we shouldn't open
              // a new style that we're going to have to immediately close in order
              // to output a tag.
              outputTag = extractedTags[tagPos] <= decorations[decPos];
            } else {
              outputTag = true;
            }
          } else {
            outputTag = false;
          }
          // Consume either a decoration or a tag or exit.
          if (outputTag) {
            emitTextUpTo(extractedTags[tagPos]);
            if (openDecoration) {
              // Close the current decoration
              html.push('</span>');
              openDecoration = null;
            }
            html.push(extractedTags[tagPos + 1]);
            tagPos += 2;
          } else if (decPos < decorations.length) {
            emitTextUpTo(decorations[decPos]);
            currentDecoration = decorations[decPos + 1];
            decPos += 2;
          } else {
            break;
          }
        }
        emitTextUpTo(sourceText.length);
        if (openDecoration) {
          html.push('</span>');
        }
        job.prettyPrintedHtml = html.join('');
      }
    
      /** Maps language-specific file extensions to handlers. */
      var langHandlerRegistry = {};
      /** Register a language handler for the given file extensions.
        * @param {function (Object)} handler a function from source code to a list
        *      of decorations.  Takes a single argument job which describes the
        *      state of the computation.   The single parameter has the form
        *      {@code {
        *        source: {string} as plain text.
        *        decorations: {Array.<number|string>} an array of style classes
        *                     preceded by the position at which they start in
        *                     job.source in order.
        *                     The language handler should assigned this field.
        *        basePos: {int} the position of source in the larger source chunk.
        *                 All positions in the output decorations array are relative
        *                 to the larger source chunk.
        *      } }
        * @param {Array.<string>} fileExtensions
        */
      function registerLangHandler(handler, fileExtensions) {
        for (var i = fileExtensions.length; --i >= 0;) {
          var ext = fileExtensions[i];
          if (!langHandlerRegistry.hasOwnProperty(ext)) {
            langHandlerRegistry[ext] = handler;
          } else if ('console' in window) {
            console.warn('cannot override language handler %s', ext);
          }
        }
      }
      function langHandlerForExtension(extension, source) {
        if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {
          // Treat it as markup if the first non whitespace character is a < and
          // the last non-whitespace character is a >.
          extension = /^\s*</.test(source)
              ? 'default-markup'
              : 'default-code';
        }
        return langHandlerRegistry[extension];
      }
      registerLangHandler(decorateSource, ['default-code']);
      registerLangHandler(
          createSimpleLexer(
              [],
              [
               [PR_PLAIN,       /^[^<?]+/],
               [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/],
               [PR_COMMENT,     /^<\!--[\s\S]*?(?:-\->|$)/],
               // Unescaped content in an unknown language
               ['lang-',        /^<\?([\s\S]+?)(?:\?>|$)/],
               ['lang-',        /^<%([\s\S]+?)(?:%>|$)/],
               [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],
               ['lang-',        /^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],
               // Unescaped content in javascript.  (Or possibly vbscript).
               ['lang-js',      /^<script\b[^>]*>([\s\S]+?)<\/script\b[^>]*>/i],
               // Contains unescaped stylesheet content
               ['lang-css',     /^<style\b[^>]*>([\s\S]+?)<\/style\b[^>]*>/i],
               ['lang-in.tag',  /^(<\/?[a-z][^<>]*>)/i]
              ]),
          ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']);
      registerLangHandler(
          createSimpleLexer(
              [
               [PR_PLAIN,        /^[\s]+/, null, ' \t\r\n'],
               [PR_ATTRIB_VALUE, /^(?:\"[^\"]*\"?|\'[^\']*\'?)/, null, '\"\'']
               ],
              [
               [PR_TAG,          /^^<\/?[a-z](?:[\w:-]*\w)?|\/?>$/],
               [PR_ATTRIB_NAME,  /^(?!style\b|on)[a-z](?:[\w:-]*\w)?/],
               ['lang-uq.val',   /^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],
               [PR_PUNCTUATION,  /^[=<>\/]+/],
               ['lang-js',       /^on\w+\s*=\s*\"([^\"]+)\"/i],
               ['lang-js',       /^on\w+\s*=\s*\'([^\']+)\'/i],
               ['lang-js',       /^on\w+\s*=\s*([^\"\'>\s]+)/i],
               ['lang-css',      /^sty\w+\s*=\s*\"([^\"]+)\"/i],
               ['lang-css',      /^sty\w+\s*=\s*\'([^\']+)\'/i],
               ['lang-css',      /^sty\w+\s*=\s*([^\"\'>\s]+)/i]
               ]),
          ['in.tag']);
      registerLangHandler(
          createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\s\S]+/]]), ['uq.val']);
      registerLangHandler(sourceDecorator({
              'keywords': CPP_KEYWORDS,
              'hashComments': true,
              'cStyleComments': true
            }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']);
      registerLangHandler(sourceDecorator({
              'keywords': 'null true false'
            }), ['json']);
      registerLangHandler(sourceDecorator({
              'keywords': CSHARP_KEYWORDS,
              'hashComments': true,
              'cStyleComments': true
            }), ['cs']);
      registerLangHandler(sourceDecorator({
              'keywords': JAVA_KEYWORDS,
              'cStyleComments': true
            }), ['java']);
      registerLangHandler(sourceDecorator({
              'keywords': SH_KEYWORDS,
              'hashComments': true,
              'multiLineStrings': true
            }), ['bsh', 'csh', 'sh']);
      registerLangHandler(sourceDecorator({
              'keywords': PYTHON_KEYWORDS,
              'hashComments': true,
              'multiLineStrings': true,
              'tripleQuotedStrings': true
            }), ['cv', 'py']);
      registerLangHandler(sourceDecorator({
              'keywords': PERL_KEYWORDS,
              'hashComments': true,
              'multiLineStrings': true,
              'regexLiterals': true
            }), ['perl', 'pl', 'pm']);
      registerLangHandler(sourceDecorator({
              'keywords': RUBY_KEYWORDS,
              'hashComments': true,
              'multiLineStrings': true,
              'regexLiterals': true
            }), ['rb']);
      registerLangHandler(sourceDecorator({
              'keywords': JSCRIPT_KEYWORDS,
              'cStyleComments': true,
              'regexLiterals': true
            }), ['js']);
      registerLangHandler(
          createSimpleLexer([], [[PR_STRING, /^[\s\S]+/]]), ['regex']);
    
      function applyDecorator(job) {
        var sourceCodeHtml = job.sourceCodeHtml;
        var opt_langExtension = job.langExtension;
    
        // Prepopulate output in case processing fails with an exception.
        job.prettyPrintedHtml = sourceCodeHtml;
    
        try {
          // Extract tags, and convert the source code to plain text.
          var sourceAndExtractedTags = extractTags(sourceCodeHtml);
          /** Plain text. @type {string} */
          var source = sourceAndExtractedTags.source;
          job.source = source;
          job.basePos = 0;
    
          /** Even entries are positions in source in ascending order.  Odd entries
            * are tags that were extracted at that position.
            * @type {Array.<number|string>}
            */
          job.extractedTags = sourceAndExtractedTags.tags;
    
          // Apply the appropriate language handler
          langHandlerForExtension(opt_langExtension, source)(job);
          // Integrate the decorations and tags back into the source code to produce
          // a decorated html string which is left in job.prettyPrintedHtml.
          recombineTagsAndDecorations(job);
        } catch (e) {
          if ('console' in window) {
            console.log(e);
            console.trace();
          }
        }
      }
    
      function prettyPrintOne(sourceCodeHtml, opt_langExtension) {
        var job = {
          sourceCodeHtml: sourceCodeHtml,
          langExtension: opt_langExtension
        };
        applyDecorator(job);
        return job.prettyPrintedHtml;
      }
    
      function prettyPrint(opt_whenDone) {
        var isIE6 = window['_pr_isIE6']();
    
        // fetch a list of nodes to rewrite
        var codeSegments = [
            document.getElementsByTagName('pre'),
            document.getElementsByTagName('code'),
    	document.getElementsByTagName('kbd'),
    	document.getElementsByTagName('samp'),
            document.getElementsByTagName('xmp') ];
        var elements = [];
        for (var i = 0; i < codeSegments.length; ++i) {
          for (var j = 0, n = codeSegments[i].length; j < n; ++j) {
            elements.push(codeSegments[i][j]);
          }
        }
        codeSegments = null;
    
        var clock = Date;
        if (!clock['now']) {
          clock = { 'now': function () { return (new Date).getTime(); } };
        }
    
        // The loop is broken into a series of continuations to make sure that we
        // don't make the browser unresponsive when rewriting a large page.
        var k = 0;
        var prettyPrintingJob;
    
        function doWork() {
          var endTime = (window['PR_SHOULD_USE_CONTINUATION'] ?
                         clock.now() + 250 /* ms */ :
                         Infinity);
          for (; k < elements.length && clock.now() < endTime; k++) {
            var cs = elements[k];
            if (cs.className && cs.className.indexOf('pp') >= 0) {
              // If the classes includes a language extensions, use it.
              // Language extensions can be specified like
              //     <pre class="pp lang-cpp">
              // the language extension "cpp" is used to find a language handler as
              // passed to PR_registerLangHandler.
              var langExtension = cs.className.match(/\blang-(\w+)\b/);
              if (langExtension) { langExtension = langExtension[1]; }
    
              // make sure this is not nested in an already prettified element
              var nested = false;
              for (var p = cs.parentNode; p; p = p.parentNode) {
                if ((p.tagName === 'pre' || p.tagName === 'code' ||
                     p.tagName === 'kbd' || p.tagName === 'samp' ||
    		 p.tagName === 'xmp') &&
                    p.className && p.className.indexOf('pp') >= 0) {
                  nested = true;
                  break;
                }
              }
              if (!nested) {
                // fetch the content as a snippet of properly escaped HTML.
                // Firefox adds newlines at the end.
                var content = getInnerHtml(cs);
                content = content.replace(/(?:\r\n?|\n)$/, '');
    
                // do the pretty printing
                prettyPrintingJob = {
                  sourceCodeHtml: content,
                  langExtension: langExtension,
                  sourceNode: cs
                };
                applyDecorator(prettyPrintingJob);
                replaceWithPrettyPrintedHtml();
              }
            }
          }
          if (k < elements.length) {
            // finish up in a continuation
            setTimeout(doWork, 250);
          } else if (opt_whenDone) {
            opt_whenDone();
          }
        }
    
        function replaceWithPrettyPrintedHtml() {
          var newContent = prettyPrintingJob.prettyPrintedHtml;
          if (!newContent) { return; }
          var cs = prettyPrintingJob.sourceNode;
    
          // push the prettified html back into the tag.
          if (!isRawContent(cs)) {
            // just replace the old html with the new
            cs.innerHTML = newContent;
          } else {
            // we need to change the tag to a <pre> since <xmp>s do not allow
            // embedded tags such as the span tags used to attach styles to
            // sections of source code.
            var pre = document.createElement('PRE');
            for (var i = 0; i < cs.attributes.length; ++i) {
              var a = cs.attributes[i];
              if (a.specified) {
                var aname = a.name.toLowerCase();
                if (aname === 'class') {
                  pre.className = a.value;  // For IE 6
                } else {
                  pre.setAttribute(a.name, a.value);
                }
              }
            }
            pre.innerHTML = newContent;
    
            // remove the old
            cs.parentNode.replaceChild(pre, cs);
            cs = pre;
          }
    
          // Replace <br>s with line-feeds so that copying and pasting works
          // on IE 6.
          // Doing this on other browsers breaks lots of stuff since \r\n is
          // treated as two newlines on Firefox, and doing this also slows
          // down rendering.
          if (isIE6 && cs.tagName === 'PRE') {
            var lineBreaks = cs.getElementsByTagName('br');
            for (var j = lineBreaks.length; --j >= 0;) {
              var lineBreak = lineBreaks[j];
              lineBreak.parentNode.replaceChild(
                  document.createTextNode('\r'), lineBreak);
            }
          }
        }
    
        doWork();
      }
    
      window['PR_normalizedHtml'] = normalizedHtml;
      window['prettyPrintOne'] = prettyPrintOne;
      window['prettyPrint'] = prettyPrint;
      window['PR'] = {
            'combinePrefixPatterns': combinePrefixPatterns,
            'createSimpleLexer': createSimpleLexer,
            'registerLangHandler': registerLangHandler,
            'sourceDecorator': sourceDecorator,
            'PR_ATTRIB_NAME': PR_ATTRIB_NAME,
            'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,
            'PR_COMMENT': PR_COMMENT,
            'PR_DECLARATION': PR_DECLARATION,
            'PR_KEYWORD': PR_KEYWORD,
            'PR_LITERAL': PR_LITERAL,
            'PR_NOCODE': PR_NOCODE,
            'PR_PLAIN': PR_PLAIN,
            'PR_PUNCTUATION': PR_PUNCTUATION,
            'PR_SOURCE': PR_SOURCE,
            'PR_STRING': PR_STRING,
            'PR_TAG': PR_TAG,
            'PR_TYPE': PR_TYPE
          };
    })();
    ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/j/html5.js����������������������������������������������������0000644�0000000�0000000�00000002551�11773544727�017433� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*@cc_on@if(@_jscript_version<9)(function(p,e){function q(a,b){if(g[a])g[a].styleSheet.cssText+=b;else{var c=r[l],d=e[j]("style");d.media=a;c.insertBefore(d,c[l]);g[a]=d;q(a,b)}}function s(a,b){for(var c=new RegExp("\\b("+m+")\\b(?!.*[;}])","gi"),d=function(k){return".iepp_"+k},h=-1;++h<a.length;){b=a[h].media||b;s(a[h].imports,b);q(b,a[h].cssText.replace(c,d))}}function t(){for(var a,b=e.getElementsByTagName("*"),c,d,h=new RegExp("^"+m+"$","i"),k=-1;++k<b.length;)if((a=b[k])&&(d=a.nodeName.match(h))){c=new RegExp("^\\s*<"+d+"(.*)\\/"+
    d+">\\s*$","i");i.innerHTML=a.outerHTML.replace(/\r|\n/g," ").replace(c,a.currentStyle.display=="block"?"<div$1/div>":"<span$1/span>");c=i.childNodes[0];c.className+=" iepp_"+d;c=f[f.length]=[a,c];a.parentNode.replaceChild(c[1],c[0])}s(e.styleSheets,"all")}function u(){for(var a=-1,b;++a<f.length;)f[a][1].parentNode.replaceChild(f[a][0],f[a][1]);for(b in g)r[l].removeChild(g[b]);g={};f=[]}for(var m="abbr article aside audio canvas command datalist details figure figcaption footer header hgroup mark meter nav output progress section summary time video".replace(/ /g,
    "|"),n=m.split("|"),r=e.documentElement,i=e.createDocumentFragment(),g={},f=[],o=-1,l="firstChild",j="createElement";++o<n.length;){e[j](n[o]);i[j](n[o])}i=i.appendChild(e[j]("div"));p.attachEvent("onbeforeprint",t);p.attachEvent("onafterprint",u)})(this,document)@end@*/�������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/packaging.html������������������������������������������������0000644�0000000�0000000�00000113415�11773544727�020427� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE html>
    <meta charset=utf-8>
    <title>Packaging Python Libraries - Dive Into Python 3</title>
    <!--[if IE]><script src=j/html5.js></script><![endif]-->
    <link rel=stylesheet href=dip3.css>
    <style>
    body{counter-reset:h1 16}
    mark{display:inline}
    </style>
    <link rel=stylesheet media='only screen and (max-device-width: 480px)' href=mobile.css>
    <link rel=stylesheet media=print href=print.css>
    <meta name=viewport content='initial-scale=1.0'>
    <form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:l5eihuescdw><input type=hidden name=ie value=UTF-8>&nbsp;<input type=search name=q size=25 placeholder="powered by Google&trade;">&nbsp;<input type=submit name=root value=Search></div></form>
    <p>You are here: <a href=index.html>Home</a> <span class=u>&#8227;</span> <a href=table-of-contents.html#packaging>Dive Into Python 3</a> <span class=u>&#8227;</span>
    <p id=level>Difficulty level: <span class=u title=advanced>&#x2666;&#x2666;&#x2666;&#x2666;&#x2662;</span>
    <h1>Packaging Python Libraries</h1>
    <blockquote class=q>
    <p><span class=u>&#x275D;</span> You&#8217;ll find the shame is like the pain; you only feel it once. <span class=u>&#x275E;</span><br>&mdash; Marquise de Merteuil, <a href=http://www.imdb.com/title/tt0094947/quotes><cite>Dangerous Liaisons</cite></a>
    </blockquote>
    <p id=toc>&nbsp;
    <h2 id=divingin>Diving In</h2>
    <p class=f>Real artists ship. Or so says Steve Jobs. Do you want to release a Python script, library, framework, or application? Excellent. The world needs more Python code. Python 3 comes with a packaging framework called Distutils. Distutils is many things: a build tool (for you), an installation tool (for your users), a package metadata format (for search engines), and more. It integrates with the <a href=http://pypi.python.org/>Python Package Index</a> (&#8220;PyPI&#8221;), a central repository for open source Python libraries.
    
    <p>All of these facets of Distutils center around the <i>setup script</i>, traditionally called <code>setup.py</code>. In fact, you&#8217;ve already seen several Distutils setup scripts in this book. You used Distutils to install <code>httplib2</code> in <a href=http-web-services.html#introducing-httplib2>HTTP Web Services</a> and again to install <code>chardet</code> in <a href=case-study-porting-chardet-to-python-3.html>Case Study: Porting <code>chardet</code> to Python 3</a>.
    
    <p>In this chapter, you&#8217;ll learn how the setup scripts for <code>chardet</code> and <code>httplib2</code> work, and you&#8217;ll step through the process of releasing your own Python software.
    
    <pre class=pp><code># chardet's setup.py
    from distutils.core import setup
    setup(
        name = "chardet",
        packages = ["chardet"],
        version = "1.0.2",
        description = "Universal encoding detector",
        author = "Mark Pilgrim",
        author_email = "mark@diveintomark.org",
        url = "http://chardet.feedparser.org/",
        download_url = "http://chardet.feedparser.org/download/python3-chardet-1.0.1.tgz",
        keywords = ["encoding", "i18n", "xml"],
        classifiers = [
            "Programming Language :: Python",
            "Programming Language :: Python :: 3",
            "Development Status :: 4 - Beta",
            "Environment :: Other Environment",
            "Intended Audience :: Developers",
            "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
            "Operating System :: OS Independent",
            "Topic :: Software Development :: Libraries :: Python Modules",
            "Topic :: Text Processing :: Linguistic",
            ],
        long_description = """\
    Universal character encoding detector
    -------------------------------------
    
    Detects
     - ASCII, UTF-8, UTF-16 (2 variants), UTF-32 (4 variants)
     - Big5, GB2312, EUC-TW, HZ-GB-2312, ISO-2022-CN (Traditional and Simplified Chinese)
     - EUC-JP, SHIFT_JIS, ISO-2022-JP (Japanese)
     - EUC-KR, ISO-2022-KR (Korean)
     - KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251 (Cyrillic)
     - ISO-8859-2, windows-1250 (Hungarian)
     - ISO-8859-5, windows-1251 (Bulgarian)
     - windows-1252 (English)
     - ISO-8859-7, windows-1253 (Greek)
     - ISO-8859-8, windows-1255 (Visual and Logical Hebrew)
     - TIS-620 (Thai)
    
    This version requires Python 3 or later; a Python 2 version is available separately.
    """
    )</code></pre>
    
    <blockquote class=note>
    <p><span class=u>&#x261E;</span><code>chardet</code> and <code>httplib2</code> are open source, but there&#8217;s no requirement that you release your own Python libraries under any particular license. The process described in this chapter will work for any Python software, regardless of license.
    </blockquote>
    
    <p class=a>&#x2042;
    
    <h2 id=cantdo>Things Distutils Can&#8217;t Do For You</h2>
    
    <p>Releasing your first Python package is a daunting process. (Releasing your second one is a little easier.) Distutils tries to automate as much of it as possible, but there are some things you simply must do yourself.
    
    <ul>
    <li><b>Choose a license</b>. This is a complicated topic, fraught with politics and peril. If you wish to release your software as open source, I humbly offer five pieces of advice:
    
    <ol>
    <li>Don&#8217;t write your own license.
    <li>Don&#8217;t write your own license.
    <li>Don&#8217;t write your own license.
    <li>It doesn&#8217;t need to be <abbr>GPL</abbr>, but <a href=http://www.dwheeler.com/essays/gpl-compatible.html>it needs to be <abbr>GPL</abbr>-compatible</a>.
    <li>Don&#8217;t write your own license.
    </ol>
    <li><b>Classify your software</b> using the PyPI classification system. I&#8217;ll explain what this means later in this chapter.
    <li><b>Write a &#8220;read me&#8221; file</b>. Don&#8217;t skimp on this. At a minimum, it should give your users an overview of what your software does and how to install it.
    </ul>
    
    <p class=a>&#x2042;
    
    <h2 id=structure>Directory Structure</h2>
    
    <p>To start packaging your Python software, you need to get your files and directories in order. The <code>httplib2</code> directory looks like this:
    
    <pre class=screen>
    <a>httplib2/                 <span class=u>&#x2460;</span></a>
    |
    <a>+--README.txt             <span class=u>&#x2461;</span></a>
    |
    <a>+--setup.py               <span class=u>&#x2462;</span></a>
    |
    <a>+--httplib2/              <span class=u>&#x2463;</span></a>
       |
       +--__init__.py
       |
       +--iri2uri.py</pre>
    <ol>
    <li>Make a root directory to hold everything. Give it the same name as your Python module.
    <li>To accomodate Windows users, your &#8220;read me&#8221; file should include a <code>.txt</code> extension, and it should use Windows-style carriage returns. Just because <em>you</em> use a fancy text editor that runs from the command line and includes its own macro language, that doesn&#8217;t mean you need to make life difficult for your users. (Your users use Notepad. Sad but true.) Even if you&#8217;re on Linux or Mac OS X, your fancy text editor undoubtedly has an option to save files with Windows-style carriage returns.
    <li>Your Distutils setup script should be named <code>setup.py</code> unless you have a good reason not to. You do not have a good reason not to.
    <li>If your Python software is a single <code>.py</code> file, you should put it in the root directory along with your &#8220;read me&#8221; file and your setup script. But <code>httplib2</code> is not a single <code>.py</code> file; it&#8217;s <a href=case-study-porting-chardet-to-python-3.html#multifile-modules>a multi-file module</a>. But that&#8217;s OK! Just put the <code>httplib2</code> directory in the root directory, so you have an <code>__init__.py</code> file within an <code>httplib2/</code> directory within the <code>httplib2/</code> root directory. That&#8217;s not a problem; in fact, it will simplify your packaging process.
    </ol>
    
    <p>The <code>chardet</code> directory looks slightly different. Like <code>httplib2</code>, it&#8217;s <a href=case-study-porting-chardet-to-python-3.html#multifile-modules>a multi-file module</a>, so there&#8217;s a <code>chardet/</code> directory within the <code>chardet/</code> root directory. In addition to the <code>README.txt</code> file, <code>chardet</code> has <abbr>HTML</abbr>-formatted documentation in the <code>docs/</code> directory. The <code>docs/</code> directory contains several <code>.html</code> and <code>.css</code> files and an <code>images/</code> subdirectory, which contains several <code>.png</code> and <code>.gif</code> files. (This will be important later.) Also, in keeping with the convention for <abbr>(L)GPL</abbr>-licensed software, it has a separate file called <code>COPYING.txt</code> which contains the complete text of the <abbr>LGPL</abbr>.
    
    <pre class=nd><code>
    chardet/
    |
    +--COPYING.txt
    |
    +--setup.py
    |
    +--README.txt
    |
    +--docs/
    |  |
    |  +--index.html
    |  |
    |  +--usage.html
    |  |
    |  +--images/ ...
    |
    +--chardet/
       |
       +--__init__.py
       |
       +--big5freq.py
       |
       +--...
    </code></pre>
    
    <p class=a>&#x2042;
    
    <h2 id=setuppy>Writing Your Setup Script</h2>
    
    <p>The Distutils setup script is a Python script. In theory, it can do anything Python can do. In practice, it should do as little as possible, in as standard a way as possible. Setup scripts should be boring. The more exotic your installation process is, the more exotic your bug reports will be.
    
    <p>The first line of every Distutils setup script is always the same:
    
    <pre class='nd pp'><code>from distutils.core import setup</code></pre>
    
    <p>This imports the <code>setup()</code> function, which is the main entry point into Distutils. 95% of all Distutils setup scripts consist of a single call to <code>setup()</code> and nothing else. (I totally just made up that statistic, but if your Distutils setup script is doing more than calling the Distutils <code>setup()</code> function, you should have a good reason. Do you have a good reason? I didn&#8217;t think so.)
    
    <p>The <code>setup()</code> function <a href=http://docs.python.org/3.1/distutils/apiref.html#distutils.core.setup>can take dozens of parameters</a>. For the sanity of everyone involved, you must use <a href=your-first-python-program.html#optional-arguments>named arguments</a> for every parameter. This is not merely a convention; it&#8217;s a hard requirement. Your setup script will crash if you try to call the <code>setup()</code> function with non-named arguments.
    
    <p>The following named arguments are required:
    
    <ul>
    <li><b>name</b>, the name of the package.
    <li><b>version</b>, the version number of the package.
    <li><b>author</b>, your full name.
    <li><b>author_email</b>, your email address.
    <li><b>url</b>, the home page of your project. This can be your <a href=http://pypi.python.org/>PyPI</a> package page if you don&#8217;t have a separate project website.
    </ul>
    
    <p>Although not required, I recommend that you also include the following in your setup script:
    
    <ul>
    <li><b>description</b>, a one-line summary of the project.
    <li><b>long_description</b>, a multi-line string in <a href=http://docutils.sourceforge.net/rst.html>reStructuredText format</a>. <a href=http://pypi.python.org/>PyPI</a> converts this to <abbr>HTML</abbr> and displays it on your package page.
    <li><b>classifiers</b>, a list of specially-formatted strings described in the next section.
    </ul>
    
    <blockquote class=note>
    <p><span class=u>&#x261E;</span>Setup script metadata is defined in <a href=http://www.python.org/dev/peps/pep-0314/><abbr>PEP</abbr> 314</a>.
    </blockquote>
    
    <p>Now let&#8217;s look at the <code>chardet</code> setup script. It has all of these required and recommended parameters, plus one I haven&#8217;t mentioned yet: <code>packages</code>.
    
    <pre class='nd pp'><code>from distutils.core import setup
    setup(
        name = 'chardet',
        <mark>packages = ['chardet']</mark>,
        version = '1.0.2',
        description = 'Universal encoding detector',
        author='Mark Pilgrim',
        ...
    )</code></pre>
    
    <p>The <code>packages</code> parameter highlights an unfortunate vocabulary overlap in the distribution process. We&#8217;ve been talking about the &#8220;package&#8221; as the thing you&#8217;re building (and potentially listing in The Python &#8220;Package&#8221; Index). But that&#8217;s not what this <code>packages</code> parameter refers to. It refers to the fact that the <code>chardet</code> module is <a href=case-study-porting-chardet-to-python-3.html#multifile-modules>a multi-file module</a>, sometimes known as&hellip; a &#8220;package.&#8221; The <code>packages</code> parameter tells Distutils to include the <code>chardet/</code> directory, its <code>__init__.py</code> file, and all the other <code>.py</code> files that constitute the <code>chardet</code> module. That&#8217;s kind of important; all this happy talk about documentation and metadata is irrelevant if you forget to include the actual code!
    
    <p class=a>&#x2042;
    
    <h2 id=trove>Classifying Your Package</h2>
    
    <p>The Python Package Index (&#8220;PyPI&#8221;) contains thousands of Python libraries. Proper classification metadata will allow people to find yours more easily. PyPI lets you <a href='http://pypi.python.org/pypi?:action=browse'>browse packages by classifier</a>. You can even select multiple classifiers to narrow your search. Classifiers are not invisible metadata that you can just ignore!
    
    <p>To classify your software, pass a <code>classifiers</code> parameter to the Distutils <code>setup()</code> function. The <code>classifiers</code> parameter is a list of strings. These strings are <em>not</em> freeform. All classifier strings should come from <a href='http://pypi.python.org/pypi?:action=list_classifiers'>this list on PyPI</a>.
    
    <p>Classifiers are optional. You can write a Distutils setup script without any classifiers at all. <strong>Don&#8217;t do that.</strong> You should <em>always</em> include at least these classifiers:
    
    <ul>
    <li><b>Programming Language</b>. In particular, you should include both <code>"Programming Language :: Python"</code> and <code>"Programming Language :: Python :: 3"</code>. If you do not include these, your package will not show up in <a href='http://pypi.python.org/pypi?:action=browse&amp;c=533&amp;show=all'>this list of Python 3-compatible libraries</a>, which linked from the sidebar of every single page of <code>pypi.python.org</code>.
    <li><b>License</b>. This is <em>the absolute first thing I look for</em> when I&#8217;m evaluating third-party libraries. Don&#8217;t make me hunt for this vital information. Don&#8217;t include more than one license classifier unless your software is explicitly available under multiple licenses. (And don&#8217;t release software under multiple licenses unless you&#8217;re forced to do so. And don&#8217;t force other people to do so. Licensing is enough of a headache; don&#8217;t make it worse.)
    <li><b>Operating System</b>. If your software only runs on Windows (or Mac OS X, or Linux), I want to know sooner rather than later. If your software runs anywhere without any platform-specific code, use the classifier <code>"Operating System :: OS Independent"</code>. Multiple <code>Operating System</code> classifiers are only necessary if your software requires specific support for each platform. (This is not common.)
    </ul>
    
    <p>I also recommend that you include the following classifiers:
    
    <ul>
    <li><b>Development Status</b>. Is your software beta quality? Alpha quality? Pre-alpha? Pick one. Be honest.
    <li><b>Intended Audience</b>. Who would download your software? The most common choices are <code>Developers</code>, <code>End Users/Desktop</code>, <code>Science/Research</code>, and <code>System Administrators</code>.
    <li><b>Framework</b>. If your software is a plugin for a larger Python framework like <a href=http://www.djangoproject.com/>Django</a> or <a href=http://www.zope.org/>Zope</a>, include the appropriate <code>Framework</code> classifier. If not, omit it.
    <li><b>Topic</b>. There are <a href='http://pypi.python.org/pypi?:action=list_classifiers'>a large number of topics to choose from</a>; choose all that apply.
    </ul>
    
    <h3 id=trove-examples>Examples of Good Package Classifiers</h3>
    
    <p>By way of example, here are the classifiers for <a href=http://pypi.python.org/pypi/Django/>Django</a>, a production-ready, cross-platform, <abbr>BSD</abbr>-licensed web application framework that runs on your web server. (Django is not yet compatible with Python 3, so the <code>Programming Language :: Python :: 3</code> classifier is not listed.)
    
    <pre><code>Programming Language :: Python
    License :: OSI Approved :: BSD License
    Operating System :: OS Independent
    Development Status :: 5 - Production/Stable
    Environment :: Web Environment
    Framework :: Django
    Intended Audience :: Developers
    Topic :: Internet :: WWW/HTTP
    Topic :: Internet :: WWW/HTTP :: Dynamic Content
    Topic :: Internet :: WWW/HTTP :: WSGI
    Topic :: Software Development :: Libraries :: Python Modules</code></pre>
    
    <p>Here are the classifiers for <a href=http://pypi.python.org/pypi/chardet><code>chardet</code></a>, the character encoding detection library covered in <a href=case-study-porting-chardet-to-python-3.html>Case Study: Porting <code>chardet</code> to Python 3</a>. <code>chardet</code> is beta quality, cross-platform, Python 3-compatible, <abbr>LGPL</abbr>-licensed, and intended for developers to integrate into their own products.
    
    <pre><code>Programming Language :: Python
    Programming Language :: Python :: 3
    License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
    Operating System :: OS Independent
    Development Status :: 4 - Beta
    Environment :: Other Environment
    Intended Audience :: Developers
    Topic :: Text Processing :: Linguistic
    Topic :: Software Development :: Libraries :: Python Modules</code></pre>
    
    <p>And here are the classifiers for <a href=http://pypi.python.org/pypi/httplib2><code>httplib2</code></a>, the library featured in the <a href=http-web-services.html><abbr>HTTP</abbr> Web Services</a> chapter. <code>httplib2</code> is beta quality, cross-platform, <abbr>MIT</abbr>-licensed, and intended for Python developers.
    
    <pre><code>Programming Language :: Python
    Programming Language :: Python :: 3
    License :: OSI Approved :: MIT License
    Operating System :: OS Independent
    Development Status :: 4 - Beta
    Environment :: Web Environment
    Intended Audience :: Developers
    Topic :: Internet :: WWW/HTTP
    Topic :: Software Development :: Libraries :: Python Modules</code></pre>
    
    <h2 id=manifest>Specifying Additional Files With A Manifest</h2>
    
    <p>By default, Distutils will include the following files in your release package:
    
    <ul>
    <li><code>README.txt</code>
    <li><code>setup.py</code>
    <li>The <code>.py</code> files needed by the multi-file modules listed in the <code>packages</code> parameter
    <li>The individual <code>.py</code> files listed in the <code>py_modules</code> parameter
    </ul>
    
    <p>That will cover <a href=#structure>all the files in the <code>httplib2</code> project</a>. But for the <code>chardet</code> project, we also want to include the <code>COPYING.txt</code> license file and the entire <code>docs/</code> directory that contains images and  <abbr>HTML</abbr> files. To tell Distutils to include these additional files and directories when it builds the <code>chardet</code> release package, you need a <i>manifest file</i>.
    
    <p>A manifest file is a text file called <code>MANIFEST.in</code>. Place it in the project&#8217;s root directory, next to <code>README.txt</code> and <code>setup.py</code>. Manifest files are <em>not</em> Python scripts; they are text files that contain a series of &#8220;commands&#8221; in a Distutils-defined format. Manifest commands allow you to include or exclude specific files and directories.
    
    <p>This is the entire manifest file for the <code>chardet</code> project:
    
    <pre class=nd><code><a>include COPYING.txt                                <span class=u>&#x2460;</span></a>
    <a>recursive-include docs *.html *.css *.png *.gif    <span class=u>&#x2461;</span></a></code></pre>
    <ol>
    <li>The first line is self-explanatory: include the <code>COPYING.txt</code> file from the project&#8217;s root directory.
    <li>The second line is a bit more complicated. The <code>recursive-include</code> command takes a directory name and one or more filenames. The filenames aren&#8217;t limited to specific files; they can include wildcards. This line means &#8220;See that <code>docs/</code> directory in the project&#8217;s root directory? Look in there (recursively) for <code>.html</code>, <code>.css</code>, <code>.png</code>, and <code>.gif</code> files. I want all of them in my release package.&#8221;
    </ol>
    
    <p>All manifest commands preserve the directory structure that you set up in your project directory. That <code>recursive-include</code> command is not going to put a bunch of <code>.html</code> and <code>.png</code> files in the root directory of the release package. It&#8217;s going to maintain the existing <code>docs/</code> directory structure, but only include those files inside that directory that match the given wildcards. (I didn&#8217;t mention it earlier, but the <code>chardet</code> documentation is actually written in <abbr>XML</abbr> and converted to <abbr>HTML</abbr> by a separate script. I don&#8217;t want to include the <abbr>XML</abbr> files in the release package, just the <abbr>HTML</abbr> and the images.)
    
    <blockquote class=note>
    <p><span class=u>&#x261E;</span>Manifest files have their own unique format. See <a href=http://docs.python.org/3.1/distutils/sourcedist.html#manifest>Specifying the files to distribute</a> and <a href=http://docs.python.org/3.1/distutils/commandref.html#sdist-cmd>the manifest template commands</a> for details.
    </blockquote>
    
    <p>To reiterate: you only need to create a manifest file if you want to include files that Distutils doesn&#8217;t include by default. If you do need a manifest file, it should only include the files and directories that Distutils wouldn&#8217;t otherwise find on its own.
    
    <h2 id=check>Checking Your Setup Script for Errors</h2>
    
    <p>There&#8217;s a lot to keep track of. Distutils comes with a built-in validation command that checks that all the required metadata is present in your setup script. For example, if you forget to include the <code>version</code> parameter, Distutils will remind you.
    
    <pre class=screen>
    <samp class=p>c:\Users\pilgrim\chardet> </samp><kbd>c:\python31\python.exe setup.py check</kbd>
    <samp>running check
    warning: check: missing required meta-data: version</samp></pre>
    
    <p>Once you include a <code>version</code> parameter (and all the other required bits of metadata), the <code>check</code> command will look like this:
    
    <pre class=screen>
    <samp class=p>c:\Users\pilgrim\chardet> </samp><kbd>c:\python31\python.exe setup.py check</kbd>
    <samp>running check</samp></pre>
    
    <p class=a>&#x2042;
    
    <h2 id=sdist>Creating a Source Distribution</h2>
    
    <p>Distutils supports building multiple types of release packages. At a minimum, you should build a &#8220;source distribution&#8221; that contains your source code, your Distutils setup script, your &#8220;read me&#8221; file, and whatever <a href=#manifest>additional files you want to include</a>. To build a source distribution, pass the <code>sdist</code> command to your Distutils setup script.
    
    <pre class=screen>
    <samp class=p>c:\Users\pilgrim\chardet> </samp><kbd><mark>c:\python31\python.exe setup.py sdist</mark></kbd>
    <samp>running sdist
    running check
    reading manifest template 'MANIFEST.in'
    writing manifest file 'MANIFEST'
    creating chardet-1.0.2
    creating chardet-1.0.2\chardet
    creating chardet-1.0.2\docs
    creating chardet-1.0.2\docs\images
    copying files to chardet-1.0.2...
    copying COPYING -> chardet-1.0.2
    copying README.txt -> chardet-1.0.2
    copying setup.py -> chardet-1.0.2
    copying chardet\__init__.py -> chardet-1.0.2\chardet
    copying chardet\big5freq.py -> chardet-1.0.2\chardet
    ...
    copying chardet\universaldetector.py -> chardet-1.0.2\chardet
    copying chardet\utf8prober.py -> chardet-1.0.2\chardet
    copying docs\faq.html -> chardet-1.0.2\docs
    copying docs\history.html -> chardet-1.0.2\docs
    copying docs\how-it-works.html -> chardet-1.0.2\docs
    copying docs\index.html -> chardet-1.0.2\docs
    copying docs\license.html -> chardet-1.0.2\docs
    copying docs\supported-encodings.html -> chardet-1.0.2\docs
    copying docs\usage.html -> chardet-1.0.2\docs
    copying docs\images\caution.png -> chardet-1.0.2\docs\images
    copying docs\images\important.png -> chardet-1.0.2\docs\images
    copying docs\images\note.png -> chardet-1.0.2\docs\images
    copying docs\images\permalink.gif -> chardet-1.0.2\docs\images
    copying docs\images\tip.png -> chardet-1.0.2\docs\images
    copying docs\images\warning.png -> chardet-1.0.2\docs\images
    creating dist
    creating 'dist\chardet-1.0.2.zip' and adding 'chardet-1.0.2' to it
    adding 'chardet-1.0.2\COPYING'
    adding 'chardet-1.0.2\PKG-INFO'
    adding 'chardet-1.0.2\README.txt'
    adding 'chardet-1.0.2\setup.py'
    adding 'chardet-1.0.2\chardet\big5freq.py'
    adding 'chardet-1.0.2\chardet\big5prober.py'
    ...
    adding 'chardet-1.0.2\chardet\universaldetector.py'
    adding 'chardet-1.0.2\chardet\utf8prober.py'
    adding 'chardet-1.0.2\chardet\__init__.py'
    adding 'chardet-1.0.2\docs\faq.html'
    adding 'chardet-1.0.2\docs\history.html'
    adding 'chardet-1.0.2\docs\how-it-works.html'
    adding 'chardet-1.0.2\docs\index.html'
    adding 'chardet-1.0.2\docs\license.html'
    adding 'chardet-1.0.2\docs\supported-encodings.html'
    adding 'chardet-1.0.2\docs\usage.html'
    adding 'chardet-1.0.2\docs\images\caution.png'
    adding 'chardet-1.0.2\docs\images\important.png'
    adding 'chardet-1.0.2\docs\images\note.png'
    adding 'chardet-1.0.2\docs\images\permalink.gif'
    adding 'chardet-1.0.2\docs\images\tip.png'
    adding 'chardet-1.0.2\docs\images\warning.png'
    removing 'chardet-1.0.2' (and everything under it)</samp></pre>
    
    <p>Several things to note here:
    
    <ul>
    <li>Distutils noticed the manifest file (<code>MANIFEST.in</code>).
    <li>Distutils successfully parsed the manifest file and added the additional files we wanted&nbsp;&mdash;&nbsp;<code>COPYING.txt</code> and the <abbr>HTML</abbr> and image files in the <code>docs/</code> directory.
    <li>If you look in your project directory, you&#8217;ll see that Distutils created a <code>dist/</code> directory. Within the <code>dist/</code> directory the <code>.zip</code> file that you can distribute.
    </ul>
    
    <pre class=screen>
    <samp class=p>c:\Users\pilgrim\chardet> </samp><kbd><mark>dir dist</mark></kbd>
    <samp> Volume in drive C has no label.
     Volume Serial Number is DED5-B4F8
    
     Directory of c:\Users\pilgrim\chardet\dist
    
    07/30/2009  06:29 PM    &lt;DIR>          .
    07/30/2009  06:29 PM    &lt;DIR>          ..
    07/30/2009  06:29 PM           206,440 <mark>chardet-1.0.2.zip</mark>
                   1 File(s)        206,440 bytes
                   2 Dir(s)  61,424,635,904 bytes free</samp></pre>
    
    <p class=a>&#x2042;
    
    <h2 id=bdist>Creating a Graphical Installer</h2>
    
    <p>In my opinion, every Python library deserves a graphical installer for Windows users. It&#8217;s easy to make (even if you don&#8217;t run Windows yourself), and Windows users appreciate it.
    
    <p>Distutils can <a href=http://docs.python.org/3.1/distutils/builtdist.html#creating-windows-installers>create a graphical Windows installer for you</a>, by passing the <code>bdist_wininst</code> command to your Distutils setup script.
    
    <pre class=screen>
    <samp class=p>c:\Users\pilgrim\chardet> </samp><kbd><mark>c:\python31\python.exe setup.py bdist_wininst</mark></kbd>
    <samp>running bdist_wininst
    running build
    running build_py
    creating build
    creating build\lib
    creating build\lib\chardet
    copying chardet\big5freq.py -> build\lib\chardet
    copying chardet\big5prober.py -> build\lib\chardet
    ...
    copying chardet\universaldetector.py -> build\lib\chardet
    copying chardet\utf8prober.py -> build\lib\chardet
    copying chardet\__init__.py -> build\lib\chardet
    installing to build\bdist.win32\wininst
    running install_lib
    creating build\bdist.win32
    creating build\bdist.win32\wininst
    creating build\bdist.win32\wininst\PURELIB
    creating build\bdist.win32\wininst\PURELIB\chardet
    copying build\lib\chardet\big5freq.py -> build\bdist.win32\wininst\PURELIB\chardet
    copying build\lib\chardet\big5prober.py -> build\bdist.win32\wininst\PURELIB\chardet
    ...
    copying build\lib\chardet\universaldetector.py -> build\bdist.win32\wininst\PURELIB\chardet
    copying build\lib\chardet\utf8prober.py -> build\bdist.win32\wininst\PURELIB\chardet
    copying build\lib\chardet\__init__.py -> build\bdist.win32\wininst\PURELIB\chardet
    running install_egg_info
    Writing build\bdist.win32\wininst\PURELIB\chardet-1.0.2-py3.1.egg-info
    creating 'c:\users\pilgrim\appdata\local\temp\tmp2f4h7e.zip' and adding '.' to it
    adding 'PURELIB\chardet-1.0.2-py3.1.egg-info'
    adding 'PURELIB\chardet\big5freq.py'
    adding 'PURELIB\chardet\big5prober.py'
    ...
    adding 'PURELIB\chardet\universaldetector.py'
    adding 'PURELIB\chardet\utf8prober.py'
    adding 'PURELIB\chardet\__init__.py'
    removing 'build\bdist.win32\wininst' (and everything under it)</samp>
    <samp class=p>c:\Users\pilgrim\chardet> </samp><kbd><mark>dir dist</mark></kbd>
    <samp>c:\Users\pilgrim\chardet>dir dist
     Volume in drive C has no label.
     Volume Serial Number is AADE-E29F
    
     Directory of c:\Users\pilgrim\chardet\dist
    
    07/30/2009  10:14 PM    &lt;DIR>          .
    07/30/2009  10:14 PM    &lt;DIR>          ..
    07/30/2009  10:14 PM           371,236 <mark>chardet-1.0.2.win32.exe</mark>
    07/30/2009  06:29 PM           206,440 chardet-1.0.2.zip
                   2 File(s)        577,676 bytes
                   2 Dir(s)  61,424,070,656 bytes free</samp></pre>
    
    <h3 id=linux>Building Installable Packages for Other Operating Systems</h3>
    
    <p>Distutils can help you <a href=http://docs.python.org/3.1/distutils/builtdist.html#creating-rpm-packages>build installable packages for Linux users</a>. In my opinion, this probably isn&#8217;t worth your time. If you want your software distributed for Linux, your time would be better spent working with community members who specialize in packaging software for major Linux distributions.
    
    <p>For example, my <code>chardet</code> library is <a href=http://packages.debian.org/python-chardet>in the Debian GNU/Linux repositories</a> (and therefore <a href=http://packages.ubuntu.com/python-chardet>in the Ubuntu repositories</a> as well). I had nothing to do with this; the packages just showed up there one day. The Debian community has <a href=http://www.debian.org/doc/packaging-manuals/python-policy/>their own policies for packaging Python libraries</a>, and the Debian <code>python-chardet</code> package is designed to follow these conventions. And since the package lives in Debian&#8217;s repositories, Debian users will receive security updates and/or new versions, depending on the system-wide settings they&#8217;ve chosen to manage their own computers.
    
    <p>The Linux packages that Distutils builds offer none of these advantages. Your time is better spent elsewhere.
    
    <p class=a>&#x2042;
    
    <h2 id=pypi>Adding Your Software to The Python Package Index</h2>
    
    <p>Uploading software to the Python Package Index is a three step process.
    
    <ol>
    <li>Register yourself
    <li>Register your software
    <li>Upload the packages you created with <code>setup.py sdist</code> and <code>setup.py bdist_*</code>
    </ol>
    
    <p>To register yourself, go to <a href="http://pypi.python.org/pypi?:action=register_form">the PyPI user registration page</a>. Enter your desired username and password, provide a valid email address, and click the <code>Register</code> button. (If you have a <abbr>PGP</abbr> or <abbr>GPG</abbr> key, you can also provide that. If you don&#8217;t have one or don&#8217;t know what that means, don&#8217;t worry about it.) Check your email; within a few minutes, you should receive a message from PyPI with a validation link. Click the link to complete the registration process.
    
    <p>Now you need to register your software with PyPI and upload it. You can do this all in one step.
    
    <pre class=screen>
    <a><samp class=p>c:\Users\pilgrim\chardet> </samp><kbd>c:\python31\python.exe setup.py register sdist bdist_wininst upload</kbd>  <span class=u>&#x2460;</span></a>
    <samp>running register
    We need to know who you are, so please choose either:
     1. use your existing login,
     2. register as a new user,
     3. have the server generate a new password for you (and email it to you), or
     4. quit</samp>
    <a><samp class=p>Your selection [default 1]:  </samp><kbd>1</kbd>                                                                 <span class=u>&#x2461;</span></a>
    <a><samp class=p>Username: </samp><kbd>MarkPilgrim</kbd>                                                                          <span class=u>&#x2462;</span></a>
    <samp class=p>Password:</samp>
    <a><samp>Registering chardet to http://pypi.python.org/pypi</samp>                                             <span class=u>&#x2463;</span></a>
    <samp>Server response (200): OK</samp>
    <a><samp>running sdist</samp>                                                                                  <span class=u>&#x2464;</span></a>
    <samp>... output trimmed for brevity ...</samp>
    <a><samp>running bdist_wininst</samp>                                                                          <span class=u>&#x2465;</span></a>
    <samp>... output trimmed for brevity ...</samp>
    <a><samp>running upload</samp>                                                                                 <span class=u>&#x2466;</span></a>
    <samp>Submitting dist\chardet-1.0.2.zip to http://pypi.python.org/pypi
    Server response (200): OK
    Submitting dist\chardet-1.0.2.win32.exe to http://pypi.python.org/pypi
    Server response (200): OK
    I can store your PyPI login so future submissions will be faster.
    (the login will be stored in c:\home\.pypirc)</samp>
    <a><samp class=p>Save your login (y/N)?</samp><kbd class=pp>n</kbd>                                                                        <span class=u>&#x2467;</span></a></pre>
    <ol>
    <li>When you release your project for the first time, Distutils will add your software to the Python Package Index and give it its own <abbr>URL</abbr>. Every time after that, it will simply update the project metadata with any changes you may have made in your <code>setup.py</code> parameters. Next, it builds a source distribution (<code>sdist</code>) and a Windows installer (<code>bdist_wininst</code>), then uploads them to PyPI (<code>upload</code>).
    <li>Type <kbd>1</kbd> or just press <kbd>ENTER</kbd> to select &#8220;use your existing login.&#8221;
    <li>Enter the username and password you selected on the <a href="http://pypi.python.org/pypi?:action=register_form">the PyPI user registration page</a>. Distuils will not echo your password; it will not even echo asterisks in place of characters. Just type your password and press <kbd>ENTER</kbd>.
    <li>Distutils registers your package with the Python Package Index&hellip;
    <li>&hellip;builds your source distribution&hellip;
    <li>&hellip;builds your Windows installer&hellip;
    <li>&hellip;and uploads them both to the Python Package Index.
    <li>If you want to automate the process of releasing new versions, you need to save your PyPI credentials in a local file. This is completely insecure and completely optional.
    </ol>
    
    <p>Congratulations, you now have your own page on the Python Package Index! The address is <code>http://pypi.python.org/pypi/<i>NAME</i></code>, where <i>NAME</i> is the string you passed in the <var>name</var> parameter in your <code>setup.py</code> file.
    
    <p>If you want to release a new version, just update your <code>setup.py</code> with the new version number, then run the same upload command again:
    
    <pre class='nd screen'>
    <samp class=p>c:\Users\pilgrim\chardet> </samp><kbd>c:\python31\python.exe setup.py register sdist bdist_wininst upload</kbd>
    </pre>
    
    <p class=a>&#x2042;
    
    <h2 id=future>The Many Possible Futures of Python Packaging</h2>
    
    <p>Distutils is not the be-all and end-all of Python packaging, but as of this writing (August 2009), it&#8217;s the only packaging framework that works in Python 3. There are a number of other frameworks for Python 2; some focus on installation, others on testing and deployment. Some or all of these may end up being ported to Python 3 in the future.
    
    <p>These frameworks focus on installation:
    
    <ul>
    <li><a href=http://pypi.python.org/pypi/setuptools>Setuptools</a>
    <li><a href=http://pypi.python.org/pypi/pip>Pip</a>
    <li><a href=http://bitbucket.org/tarek/distribute/>Distribute</a>
    </ul>
    
    <p>These focus on testing and deployment:
    
    <ul>
    <li><a href=http://pypi.python.org/pypi/virtualenv><code>virtualenv</code></a>
    <li><a href=http://pypi.python.org/pypi/zc.buildout><code>zc.buildout</code></a>
    <li><a href=http://www.blueskyonmars.com/projects/paver/>Paver</a>
    <li><a href=http://fabfile.org/>Fabric</a>
    <li><a href=http://www.py2exe.org/><code>py2exe</code></a>
    </ul>
    
    <p class=a>&#x2042;
    
    <h2 id=furtherreading>Further Reading</h2>
    
    <p>On Distutils:
    
    <ul>
    <li><a href=http://docs.python.org/3.1/distutils/>Distributing Python Modules with Distutils</a>
    <li><a href=http://docs.python.org/3.1/distutils/apiref.html#module-distutils.core>Core Distutils functionality</a> lists all the possible arguments to the <code>setup()</code> function
    <li><a href=http://wiki.python.org/moin/Distutils/Cookbook>Distutils Cookbook</a>
    <li><a href=http://www.python.org/dev/peps/pep-0370/><abbr>PEP</abbr> 370: Per user <code>site-packages</code> directory</a>
    <li><a href=http://jessenoller.com/2009/07/19/pep-370-per-user-site-packages-and-environment-stew/><abbr>PEP</abbr> 370 and &#8220;environment stew&#8221;</a>
    </ul>
    
    <p>On other packaging frameworks:
    
    <ul>
    <li><a href=http://groups.google.com/group/django-developers/msg/5407cdb400157259>The Python packaging ecosystem</a>
    <li><a href=http://www.b-list.org/weblog/2008/dec/14/packaging/>On packaging</a>
    <li><a href=http://blog.ianbicking.org/2008/12/14/a-few-corrections-to-on-packaging/>A few corrections to &#8220;On packaging&#8221;</a>
    <li><a href=http://www.b-list.org/weblog/2008/dec/15/pip/>Why I like Pip</a>
    <li><a href=http://cournape.wordpress.com/2009/04/01/python-packaging-a-few-observations-cabal-for-a-solution/>Python packaging: a few observations</a>
    <li><a href=http://jacobian.org/writing/nobody-expects-python-packaging/>Nobody expects Python packaging!</a>
    </ul>
    
    <p class=v><a rel=prev href=case-study-porting-chardet-to-python-3.html title='back to &#8220;Case Study: Porting chardet to Python 3&#8221;'><span class=u>&#x261C;</span></a> <a rel=next href=porting-code-to-python-3-with-2to3.html title='onward to &#8220;Porting Code to Python 3 with 2to3&#8221;'><span class=u>&#x261E;</span></a>
    <p class=c>&copy; 2001&ndash;11 <a href=about.html>Mark Pilgrim</a>
    <script src=j/jquery.js></script>
    <script src=j/prettify.js></script>
    <script src=j/dip3.js></script>
    ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/native-datatypes.html�����������������������������������������0000644�0000000�0000000�00000222527�11773544727�021772� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE html>
    <meta charset=utf-8>
    <title>Native datatypes - Dive Into Python 3</title>
    <!--[if IE]><script src=j/html5.js></script><![endif]-->
    <link rel=stylesheet href=dip3.css>
    <style>
    body{counter-reset:h1 2}
    </style>
    <link rel=stylesheet media='only screen and (max-device-width: 480px)' href=mobile.css>
    <link rel=stylesheet media=print href=print.css>
    <meta name=viewport content='initial-scale=1.0'>
    <form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:l5eihuescdw><input type=hidden name=ie value=UTF-8>&nbsp;<input type=search name=q size=25 placeholder="powered by Google&trade;">&nbsp;<input type=submit name=root value=Search></div></form>
    <p>You are here: <a href=index.html>Home</a> <span class=u>&#8227;</span> <a href=table-of-contents.html#native-datatypes>Dive Into Python 3</a> <span class=u>&#8227;</span>
    <p id=level>Difficulty level: <span class=u title=beginner>&#x2666;&#x2666;&#x2662;&#x2662;&#x2662;</span>
    <h1>Native Datatypes</h1>
    <blockquote class=q>
    <p><span class=u>&#x275D;</span> Wonder is the foundation of all philosophy, inquiry its progress, ignorance its end. <span class=u>&#x275E;</span><br>&mdash; Michel de Montaigne
    </blockquote>
    <p id=toc>&nbsp;
    <h2 id=divingin>Diving In</h2>
    <p class=f>Datatypes. Set aside <a href=your-first-python-program.html>your first Python program</a> for just a minute, and let&#8217;s talk about datatypes. In Python, <a href=your-first-python-program.html#declaringfunctions>every value has a datatype</a>, but you don&#8217;t need to declare the datatype of variables. How does that work? Based on each variable&#8217;s original assignment, Python figures out what type it is and keeps tracks of that internally.
    <p>Python has many native datatypes. Here are the important ones:
    <ol>
    <li><b>Booleans</b> are either <code>True</code> or <code>False</code>.
    <li><b>Numbers</b> can be integers (<code>1</code> and <code>2</code>), floats (<code>1.1</code> and <code>1.2</code>), fractions (<code>1/2</code> and <code>2/3</code>), or even <a href=http://en.wikipedia.org/wiki/Complex_number>complex numbers</a>.
    <li><b>Strings</b> are sequences of Unicode characters, <i>e.g.</i> an <abbr>HTML</abbr> document.
    <li><b>Bytes</b> and <b>byte arrays</b>, <i>e.g.</i> a <abbr>JPEG</abbr> image file.
    <li><b>Lists</b> are ordered sequences of values.
    <li><b>Tuples</b> are ordered, immutable sequences of values.
    <li><b>Sets</b> are unordered bags of values.
    <li><b>Dictionaries</b> are unordered bags of key-value pairs.
    </ol>
    <p>Of course, there are more types than these. <a href=your-first-python-program.html#everythingisanobject>Everything is an object</a> in Python, so there are types like <i>module</i>, <i>function</i>, <i>class</i>, <i>method</i>, <i>file</i>, and even <i>compiled code</i>. You&#8217;ve already seen some of these: <a href=your-first-python-program.html#runningscripts>modules have names</a>, <a href=your-first-python-program.html#docstrings>functions have <code>docstrings</code></a>, <i class=baa>&amp;</i>c. You&#8217;ll learn about classes in <a href=iterators.html>Classes <i class=baa>&amp;</i> Iterators</a>, and about files in <a href=files.html>Files</a>.
    <p>Strings and bytes are important enough&nbsp;&mdash;&nbsp;and complicated enough&nbsp;&mdash;&nbsp;that they get their own chapter. Let&#8217;s look at the others first.
    <p class=a>&#x2042;
    
    <h2 id=booleans>Booleans</h2>
    <aside>You can use virtually any expression in a boolean context.</aside>
    <p>Booleans are either true or false. Python has two constants, cleverly named <code><dfn>True</dfn></code> and <code><dfn>False</dfn></code>, which can be used to assign <dfn>boolean</dfn> values directly. Expressions can also evaluate to a boolean value. In certain places (like <code>if</code> statements), Python expects an expression to evaluate to a boolean value. These places are called <i>boolean contexts</i>. You can use virtually any expression in a boolean context, and Python will try to determine its truth value. Different datatypes have different rules about which values are true or false in a boolean context. (This will make more sense once you see some concrete examples later in this chapter.)
    <p>For example, take this snippet from <a href=your-first-python-program.html#divingin><code>humansize.py</code></a>:
    <pre class='nd pp'><code>if size &lt; 0:
        raise ValueError('number must be non-negative')</code></pre>
    <p><var>size</var> is an integer, 0 is an integer, and <code>&lt;</code> is a numerical operator. The result of the expression <code>size &lt; 0</code> is always a boolean. You can test this yourself in the Python interactive shell:
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>size = 1</kbd>
    <samp class=p>>>> </samp><kbd class=pp>size &lt; 0</kbd>
    <samp class=pp>False</samp>
    <samp class=p>>>> </samp><kbd class=pp>size = 0</kbd>
    <samp class=p>>>> </samp><kbd class=pp>size &lt; 0</kbd>
    <samp class=pp>False</samp>
    <samp class=p>>>> </samp><kbd class=pp>size = -1</kbd>
    <samp class=p>>>> </samp><kbd class=pp>size &lt; 0</kbd>
    <samp class=pp>True</samp></pre>
    <p>Due to some legacy issues left over from Python 2, booleans can be treated as numbers. <code>True</code> is <code>1</code>; <code>False</code> is 0.
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>True + True</kbd>
    <samp class=pp>2</samp>
    <samp class=p>>>> </samp><kbd class=pp>True - False</kbd>
    <samp class=pp>1</samp>
    <samp class=p>>>> </samp><kbd class=pp>True * False</kbd>
    <samp class=pp>0</samp>
    <samp class=p>>>> </samp><kbd class=pp>True / False</kbd>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
    ZeroDivisionError: int division or modulo by zero</samp></pre>
    <p>Ew, ew, ew! Don&#8217;t do that. Forget I even mentioned it.
    
    <p class=a>&#x2042;
    
    <h2 id=numbers>Numbers</h2>
    <p>Numbers are awesome. There are so many to choose from. Python supports both <dfn>integer</dfn>s and <dfn>floating point</dfn> numbers. There&#8217;s no type declaration to distinguish them; Python tells them apart by the presence or absence of a <dfn>decimal</dfn> point.
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>type(1)</kbd>                 <span class=u>&#x2460;</span></a>
    <samp class=pp>&lt;class 'int'></samp>
    <a><samp class=p>>>> </samp><kbd class=pp>isinstance(1, int)</kbd>      <span class=u>&#x2461;</span></a>
    <samp class=pp>True</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>1 + 1</kbd>                   <span class=u>&#x2462;</span></a>
    <samp class=pp>2</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>1 + 1.0</kbd>                 <span class=u>&#x2463;</span></a>
    <samp class=pp>2.0</samp>
    <samp class=p>>>> </samp><kbd class=pp>type(2.0)</kbd>
    <samp class=pp>&lt;class 'float'></samp></pre>
    <ol>
    <li>You can use the <code>type()</code> function to check the type of any value or variable. As you might expect, <code>1</code> is an <code>int</code>.
    <li>Similarly, you can use the <code>isinstance()</code> function to check whether a value or variable is of a given type.
    <li>Adding an <code>int</code> to an <code>int</code> yields an <code>int</code>.
    <li>Adding an <code>int</code> to a <code>float</code> yields a <code>float</code>. Python coerces the <code>int</code> into a <code>float</code> to perform the addition, then returns a <code>float</code> as the result.
    </ol>
    <h3 id=number-coercion>Coercing Integers To Floats And Vice-Versa</h3>
    <p>As you just saw, some operators (like addition) will coerce integers to floating point numbers as needed. You can also coerce them by yourself.
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>float(2)</kbd>                <span class=u>&#x2460;</span></a>
    <samp class=pp>2.0</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>int(2.0)</kbd>                <span class=u>&#x2461;</span></a>
    <samp class=pp>2</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>int(2.5)</kbd>                <span class=u>&#x2462;</span></a>
    <samp class=pp>2</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>int(-2.5)</kbd>               <span class=u>&#x2463;</span></a>
    <samp class=pp>-2</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>1.12345678901234567890</kbd>  <span class=u>&#x2464;</span></a>
    <samp class=pp>1.1234567890123457</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>type(1000000000000000)</kbd>  <span class=u>&#x2465;</span></a>
    <samp class=pp>&lt;class 'int'></samp></pre>
    <ol>
    <li>You can explicitly coerce an <code>int</code> to a <code>float</code> by calling the <code>float()</code> function.
    <li>Unsurprisingly, you can also coerce a <code>float</code> to an <code>int</code> by calling <code>int()</code>.
    <li>The <code>int()</code> function will truncate, not round.
    <li>The <code>int()</code> function truncates negative numbers towards 0. It&#8217;s a true truncate function, not a floor function.
    <li>Floating point numbers are accurate to 15 decimal places.
    <li>Integers can be arbitrarily large.
    </ol>
    <blockquote class='note compare python2'>
    <p><span class=u>&#x261E;</span>Python 2 had separate types for <code>int</code> and <code>long</code>. The <code>int</code> datatype was limited by <code>sys.maxint</code>, which varied by platform but was usually <code>2<sup>32</sup>-1</code>. Python 3 has just one integer type, which behaves mostly like the old <code>long</code> type from Python 2. See <a href=http://www.python.org/dev/peps/pep-0237><abbr>PEP</abbr> 237</a> for details.
    </blockquote>
    <h3 id=common-numerical-operations>Common Numerical Operations</h3>
    <p>You can do all kinds of things with numbers.
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>11 / 2</kbd>      <span class=u>&#x2460;</span></a>
    <samp class=pp>5.5</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>11 // 2</kbd>     <span class=u>&#x2461;</span></a>
    <samp class=pp>5</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>&minus;11 // 2</kbd>    <span class=u>&#x2462;</span></a>
    <samp class=pp>&minus;6</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>11.0 // 2</kbd>   <span class=u>&#x2463;</span></a>
    <samp class=pp>5.0</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>11 ** 2</kbd>     <span class=u>&#x2464;</span></a>
    <samp class=pp>121</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>11 % 2</kbd>      <span class=u>&#x2465;</span></a>
    <samp class=pp>1</samp>
    </pre>
    <ol>
    <li>The <code>/</code> operator performs floating point division. It returns a <code>float</code> even if both the numerator and denominator are <code>int</code>s.
    <li>The <code>//</code> operator performs a quirky kind of integer division. When the result is positive, you can think of it as truncating (not rounding) to 0 decimal places, but be careful with that.
    <li>When integer-dividing negative numbers, the <code>//</code> operator rounds &#8220;up&#8221; to the nearest integer. Mathematically speaking, it&#8217;s rounding &#8220;down&#8221; since <code>&minus;6</code> is less than <code>&minus;5</code>, but it could trip you up if you were expecting it to truncate to <code>&minus;5</code>.
    <li>The <code>//</code> operator doesn&#8217;t always return an integer. If either the numerator or denominator is a <code>float</code>, it will still round to the nearest integer, but the actual return value will be a <code>float</code>.
    <li>The <code>**</code> operator means &#8220;raised to the power of.&#8221;  <code>11<sup>2</sup></code> is <code>121</code>.
    <li>The <code>%</code> operator gives the remainder after performing integer division. <code>11</code> divided by <code>2</code> is <code>5</code> with a remainder of <code>1</code>, so the result here is <code>1</code>.
    </ol>
    <blockquote class='note compare python2'>
    <p><span class=u>&#x261E;</span>In Python 2, the <code>/</code> operator usually meant integer division, but you could make it behave like floating point division by including a special directive in your code. In Python 3, the <code>/</code> operator always means floating point division. See <a href=http://www.python.org/dev/peps/pep-0238/><abbr>PEP</abbr> 238</a> for details.
    </blockquote>
    <h3 id=fractions>Fractions</h3>
    <p>Python isn&#8217;t limited to integers and floating point numbers. It can also do all the fancy math you learned in high school and promptly forgot about.
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>import fractions</kbd>              <span class=u>&#x2460;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>x = fractions.Fraction(1, 3)</kbd>  <span class=u>&#x2461;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>x</kbd>
    <samp class=pp>Fraction(1, 3)</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>x * 2</kbd>                         <span class=u>&#x2462;</span></a>
    <samp class=pp>Fraction(2, 3)</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>fractions.Fraction(6, 4)</kbd>      <span class=u>&#x2463;</span></a>
    <samp class=pp>Fraction(3, 2)</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>fractions.Fraction(0, 0)</kbd>      <span class=u>&#x2464;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
      File "fractions.py", line 96, in __new__
        raise ZeroDivisionError('Fraction(%s, 0)' % numerator)
    ZeroDivisionError: Fraction(0, 0)</samp></pre>
    <ol>
    <li>To start using fractions, import the <code>fractions</code> module.
    <li>To define a fraction, create a <code>Fraction</code> object and pass in the numerator and denominator.
    <li>You can perform all the usual mathematical operations with fractions. Operations return a new <code>Fraction</code> object. <code>2 * (1/3) = (2/3)</code>
    <li>The <code>Fraction</code> object will automatically reduce fractions. <code>(6/4) = (3/2)</code>
    <li>Python has the good sense not to create a fraction with a zero denominator.
    </ol>
    <h3 id=trig>Trigonometry</h3>
    <p>You can also do basic trigonometry in Python.
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>import math</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>math.pi</kbd>                <span class=u>&#x2460;</span></a>
    <samp class=pp>3.1415926535897931</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>math.sin(math.pi / 2)</kbd>  <span class=u>&#x2461;</span></a>
    <samp class=pp>1.0</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>math.tan(math.pi / 4)</kbd>  <span class=u>&#x2462;</span></a>
    <samp class=pp>0.99999999999999989</samp></pre>
    <ol>
    <li>The <code>math</code> module has a constant for &pi;, the ratio of a circle&#8217;s circumference to its diameter.
    <li>The <code>math</code> module has all the basic trigonometric functions, including <code>sin()</code>, <code>cos()</code>, <code>tan()</code>, and variants like <code>asin()</code>.
    <li>Note, however, that Python does not have infinite precision. <code>tan(&pi; / 4)</code> should return <code>1.0</code>, not <code>0.99999999999999989</code>.
    </ol>
    <h3 id=numbers-in-a-boolean-context>Numbers In A Boolean Context</h3>
    <aside>Zero values are false, and non-zero values are true.</aside>
    <p>You can use numbers <a href=#booleans>in a boolean context</a>, such as an <code>if</code> statement. Zero values are false, and non-zero values are true.
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>def is_it_true(anything):</kbd>             <span class=u>&#x2460;</span></a>
    <samp class=p>... </samp><kbd class=pp>  if anything:</kbd>
    <samp class=p>... </samp><kbd class=pp>    print("yes, it's true")</kbd>
    <samp class=p>... </samp><kbd class=pp>  else:</kbd>
    <samp class=p>... </samp><kbd class=pp>    print("no, it's false")</kbd>
    <samp class=p>...</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>is_it_true(1)</kbd>                         <span class=u>&#x2461;</span></a>
    <samp>yes, it's true</samp>
    <samp class=p>>>> </samp><kbd class=pp>is_it_true(-1)</kbd>
    <samp>yes, it's true</samp>
    <samp class=p>>>> </samp><kbd class=pp>is_it_true(0)</kbd>
    <samp>no, it's false</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>is_it_true(0.1)</kbd>                       <span class=u>&#x2462;</span></a>
    <samp>yes, it's true</samp>
    <samp class=p>>>> </samp><kbd class=pp>is_it_true(0.0)</kbd>
    <samp>no, it's false</samp>
    <samp class=p>>>> </samp><kbd class=pp>import fractions</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>is_it_true(fractions.Fraction(1, 2))</kbd>  <span class=u>&#x2463;</span></a>
    <samp>yes, it's true</samp>
    <samp class=p>>>> </samp><kbd class=pp>is_it_true(fractions.Fraction(0, 1))</kbd>
    <samp>no, it's false</samp></pre>
    <ol>
    <li>Did you know you can define your own functions in the Python interactive shell? Just press <kbd>ENTER</kbd> at the end of each line, and <kbd>ENTER</kbd> on a blank line to finish.
    <li>In a boolean context, non-zero integers are true; 0 is false.
    <li>Non-zero floating point numbers are true; <code>0.0</code> is false. Be careful with this one! If there&#8217;s the slightest rounding error (not impossible, as you saw in the previous section) then Python will be testing <code>0.0000000000001</code> instead of 0 and will return <code>True</code>.
    <li>Fractions can also be used in a boolean context. <code>Fraction(0, n)</code> is false for all values of <var>n</var>. All other fractions are true.
    </ol>
    <p class=a>&#x2042;
    
    <h2 id=lists>Lists</h2>
    <p>Lists are Python&#8217;s workhorse datatype. When I say &#8220;<dfn>list</dfn>,&#8221; you might be thinking &#8220;array whose size I have to declare in advance, that can only contain items of the same type, <i class=baa>&amp;</i>c.&#8221; Don&#8217;t think that. Lists are much cooler than that.
    <blockquote class='note compare perl5'>
    <p><span class=u>&#x261E;</span>A list in Python is like an array in Perl 5. In Perl 5, variables that store arrays always start with the <code>@</code> character; in Python, variables can be named anything, and Python keeps track of the datatype internally.
    </blockquote>
    <blockquote class='note compare java'>
    <p><span class=u>&#x261E;</span>A list in Python is much more than an array in Java (although it can be used as one if that&#8217;s really all you want out of life). A better analogy would be to the <code>ArrayList</code> class, which can hold arbitrary objects and can expand dynamically as new items are added.
    </blockquote>
    <h3 id=creatinglists>Creating A List</h3>
    <p>Creating a list is easy: use square brackets to wrap a comma-separated list of values.
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list = ['a', 'b', 'mpilgrim', 'z', 'example']</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_list</kbd>
    <samp class=pp>['a', 'b', 'mpilgrim', 'z', 'example']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list[0]</kbd>                                        <span class=u>&#x2461;</span></a>
    <samp class=pp>'a'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list[4]</kbd>                                        <span class=u>&#x2462;</span></a>
    <samp class=pp>'example'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list[-1]</kbd>                                       <span class=u>&#x2463;</span></a>
    <samp class=pp>'example'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list[-3]</kbd>                                       <span class=u>&#x2464;</span></a>
    <samp class=pp>'mpilgrim'</samp></pre>
    <ol>
    <li>First, you define a list of five items. Note that they retain their original order. This is not an accident. A list is an ordered set of items.
    <li>A list can be used like a zero-based array. The first item of any non-empty list is always <code>a_list[0]</code>.
    <li>The last item of this five-item list is <code>a_list[4]</code>, because lists are always zero-based.
    <li>A negative index accesses items from the end of the list counting backwards. The last item of any non-empty list is always <code>a_list[-1]</code>.
    <li>If the negative index is confusing to you, think of it this way: <code>a_list[-<var>n</var>] == a_list[len(a_list) - <var>n</var>]</code>. So in this list, <code>a_list[-3] == a_list[5 - 3] == a_list[2]</code>.
    </ol>
    <h3 id=slicinglists>Slicing A List</h3>
    <aside>a_list[0] is the first item of a_list.</aside>
    <p>Once you&#8217;ve defined a list, you can get any part of it as a new list. This is called <i>slicing</i> the list.
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_list</kbd>
    <samp class=pp>['a', 'b', 'mpilgrim', 'z', 'example']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list[1:3]</kbd>            <span class=u>&#x2460;</span></a>
    <samp class=pp>['b', 'mpilgrim']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list[1:-1]</kbd>           <span class=u>&#x2461;</span></a>
    <samp class=pp>['b', 'mpilgrim', 'z']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list[0:3]</kbd>            <span class=u>&#x2462;</span></a>
    <samp class=pp>['a', 'b', 'mpilgrim']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list[:3]</kbd>             <span class=u>&#x2463;</span></a>
    <samp class=pp>['a', 'b', 'mpilgrim']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list[3:]</kbd>             <span class=u>&#x2464;</span></a>
    <samp class=pp>['z', 'example']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list[:]</kbd>              <span class=u>&#x2465;</span></a>
    <samp class=pp>['a', 'b', 'mpilgrim', 'z', 'example']</samp></pre>
    <ol>
    <li>You can get a part of a list, called a &#8220;slice&#8221;, by specifying two indices. The return value is a new list containing all the items of the list, in order, starting with the first slice index (in this case <code>a_list[1]</code>), up to but not including the second slice index (in this case <code>a_list[3]</code>).
    <li>Slicing works if one or both of the slice indices is negative. If it helps, you can think of it this way: reading the list from left to right, the first slice index specifies the first item you want, and the second slice index specifies the first item you don&#8217;t want. The return value is everything in between.
    <li>Lists are zero-based, so <code>a_list[0:3]</code> returns the first three items of the list, starting at <code>a_list[0]</code>, up to but not including <code>a_list[3]</code>.
    <li>If the left slice index is 0, you can leave it out, and 0 is implied. So <code>a_list[:3]</code> is the same as <code>a_list[0:3]</code>, because the starting 0 is implied.
    <li>Similarly, if the right slice index is the length of the list, you can leave it out. So <code>a_list[3:]</code> is the same as <code>a_list[3:5]</code>, because this list has five items.  There is a pleasing symmetry here. In this five-item list, <code>a_list[:3]</code> returns the first 3 items, and <code>a_list[3:]</code> returns the last two items. In fact, <code>a_list[:<var>n</var>]</code> will always return the first <var>n</var> items, and <code>a_list[<var>n</var>:]</code> will return the rest, regardless of the length of the list.
    <li>If both slice indices are left out, all items of the list are included. But this is not the same as the original <var>a_list</var> variable. It is a new list that happens to have all the same items. <code>a_list[:]</code> is shorthand for making a complete copy of a list.
    </ol>
    <h3 id=extendinglists>Adding Items To A List</h3>
    <p>There are four ways to add items to a list.
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_list = ['a']</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list = a_list + [2.0, 3]</kbd>    <span class=u>&#x2460;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list</kbd>                        <span class=u>&#x2461;</span></a>
    <samp class=pp>['a', 2.0, 3]</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list.append(True)</kbd>           <span class=u>&#x2462;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_list</kbd>
    <samp class=pp>['a', 2.0, 3, True]</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list.extend(['four', '&Omega;'])</kbd>  <span class=u>&#x2463;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_list</kbd>
    <samp class=pp>['a', 2.0, 3, True, 'four', '&Omega;']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list.insert(0, '&Omega;')</kbd>         <span class=u>&#x2464;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_list</kbd>
    <samp class=pp>['&Omega;', 'a', 2.0, 3, True, 'four', '&Omega;']</samp></pre>
    <ol>
    <li>The <code>+</code> operator concatenates lists to create a new list. A list can contain any number of items; there is no size limit (other than available memory). However, if memory is a concern, you should be aware that list concatenation creates a second list in memory. In this case, that new list is immediately assigned to the existing variable <var>a_list</var>. So this line of code is really a two-step process&nbsp;&mdash;&nbsp;concatenation then assignment&nbsp;&mdash;&nbsp;which can (temporarily) consume a lot of memory when you&#8217;re dealing with large lists.
    <li>A list can contain items of any datatype, and the items in a single list don&#8217;t all need to be the same type. Here we have a list containing a string, a floating point number, and an integer.
    <li>The <code>append()</code> method adds a single item to the end of the list. (Now we have <em>four</em> different datatypes in the list!)
    <li>Lists are implemented as classes.  &#8220;Creating&#8221; a list is really instantiating a class.  As such, a list has methods that operate on it. The <code>extend()</code> method takes one argument, a list, and appends each of the items of the argument to the original list.
    <li>The <code>insert()</code> method inserts a single item into a list. The first argument is the index of the first item in the list that will get bumped out of position. List items do not need to be unique; for example, there are now two separate items with the value <code>'&Omega;'</code>: the first item, <code>a_list[0]</code>, and the last item, <code>a_list[6]</code>.
    </ol>
    
    <blockquote class='note compare perl'>
    <p><span class=u>&#x261E;</span><code><var>a_list</var>.insert(0, <var>value</var>)</code> is like the <code>unshift()</code> function in Perl. It adds an item to the beginning of the list, and all the other items have their positional index bumped up to make room.
    </blockquote>
    
    <p>Let&#8217;s look closer at the difference between <code>append()</code> and <code>extend()</code>.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_list = ['a', 'b', 'c']</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list.extend(['d', 'e', 'f'])</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_list</kbd>
    <samp class=pp>['a', 'b', 'c', 'd', 'e', 'f']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>len(a_list)</kbd>                     <span class=u>&#x2461;</span></a>
    <samp class=pp>6</samp>
    <samp class=p>>>> </samp><kbd class=pp>a_list[-1]</kbd>
    <samp class=pp>'f'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list.append(['g', 'h', 'i'])</kbd>  <span class=u>&#x2462;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_list</kbd>
    <samp class=pp>['a', 'b', 'c', 'd', 'e', 'f', ['g', 'h', 'i']]</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>len(a_list)</kbd>                     <span class=u>&#x2463;</span></a>
    <samp class=pp>7</samp>
    <samp class=p>>>> </samp><kbd class=pp>a_list[-1]</kbd>
    <samp class=pp>['g', 'h', 'i']</samp></pre>
    <ol>
    <li>The <code>extend()</code> method takes a single argument, which is always a list, and adds each of the items of that list to <var>a_list</var>.
    <li>If you start with a list of three items and extend it with a list of another three items, you end up with a list of six items.
    <li>On the other hand, the <code>append()</code> method takes a single argument, which can be any datatype. Here, you&#8217;re calling the <code>append()</code> method with a list of three items.
    <li>If you start with a list of six items and append a list onto it, you end up with... a list of seven items. Why seven? Because the last item (which you just appended) <em>is itself a list</em>. Lists can contain any type of data, including other lists. That may be what you want, or it may not. But it&#8217;s what you asked for, and it&#8217;s what you got.
    </ol>
    <h3 id=searchinglists>Searching For Values In A List</h3>
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_list = ['a', 'b', 'new', 'mpilgrim', 'new']</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list.count('new')</kbd>       <span class=u>&#x2460;</span></a>
    <samp class=pp>2</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>'new' in a_list</kbd>           <span class=u>&#x2461;</span></a>
    <samp class=pp>True</samp>
    <samp class=p>>>> </samp><kbd class=pp>'c' in a_list</kbd>
    <samp class=pp>False</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list.index('mpilgrim')</kbd>  <span class=u>&#x2462;</span></a>
    <samp class=pp>3</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list.index('new')</kbd>       <span class=u>&#x2463;</span></a>
    <samp class=pp>2</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list.index('c')</kbd>         <span class=u>&#x2464;</span></a>
    <samp class=traceback>Traceback (innermost last):
      File "&lt;interactive input>", line 1, in ?
    ValueError: list.index(x): x not in list</samp></pre>
    <ol>
    <li>As you might expect, the <code>count()</code> method returns the number of occurrences of a specific value in a list.
    <li>If all you want to know is whether a value is in the list or not, the <code>in</code> operator is slightly faster than using the <code>count()</code> method. The <code>in</code> operator always returns <code>True</code> or <code>False</code>; it will not tell you how many times the value appears in the list.
    <li>Neither the <code>in</code> operator nor the <code>count()</code> method will tell you <em>where</em> in the list a value appears. If you need to know where in the list a value is, call the <code>index()</code> method. By default it will search the entire list, although you can specify an optional second argument of the (0-based) index to start from, and even an optional third argument of the (0-based) index to stop searching.
    <li>The <code>index()</code> method finds the <em>first</em> occurrence of a value in the list. In this case, <code>'new'</code> occurs twice in the list, in <code>a_list[2]</code> and <code>a_list[4]</code>, but the <code>index()</code> method will return only the index of the first occurrence.
    <li>As you might <em>not</em> expect, if the value is not found in the list, the <code>index()</code> method will raise an exception.
    </ol>
    
    <p>Wait, what? That&#8217;s right: the <code>index()</code> method raises an exception if it doesn&#8217;t find the value in the list. This is notably different from most languages, which will return some invalid index (like <code>-1</code>). While this may seem annoying at first, I think you will come to appreciate it. It means your program will crash at the source of the problem instead of failing strangely and silently later. Remember, <a href=#creatinglists><code>-1</code> is a valid list index</a>. If the <code>index()</code> method returned <code>-1</code>, that could lead to some not-so-fun debugging sessions!
    
    <h3 id=removingfromlists>Removing Items From A List</h3>
    
    <aside>Lists never have gaps.</aside>
    
    <p>Lists can expand and contract automatically. You&#8217;ve seen the expansion part. There are several different ways to remove items from a list as well.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_list = ['a', 'b', 'new', 'mpilgrim', 'new']</kbd>
    <samp class=p>>>> </samp><kbd class=pp>a_list[1]</kbd>
    <samp class=pp>'b'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>del a_list[1]</kbd>         <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_list</kbd>
    <samp class=pp>['a', 'new', 'mpilgrim', 'new']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list[1]</kbd>             <span class=u>&#x2461;</span></a>
    <samp class=pp>'new'</samp></pre>
    <ol>
    <li>You can use the <code><dfn>del</dfn></code> statement to delete a specific item from a list.
    <li>Accessing index <code>1</code> after deleting index <code>1</code> does <em>not</em> result in an error. All items after the deleted item shift their positional index to &#8220;fill the gap&#8221; created by deleting the item.
    </ol>
    
    <p>Don&#8217;t know the positional index? Not a problem; you can remove items by value instead.
    
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list.remove('new')</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_list</kbd>
    <samp class=pp>['a', 'mpilgrim', 'new']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list.remove('new')</kbd>  <span class=u>&#x2461;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_list</kbd>
    <samp class=pp>['a', 'mpilgrim']</samp>
    <samp class=p>>>> </samp><kbd class=pp>a_list.remove('new')</kbd>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
    ValueError: list.remove(x): x not in list</samp></pre>
    <ol>
    <li>You can also remove an item from a list with the <code>remove()</code> method. The <code>remove()</code> method takes a <em>value</em> and removes the first occurrence of that value from the list. Again, all items after the deleted item will have their positional indices bumped down to &#8220;fill the gap.&#8221; Lists never have gaps.
    <li>You can call the <code>remove()</code> method as often as you like, but it will raise an exception if you try to remove a value that isn&#8217;t in the list.
    </ol>
    
    <h3 id=popgoestheweasel>Removing Items From A List: Bonus Round</h3>
    
    <p>Another interesting list method is <code>pop()</code>. The <code>pop()</code> method is yet another way to <a href=#removingfromlists>remove items from a list</a>, but with a twist.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_list = ['a', 'b', 'new', 'mpilgrim']</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list.pop()</kbd>   <span class=u>&#x2460;</span></a>
    <samp class=pp>'mpilgrim'</samp>
    <samp class=p>>>> </samp><kbd class=pp>a_list</kbd>
    <samp class=pp>['a', 'b', 'new']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list.pop(1)</kbd>  <span class=u>&#x2461;</span></a>
    <samp class=pp>'b'</samp>
    <samp class=p>>>> </samp><kbd class=pp>a_list</kbd>
    <samp class=pp>['a', 'new']</samp>
    <samp class=p>>>> </samp><kbd class=pp>a_list.pop()</kbd>
    <samp class=pp>'new'</samp>
    <samp class=p>>>> </samp><kbd class=pp>a_list.pop()</kbd>
    <samp class=pp>'a'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list.pop()</kbd>   <span class=u>&#x2462;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
    IndexError: pop from empty list</samp></pre>
    <ol>
    <li>When called without arguments, the <code>pop()</code> list method removes the last item in the list <em>and returns the value it removed</em>.
    <li>You can pop arbitrary items from a list. Just pass a positional index to the <code>pop()</code> method. It will remove that item, shift all the items after it to &#8220;fill the gap,&#8221; and return the value it removed.
    <li>Calling <code>pop()</code> on an empty list raises an exception.
    </ol>
    
    <blockquote class='note compare perl'>
    <p><span class=u>&#x261E;</span>Calling the <code>pop()</code> list method without an argument is like the <code>pop()</code> function in Perl. It removes the last item from the list and returns the value of the removed item. Perl has another function, <code>shift()</code>, which removes the first item and returns its value; in Python, this is equivalent to <code><var>a_list</var>.pop(0)</code>.
    </blockquote>
    
    <h3 id=lists-in-a-boolean-context>Lists In A Boolean Context</h3>
    <aside>Empty lists are false; all other lists are true.</aside>
    <p>You can also use a list in <a href=#booleans>a boolean context</a>, such as an <code>if</code> statement.
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>def is_it_true(anything):</kbd>
    <samp class=p>... </samp><kbd class=pp>  if anything:</kbd>
    <samp class=p>... </samp><kbd class=pp>    print("yes, it's true")</kbd>
    <samp class=p>... </samp><kbd class=pp>  else:</kbd>
    <samp class=p>... </samp><kbd class=pp>    print("no, it's false")</kbd>
    <samp class=p>...</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>is_it_true([])</kbd>             <span class=u>&#x2460;</span></a>
    <samp>no, it's false</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>is_it_true(['a'])</kbd>          <span class=u>&#x2461;</span></a>
    <samp>yes, it's true</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>is_it_true([False])</kbd>        <span class=u>&#x2462;</span></a>
    <samp>yes, it's true</samp></pre>
    <ol>
    <li>In a boolean context, an empty list is false.
    <li>Any list with at least one item is true.
    <li>Any list with at least one item is true. The value of the items is irrelevant.
    </ol>
    
    <p class=a>&#x2042;
    
    <h2 id=tuples>Tuples</h2>
    
    <p>A <dfn>tuple</dfn> is an immutable list.  A tuple can not be changed in any way once it is created.
    
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>a_tuple = ("a", "b", "mpilgrim", "z", "example")</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_tuple</kbd>
    <samp class=pp>('a', 'b', 'mpilgrim', 'z', 'example')</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_tuple[0]</kbd>                                        <span class=u>&#x2461;</span></a>
    <samp class=pp>'a'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_tuple[-1]</kbd>                                       <span class=u>&#x2462;</span></a>
    <samp class=pp>'example'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_tuple[1:3]</kbd>                                      <span class=u>&#x2463;</span></a>
    <samp class=pp>('b', 'mpilgrim')</samp></pre>
    <ol>
    <li>A tuple is defined in the same way as a list, except that the whole set of elements is enclosed in parentheses instead of square brackets.
    <li>The elements of a tuple have a defined order, just like a list. Tuple indices are zero-based, just like a list, so the first element of a non-empty tuple is always <code>a_tuple[0]</code>.
    <li>Negative indices count from the end of the tuple, just like a list.
    <li>Slicing works too, just like a list. When you slice a list, you get a new list; when you slice a tuple, you get a new tuple.
    </ol>
    
    <p>The major difference between tuples and lists is that tuples can not be changed. In technical terms, tuples are <dfn>immutable</dfn>. In practical terms, they have no methods that would allow you to change them. Lists have methods like <code>append()</code>, <code>extend()</code>, <code>insert()</code>, <code>remove()</code>, and <code>pop()</code>. Tuples have none of these methods. You can slice a tuple (because that creates a new tuple), and you can check whether a tuple contains a particular value (because that doesn&#8217;t change the tuple), and&hellip; that&#8217;s about it.
    
    <pre class=screen>
    # continued from the previous example
    <samp class=p>>>> </samp><kbd class=pp>a_tuple</kbd>
    <samp class=pp>('a', 'b', 'mpilgrim', 'z', 'example')</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_tuple.append("new")</kbd>               <span class=u>&#x2460;</span></a>
    <samp class=traceback>Traceback (innermost last):
      File "&lt;interactive input>", line 1, in ?
    AttributeError: 'tuple' object has no attribute 'append'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_tuple.remove("z")</kbd>                 <span class=u>&#x2461;</span></a>
    <samp class=traceback>Traceback (innermost last):
      File "&lt;interactive input>", line 1, in ?
    AttributeError: 'tuple' object has no attribute 'remove'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_tuple.index("example")</kbd>            <span class=u>&#x2462;</span></a>
    <samp class=pp>4</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>"z" in a_tuple</kbd>                      <span class=u>&#x2463;</span></a>
    <samp class=pp>True</samp></pre>
    <ol>
    <li>You can&#8217;t add elements to a tuple. Tuples have no <code>append()</code> or <code>extend()</code> method.
    <li>You can&#8217;t remove elements from a tuple. Tuples have no <code>remove()</code> or <code>pop()</code> method.
    <li>You <em>can</em> find elements in a tuple, since this doesn&#8217;t change the tuple.
    <li>You can also use the <code>in</code> operator to check if an element exists in the tuple.
    </ol>
    
    <p>So what are tuples good for?</p> 
    
    <ul> 
    <li>Tuples are faster than lists.  If you&#8217;re defining a constant set of values and all you&#8217;re ever going to do with it is iterate through it, use a tuple instead of a list.
    <li>It makes your code safer if you &#8220;write-protect&#8221; data that doesn&#8217;t need to be changed. Using a tuple instead of a list is like having an implied <code>assert</code> statement that shows this data is constant, and that special thought (and a specific function) is required to override that.
    <li>Some tuples can be used as dictionary keys (specifically, tuples that contain <i>immutable</i> values like strings, numbers, and other tuples). Lists can never be used as dictionary keys, because lists are not immutable.
    </ul>
    
    <blockquote class=note>
    <p><span class=u>&#x261E;</span>Tuples can be converted into lists, and vice-versa. The built-in <code>tuple()</code> function takes a list and returns a tuple with the same elements, and the <code>list()</code> function takes a tuple and returns a list. In effect, <code>tuple()</code> freezes a list, and <code>list()</code> thaws a tuple.
    </blockquote>
    
    <h3 id=tuples-in-a-boolean-context>Tuples In A Boolean Context</h3>
    
    <p>You can use tuples in <a href=#booleans>a boolean context</a>, such as an <code>if</code> statement.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>def is_it_true(anything):</kbd>
    <samp class=p>... </samp><kbd class=pp>  if anything:</kbd>
    <samp class=p>... </samp><kbd class=pp>    print("yes, it's true")</kbd>
    <samp class=p>... </samp><kbd class=pp>  else:</kbd>
    <samp class=p>... </samp><kbd class=pp>    print("no, it's false")</kbd>
    <samp class=p>...</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>is_it_true(())</kbd>             <span class=u>&#x2460;</span></a>
    <samp>no, it's false</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>is_it_true(('a', 'b'))</kbd>     <span class=u>&#x2461;</span></a>
    <samp>yes, it's true</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>is_it_true((False,))</kbd>       <span class=u>&#x2462;</span></a>
    <samp>yes, it's true</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>type((False))</kbd>              <span class=u>&#x2463;</span></a>
    <samp class=pp>&lt;class 'bool'></samp>
    <samp class=p>>>> </samp><kbd class=pp>type((False,))</kbd>
    <samp class=pp>&lt;class 'tuple'></samp></pre>
    <ol>
    <li>In a boolean context, an empty tuple is false.
    <li>Any tuple with at least one item is true.
    <li>Any tuple with at least one item is true. The value of the items is irrelevant. But what&#8217;s that comma doing there?
    <li>To create a tuple of one item, you need a comma after the value. Without the comma, Python just assumes you have an extra pair of parentheses, which is harmless, but it doesn&#8217;t create a tuple.
    </ol>
    
    <h3 id=multivar>Assigning Multiple Values At Once</h3>
    
    <p>Here&#8217;s a cool programming shortcut: in Python, you can use a tuple to assign multiple values at once.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>v = ('a', 2, True)</kbd>
    <a><samp class=p>>>> </samp><kbd>(x, y, z) = v</kbd>       <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>x</kbd>
    <samp class=pp>'a'</samp>
    <samp class=p>>>> </samp><kbd class=pp>y</kbd>
    <samp class=pp>2</samp>
    <samp class=p>>>> </samp><kbd class=pp>z</kbd>
    <samp class=pp>True</samp></pre>
    <ol>
    <li><var>v</var> is a tuple of three elements, and <code>(x, y, z)</code> is a tuple of three variables. Assigning one to the other assigns each of the values of <var>v</var> to each of the variables, in order.
    </ol>
    
    <p>This has all kinds of uses. Suppose you want to assign names to a range of values. You can use the built-in <code>range()</code> function with multi-variable assignment to quickly assign consecutive values.
    
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7)</kbd>  <span class=u>&#x2460;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>MONDAY</kbd>                                                                       <span class=u>&#x2461;</span></a>
    <samp class=pp>0</samp>
    <samp class=p>>>> </samp><kbd class=pp>TUESDAY</kbd>
    <samp class=pp>1</samp>
    <samp class=p>>>> </samp><kbd class=pp>SUNDAY</kbd>
    <samp class=pp>6</samp></pre>
    <ol>
    <li>The built-in <code>range()</code> function constructs a sequence of integers. (Technically, the <code>range()</code> function returns an <a href=iterators.html>iterator</a>, not a list or a tuple, but you&#8217;ll learn about that distinction later.) <var>MONDAY</var>, <var>TUESDAY</var>, <var>WEDNESDAY</var>, <var>THURSDAY</var>, <var>FRIDAY</var>, <var>SATURDAY</var>, and <var>SUNDAY</var> are the variables you&#8217;re defining. (This example came from the <code>calendar</code> module, a fun little module that prints calendars, like the <abbr>UNIX</abbr> program <code>cal</code>. The <code>calendar</code> module defines integer constants for days of the week.)
    <li>Now each variable has its value: <var>MONDAY</var> is 0, <var>TUESDAY</var> is <code>1</code>, and so forth.
    </ol>
    
    <p>You can also use multi-variable assignment to build functions that return multiple values, simply by returning a tuple of all the values. The caller can treat it as a single tuple, or it can assign the values to individual variables. Many standard Python libraries do this, including the <code>os</code> module, which you'll learn about in <a href=comprehensions.html#os>the next chapter</a>.
    
    <p class=a>&#x2042;
    
    <h2 id=sets>Sets</h2>
    
    <p>A <dfn>set</dfn> is an unordered &#8220;bag&#8221; of unique values. A single set can contain values of any immutable datatype. Once you have two sets, you can do standard set operations like union, intersection, and set difference.
    
    <h3 id=creating-a-set>Creating A Set</h3>
    
    <p>First things first. Creating a set is easy.
    
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set = {1}</kbd>     <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_set</kbd>
    <samp class=pp>{1}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>type(a_set)</kbd>     <span class=u>&#x2461;</span></a>
    <samp class=pp>&lt;class 'set'></samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set = {1, 2}</kbd>  <span class=u>&#x2462;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_set</kbd>
    <samp class=pp>{1, 2}</samp></pre>
    <ol>
    <li>To create a set with one value, put the value in curly brackets (<code>{}</code>).
    <li>Sets are actually implemented as <a href=iterators.html#defining-classes>classes</a>, but don&#8217;t worry about that for now.
    <li>To create a set with multiple values, separate the values with commas and wrap it all up with curly brackets.
    </ol>
    
    <p>You can also create a set out of a <a href=#lists>list</a>.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_list = ['a', 'b', 'mpilgrim', True, False, 42]</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set = set(a_list)</kbd>                           <span class=u>&#x2460;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set</kbd>                                         <span class=u>&#x2461;</span></a>
    <samp class=pp>{'a', False, 'b', True, 'mpilgrim', 42}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list</kbd>                                        <span class=u>&#x2462;</span></a>
    <samp class=pp>['a', 'b', 'mpilgrim', True, False, 42]</samp></pre>
    <ol>
    <li>To create a set from a list, use the <code>set()</code> function. (Pedants who know about how sets are implemented will point out that this is not really calling a function, but instantiating a class. I <em>promise</em> you will learn the difference later in this book. For now, just know that <code>set()</code> acts like a function, and it returns a set.)
    <li>As I mentioned earlier, a single set can contain values of any datatype. And, as I mentioned earlier, sets are <em>unordered</em>. This set does not remember the original order of the list that was used to create it. If you were to add items to this set, it would not remember the order in which you added them.
    <li>The original list is unchanged.
    </ol>
    
    <p id=emptyset>Don&#8217;t have any values yet? Not a problem. You can create an empty set.
    
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set = set()</kbd>    <span class=u>&#x2460;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set</kbd>            <span class=u>&#x2461;</span></a>
    <samp class=pp>set()</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>type(a_set)</kbd>      <span class=u>&#x2462;</span></a>
    <samp class=pp>&lt;class 'set'></samp>
    <a><samp class=p>>>> </samp><kbd class=pp>len(a_set)</kbd>       <span class=u>&#x2463;</span></a>
    <samp class=pp>0</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>not_sure = {}</kbd>    <span class=u>&#x2464;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>type(not_sure)</kbd>
    <samp class=pp>&lt;class 'dict'></samp></pre>
    <ol>
    <li>To create an empty set, call <code>set()</code> with no arguments.
    <li>The printed representation of an empty set looks a bit strange. Were you expecting <code>{}</code>, perhaps? That would denote an empty dictionary, not an empty set. You&#8217;ll learn about dictionaries later in this chapter.
    <li>Despite the strange printed representation, this <em>is</em> a set&hellip;
    <li>&hellip;and this set has no members.
    <li>Due to historical quirks carried over from Python 2, you can not create an empty set with two curly brackets. This actually creates an empty dictionary, not an empty set.
    </ol>
    
    <h3 id=modifying-sets>Modifying A Set</h3>
    
    <p>There are two different ways to add values to an existing set: the <code>add()</code> method, and the <code>update()</code> method.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_set = {1, 2}</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.add(4)</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_set</kbd>
    <samp class=pp>{1, 2, 4}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>len(a_set)</kbd>    <span class=u>&#x2461;</span></a>
    <samp class=pp>3</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.add(1)</kbd>  <span class=u>&#x2462;</span></a>
    <samp class=pp>>>> </samp><kbd class=pp>a_set</kbd>
    <samp class=pp>{1, 2, 4}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>len(a_set)</kbd>    <span class=u>&#x2463;</span></a>
    <samp class=pp>3</samp></pre>
    <ol>
    <li>The <code>add()</code> method takes a single argument, which can be any datatype, and adds the given value to the set.
    <li>This set now has 3 members.
    <li>Sets are bags of <em>unique values</em>. If you try to add a value that already exists in the set, it will do nothing. It won&#8217;t raise an error; it&#8217;s just a no-op.
    <li>This set <em>still</em> has 3 members.
    </ol>
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_set = {1, 2, 3}</kbd>
    <samp class=p>>>> </samp><kbd class=pp>a_set</kbd>
    <samp class=pp>{1, 2, 3}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.update({2, 4, 6})</kbd>                       <span class=u>&#x2460;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set</kbd>                                         <span class=u>&#x2461;</span></a>
    <samp class=pp>{1, 2, 3, 4, 6}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.update({3, 6, 9}, {1, 2, 3, 5, 8, 13})</kbd>  <span class=u>&#x2462;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_set</kbd>
    <samp class=pp>{1, 2, 3, 4, 5, 6, 8, 9, 13}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.update([10, 20, 30])</kbd>                    <span class=u>&#x2463;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_set</kbd>
    <samp class=pp>{1, 2, 3, 4, 5, 6, 8, 9, 10, 13, 20, 30}</samp></pre>
    <ol>
    <li>The <code>update()</code> method takes one argument, a set, and adds all its members to the original set. It&#8217;s as if you called the <code>add()</code> method with each member of the set.
    <li>Duplicate values are ignored, since sets can not contain duplicates.
    <li>You can actually call the <code>update()</code> method with any number of arguments. When called with two sets, the <code>update()</code> method adds all the members of each set to the original set (dropping duplicates).
    <li>The <code>update()</code> method can take objects of a number of different datatypes, including lists. When called with a list, the <code>update()</code> method adds all the items of the list to the original set.
    </ol>
    
    <h3 id=removing-from-sets>Removing Items From A Set</h3>
    
    <p>There are three ways to remove individual values from a set. The first two, <code>discard()</code> and <code>remove()</code>, have one subtle difference.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45}</kbd>
    <samp class=p>>>> </samp><kbd class=pp>a_set</kbd>
    <samp class=pp>{1, 3, 36, 6, 10, 45, 15, 21, 28}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.discard(10)</kbd>                        <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_set</kbd>
    <samp class=pp>{1, 3, 36, 6, 45, 15, 21, 28}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.discard(10)</kbd>                        <span class=u>&#x2461;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_set</kbd>
    <samp class=pp>{1, 3, 36, 6, 45, 15, 21, 28}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.remove(21)</kbd>                         <span class=u>&#x2462;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_set</kbd>
    <samp class=pp>{1, 3, 36, 6, 45, 15, 28}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.remove(21)</kbd>                         <span class=u>&#x2463;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
    KeyError: 21</samp></pre>
    <ol>
    <li>The <code>discard()</code> method takes a single value as an argument and removes that value from the set.
    <li>If you call the <code>discard()</code> method with a value that doesn&#8217;t exist in the set, it does nothing. No error; it&#8217;s just a no-op.
    <li>The <code>remove()</code> method also takes a single value as an argument, and it also removes that value from the set.
    <li>Here&#8217;s the difference: if the value doesn&#8217;t exist in the set, the <code>remove()</code> method raises a <code>KeyError</code> exception.
    </ol>
    
    <p>Like lists, sets have a <code>pop()</code> method.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45}</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.pop()</kbd>                                <span class=u>&#x2460;</span></a>
    <samp class=pp>1</samp>
    <samp class=p>>>> </samp><kbd class=pp>a_set.pop()</kbd>
    <samp class=pp>3</samp>
    <samp class=p>>>> </samp><kbd class=pp>a_set.pop()</kbd>
    <samp class=pp>36</samp>
    <samp class=p>>>> </samp><kbd class=pp>a_set</kbd>
    <samp class=pp>{6, 10, 45, 15, 21, 28}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.clear()</kbd>                              <span class=u>&#x2461;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_set</kbd>
    <samp class=pp>set()</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.pop()</kbd>                                <span class=u>&#x2462;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
    KeyError: 'pop from an empty set'</samp></pre>
    <ol>
    <li>The <code>pop()</code> method removes a single value from a set and returns the value. However, since sets are unordered, there is no &#8220;last&#8221; value in a set, so there is no way to control which value gets removed. It is completely arbitrary.
    <li>The <code>clear()</code> method removes <em>all</em> values from a set, leaving you with an empty set. This is equivalent to <code>a_set = set()</code>, which would create a new empty set and overwrite the previous value of the <var>a_set</var> variable.
    <li>Attempting to pop a value from an empty set will raise a <code>KeyError</code> exception.
    </ol>
    
    <h3 id=common-set-operations>Common Set Operations</h3>
    
    <p>Python&#8217;s <code>set</code> type supports several common set operations.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_set = {2, 4, 5, 9, 12, 21, 30, 51, 76, 127, 195}</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>30 in a_set</kbd>                                                     <span class=u>&#x2460;</span></a>
    <samp class=pp>True</samp>
    <samp class=p>>>> </samp><kbd class=pp>31 in a_set</kbd>
    <samp class=pp>False</samp>
    <samp class=p>>>> </samp><kbd class=pp>b_set = {1, 2, 3, 5, 6, 8, 9, 12, 15, 17, 18, 21}</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.union(b_set)</kbd>                                              <span class=u>&#x2461;</span></a>
    <samp class=pp>{1, 2, 195, 4, 5, 6, 8, 12, 76, 15, 17, 18, 3, 21, 30, 51, 9, 127}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.intersection(b_set)</kbd>                                       <span class=u>&#x2462;</span></a>
    <samp class=pp>{9, 2, 12, 5, 21}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.difference(b_set)</kbd>                                         <span class=u>&#x2463;</span></a>
    <samp class=pp>{195, 4, 76, 51, 30, 127}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.symmetric_difference(b_set)</kbd>                               <span class=u>&#x2464;</span></a>
    <samp class=pp>{1, 3, 4, 6, 8, 76, 15, 17, 18, 195, 127, 30, 51}</samp></pre>
    <ol>
    <li>To test whether a value is a member of a set, use the <code>in</code> operator. This works the same as lists.
    <li>The <code>union()</code> method returns a new set containing all the elements that are in <em>either</em> set.
    <li>The <code>intersection()</code> method returns a new set containing all the elements that are in <em>both</em> sets.
    <li>The <code>difference()</code> method returns a new set containing all the elements that are in <var>a_set</var> but not <var>b_set</var>.
    <li>The <code>symmetric_difference()</code> method returns a new set containing all the elements that are in <em>exactly one</em> of the sets.
    </ol>
    
    <p>Three of these methods are symmetric.
    
    <pre class=screen>
    # continued from the previous example
    <a><samp class=p>>>> </samp><kbd class=pp>b_set.symmetric_difference(a_set)</kbd>                                       <span class=u>&#x2460;</span></a>
    <samp class=pp>{3, 1, 195, 4, 6, 8, 76, 15, 17, 18, 51, 30, 127}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>b_set.symmetric_difference(a_set) == a_set.symmetric_difference(b_set)</kbd>  <span class=u>&#x2461;</span></a>
    <samp class=pp>True</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>b_set.union(a_set) == a_set.union(b_set)</kbd>                                <span class=u>&#x2462;</span></a>
    <samp class=pp>True</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>b_set.intersection(a_set) == a_set.intersection(b_set)</kbd>                  <span class=u>&#x2463;</span></a>
    <samp class=pp>True</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>b_set.difference(a_set) == a_set.difference(b_set)</kbd>                      <span class=u>&#x2464;</span></a>
    <samp class=pp>False</samp></pre>
    <ol>
    <li>The symmetric difference of <var>a_set</var> from <var>b_set</var> <em>looks</em> different than the symmetric difference of <var>b_set</var> from <var>a_set</var>, but remember, sets are unordered. Any two sets that contain all the same values (with none left over) are considered equal.
    <li>And that&#8217;s exactly what happens here. Don&#8217;t be fooled by the Python Shell&#8217;s printed representation of these sets. They contain the same values, so they are equal.
    <li>The union of two sets is also symmetric.
    <li>The intersection of two sets is also symmetric.
    <li>The difference of two sets is not symmetric. That makes sense; it&#8217;s analogous to subtracting one number from another. The order of the operands matters.
    </ol>
    
    <p>Finally, there are a few questions you can ask of sets.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_set = {1, 2, 3}</kbd>
    <samp class=p>>>> </samp><kbd class=pp>b_set = {1, 2, 3, 4}</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.issubset(b_set)</kbd>    <span class=u>&#x2460;</span></a>
    <samp class=pp>True</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>b_set.issuperset(a_set)</kbd>  <span class=u>&#x2461;</span></a>
    <samp class=pp>True</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_set.add(5)</kbd>             <span class=u>&#x2462;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_set.issubset(b_set)</kbd>
    <samp class=pp>False</samp>
    <samp class=p>>>> </samp><kbd class=pp>b_set.issuperset(a_set)</kbd>
    <samp class=pp>False</samp></pre>
    <ol>
    <li><var>a_set</var> is a <dfn>subset</dfn> of <var>b_set</var>&nbsp;&mdash;&nbsp;all the members of <var>a_set</var> are also members of <var>b_set</var>.
    <li>Asking the same question in reverse, <var>b_set</var> is a <dfn>superset</dfn> of <var>a_set</var>, because all the members of <var>a_set</var> are also members of <var>b_set</var>.
    <li>As soon as you add a value to <var>a_set</var> that is not in <var>b_set</var>, both tests return <code>False</code>.
    </ol>
    
    <h3 id=sets-in-a-boolean-context>Sets In A Boolean Context</h3>
    
    <p>You can use sets in <a href=#booleans>a boolean context</a>, such as an <code>if</code> statement.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>def is_it_true(anything):</kbd>
    <samp class=p>... </samp><kbd class=pp>  if anything:</kbd>
    <samp class=p>... </samp><kbd class=pp>    print("yes, it's true")</kbd>
    <samp class=p>... </samp><kbd class=pp>  else:</kbd>
    <samp class=p>... </samp><kbd class=pp>    print("no, it's false")</kbd>
    <samp class=p>...</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>is_it_true(set())</kbd>          <span class=u>&#x2460;</span></a>
    <samp>no, it's false</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>is_it_true({'a'})</kbd>          <span class=u>&#x2461;</span></a>
    <samp>yes, it's true</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>is_it_true({False})</kbd>        <span class=u>&#x2462;</span></a>
    <samp>yes, it's true</samp></pre>
    <ol>
    <li>In a boolean context, an empty set is false.
    <li>Any set with at least one item is true.
    <li>Any set with at least one item is true. The value of the items is irrelevant.
    </ol>
    
    <p class=a>&#x2042;
    
    <h2 id=dictionaries>Dictionaries</h2>
    
    <p>A <dfn>dictionary</dfn> is an unordered set of key-value pairs. When you add a key to a dictionary, you must also add a value for that key. (You can always change the value later.) Python dictionaries are optimized for retrieving the value when you know the key, but not the other way around.
    <blockquote class='note compare perl5'>
    <p><span class=u>&#x261E;</span>A dictionary in Python is like a hash in Perl 5. In Perl 5, variables that store hashes always start with a <code>%</code> character. In Python, variables can be named anything, and Python keeps track of the datatype internally.
    </blockquote>
    <h3 id=creating-dictionaries>Creating A Dictionary</h3>
    <p>Creating a dictionary is easy. The syntax is similar to <a href=#sets>sets</a>, but instead of values, you have key-value pairs. Once you have a dictionary, you can look up values by their key.
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>a_dict = {'server': 'db.diveintopython3.org', 'database': 'mysql'}</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_dict</kbd>
    <samp class=pp>{'server': 'db.diveintopython3.org', 'database': 'mysql'}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_dict['server']</kbd>                                                    <span class=u>&#x2461;</span></a>
    'db.diveintopython3.org'
    <a><samp class=p>>>> </samp><kbd class=pp>a_dict['database']</kbd>                                                  <span class=u>&#x2462;</span></a>
    'mysql'
    <a><samp class=p>>>> </samp><kbd class=pp>a_dict['db.diveintopython3.org']</kbd>                                    <span class=u>&#x2463;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
    KeyError: 'db.diveintopython3.org'</samp></pre>
    <ol>
    <li>First, you create a new dictionary with two items and assign it to the variable <var>a_dict</var>. Each item is a key-value pair, and the whole set of items is enclosed in curly braces.
    <li><code>'server'</code> is a key, and its associated value, referenced by <code>a_dict['server']</code>, is <code>'db.diveintopython3.org'</code>.
    <li><code>'database'</code> is a key, and its associated value, referenced by <code>a_dict['database']</code>, is <code>'mysql'</code>.
    <li>You can get values by key, but you can&#8217;t get keys by value. So <code>a_dict['server']</code> is <code>'db.diveintopython3.org'</code>, but <code>a_dict['db.diveintopython3.org']</code> raises an exception, because <code>'db.diveintopython3.org'</code> is not a key.
    </ol>
    <h3 id=modifying-dictionaries>Modifying A Dictionary</h3>
    <p>Dictionaries do not have any predefined size limit. You can add new key-value pairs to a dictionary at any time, or you can modify the value of an existing key. Continuing from the previous example:
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_dict</kbd>
    <samp class=pp>{'server': 'db.diveintopython3.org', 'database': 'mysql'}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_dict['database'] = 'blog'</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_dict</kbd>
    <samp class=pp>{'server': 'db.diveintopython3.org', 'database': 'blog'}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_dict['user'] = 'mark'</kbd>      <span class=u>&#x2461;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>a_dict</kbd>                       <span class=u>&#x2462;</span></a>
    <samp class=pp>{'server': 'db.diveintopython3.org', 'user': 'mark', 'database': 'blog'}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_dict['user'] = 'dora'</kbd>      <span class=u>&#x2463;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_dict</kbd>
    <samp class=pp>{'server': 'db.diveintopython3.org', 'user': 'dora', 'database': 'blog'}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_dict['User'] = 'mark'</kbd>      <span class=u>&#x2464;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_dict</kbd>
    <samp class=pp>{'User': 'mark', 'server': 'db.diveintopython3.org', 'user': 'dora', 'database': 'blog'}</samp></pre>
    <ol>
    <li>You can not have duplicate keys in a dictionary. Assigning a value to an existing key will wipe out the old value.
    <li>You can add new key-value pairs at any time. This syntax is identical to modifying existing values.
    <li>The new dictionary item (key <code>'user'</code>, value <code>'mark'</code>) appears to be in the middle. In fact, it was just a coincidence that the items appeared to be in order in the first example; it is just as much a coincidence that they appear to be out of order now.
    <li>Assigning a value to an existing dictionary key simply replaces the old value with the new one.
    <li>Will this change the value of the <code>user</code> key back to "mark"?  No!  Look at the key closely&nbsp;&mdash;&nbsp;that&#8217;s a capital <kbd>U</kbd> in <kbd>"User"</kbd>. Dictionary keys are case-sensitive, so this statement is creating a new key-value pair, not overwriting an existing one. It may look similar to you, but as far as Python is concerned, it&#8217;s completely different.
    </ol>
    <h3 id=mixed-value-dictionaries>Mixed-Value Dictionaries</h3>
    <p>Dictionaries aren&#8217;t just for strings. Dictionary values can be any datatype, including integers, booleans, arbitrary objects, or even other dictionaries. And within a single dictionary, the values don&#8217;t all need to be the same type; you can mix and match as needed. Dictionary keys are more restricted, but they can be strings, integers, and a few other types. You can also mix and match key datatypes within a dictionary.
    <p>In fact, you&#8217;ve already seen a dictionary with non-string keys and values, in <a href=your-first-python-program.html#divingin>your first Python program</a>.
    <pre class='nd pp'><code>SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
                1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}</code></pre>
    <p>Let's tear that apart in the interactive shell.
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],</kbd>
    <samp class=p>... </samp><kbd class=pp>            1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>len(SUFFIXES)</kbd>      <span class=u>&#x2460;</span></a>
    <samp class=pp>2</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>1000 in SUFFIXES</kbd>   <span class=u>&#x2461;</span></a>
    <samp class=pp>True</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>SUFFIXES[1000]</kbd>     <span class=u>&#x2462;</span></a>
    <samp class=pp>['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>SUFFIXES[1024]</kbd>     <span class=u>&#x2463;</span></a>
    <samp class=pp>['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>SUFFIXES[1000][3]</kbd>  <span class=u>&#x2464;</span></a>
    <samp class=pp>'TB'</samp></pre>
    <ol>
    <li>Like <a href=#lists>lists</a> and <a href=#sets>sets</a>, the <code>len()</code> function gives you the number of keys in a dictionary.
    <li>And like lists and sets, you can use the <code>in</code> operator to test whether a specific key is defined in a dictionary.
    <li><code>1000</code> <em>is</em> a key in the <code>SUFFIXES</code> dictionary; its value is a list of eight items (eight strings, to be precise).
    <li>Similarly, <code>1024</code> is a key in the <code>SUFFIXES</code> dictionary; its value is also a list of eight items.
    <li>Since <code>SUFFIXES[1000]</code> is a list, you can address individual items in the list by their 0-based index.
    </ol>
    <h3 id=dictionaries-in-a-boolean-context>Dictionaries In A Boolean Context</h3>
    <aside>Empty dictionaries are false; all other dictionaries are true.</aside>
    <p>You can also use a dictionary in <a href=#booleans>a boolean context</a>, such as an <code>if</code> statement.
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>def is_it_true(anything):</kbd>
    <samp class=p>... </samp><kbd class=pp>  if anything:</kbd>
    <samp class=p>... </samp><kbd class=pp>    print("yes, it's true")</kbd>
    <samp class=p>... </samp><kbd class=pp>  else:</kbd>
    <samp class=p>... </samp><kbd class=pp>    print("no, it's false")</kbd>
    <samp class=p>...</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>is_it_true({})</kbd>             <span class=u>&#x2460;</span></a>
    <samp>no, it's false</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>is_it_true({'a': 1})</kbd>       <span class=u>&#x2461;</span></a>
    <samp>yes, it's true</samp></pre>
    <ol>
    <li>In a boolean context, an empty dictionary is false.
    <li>Any dictionary with at least one key-value pair is true.
    </ol>
    <p class=a>&#x2042;
    
    <h2 id=none><code>None</code></h2>
    <p><code><dfn>None</dfn></code> is a special constant in Python. It is a <dfn>null</dfn> value. <code>None</code> is not the same as <code>False</code>. <code>None</code> is not 0. <code>None</code> is not an empty string. Comparing <code>None</code> to anything other than <code>None</code> will always return <code>False</code>.
    <p><code>None</code> is the only null value. It has its own datatype (<code>NoneType</code>). You can assign <code>None</code> to any variable, but you can not create other <code>NoneType</code> objects. All variables whose value is <code>None</code> are equal to each other.
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>type(None)</kbd>
    <samp class=pp>&lt;class 'NoneType'></samp>
    <samp class=p>>>> </samp><kbd class=pp>None == False</kbd>
    <samp class=pp>False</samp>
    <samp class=p>>>> </samp><kbd class=pp>None == 0</kbd>
    <samp class=pp>False</samp>
    <samp class=p>>>> </samp><kbd class=pp>None == ''</kbd>
    <samp class=pp>False</samp>
    <samp class=p>>>> </samp><kbd class=pp>None == None</kbd>
    <samp class=pp>True</samp>
    <samp class=p>>>> </samp><kbd class=pp>x = None</kbd>
    <samp class=p>>>> </samp><kbd class=pp>x == None</kbd>
    <samp class=pp>True</samp>
    <samp class=p>>>> </samp><kbd class=pp>y = None</kbd>
    <samp class=p>>>> </samp><kbd class=pp>x == y</kbd>
    <samp class=pp>True</samp>
    </pre>
    <h3 id=none-in-a-boolean-context><code>None</code> In A Boolean Context</h3>
    <p>In <a href=#booleans>a boolean context</a>, <code>None</code> is false and <code>not None</code> is true.
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>def is_it_true(anything):</kbd>
    <samp class=p>... </samp><kbd class=pp>  if anything:</kbd>
    <samp class=p>... </samp><kbd class=pp>    print("yes, it's true")</kbd>
    <samp class=p>... </samp><kbd class=pp>  else:</kbd>
    <samp class=p>... </samp><kbd class=pp>    print("no, it's false")</kbd>
    <samp class=p>...</samp>
    <samp class=p>>>> </samp><kbd class=pp>is_it_true(None)</kbd>
    <samp>no, it's false</samp>
    <samp class=p>>>> </samp><kbd class=pp>is_it_true(not None)</kbd>
    <samp>yes, it's true</samp></pre>
    <p class=a>&#x2042;
    
    <h2 id=furtherreading>Further Reading</h2>
    <ul>
    <li><a href=http://docs.python.org/3.1/library/stdtypes.html#boolean-operations-and-or-not>Boolean operations</a>
    <li><a href=http://docs.python.org/3.1/library/stdtypes.html#numeric-types-int-float-long-complex>Numeric types</a>
    <li><a href=http://docs.python.org/3.1/library/stdtypes.html#sequence-types-str-unicode-list-tuple-buffer-xrange>Sequence types</a>
    <li><a href=http://docs.python.org/3.1/library/stdtypes.html#set-types-set-frozenset>Set types</a>
    <li><a href=http://docs.python.org/3.1/library/stdtypes.html#mapping-types-dict>Mapping types</a>
    <li><a href=http://docs.python.org/3.1/library/fractions.html><code>fractions</code> module</a>
    <li><a href=http://docs.python.org/3.1/library/math.html><code>math</code> module</a>
    <li><a href=http://www.python.org/dev/peps/pep-0237/><abbr>PEP</abbr> 237: Unifying Long Integers and Integers</a>
    <li><a href=http://www.python.org/dev/peps/pep-0238/><abbr>PEP</abbr> 238: Changing the Division Operator</a>
    </ul>
    <p class=v><a href=your-first-python-program.html rel=prev title='back to &#8220;Your First Python Program&#8221;'><span class=u>&#x261C;</span></a> <a href=comprehensions.html rel=next title='onward to &#8220;Comprehensions&#8221;'><span class=u>&#x261E;</span></a>
    <p class=c>&copy; 2001&ndash;11 <a href=about.html>Mark Pilgrim</a>
    <script src=j/jquery.js></script>
    <script src=j/prettify.js></script>
    <script src=j/dip3.js></script>
    �������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/installing-python.html����������������������������������������0000644�0000000�0000000�00000074274�11773544727�022177� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE html>
    <meta charset=utf-8>
    <title>Installing Python - Dive Into Python 3</title>
    <!--[if IE]><script src=j/html5.js></script><![endif]-->
    <link rel=stylesheet href=dip3.css>
    <style>
    body{counter-reset:h1 0}
    .i{list-style:none;margin:0;padding:0}
    #which{padding-top:1.75em}
    h2,.i>li{clear:both}
    #divingin,#which{clear:none}
    </style>
    <link rel=stylesheet media='only screen and (max-device-width: 480px)' href=mobile.css>
    <link rel=stylesheet media=print href=print.css>
    <meta name=viewport content='initial-scale=1.0'>
    <form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:l5eihuescdw><input type=hidden name=ie value=UTF-8>&nbsp;<input type=search name=q size=25 placeholder="powered by Google&trade;">&nbsp;<input type=submit name=sa value=Search></div></form>
    <p>You are here: <a href=index.html>Home</a> <span class=u>&#8227;</span> <a href=table-of-contents.html#installing-python>Dive Into Python 3</a> <span class=u>&#8227;</span>
    <p id=level>Difficulty level: <span class=u title=novice>&#x2666;&#x2662;&#x2662;&#x2662;&#x2662;</span>
    <h1>Installing Python</h1>
    <blockquote class=q>
    <p><span class=u>&#x275D;</span> <i lang=la>Tempora mutantur nos et mutamur in illis.</i> (Times change, and we change with them.) <span class=u>&#x275E;</span><br>&mdash; ancient Roman proverb
    </blockquote>
    <p id=toc>&nbsp;
    <h2 id=divingin>Diving In</h2>
    <p class=f>Before you can start programming in Python 3, you need to install it. Or do you?
    
    <h2 id=which>Which Python Is Right For You?</h2>
    
    <p>If you're using an account on a hosted server, your <abbr>ISP</abbr> may have already installed Python 3. If you&#8217;re running Linux at home, you may already have Python 3, too. Most popular GNU/Linux distributions come with Python 2 in the default installation; a small but growing number of distributions also include Python 3. Mac OS X includes a command-line version of Python 2, but as of this writing it does not include Python 3. Microsoft Windows does not come with any version of Python. But don&#8217;t despair! You can point-and-click your way through installing Python, regardless of what operating system you have.
    
    <p>The easiest way to check for Python 3 on your Linux or Mac OS X system is <a href=troubleshooting.html#getting-to-the-command-line>from the command line</a>. Once you&#8217;re at a command line prompt, just type <kbd>python3</kbd> (all lowercase, no spaces), press <kbd>ENTER</kbd>, and see what happens. On my home Linux system, Python 3.1 is already installed, and this command gets me into the <i>Python <dfn>interactive shell</dfn></i>.
    
    <pre class='nd screen cmdline'>
    <samp class=p>mark@atlantis:~$ </samp><kbd>python3</kbd>
    <samp>Python 3.1 (r31:73572, Jul 28 2009, 06:52:23) 
    [GCC 4.2.4 (Ubuntu 4.2.4-1ubuntu4)] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>></samp></pre>
    
    <p>(Type <kbd>exit()</kbd> and press <kbd>ENTER</kbd> to exit the Python interactive shell.)
    
    <p>My <a href=http://cornerhost.com/>web hosting provider</a> also runs Linux and provides command-line access, but my server does not have Python 3 installed. (Boo!)
    
    <pre class='nd screen cmdline'>
    <samp class=p>mark@manganese:~$ </samp><kbd>python3</kbd>
    <samp>bash: python3: command not found</samp></pre>
    
    <p>So back to the question that started this section, &#8220;Which Python is right for you?&#8221;  Whichever one runs on the computer you already have.
    
    <p>[Read on for Windows instructions, or skip to <a href=#macosx>Installing on Mac OS X</a>, <a href=#ubuntu>Installing on Ubuntu Linux</a>, or <a href=#other>Installing on Other Platforms</a>.]
    
    <p class=a>&#x2042;
    
    <h2 id=windows>Installing on Microsoft Windows</h2>
    
    <p>Windows comes in two architectures these days: 32-bit and 64-bit. Of course, there are lots of different <i>versions</i> of Windows&nbsp;&mdash;&nbsp;XP, Vista, Windows 7&nbsp;&mdash;&nbsp;but Python runs on all of them. The more important distinction is 32-bit v. 64-bit. If you have no idea what architecture you&#8217;re running, it&#8217;s probably 32-bit.
    
    <p>Visit <a href=http://python.org/download/><code>python.org/download/</code></a> and download the appropriate Python 3 Windows installer for your architecture. Your choices will look something like this:
    
    <ul>
    <li><b>Python 3.1 Windows installer</b> (Windows binary&nbsp;&mdash;&nbsp;does not include source)
    <li><b>Python 3.1 Windows AMD64 installer</b> (Windows AMD64 binary&nbsp;&mdash;&nbsp;does not include source)
    </ul>
    
    <p>I don&#8217;t want to include direct download links here, because minor updates of Python happen all the time and I don&#8217;t want to be responsible for you missing important updates. You should always install the most recent version of Python 3.x unless you have some esoteric reason not to.
    
    <ol class=i>
    <li>
    <p class='ss nm'><img src=i/win-install-0-security-warning.png width=409 height=309 alt='[Windows dialog: open file security warning]'>
    <p>Once your download is complete, double-click the <code>.msi</code> file. Windows will pop up a security alert, since you&#8217;re about to be running executable code. The official Python installer is digitally signed by the <a href=http://www.python.org/psf/>Python Software Foundation</a>, the non-profit corporation that oversees Python development. Don&#8217;t accept imitations!
    <p>Click the <code>Run</code> button to launch the Python 3 installer.
    
    <li>
    <p class='ss nm'><img src=i/win-install-1-all-users-or-just-me.png width=499 height=432 alt='[Python installer: select whether to install Python 3.1 for all users of this computer]'>
    <p>The first question the installer will ask you is whether you want to install Python 3 for all users or just for you. The default choice is &#8220;install for all users,&#8221; which is the best choice unless you have a good reason to choose otherwise. (One possible reason why you would want to &#8220;install just for me&#8221; is that you are installing Python on your company&#8217;s computer and you don&#8217;t have administrative rights on your Windows account. But then, why are you installing Python without permission from your company&#8217;s Windows administrator? Don&#8217;t get me in trouble here!)
    <p>Click the <code>Next</code> button to accept your choice of installation type.
    
    <li>
    <p class='ss nm'><img src=i/win-install-2-destination-directory.png width=499 height=432 alt='[Python installer: select destination directory]'>
    <p>Next, the installer will prompt you to choose a destination directory. The default for all versions of Python 3.1.x is <code>C:\Python31\</code>, which should work well for most users unless you have a specific reason to change it. If you maintain a separate drive letter for installing applications, you can browse to it using the embedded controls, or simply type the pathname in the box below. You are not limited to installing Python on the <code>C:</code> drive; you can install it on any drive, in any folder.
    <p>Click the <code>Next</code> button to accept your choice of destination directory.
    
    <li>
    <p class='ss nm'><img src=i/win-install-3-customize.png width=499 height=432 alt='[Python installer: customize Python 3.1]'>
    <p>The next page looks complicated, but it&#8217;s not really. Like many installers, you have the option not to install every single component of Python 3. If disk space is especially tight, you can exclude certain components.
    <ul>
    <li><b>Register Extensions</b> allows you to double-click Python scripts (<code>.py</code> files) and run them. Recommended but not required. (This option doesn&#8217;t require any disk space, so there is little point in excluding it.)
    <li><b>Tcl/Tk</b> is the graphics library used by the Python Shell, which you will use throughout this book. I strongly recommend keeping this option.
    <li><b>Documentation</b> installs a help file that contains much of the information on <a href=http://docs.python.org/><code>docs.python.org</code></a>. Recommended if you are on dialup or have limited Internet access.
    <li><b>Utility Scripts</b> includes the <code>2to3.py</code> script which you&#8217;ll learn about <a href=case-study-porting-chardet-to-python-3.html>later in this book</a>. Required if you want to learn about migrating existing Python 2 code to Python 3. If you have no existing Python 2 code, you can skip this option.
    <li><b>Test Suite</b> is a collection of scripts used to test the Python interpreter itself. We will not use it in this book, nor have I ever used it in the course of programming in Python. Completely optional.
    </ul>
    
    <li>
    <p class='ss nm'><img src=i/win-install-3a-disk-usage.png width=499 height=432 alt='[Python installer: disk space requirements]'>
    <p>If you&#8217;re unsure how much disk space you have, click the <code>Disk Usage</code> button. The installer will list your drive letters, compute how much space is available on each drive, and calculate how much would be left after installation.
    <p>Click the <code>OK</code> button to return to the &#8220;Customizing Python&#8221; page.
    
    <li>
    <p class='ss nm'><img src=i/win-install-3b-test-suite.png width=499 height=432 alt='[Python installer: removing Test Suite option will save 7908KB on your hard drive]'>
    <p>If you decide to exclude an option, select the drop-down button before the option and select &#8220;Entire feature will be unavailable.&#8221; For example, excluding the test suite will save you a whopping 7908<abbr>KB</abbr> of disk space.
    <p>Click the <code>Next</code> button to accept your choice of options.
    
    <li>
    <p class='ss nm'><img src=i/win-install-4-copying.png width=499 height=432 alt='[Python installer: progress meter]'>
    <p>The installer will copy all the necessary files to your chosen destination directory. (This happens so quickly, I had to try it three times to even get a screenshot of it!)
    
    <li>
    <p class='ss nm'><img src=i/win-install-5-finish.png width=499 height=432 alt='[Python installer: installation completed. Special Windows thanks to Mark Hammond, without whose years of freely shared Windows expertise, Python for Windows would still be Python for DOS.]'>
    <p>Click the <code>Finish</code> button to exit the installer.
    
    <li>
    <p class='ss nm'><img src=i/win-interactive-shell.png width=677 height=715 alt='[Windows Python Shell, a graphical interactive shell for Python]'>
    <p>In your <code>Start</code> menu, there should be a new item called <code>Python 3.1</code>. Within that, there is a program called <abbr>IDLE</abbr>. Select this item to run the interactive Python Shell.
    
    </ol>
    
    <p>[Skip to <a href=#idle>using the Python Shell</a>]
    
    <p class=a>&#x2042;
    
    <h2 id=macosx>Installing on Mac OS X</h2>
    
    <p>All modern Macintosh computers use the Intel chip (like most Windows PCs). Older Macs used PowerPC chips. You don&#8217;t need to understand the difference, because there&#8217;s just one Mac Python installer for all Macs.
    
    <p>Visit <a href=http://python.org/download/><code>python.org/download/</code></a> and download the Mac installer. It will be called something like <b>Python 3.1 Mac Installer Disk Image</b>, although the version number may vary. Be sure to download version 3.x, not 2.x.
    
    <ol class=i>
    
    <li>
    <p class='ss nm'><img src=i/mac-install-0-dmg-contents.png width=752 height=438 alt='[contents of Python installer disk image]'>
    <p>Your browser should automatically mount the disk image and open a Finder window to show you the contents. (If this doesn&#8217;t happen, you&#8217;ll need to find the disk image in your downloads folder and double-click to mount it. It will be named something like <code>python-3.1.dmg</code>.) The disk image contains a number of text files (<code>Build.txt</code>, <code>License.txt</code>, <code>ReadMe.txt</code>), and the actual installer package, <code>Python.mpkg</code>.
    <p>Double-click the <code>Python.mpkg</code> installer package to launch the Mac Python installer.
    
    <li>
    <p class='ss nm'><img src=i/mac-install-1-welcome.png width=622 height=442 alt='[Python installer: welcome screen]'>
    <p>The first page of the installer gives a brief description of Python itself, then refers you to the <code>ReadMe.txt</code> file (which you didn&#8217;t read, did you?) for more details.
    <p>Click the <code>Continue</code> button to move along.
    
    <li>
    <p class='ss nm'><img src=i/mac-install-2-information.png width=622 height=442 alt='[Python installer: information about supported architectures, disk space, and acceptable destination folders]'>
    <p>The next page actually contains some important information: Python requires Mac OS X 10.3 or later. If you are still running Mac OS X 10.2, you should really upgrade. Apple no longer provides security updates for your operating system, and your computer is probably at risk if you ever go online. Also, you can&#8217;t run Python 3.
    <p>Click the <code>Continue</code> button to advance.
    
    <li>
    <p class='ss nm'><img src=i/mac-install-3-license.png width=622 height=442 alt='[Python installer: software license agreement]'>
    <p>Like all good installers, the Python installer displays the software license agreement. Python is open source, and its license is <a href=http://opensource.org/licenses/>approved by the Open Source Initiative</a>. Python has had a number of owners and sponsors throughout its history, each of which has left its mark on the software license. But the end result is this: Python is open source, and you may use it on any platform, for any purpose, without fee or obligation of reciprocity.
    <p>Click the <code>Continue</code> button once again.
    
    <li>
    <p class='ss nm'><img src=i/mac-install-4-license-dialog.png width=622 height=442 alt='[Python installer: dialog to accept license agreement]'>
    <p>Due to quirks in the standard Apple installer framework, you must &#8220;agree&#8221; to the software license in order to complete the installation. Since Python is open source, you are really &#8220;agreeing&#8221; that the license is granting you additional rights, rather than taking them away.
    <p>Click the <code>Agree</code> button to continue.
    
    <li>
    <p class='ss nm'><img src=i/mac-install-5-standard-install.png width=622 height=442 alt='[Python installer: standard install screen]'>
    <p>The next screen allows you to change your install location. You <strong>must</strong> install Python on your boot drive, but due to limitations of the installer, it does not enforce this. In truth, I have never had the need to change the install location.
    <p>From this screen, you can also customize the installation to exclude certain features. If you want to do this, click the <code>Customize</code> button; otherwise click the <code>Install</code> button.
    
    <li>
    <p class='ss nm'><img src=i/mac-install-6-custom-install.png width=622 height=442 alt='[Python installer: custom install screen]'>
    <p>If you choose a Custom Install, the installer will present you with the following list of features:
    <ul>
    <li><b>Python Framework</b>. This is the guts of Python, and is both selected and disabled because it must be installed.
    <li><b>GUI Applications</b> includes IDLE, the graphical Python Shell which you will use throughout this book. I strongly recommend keeping this option selected.
    <li><b>UNIX command-line tools</b> includes the command-line <code>python3</code> application. I strongly recommend keeping this option, too.
    <li><b>Python Documentation</b> contains much of the information on <a href=http://docs.python.org/><code>docs.python.org</code></a>. Recommended if you are on dialup or have limited Internet access.
    <li><b>Shell profile updater</b> controls whether to update your shell profile (used in <code>Terminal.app</code>) to ensure that this version of Python is on the search path of your shell. You probably don&#8217;t need to change this.
    <li><b>Fix system Python</b> should not be changed. (It tells your Mac to use Python 3 as the default Python for all scripts, including built-in system scripts from Apple. This would be very bad, since most of those scripts are written for Python 2, and they would fail to run properly under Python 3.)
    </ul>
    <p>Click the <code>Install</code> button to continue.
    
    <li>
    <p class='ss nm'><img src=i/mac-install-7-admin-password.png width=622 height=457 alt='[Python installer: dialog to enter administrative password]'>
    <p>Because it installs system-wide frameworks and binaries in <code>/usr/local/bin/</code>, the installer will ask you for an administrative password. There is no way to install Mac Python without administrator privileges.
    <p>Click the <code>OK</code> button to begin the installation.
    
    <li>
    <p class='ss nm'><img src=i/mac-install-8-progress.png width=622 height=442 alt='[Python installer: progress meter]'>
    <p>The installer will display a progress meter while it installs the features you&#8217;ve selected.
    
    <li>
    <p class='ss nm'><img src=i/mac-install-9-succeeded.png width=622 height=442 alt='[Python installer: install succeeded]'>
    <p>Assuming all went well, the installer will give you a big green checkmark to tell you that the installation completed successfully.
    <p>Click the <code>Close</code> button to exit the installer.
    
    <li>
    <p class='ss nm'><img src=i/mac-install-10-application-folder.png width=488 height=482 alt='[contents of /Applications/Python 3.1/ folder]'>
    <p>Assuming you didn&#8217;t change the install location, you can find the newly installed files in the <code>Python 3.1</code> folder within your <code>/Applications</code> folder. The most important piece is <abbr>IDLE</abbr>, the graphical Python Shell.
    <p>Double-click <abbr>IDLE</abbr> to launch the Python Shell.
    
    <li>
    <p class='ss nm'><img src=i/mac-interactive-shell.png width=522 height=538 alt='[Mac Python Shell, a graphical interactive shell for Python]'>
    <p>The Python Shell is where you will spend most of your time exploring Python. Examples throughout this book will assume that you can find your way into the Python Shell.
    
    </ol>
    
    <p>[Skip to <a href=#idle>using the Python Shell</a>]
    
    <p class=a>&#x2042;
    
    <h2 id=ubuntu>Installing on Ubuntu Linux</h2>
    
    <p>Modern Linux distributions are backed by vast repositories of precompiled applications, ready to install. The exact details vary by distribution. In Ubuntu Linux, the easiest way to install Python 3 is through the <code>Add/Remove</code> application in your <code>Applications</code> menu.
    
    <ol class=i>
    <li>
    <p class='ss nm'><img src=i/ubu-install-0-add-remove-programs.png width=920 height=473 alt='[Add/Remove: Canonical-maintained applications]'>
    <p>When you first launch the <code>Add/Remove</code> application, it will show you a list of preselected applications in different categories. Some are already installed; most are not. Because the repository contains over 10,000 applications, there are different filters you can apply to see small parts of the repository. The default filter is &#8220;Canonical-maintained applications,&#8221; which is a small subset of the total number of applications that are officially supported by Canonical, the company that creates and maintains Ubuntu Linux.
    
    <li>
    <p class='ss nm'><img src=i/ubu-install-1-all-open-source-applications.png width=920 height=473 alt='[Add/Remove: all open source applications]'>
    <p>Python 3 is not maintained by Canonical, so the first step is to drop down this filter menu and select &#8220;All Open Source applications.&#8221;
    
    <li>
    <p class='ss nm'><img src=i/ubu-install-2-search-python-3.png width=920 height=473 alt='[Add/Remove: search for Python 3]'>
    <p>Once you&#8217;ve widened the filter to include all open source applications, use the Search box immediately after the filter menu to search for <kbd>Python 3</kbd>.
    
    <li>
    <p class='ss nm'><img src=i/ubu-install-3-select-python-3.png width=920 height=473 alt='[Add/Remove: select Python 3.0 package]'>
    <p>Now the list of applications narrows to just those matching <kbd>Python 3</kbd>. You&#8217;re going to check two packages. The first is <code>Python (v3.0)</code>. This contains the Python interpreter itself.
    <li>
    <p class='ss nm'><img src=i/ubu-install-4-select-idle.png width=920 height=473 alt='[Add/Remove: select IDLE for Python 3.0 package]'>
    <p>The second package you want is immediately above: <code>IDLE (using Python-3.0)</code>. This is a graphical Python Shell that you will use throughout this book.
    <p>After you&#8217;ve checked those two packages, click the <code>Apply Changes</code> button to continue.
    
    <li>
    <p class='ss nm'><img src=i/ubu-install-5-apply-changes.png width=635 height=364 alt='[Add/Remove: apply changes]'>
    <p>The package manager will ask you to confirm that you want to add both <code>IDLE (using Python-3.0)</code> and <code>Python (v3.0)</code>.
    <p>Click the <code>Apply</code> button to continue.
    
    <li>
    <p class='ss nm'><img src=i/ubu-install-6-download-progress.png width=287 height=211 alt='[Add/Remove: download progress meter]'>
    <p>The package manager will show you a progress meter while it downloads the necessary packages from Canonical&#8217;s Internet repository.
    
    <li>
    <p class='ss nm'><img src=i/ubu-install-7-install-progress.png width=486 height=258 alt='[Add/Remove: installation progress meter]'>
    <p>Once the packages are downloaded, the package manager will automatically begin installing them.
    
    <li>
    <p class='ss nm'><img src=i/ubu-install-8-success.png width=591 height=296 alt='[Add/Remove: new applications have been installed]'>
    <p>If all went well, the package manager will confirm that both packages were successfully installed. From here, you can double-click <abbr>IDLE</abbr> to launch the Python Shell, or click the <code>Close</code> button to exit the package manager.
    <p>You can always relaunch the Python Shell by going to your <code>Applications</code> menu, then the <code>Programming</code> submenu, and selecting <abbr>IDLE</abbr>.
    
    <li>
    <p class='ss nm'><img src=i/ubu-interactive-shell.png width=679 height=687 alt='[Linux Python Shell, a graphical interactive shell for Python]'>
    <p>The Python Shell is where you will spend most of your time exploring Python. Examples throughout this book will assume that you can find your way into the Python Shell.
    
    </ol>
    
    <p>[Skip to <a href=#idle>using the Python Shell</a>]
    
    <p class=a>&#x2042;
    
    <h2 id=other>Installing on Other Platforms</h2>
    
    <p>Python 3 is available on a number of different platforms. In particular, it is available in virtually every Linux, <abbr>BSD</abbr>, and Solaris-based distribution. For example, RedHat Linux uses the <code>yum</code> package manager. FreeBSD has its <a href=http://www.freebsd.org/ports/>ports and packages collection</a>, <abbr>SUSE</abbr> has <code>zypper</code>, and Solaris has <code>pkgadd</code>. A quick web search for <code>Python 3</code> + <i>your operating system</i> should tell you whether a Python 3 package is available, and if so, how to install it.
    
    <p class=a>&#x2042;
    
    <h2 id=idle>Using The Python Shell</h2>
    
    <p>The Python Shell is where you can explore Python syntax, get interactive help on commands, and debug short programs. The graphical Python Shell (named <abbr>IDLE</abbr>) also contains a decent text editor that supports Python syntax coloring and integrates with the Python Shell. If you don&#8217;t already have a favorite text editor, you should give <abbr>IDLE</abbr> a try.
    
    <p>First things first. The Python Shell itself is an amazing interactive playground. Throughout this book, you&#8217;ll see examples like this:
    
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>1 + 1</kbd>
    <samp class=pp>2</samp></pre>
    
    <p>The three angle brackets, <samp class=p>>>></samp>, denote the Python Shell prompt. Don&#8217;t type that part. That&#8217;s just to let you know that this example is meant to be followed in the Python Shell.
    
    <p><kbd class=pp>1 + 1</kbd> is the part you type. You can type any valid Python expression or command in the Python Shell. Don&#8217;t be shy; it won&#8217;t bite! The worst that will happen is you&#8217;ll get an error message. Commands get executed immediately (once you press <kbd>ENTER</kbd>); expressions get evaluated immediately, and the Python Shell prints out the result.
    
    <p><samp class=pp>2</samp> is the result of evaluating this expression. As it happens, <kbd class=pp>1 + 1</kbd> is a valid Python expression. The result, of course, is <samp class=pp>2</samp>.
    
    <p>Let&#8217;s try another one.
    
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>print('Hello world!')</kbd>
    <samp>Hello world!</samp>
    </pre>
    
    <p>Pretty simple, no? But there&#8217;s lots more you can do in the Python shell. If you ever get stuck&nbsp;&mdash;&nbsp;you can&#8217;t remember a command, or you can&#8217;t remember the proper arguments to pass a certain function&nbsp;&mdash;&nbsp;you can get interactive help in the Python Shell. Just type <kbd>help</kbd> and press <kbd>ENTER</kbd>.
    
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd>help</kbd>
    <samp>Type help() for interactive help, or help(object) for help about object.</samp></pre>
    
    <p>There are two modes of help. You can get help about a single object, which just prints out the documentation and returns you to the Python Shell prompt. You can also enter <i>help mode</i>, where instead of evaluating Python expressions, you just type keywords or command names and it will print out whatever it knows about that command.
    
    <p>To enter the interactive help mode, type <kbd>help()</kbd> and press <kbd>ENTER</kbd>.
    
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>help()</kbd>
    <samp>Welcome to Python 3.0!  This is the online help utility.
    
    If this is your first time using Python, you should definitely check out
    the tutorial on the Internet at http://docs.python.org/tutorial/.
    
    Enter the name of any module, keyword, or topic to get help on writing
    Python programs and using Python modules.  To quit this help utility and
    return to the interpreter, just type "quit".
    
    To get a list of available modules, keywords, or topics, type "modules",
    "keywords", or "topics".  Each module also comes with a one-line summary
    of what it does; to list the modules whose summaries contain a given word
    such as "spam", type "modules spam".
    </samp>
    <samp class=p>help> </samp></pre>
    
    <p>Note how the prompt changes from <samp class=p>>>></samp> to <samp class=p>help></samp>. This reminds you that you&#8217;re in the interactive help mode. Now you can enter any keyword, command, module name, function name&nbsp;&mdash;&nbsp;pretty much anything Python understands&nbsp;&mdash;&nbsp;and read documentation on it.
    
    <pre class=screen>
    <a><samp class=p>help> </samp><kbd class=pp>print</kbd>                                                                 <span class=u>&#x2460;</span></a>
    <samp>Help on built-in function print in module builtins:
    
    print(...)
        print(value, ..., sep=' ', end='\n', file=sys.stdout)
        
        Prints the values to a stream, or to sys.stdout by default.
        Optional keyword arguments:
        file: a file-like object (stream); defaults to the current sys.stdout.
        sep:  string inserted between values, default a space.
        end:  string appended after the last value, default a newline.
    </samp>
    <a><samp class=p>help> </samp><kbd class=pp>PapayaWhip</kbd>                                                            <span class=u>&#x2461;</span></a>
    <samp>no Python documentation found for 'PapayaWhip'
    </samp>
    <a><samp class=p>help> </samp><kbd class=pp>quit</kbd>                                                                  <span class=u>&#x2462;</span></a>
    <samp>
    You are now leaving help and returning to the Python interpreter.
    If you want to ask for help on a particular object directly from the
    interpreter, you can type "help(object)".  Executing "help('string')"
    has the same effect as typing a particular string at the help> prompt.</samp>
    <a><samp class=p>>>> </samp>                                                                        <span class=u>&#x2463;</span></a></pre>
    <ol>
    <li>To get documentation on the <code>print()</code> function, just type <kbd>print</kbd> and press <kbd>ENTER</kbd>. The interactive help mode will display something akin to a man page: the function name, a brief synopsis, the function&#8217;s arguments and their default values, and so on. If the documentation seems opaque to you, don&#8217;t panic. You&#8217;ll learn more about all these concepts in the next few chapters.
    <li>Of course, the interactive help mode doesn&#8217;t know everything. If you type something that isn&#8217;t a Python command, module, function, or other built-in keyword, the interactive help mode will just shrug its virtual shoulders.
    <li>To quit the interactive help mode, type <kbd>quit</kbd> and press <kbd>ENTER</kbd>.
    <li>The prompt changes back to <samp class=p>>>></samp> to signal that you&#8217;ve left the interactive help mode and returned to the Python Shell.
    </ol>
    
    <p><abbr>IDLE</abbr>, the graphical Python Shell, also includes a Python-aware text editor.
    
    <p class=a>&#x2042;
    
    <h2 id=editors>Python Editors and IDEs</h2>
    
    <p><abbr>IDLE</abbr> is not the only game in town when it comes to writing programs in Python. While it&#8217;s useful to get started with learning the language itself, many developers prefer other text editors or Integrated Development Environments (<abbr>IDE</abbr>s). I won&#8217;t cover them here, but the Python community maintains <a href=http://wiki.python.org/moin/PythonEditors>a list of Python-aware editors</a> that covers a wide range of supported platforms and software licenses.
    
    <p>You might also want to check out the <a href=http://wiki.python.org/moin/IntegratedDevelopmentEnvironments>list of Python-aware <abbr>IDE</abbr>s</a>, although few of them support Python 3 yet. One that does is <a href=http://pydev.sourceforge.net/>PyDev</a>, a plugin for <a href=http://eclipse.org/>Eclipse</a> that turns Eclipse into a full-fledged Python <abbr>IDE</abbr>. Both Eclipse and PyDev are cross-platform and open source.
    
    <p>On the commercial front, there is ActiveState&#8217;s <a href=http://www.activestate.com/komodo/>Komodo <abbr>IDE</abbr></a>. It has per-user licensing, but students can get a discount, and a free time-limited trial version is available.
    
    <p>I&#8217;ve been programming in Python for nine years, and I edit my Python programs in <a href=http://www.gnu.org/software/emacs/>GNU Emacs</a> and debug them in the command-line Python Shell. There&#8217;s no right or wrong way to develop in Python. Find a way that works for you!
    
    <p class=v><a href=whats-new.html rel=prev title='back to &#8220;What&#8217;s New In Dive Into Python 3&#8221;'><span class=u>&#x261C;</span></a> <a href=your-first-python-program.html rel=next title='onward to &#8220;Your First Python Program&#8221;'><span class=u>&#x261E;</span></a>
    
    <p class=c>&copy; 2001&ndash;11 <a href=about.html>Mark Pilgrim</a>
    <script src=j/jquery.js></script>
    <script src=j/prettify.js></script>
    <script src=j/dip3.js></script>
    ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/case-study-porting-chardet-to-python-3.html�������������������0000644�0000000�0000000�00000200407�11773544727�025751� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE html>
    <meta charset=utf-8>
    <title>Case study: porting chardet to Python 3 - Dive Into Python 3</title>
    <!--[if IE]><script src=j/html5.js></script><![endif]-->
    <link rel=stylesheet href=dip3.css>
    <style>
    body{counter-reset:h1 15}
    ins,del{line-height:2.154;text-decoration:none;font-style:normal;display:inline-block;width:100%}
    ins{background:#9f9}
    del{background:#f87}
    </style>
    <link rel=stylesheet media='only screen and (max-device-width: 480px)' href=mobile.css>
    <link rel=stylesheet media=print href=print.css>
    <meta name=viewport content='initial-scale=1.0'>
    <form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:l5eihuescdw><input type=hidden name=ie value=UTF-8>&nbsp;<input type=search name=q size=25 placeholder="powered by Google&trade;">&nbsp;<input type=submit name=sa value=Search></div></form>
    <p>You are here: <a href=index.html>Home</a> <span class=u>&#8227;</span> <a href=table-of-contents.html#case-study-porting-chardet-to-python-3>Dive Into Python 3</a> <span class=u>&#8227;</span>
    <p id=level>Difficulty level: <span class=u title=pro>&#x2666;&#x2666;&#x2666;&#x2666;&#x2666;</span>
    <h1>Case Study: Porting <code>chardet</code> to Python 3</h1>
    <blockquote class=q>
    <p><span class=u>&#x275D;</span> Words, words. They&#8217;re all we have to go on. <span class=u>&#x275E;</span><br>&mdash; <a href=http://www.imdb.com/title/tt0100519/quotes>Rosencrantz and Guildenstern are Dead</a>
    </blockquote>
    <p id=toc>&nbsp;
    <h2 id=divingin>Diving In</h2>
    <p class=f>Question: what&#8217;s the #1 cause of gibberish text on the web, in your inbox, and across every computer system ever written? It&#8217;s character encoding. In the <a href=strings.html>Strings</a> chapter, I talked about the history of character encoding and the creation of Unicode, the &#8220;one encoding to rule them all.&#8221; I&#8217;d love it if I never had to see a gibberish character on a web page again, because all authoring systems stored accurate encoding information, all transfer protocols were Unicode-aware, and every system that handled text maintained perfect fidelity when converting between encodings.
    <p>I&#8217;d also like a pony.
    <p>A Unicode pony.
    <p>A Unipony, as it were.
    <p>I&#8217;ll settle for character encoding auto-detection.
    
    <p class=a>&#x2042;
    
    <h2 id=faq.what>What is Character Encoding Auto-Detection?</h2>
    <p>It means taking a sequence of bytes in an unknown character encoding, and attempting to determine the encoding so you can read the text. It&#8217;s like cracking a code when you don&#8217;t have the decryption key.
    
    <h3 id=faq.impossible>Isn&#8217;t That Impossible?</h3>
    <p>In general, yes. However, some encodings are optimized for specific languages, and languages are not random. Some character sequences pop up all the time, while other sequences make no sense. A person fluent in English who opens a newspaper and finds &#8220;txzqJv 2!dasd0a QqdKjvz&#8221; will instantly recognize that that isn&#8217;t English (even though it is composed entirely of English letters). By studying lots of &#8220;typical&#8221; text, a computer algorithm can simulate this kind of fluency and make an educated guess about a text&#8217;s language.
    <p>In other words, encoding detection is really language detection, combined with knowledge of which languages tend to use which character encodings.
    
    <h3 id=faq.who>Does Such An Algorithm Exist?</h3>
    <p>As it turns out, yes. All major browsers have character encoding auto-detection, because the web is full of pages that have no encoding information whatsoever. <a href=http://lxr.mozilla.org/seamonkey/source/extensions/universalchardet/src/base/>Mozilla Firefox contains an encoding auto-detection library</a> which is open source. <a href=http://chardet.feedparser.org/>I ported the library to Python 2</a> and dubbed it the <code>chardet</code> module. This chapter will take you step-by-step through the process of porting the <code>chardet</code> module from Python 2 to Python 3.
    
    <p class=a>&#x2042;
    
    <h2 id=divingin2>Introducing The <code>chardet</code> Module</h2>
    <p>Before we set off porting the code, it would help if you understood how the code worked! This is a brief guide to navigating the code itself. The <code>chardet</code> library is too large to include inline here, but you can <a href=http://chardet.feedparser.org/download/>download it from <code>chardet.feedparser.org</code></a>.
    <aside>Encoding detection is really language detection in drag.</aside>
    <p>The main entry point for the detection algorithm is <code>universaldetector.py</code>, which has one class, <code>UniversalDetector</code>. (You might think the main entry point is the <code>detect</code> function in <code>chardet/__init__.py</code>, but that&#8217;s really just a convenience function that creates a <code>UniversalDetector</code> object, calls it, and returns its result.)
    <p>There are 5 categories of encodings that <code>UniversalDetector</code> handles:
    <ol>
    <li><abbr>UTF-n</abbr> with a Byte Order Mark (<abbr>BOM</abbr>). This includes <abbr>UTF-8</abbr>, both Big-Endian and Little-Endian variants of <abbr>UTF-16</abbr>, and all 4 byte-order variants of <abbr>UTF-32</abbr>.
    <li>Escaped encodings, which are entirely 7-bit <abbr>ASCII</abbr> compatible, where non-<abbr>ASCII</abbr> characters start with an escape sequence. Examples: <abbr>ISO-2022-JP</abbr> (Japanese) and <abbr>HZ-GB-2312</abbr> (Chinese).
    <li>Multi-byte encodings, where each character is represented by a variable number of bytes. Examples: <abbr>Big5</abbr> (Chinese), <abbr>SHIFT_JIS</abbr> (Japanese), <abbr>EUC-KR</abbr> (Korean), and <abbr>UTF-8</abbr> without a <abbr>BOM</abbr>.
    <li>Single-byte encodings, where each character is represented by one byte. Examples: <abbr>KOI8-R</abbr> (Russian), <abbr>windows-1255</abbr> (Hebrew), and <abbr>TIS-620</abbr> (Thai).
    <li><abbr>windows-1252</abbr>, which is used primarily on Microsoft Windows by middle managers who wouldn&#8217;t know a character encoding from a hole in the ground.
    </ol>
    <h3 id=how.bom><abbr>UTF-n</abbr> With A <abbr>BOM</abbr></h3>
    <p>If the text starts with a <abbr>BOM</abbr>, we can reasonably assume that the text is encoded in <abbr>UTF-8</abbr>, <abbr>UTF-16</abbr>, or <abbr>UTF-32</abbr>. (The <abbr>BOM</abbr> will tell us exactly which one; that&#8217;s what it&#8217;s for.)  This is handled inline in <code>UniversalDetector</code>, which returns the result immediately without any further processing.
    <h3 id=how.esc>Escaped Encodings</h3>
    <p>If the text contains a recognizable escape sequence that might indicate an escaped encoding, <code>UniversalDetector</code> creates an <code>EscCharSetProber</code> (defined in <code>escprober.py</code>) and feeds it the text.
    <p><code>EscCharSetProber</code> creates a series of state machines, based on models of <abbr>HZ-GB-2312</abbr>, <abbr>ISO-2022-CN</abbr>, <abbr>ISO-2022-JP</abbr>, and <abbr>ISO-2022-KR</abbr> (defined in <code>escsm.py</code>). <code>EscCharSetProber</code> feeds the text to each of these state machines, one byte at a time. If any state machine ends up uniquely identifying the encoding, <code>EscCharSetProber</code> immediately returns the positive result to <code>UniversalDetector</code>, which returns it to the caller. If any state machine hits an illegal sequence, it is dropped and processing continues with the other state machines.
    <h3 id=how.mb>Multi-Byte Encodings</h3>
    <p>Assuming no <abbr>BOM</abbr>, <code>UniversalDetector</code> checks whether the text contains any high-bit characters. If so, it creates a series of &#8220;probers&#8221; for detecting multi-byte encodings, single-byte encodings, and as a last resort, <code>windows-1252</code>.
    <p>The multi-byte encoding prober, <code>MBCSGroupProber</code> (defined in <code>mbcsgroupprober.py</code>), is really just a shell that manages a group of other probers, one for each multi-byte encoding: <abbr>Big5</abbr>, <abbr>GB2312</abbr>, <abbr>EUC-TW</abbr>, <abbr>EUC-KR</abbr>, <abbr>EUC-JP</abbr>, <abbr>SHIFT_JIS</abbr>, and <abbr>UTF-8</abbr>. <code>MBCSGroupProber</code> feeds the text to each of these encoding-specific probers and checks the results. If a prober reports that it has found an illegal byte sequence, it is dropped from further processing (so that, for instance, any subsequent calls to <code>UniversalDetector</code>.<code>feed()</code> will skip that prober). If a prober reports that it is reasonably confident that it has detected the encoding, <code>MBCSGroupProber</code> reports this positive result to <code>UniversalDetector</code>, which reports the result to the caller.
    <p>Most of the multi-byte encoding probers are inherited from <code>MultiByteCharSetProber</code> (defined in <code>mbcharsetprober.py</code>), and simply hook up the appropriate state machine and distribution analyzer and let <code>MultiByteCharSetProber</code> do the rest of the work. <code>MultiByteCharSetProber</code> runs the text through the encoding-specific state machine, one byte at a time, to look for byte sequences that would indicate a conclusive positive or negative result. At the same time, <code>MultiByteCharSetProber</code> feeds the text to an encoding-specific distribution analyzer.
    <p>The distribution analyzers (each defined in <code>chardistribution.py</code>) use language-specific models of which characters are used most frequently. Once <code>MultiByteCharSetProber</code> has fed enough text to the distribution analyzer, it calculates a confidence rating based on the number of frequently-used characters, the total number of characters, and a language-specific distribution ratio. If the confidence is high enough, <code>MultiByteCharSetProber</code> returns the result to <code>MBCSGroupProber</code>, which returns it to <code>UniversalDetector</code>, which returns it to the caller.
    <p>The case of Japanese is more difficult. Single-character distribution analysis is not always sufficient to distinguish between <code>EUC-JP</code> and <code>SHIFT_JIS</code>, so the <code>SJISProber</code> (defined in <code>sjisprober.py</code>) also uses 2-character distribution analysis. <code>SJISContextAnalysis</code> and <code>EUCJPContextAnalysis</code> (both defined in <code>jpcntx.py</code> and both inheriting from a common <code>JapaneseContextAnalysis</code> class) check the frequency of Hiragana syllabary characters within the text. Once enough text has been processed, they return a confidence level to <code>SJISProber</code>, which checks both analyzers and returns the higher confidence level to <code>MBCSGroupProber</code>.
    <h3 id=how.sb>Single-Byte Encodings</h3>
    <aside>Seriously, where&#8217;s my Unicode pony?</aside>
    <p>The single-byte encoding prober, <code>SBCSGroupProber</code> (defined in <code>sbcsgroupprober.py</code>), is also just a shell that manages a group of other probers, one for each combination of single-byte encoding and language: <code>windows-1251</code>, <code>KOI8-R</code>, <code>ISO-8859-5</code>, <code>MacCyrillic</code>, <code>IBM855</code>, and <code>IBM866</code> (Russian); <code>ISO-8859-7</code> and <code>windows-1253</code> (Greek); <code>ISO-8859-5</code> and <code>windows-1251</code> (Bulgarian); <code>ISO-8859-2</code> and <code>windows-1250</code> (Hungarian); <code>TIS-620</code> (Thai); <code>windows-1255</code> and <code>ISO-8859-8</code> (Hebrew).
    <p><code>SBCSGroupProber</code> feeds the text to each of these encoding+language-specific probers and checks the results. These probers are all implemented as a single class, <code>SingleByteCharSetProber</code> (defined in <code>sbcharsetprober.py</code>), which takes a language model as an argument. The language model defines how frequently different 2-character sequences appear in typical text. <code>SingleByteCharSetProber</code> processes the text and tallies the most frequently used 2-character sequences. Once enough text has been processed, it calculates a confidence level based on the number of frequently-used sequences, the total number of characters, and a language-specific distribution ratio.
    <p>Hebrew is handled as a special case. If the text appears to be Hebrew based on 2-character distribution analysis, <code>HebrewProber</code> (defined in <code>hebrewprober.py</code>) tries to distinguish between Visual Hebrew (where the source text actually stored &#8220;backwards&#8221; line-by-line, and then displayed verbatim so it can be read from right to left) and Logical Hebrew (where the source text is stored in reading order and then rendered right-to-left by the client). Because certain characters are encoded differently based on whether they appear in the middle of or at the end of a word, we can make a reasonable guess about direction of the source text, and return the appropriate encoding (<code>windows-1255</code> for Logical Hebrew, or <code>ISO-8859-8</code> for Visual Hebrew).
    <h3 id=how.windows1252><code>windows-1252</code></h3>
    <p>If <code>UniversalDetector</code> detects a high-bit character in the text, but none of the other multi-byte or single-byte encoding probers return a confident result, it creates a <code>Latin1Prober</code> (defined in <code>latin1prober.py</code>) to try to detect English text in a <code>windows-1252</code> encoding. This detection is inherently unreliable, because English letters are encoded in the same way in many different encodings. The only way to distinguish <code>windows-1252</code> is through commonly used symbols like smart quotes, curly apostrophes, copyright symbols, and the like. <code>Latin1Prober</code> automatically reduces its confidence rating to allow more accurate probers to win if at all possible.
    <p class=a>&#x2042;
    
    <h2 id=running2to3>Running <code>2to3</code></h2>
    <p>We&#8217;re going to migrate the <code>chardet</code> module from Python 2 to Python 3. Python 3 comes with a utility script called <code>2to3</code>, which takes your actual Python 2 source code as input and auto-converts as much as it can to Python 3. In some cases this is easy&nbsp;&mdash;&nbsp;a function was renamed or moved to a different module&nbsp;&mdash;&nbsp;but in other cases it can get pretty complex. To get a sense of all that it <em>can</em> do, refer to the appendix, <a href=porting-code-to-python-3-with-2to3.html>Porting code to Python 3 with <code>2to3</code></a>. In this chapter, we&#8217;ll start by running <code>2to3</code> on the <code>chardet</code> package, but as you&#8217;ll see, there will still be a lot of work to do after the automated tools have performed their magic.
    <p>The main <code>chardet</code> package is split across several different files, all in the same directory. The <code>2to3</code> script makes it easy to convert multiple files at once: just pass a directory as a command line argument, and <code>2to3</code> will convert each of the files in turn.
    <pre class=screen><samp class=p>C:\home\chardet> </samp><kbd>python c:\Python30\Tools\Scripts\2to3.py -w chardet\</kbd>
    <samp>RefactoringTool: Skipping implicit fixer: buffer
    RefactoringTool: Skipping implicit fixer: idioms
    RefactoringTool: Skipping implicit fixer: set_literal
    RefactoringTool: Skipping implicit fixer: ws_comma
    --- chardet\__init__.py (original)
    +++ chardet\__init__.py (refactored)
    @@ -18,7 +18,7 @@
     __version__ = "1.0.1"
    
     def detect(aBuf):
    <del>-    import universaldetector</del>
    <ins>+    from . import universaldetector</ins>
         u = universaldetector.UniversalDetector()
         u.reset()
         u.feed(aBuf)
    --- chardet\big5prober.py (original)
    +++ chardet\big5prober.py (refactored)
    @@ -25,10 +25,10 @@
     # 02110-1301  USA
     ######################### END LICENSE BLOCK #########################
    
    <del>-from mbcharsetprober import MultiByteCharSetProber</del>
    <del>-from codingstatemachine import CodingStateMachine</del>
    <del>-from chardistribution import Big5DistributionAnalysis</del>
    <del>-from mbcssm import Big5SMModel</del>
    <ins>+from .mbcharsetprober import MultiByteCharSetProber</ins>
    <ins>+from .codingstatemachine import CodingStateMachine</ins>
    <ins>+from .chardistribution import Big5DistributionAnalysis</ins>
    <ins>+from .mbcssm import Big5SMModel</ins>
    
     class Big5Prober(MultiByteCharSetProber):
         def __init__(self):
    --- chardet\chardistribution.py (original)
    +++ chardet\chardistribution.py (refactored)
    @@ -25,12 +25,12 @@
     # 02110-1301  USA
     ######################### END LICENSE BLOCK #########################
    
    <del>-import constants</del>
    <del>-from euctwfreq import EUCTWCharToFreqOrder, EUCTW_TABLE_SIZE, EUCTW_TYPICAL_DISTRIBUTION_RATIO</del>
    <del>-from euckrfreq import EUCKRCharToFreqOrder, EUCKR_TABLE_SIZE, EUCKR_TYPICAL_DISTRIBUTION_RATIO</del>
    <del>-from gb2312freq import GB2312CharToFreqOrder, GB2312_TABLE_SIZE, GB2312_TYPICAL_DISTRIBUTION_RATIO</del>
    <del>-from big5freq import Big5CharToFreqOrder, BIG5_TABLE_SIZE, BIG5_TYPICAL_DISTRIBUTION_RATIO</del>
    <del>-from jisfreq import JISCharToFreqOrder, JIS_TABLE_SIZE, JIS_TYPICAL_DISTRIBUTION_RATIO</del>
    <ins>+from . import constants</ins>
    <ins>+from .euctwfreq import EUCTWCharToFreqOrder, EUCTW_TABLE_SIZE, EUCTW_TYPICAL_DISTRIBUTION_RATIO</ins>
    <ins>+from .euckrfreq import EUCKRCharToFreqOrder, EUCKR_TABLE_SIZE, EUCKR_TYPICAL_DISTRIBUTION_RATIO</ins>
    <ins>+from .gb2312freq import GB2312CharToFreqOrder, GB2312_TABLE_SIZE, GB2312_TYPICAL_DISTRIBUTION_RATIO</ins>
    <ins>+from .big5freq import Big5CharToFreqOrder, BIG5_TABLE_SIZE, BIG5_TYPICAL_DISTRIBUTION_RATIO</ins>
    <ins>+from .jisfreq import JISCharToFreqOrder, JIS_TABLE_SIZE, JIS_TYPICAL_DISTRIBUTION_RATIO</ins>
    
     ENOUGH_DATA_THRESHOLD = 1024
     SURE_YES = 0.99
    .
    .
    <mark>. (it goes on like this for a while)</mark>
    .
    .
    RefactoringTool: Files that were modified:
    RefactoringTool: chardet\__init__.py
    RefactoringTool: chardet\big5prober.py
    RefactoringTool: chardet\chardistribution.py
    RefactoringTool: chardet\charsetgroupprober.py
    RefactoringTool: chardet\codingstatemachine.py
    RefactoringTool: chardet\constants.py
    RefactoringTool: chardet\escprober.py
    RefactoringTool: chardet\escsm.py
    RefactoringTool: chardet\eucjpprober.py
    RefactoringTool: chardet\euckrprober.py
    RefactoringTool: chardet\euctwprober.py
    RefactoringTool: chardet\gb2312prober.py
    RefactoringTool: chardet\hebrewprober.py
    RefactoringTool: chardet\jpcntx.py
    RefactoringTool: chardet\langbulgarianmodel.py
    RefactoringTool: chardet\langcyrillicmodel.py
    RefactoringTool: chardet\langgreekmodel.py
    RefactoringTool: chardet\langhebrewmodel.py
    RefactoringTool: chardet\langhungarianmodel.py
    RefactoringTool: chardet\langthaimodel.py
    RefactoringTool: chardet\latin1prober.py
    RefactoringTool: chardet\mbcharsetprober.py
    RefactoringTool: chardet\mbcsgroupprober.py
    RefactoringTool: chardet\mbcssm.py
    RefactoringTool: chardet\sbcharsetprober.py
    RefactoringTool: chardet\sbcsgroupprober.py
    RefactoringTool: chardet\sjisprober.py
    RefactoringTool: chardet\universaldetector.py
    RefactoringTool: chardet\utf8prober.py</samp></pre>
    <p>Now run the <code>2to3</code> script on the testing harness, <code>test.py</code>.
    <pre class='nd screen'><samp class=p>C:\home\chardet> </samp><kbd>python c:\Python30\Tools\Scripts\2to3.py -w test.py</kbd>
    <samp>RefactoringTool: Skipping implicit fixer: buffer
    RefactoringTool: Skipping implicit fixer: idioms
    RefactoringTool: Skipping implicit fixer: set_literal
    RefactoringTool: Skipping implicit fixer: ws_comma
    --- test.py (original)
    +++ test.py (refactored)
    @@ -4,7 +4,7 @@
     count = 0
     u = UniversalDetector()
     for f in glob.glob(sys.argv[1]):
    <del>-    print f.ljust(60),</del>
    <ins>+    print(f.ljust(60), end=' ')</ins>
         u.reset()
         for line in file(f, 'rb'):
             u.feed(line)
    @@ -12,8 +12,8 @@
         u.close()
         result = u.result
         if result['encoding']:
    <del>-        print result['encoding'], 'with confidence', result['confidence']</del>
    <ins>+        print(result['encoding'], 'with confidence', result['confidence'])</ins>
         else:
    <del>-        print '******** no result'</del>
    <ins>+        print('******** no result')</ins>
         count += 1
    <del>-print count, 'tests'</del>
    <ins>+print(count, 'tests')</ins>
    RefactoringTool: Files that were modified:
    RefactoringTool: test.py</samp></pre>
    <p>Well, that wasn&#8217;t so hard. Just a few imports and print statements to convert. Speaking of which, what <em>was</em> the problem with all those import statements? To answer that, you need to understand how the <code>chardet</code> module is split into multiple files.
    
    <p class=a>&#x2042;
    
    <h2 id=multifile-modules>A Short Digression Into Multi-File Modules</h2>
    
    <p><code>chardet</code> is a <i>multi-file module</i>. I could have chosen to put all the code in one file (named <code>chardet.py</code>), but I didn&#8217;t. Instead, I made a directory (named <code>chardet</code>), then I made an <code>__init__.py</code> file in that directory. <em>If Python sees an <code>__init__.py</code> file in a directory, it assumes that all of the files in that directory are part of the same module.</em> The module&#8217;s name is the name of the directory. Files within the directory can reference other files within the same directory, or even within subdirectories. (More on that in a minute.) But the entire collection of files is presented to other Python code as a single module&nbsp;&mdash;&nbsp;as if all the functions and classes were in a single <code>.py</code> file.
    
    <p>What goes in the <code>__init__.py</code> file? Nothing. Everything. Something in between. The <code>__init__.py</code> file doesn&#8217;t need to define anything; it can literally be an empty file. Or you can use it to define your main entry point functions. Or you put all your functions in it. Or all but one.
    
    <blockquote class=note>
    <p><span class=u>&#x261E;</span>A directory with an <code>__init__.py</code> file is always treated as a multi-file module. Without an <code>__init__.py</code> file, a directory is just a directory of unrelated <code>.py</code> files.
    </blockquote>
    
    <p>Let&#8217;s see how that works in practice.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>import chardet</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>dir(chardet)</kbd>             <span class=u>&#x2460;</span></a>
    <samp class=pp>['__builtins__', '__doc__', '__file__', '__name__',
     '__package__', '__path__', '__version__', 'detect']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>chardet</kbd>                  <span class=u>&#x2461;</span></a>
    <samp class=pp>&lt;module 'chardet' from 'C:\Python31\lib\site-packages\chardet\__init__.py'></samp></pre>
    <ol>
    <li>Other than the usual class attributes, the only thing in the <code>chardet</code> module is a <code>detect()</code> function.
    <li>Here&#8217;s your first clue that the <code>chardet</code> module is more than just a file: the &#8220;module&#8221; is listed as the <code>__init__.py</code> file within the <code>chardet/</code> directory.
    </ol>
    
    <p>Let&#8217;s take a peek in that <code>__init__.py</code> file.
    
    <pre class=pp><code><a>def detect(aBuf):                              <span class=u>&#x2460;</span></a>
    <a>    from . import universaldetector            <span class=u>&#x2461;</span></a>
        u = universaldetector.UniversalDetector()
        u.reset()
        u.feed(aBuf)
        u.close()
        return u.result</code></pre>
    <ol>
    <li>The <code>__init__.py</code> file defines the <code>detect()</code> function, which is the main entry point into the <code>chardet</code> library.
    <li>But the <code>detect()</code> function hardly has any code! In fact, all it really does is import the <code>universaldetector</code> module and start using it. But where is <code>universaldetector</code> defined?
    </ol>
    
    <p>The answer lies in that odd-looking <code>import</code> statement:
    
    <pre class='nd pp'><code>from . import universaldetector</code></pre>
    
    <p>Translated into English, that means &#8220;import the <code>universaldetector</code> module; that&#8217;s in the same directory I am,&#8221; where &#8220;I&#8221; is the <code>chardet/__init__.py</code> file. This is called a <i>relative import</i>. It&#8217;s a way for the files within a multi-file module to reference each other, without worrying about naming conflicts with other modules you may have installed in <a href=your-first-python-program.html#importsearchpath>your import search path</a>. This <code>import</code> statement will <em>only</em> look for the <code>universaldetector</code> module within the <code>chardet/</code> directory itself.
    
    <p>These two concepts&nbsp;&mdash;&nbsp;<code>__init__.py</code> and relative imports&nbsp;&mdash;&nbsp;mean that you can break up your module into as many pieces as you like. The <code>chardet</code> module comprises 36 <code>.py</code> files&nbsp;&mdash;&nbsp;36! Yet all you need to do to start using it is <code>import chardet</code>, then you can call the main <code>chardet.detect()</code> function. Unbeknownst to your code, the <code>detect()</code> function is actually defined in the <code>chardet/__init__.py</code> file. Also unbeknownst to you, the <code>detect()</code> function uses a relative import to reference a class defined in <code>chardet/universaldetector.py</code>, which in turn uses relative imports on five other files, all contained in the <code>chardet/</code> directory.
    
    <blockquote class=note>
    <p><span class=u>&#x261E;</span>If you ever find yourself writing a large library in Python (or more likely, when you realize that your small library has grown into a large one), take the time to refactor it into a multi-file module. It&#8217;s one of the many things Python is good at, so take advantage of it.
    </blockquote>
    
    <p class=a>&#x2042;
    
    <h2 id=manual>Fixing What <code>2to3</code> Can&#8217;t</h2>
    <h3 id=falseisinvalidsyntax><code>False</code> is invalid syntax</h3>
    <aside>You do have tests, right?</aside>
    <p>Now for the real test: running the test harness against the test suite. Since the test suite is designed to cover all the possible code paths, it&#8217;s a good way to test our ported code to make sure there aren&#8217;t any bugs lurking anywhere.
    <pre class='nd screen'><samp class=p>C:\home\chardet> </samp><kbd>python test.py tests\*\*</kbd>
    <samp class=traceback>Traceback (most recent call last):
      File "test.py", line 1, in &lt;module>
        from chardet.universaldetector import UniversalDetector
      File "C:\home\chardet\chardet\universaldetector.py", line 51
        self.done = constants.False
                                  ^
    SyntaxError: invalid syntax</samp></pre>
    <p>Hmm, a small snag. In Python 3, <code>False</code> is a reserved word, so you can&#8217;t use it as a variable name. Let&#8217;s look at <code>constants.py</code> to see where it&#8217;s defined. Here&#8217;s the original version from <code>constants.py</code>, before the <code>2to3</code> script changed it:
    <pre class='nd pp'><code>import __builtin__
    if not hasattr(__builtin__, 'False'):
        False = 0
        True = 1
    else:
        False = __builtin__.False
        True = __builtin__.True</code></pre>
    <p>This piece of code is designed to allow this library to run under older versions of Python 2. Prior to Python 2.3, Python had no built-in <code>bool</code> type. This code detects the absence of the built-in constants <code>True</code> and <code>False</code>, and defines them if necessary.
    <p>However, Python 3 will always have a <code>bool</code> type, so this entire code snippet is unnecessary. The simplest solution is to replace all instances of <code>constants.True</code> and <code>constants.False</code> with <code>True</code> and <code>False</code>, respectively, then delete this dead code from <code>constants.py</code>.
    <p>So this line in <code>universaldetector.py</code>:
    <pre class='nd pp'><code>self.done = constants.False</code></pre>
    <p>Becomes
    <pre class='nd pp'><code>self.done = False</code></pre>
    <p>Ah, wasn&#8217;t that satisfying? The code is shorter and more readable already.
    <h3 id=nomodulenamedconstants>No module named <code>constants</code></h3>
    <p>Time to run <code>test.py</code> again and see how far it gets.
    <pre class='nd screen'><samp class=p>C:\home\chardet> </samp><kbd>python test.py tests\*\*</kbd>
    <samp class=traceback>Traceback (most recent call last):
      File "test.py", line 1, in &lt;module>
        from chardet.universaldetector import UniversalDetector
      File "C:\home\chardet\chardet\universaldetector.py", line 29, in &lt;module>
        import constants, sys
    ImportError: No module named constants</samp></pre>
    <p>What&#8217;s that you say? No module named <code>constants</code>? Of course there&#8217;s a module named <code>constants</code>. It&#8217;s right there, in <code>chardet/constants.py</code>.
    
    <p>Remember when the <code>2to3</code> script fixed up all those import statements? This library has a lot of relative imports&nbsp;&mdash;&nbsp;that is, <a href=#multifile-modules>modules that import other modules within the same library</a>&nbsp;&mdash;&nbsp;but <em>the logic behind relative imports has changed in Python 3</em>. In Python 2, you could just <code>import constants</code> and it would look in the <code>chardet/</code> directory first. In Python 3, <a href=http://www.python.org/dev/peps/pep-0328/>all import statements are absolute by default</a>. If you want to do a relative import in Python 3, you need to be explicit about it:
    <pre class='nd pp'><code>from . import constants</code></pre>
    <p>But wait. Wasn&#8217;t the <code>2to3</code> script supposed to take care of these for you? Well, it did, but this particular import statement combines two different types of imports into one line: a relative import of the <code>constants</code> module within the library, and an absolute import of the <code>sys</code> module that is pre-installed in the Python standard library. In Python 2, you could combine these into one import statement. In Python 3, you can&#8217;t, and the <code>2to3</code> script is not smart enough to split the import statement into two.
    <p>The solution is to split the import statement manually. So this two-in-one import:
    <pre class='nd pp'><code>import constants, sys</code></pre>
    <p>Needs to become two separate imports:
    <pre class='nd pp'><code>from . import constants
    import sys</code></pre>
    <p>There are variations of this problem scattered throughout the <code>chardet</code> library. In some places it&#8217;s &#8220;<code>import constants, sys</code>&#8221;; in other places, it&#8217;s &#8220;<code>import constants, re</code>&#8221;. The fix is the same: manually split the import statement into two lines, one for the relative import, the other for the absolute import.
    <p>Onward!
    <h3 id=namefileisnotdefined>Name <var>'file'</var> is not defined</h3>
    <aside>open() is the new file(). PapayaWhip is the new black.</aside>
    <p>And here we go again, running <code>test.py</code> to try to execute our test cases&hellip;
    <pre class='nd screen'><samp class=p>C:\home\chardet> </samp><kbd>python test.py tests\*\*</kbd>
    <samp>tests\ascii\howto.diveintomark.org.xml</samp>
    <samp class=traceback>Traceback (most recent call last):
      File "test.py", line 9, in &lt;module>
        for line in file(f, 'rb'):
    NameError: name 'file' is not defined</samp></pre>
    <p>This one surprised me, because I&#8217;ve been using this idiom as long as I can remember. In Python 2, the global <code>file()</code> function was an alias for the <code>open()</code> function, which was the standard way of <a href=files.html#reading>opening text files for reading</a>. In Python 3, the global <code>file()</code> function no longer exists, but the <code>open()</code> function still exists.
    <p>Thus, the simplest solution to the problem of the missing <code>file()</code> is to call the <code>open()</code> function instead:
    <pre class='nd pp'><code>for line in open(f, 'rb'):</code></pre>
    <p>And that&#8217;s all I have to say about that.
    <h3 id=cantuseastringpattern>Can&#8217;t use a string pattern on a bytes-like object</h3>
    <p>Now things are starting to get interesting. And by &#8220;interesting,&#8221; I mean &#8220;confusing as all hell.&#8221;
    <pre class='nd screen'><samp class=p>C:\home\chardet> </samp><kbd>python test.py tests\*\*</kbd>
    <samp>tests\ascii\howto.diveintomark.org.xml</samp>
    <samp class=traceback>Traceback (most recent call last):
      File "test.py", line 10, in &lt;module>
        u.feed(line)
      File "C:\home\chardet\chardet\universaldetector.py", line 98, in feed
        if self._highBitDetector.search(aBuf):
    TypeError: can't use a string pattern on a bytes-like object</samp></pre>
    <p>To debug this, let&#8217;s see what <var>self._highBitDetector</var> is. It&#8217;s defined in the <var>__init__</var> method of the <var>UniversalDetector</var> class:
    <pre class='nd pp'><code>class UniversalDetector:
        def __init__(self):
            self._highBitDetector = re.compile(r'[\x80-\xFF]')</code></pre>
    <p>This pre-compiles a regular expression designed to find non-<abbr>ASCII</abbr> characters in the range 128&ndash;255 (0x80&ndash;0xFF). Wait, that&#8217;s not quite right; I need to be more precise with my terminology. This pattern is designed to find non-<abbr>ASCII</abbr> <em>bytes</em> in the range 128-255.
    <p>And therein lies the problem.
    <p>In Python 2, a string was an array of bytes whose character encoding was tracked separately. If you wanted Python 2 to keep track of the character encoding, you had to use a Unicode string (<code>u''</code>) instead. But in Python 3, a string is always what Python 2 called a Unicode string&nbsp;&mdash;&nbsp;that is, an array of Unicode characters (of possibly varying byte lengths). Since this regular expression is defined by a string pattern, it can only be used to search a string&nbsp;&mdash;&nbsp;again, an array of characters. But what we&#8217;re searching is not a string, it&#8217;s a byte array. Looking at the traceback, this error occurred in <code>universaldetector.py</code>:
    <pre class='nd pp'><code>def feed(self, aBuf):
        .
        .
        .
        if self._mInputState == ePureAscii:
            if self._highBitDetector.search(aBuf):</code></pre>
    <p>And what is <var>aBuf</var>? Let&#8217;s backtrack further to a place that calls <code>UniversalDetector.feed()</code>. One place that calls it is the test harness, <code>test.py</code>.
    <pre class='nd pp'><code>u = UniversalDetector()
    .
    .
    .
    for line in open(f, 'rb'):
        u.feed(line)</code></pre>
    <aside>Not an array of characters, but an array of bytes.</aside>
    <p>And here we find our answer: in the <code>UniversalDetector.feed()</code> method, <var>aBuf</var> is a line read from a file on disk. Look carefully at the parameters used to open the file: <code>'rb'</code>. <code>'r'</code> is for &#8220;read&#8221;; OK, big deal, we&#8217;re reading the file. Ah, but <a href=files.html#binary><code>'b'</code> is for &#8220;binary.&#8221;</a> Without the <code>'b'</code> flag, this <code>for</code> loop would read the file, line by line, and convert each line into a string&nbsp;&mdash;&nbsp;an array of Unicode characters&nbsp;&mdash;&nbsp;according to the system default character encoding. But with the <code>'b'</code> flag, this <code>for</code> loop reads the file, line by line, and stores each line exactly as it appears in the file, as an array of bytes. That byte array gets passed to <code>UniversalDetector.feed()</code>, and eventually gets passed to the pre-compiled regular expression, <var>self._highBitDetector</var>, to search for high-bit&hellip; characters. But we don&#8217;t have characters; we have bytes. Oops.
    <p>What we need this regular expression to search is not an array of characters, but an array of bytes.
    <p>Once you realize that, the solution is not difficult. Regular expressions defined with strings can search strings. Regular expressions defined with byte arrays can search byte arrays. To define a byte array pattern, we simply change the type of the argument we use to define the regular expression to a byte array. (There is one other case of this same problem, on the very next line.)
    <pre class='nd pp'><code>  class UniversalDetector:
          def __init__(self):
    <del>-         self._highBitDetector = re.compile(r'[\x80-\xFF]')</del>
    <del>-         self._escDetector = re.compile(r'(\033|~{)')</del>
    <ins>+         self._highBitDetector = re.compile(b'[\x80-\xFF]')</ins>
    <ins>+         self._escDetector = re.compile(b'(\033|~{)')</ins>
              self._mEscCharSetProber = None
              self._mCharSetProbers = []
              self.reset()</code></pre>
    <p>Searching the entire codebase for other uses of the <code>re</code> module turns up two more instances, in <code>charsetprober.py</code>. Again, the code is defining regular expressions as strings but executing them on <var>aBuf</var>, which is a byte array. The solution is the same: define the regular expression patterns as byte arrays.
    <pre class='nd pp'><code>  class CharSetProber:
          .
          .
          .
          def filter_high_bit_only(self, aBuf):
    <del>-         aBuf = re.sub(r'([\x00-\x7F])+', ' ', aBuf)</del>
    <ins>+         aBuf = re.sub(b'([\x00-\x7F])+', b' ', aBuf)</ins>
              return aBuf
        
          def filter_without_english_letters(self, aBuf):
    <del>-         aBuf = re.sub(r'([A-Za-z])+', ' ', aBuf)</del>
    <ins>+         aBuf = re.sub(b'([A-Za-z])+', b' ', aBuf)</ins>
              return aBuf</code></pre>
            
    <h3 id=cantconvertbytesobject>Can't convert <code>'bytes'</code> object to <code>str</code> implicitly</h3>
    <p>Curiouser and curiouser&hellip;
    <pre class='nd screen'><samp class=p>C:\home\chardet> </samp><kbd>python test.py tests\*\*</kbd>
    <samp>tests\ascii\howto.diveintomark.org.xml</samp>
    <samp class=traceback>Traceback (most recent call last):
      File "test.py", line 10, in &lt;module>
        u.feed(line)
      File "C:\home\chardet\chardet\universaldetector.py", line 100, in feed
        elif (self._mInputState == ePureAscii) and self._escDetector.search(self._mLastChar + aBuf):
    TypeError: Can't convert 'bytes' object to str implicitly</samp></pre>
    <p>There&#8217;s an unfortunate clash of coding style and Python interpreter here. The <code>TypeError</code> could be anywhere on that line, but the traceback doesn&#8217;t tell you exactly where it is. It could be in the first conditional or the second, and the traceback would look the same. To narrow it down, you should split the line in half, like this:
    <pre class='nd pp'><code>elif (self._mInputState == ePureAscii) and \
        self._escDetector.search(self._mLastChar + aBuf):</code></pre>
    <p>And re-run the test:
    <pre class='nd screen'><samp class=p>C:\home\chardet> </samp><kbd>python test.py tests\*\*</kbd>
    <samp>tests\ascii\howto.diveintomark.org.xml</samp>
    <samp class=traceback>Traceback (most recent call last):
      File "test.py", line 10, in &lt;module>
        u.feed(line)
      File "C:\home\chardet\chardet\universaldetector.py", line 101, in feed
        self._escDetector.search(self._mLastChar + aBuf):
    TypeError: Can't convert 'bytes' object to str implicitly</samp></pre>
    <p>Aha! The problem was not in the first conditional (<code>self._mInputState == ePureAscii</code>) but in the second one. So what could cause a <code>TypeError</code> there? Perhaps you&#8217;re thinking that the <code>search()</code> method is expecting a value of a different type, but that wouldn&#8217;t generate this traceback. Python functions can take any value; if you pass the right number of arguments, the function will execute. It may <em>crash</em> if you pass it a value of a different type than it&#8217;s expecting, but if that happened, the traceback would point to somewhere inside the function. But this traceback says it never got as far as calling the <code>search()</code> method. So the problem must be in that <code>+</code> operation, as it&#8217;s trying to construct the value that it will eventually pass to the <code>search()</code> method.
    <p>We know from <a href=#cantuseastringpattern>previous debugging</a> that <var>aBuf</var> is a byte array. So what is <code>self._mLastChar</code>? It&#8217;s an instance variable, defined in the <code>reset()</code> method, which is actually called from the <code>__init__()</code> method.
    <pre class='nd pp'><code>class UniversalDetector:
        def __init__(self):
            self._highBitDetector = re.compile(b'[\x80-\xFF]')
            self._escDetector = re.compile(b'(\033|~{)')
            self._mEscCharSetProber = None
            self._mCharSetProbers = []
    <mark>        self.reset()</mark>
    
        def reset(self):
            self.result = {'encoding': None, 'confidence': 0.0}
            self.done = False
            self._mStart = True
            self._mGotData = False
            self._mInputState = ePureAscii
    <mark>        self._mLastChar = ''</mark></code></pre>
    <p>And now we have our answer. Do you see it? <var>self._mLastChar</var> is a string, but <var>aBuf</var> is a byte array. And you can&#8217;t concatenate a string to a byte array&nbsp;&mdash;&nbsp;not even a zero-length string.
    <p>So what is <var>self._mLastChar</var> anyway? In the <code>feed()</code> method, just a few lines down from where the trackback occurred.
    <pre class='nd pp'><code>if self._mInputState == ePureAscii:
        if self._highBitDetector.search(aBuf):
            self._mInputState = eHighbyte
        elif (self._mInputState == ePureAscii) and \
                self._escDetector.search(self._mLastChar + aBuf):
            self._mInputState = eEscAscii
    
    <mark>self._mLastChar = aBuf[-1]</mark></code></pre>
    <p>The calling function calls this <code>feed()</code> method over and over again with a few bytes at a time. The method processes the bytes it was given (passed in as <var>aBuf</var>), then stores the last byte in <var>self._mLastChar</var> in case it&#8217;s needed during the next call. (In a multi-byte encoding, the <code>feed()</code> method might get called with half of a character, then called again with the other half.)  But because <var>aBuf</var> is now a byte array instead of a string, <var>self._mLastChar</var> needs to be a byte array as well. Thus:
    <pre class='nd pp'><code>  def reset(self):
          .
          .
          .
    <del>-     self._mLastChar = ''</del>
    <ins>+     self._mLastChar = b''</ins></code></pre>
    <p>Searching the entire codebase for &#8220;<code>mLastChar</code>&#8221; turns up a similar problem in <code>mbcharsetprober.py</code>, but instead of tracking the last character, it tracks the last <em>two</em> characters. The <code>MultiByteCharSetProber</code> class uses a list of 1-character strings to track the last two characters. In Python 3, it needs to use a list of integers, because it&#8217;s not really tracking characters, it&#8217;s tracking bytes. (Bytes are just integers from <code>0-255</code>.)
    <pre class='nd pp'><code>  class MultiByteCharSetProber(CharSetProber):
          def __init__(self):
              CharSetProber.__init__(self)
              self._mDistributionAnalyzer = None
              self._mCodingSM = None
    <del>-         self._mLastChar = ['\x00', '\x00']</del>
    <ins>+         self._mLastChar = [0, 0]</ins>
    
          def reset(self):
              CharSetProber.reset(self)
              if self._mCodingSM:
                  self._mCodingSM.reset()
              if self._mDistributionAnalyzer:
                  self._mDistributionAnalyzer.reset()
    <del>-         self._mLastChar = ['\x00', '\x00']</del>
    <ins>+         self._mLastChar = [0, 0]</ins></code></pre>
    <h3 id=unsupportedoperandtypeforplus>Unsupported operand type(s) for +: <code>'int'</code> and <code>'bytes'</code></h3>
    <p>I have good news, and I have bad news. The good news is we&#8217;re making progress&hellip;
    <pre class='nd screen'><samp class=p>C:\home\chardet> </samp><kbd>python test.py tests\*\*</kbd>
    <samp>tests\ascii\howto.diveintomark.org.xml</samp>
    <samp class=traceback>Traceback (most recent call last):
      File "test.py", line 10, in &lt;module>
        u.feed(line)
      File "C:\home\chardet\chardet\universaldetector.py", line 101, in feed
        self._escDetector.search(self._mLastChar + aBuf):
    TypeError: unsupported operand type(s) for +: 'int' and 'bytes'</samp></pre>
    <p>&hellip;The bad news is it doesn&#8217;t always feel like progress.
    <p>But this is progress! Really! Even though the traceback calls out the same line of code, it&#8217;s a different error than it used to be. Progress! So what&#8217;s the problem now? The last time I checked, this line of code didn&#8217;t try to concatenate an <code>int</code> with a byte array (<code>bytes</code>). In fact, you just spent a lot of time <a href=#cantconvertbytesobject>ensuring that <var>self._mLastChar</var> was a byte array</a>. How did it turn into an <code>int</code>?
    <p>The answer lies not in the previous lines of code, but in the following lines.
    <pre class='nd pp'><code>if self._mInputState == ePureAscii:
        if self._highBitDetector.search(aBuf):
            self._mInputState = eHighbyte
        elif (self._mInputState == ePureAscii) and \
                self._escDetector.search(self._mLastChar + aBuf):
            self._mInputState = eEscAscii
    
    <mark>self._mLastChar = aBuf[-1]</mark></code></pre>
    <aside>Each item in a string is a string. Each item in a byte array is an integer.</aside>
    <p>This error doesn&#8217;t occur the first time the <code>feed()</code> method gets called; it occurs the <em>second time</em>, after <var>self._mLastChar</var> has been set to the last byte of <var>aBuf</var>. Well, what&#8217;s the problem with that? Getting a single element from a byte array yields an integer, not a byte array. To see the difference, follow me to the interactive shell:
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>aBuf = b'\xEF\xBB\xBF'</kbd>         <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>len(aBuf)</kbd>
    <samp class=pp>3</samp>
    <samp class=p>>>> </samp><kbd class=pp>mLastChar = aBuf[-1]</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>mLastChar</kbd>                      <span class=u>&#x2461;</span></a>
    <samp class=pp>191</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>type(mLastChar)</kbd>                <span class=u>&#x2462;</span></a>
    <samp class=pp>&lt;class 'int'></samp>
    <a><samp class=p>>>> </samp><kbd class=pp>mLastChar + aBuf</kbd>               <span class=u>&#x2463;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
    TypeError: unsupported operand type(s) for +: 'int' and 'bytes'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>mLastChar = aBuf[-1:]</kbd>          <span class=u>&#x2464;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>mLastChar</kbd>
    <samp class=pp>b'\xbf'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>mLastChar + aBuf</kbd>               <span class=u>&#x2465;</span></a>
    <samp class=pp>b'\xbf\xef\xbb\xbf'</samp></pre>
    <ol>
    <li>Define a byte array of length 3.
    <li>The last element of the byte array is 191.
    <li>That&#8217;s an integer.
    <li>Concatenating an integer with a byte array doesn&#8217;t work. You&#8217;ve now replicated the error you just found in <code>universaldetector.py</code>.
    <li>Ah, here&#8217;s the fix. Instead of taking the last element of the byte array, use <a href=native-datatypes.html#slicinglists>list slicing</a> to create a new byte array containing just the last element. That is, start with the last element and continue the slice until the end of the byte array. Now <var>mLastChar</var> is a byte array of length 1.
    <li>Concatenating a byte array of length 1 with a byte array of length 3 returns a new byte array of length 4.
    </ol>
    <p>So, to ensure that the <code>feed()</code> method in <code>universaldetector.py</code> continues to work no matter how often it&#8217;s called, you need to <a href=#cantconvertbytesobject>initialize <var>self._mLastChar</var> as a 0-length byte array</a>, then <em>make sure it stays a byte array</em>.
    <pre class='nd pp'><code>              self._escDetector.search(self._mLastChar + aBuf):
              self._mInputState = eEscAscii
    
    <del>- self._mLastChar = aBuf[-1]</del>
    <ins>+ self._mLastChar = aBuf[-1:]</ins></code></pre>
    <h3 id=ordexpectedstring><code>ord()</code> expected string of length 1, but <code>int</code> found</h3>
    <p>Tired yet? You&#8217;re almost there&hellip;
    <pre class='nd screen'><samp class=p>C:\home\chardet> </samp><kbd>python test.py tests\*\*</kbd>
    <samp>tests\ascii\howto.diveintomark.org.xml                       ascii with confidence 1.0
    tests\Big5\0804.blogspot.com.xml</samp>
    <samp class=traceback>Traceback (most recent call last):
      File "test.py", line 10, in &lt;module>
        u.feed(line)
      File "C:\home\chardet\chardet\universaldetector.py", line 116, in feed
        if prober.feed(aBuf) == constants.eFoundIt:
      File "C:\home\chardet\chardet\charsetgroupprober.py", line 60, in feed
        st = prober.feed(aBuf)
      File "C:\home\chardet\chardet\utf8prober.py", line 53, in feed
        codingState = self._mCodingSM.next_state(c)
      File "C:\home\chardet\chardet\codingstatemachine.py", line 43, in next_state
        byteCls = self._mModel['classTable'][ord(c)]
    TypeError: ord() expected string of length 1, but int found</samp></pre>
    <p>OK, so <var>c</var> is an <code>int</code>, but the <code>ord()</code> function was expecting a 1-character string. Fair enough. Where is <var>c</var> defined?
    <pre class='nd pp'><code># codingstatemachine.py
    def next_state(self, c):
        # for each byte we get its class
        # if it is first byte, we also get byte length
        byteCls = self._mModel['classTable'][ord(c)]</code></pre>
    <p>That&#8217;s no help; it&#8217;s just passed into the function. Let&#8217;s pop the stack.
    <pre class='nd pp'><code># utf8prober.py
    def feed(self, aBuf):
        for c in aBuf:
            codingState = self._mCodingSM.next_state(c)</code></pre>
    <p>Do you see it? In Python 2, <var>aBuf</var> was a string, so <var>c</var> was a 1-character string. (That&#8217;s what you get when you iterate over a string&nbsp;&mdash;&nbsp;all the characters, one by one.) But now, <var>aBuf</var> is a byte array, so <var>c</var> is an <code>int</code>, not a 1-character string. In other words, there&#8217;s no need to call the <code>ord()</code> function because <var>c</var> is already an <code>int</code>!
    <p>Thus:
    <pre class='nd pp'><code>  def next_state(self, c):
          # for each byte we get its class
          # if it is first byte, we also get byte length
    <del>-     byteCls = self._mModel['classTable'][ord(c)]</del>
    <ins>+     byteCls = self._mModel['classTable'][c]</ins></code></pre>
    <p>Searching the entire codebase for instances of &#8220;<code>ord(c)</code>&#8221; uncovers similar problems in <code>sbcharsetprober.py</code>&hellip;
    <pre class='nd pp'><code># sbcharsetprober.py
    def feed(self, aBuf):
        if not self._mModel['keepEnglishLetter']:
            aBuf = self.filter_without_english_letters(aBuf)
        aLen = len(aBuf)
        if not aLen:
            return self.get_state()
        for c in aBuf:
    <mark>        order = self._mModel['charToOrderMap'][ord(c)]</mark></code></pre>
    <p>&hellip;and <code>latin1prober.py</code>&hellip;
    <pre class='nd pp'><code># latin1prober.py
    def feed(self, aBuf):
        aBuf = self.filter_with_english_letters(aBuf)
        for c in aBuf:
    <mark>        charClass = Latin1_CharToClass[ord(c)]</mark></code></pre>
    <p><var>c</var> is iterating over <var>aBuf</var>, which means it is an integer, not a 1-character string.  The solution is the same: change <code>ord(c)</code> to just plain <code>c</code>.
    <pre class='nd pp'><code>  # sbcharsetprober.py
      def feed(self, aBuf):
          if not self._mModel['keepEnglishLetter']:
              aBuf = self.filter_without_english_letters(aBuf)
          aLen = len(aBuf)
          if not aLen:
              return self.get_state()
          for c in aBuf:
    <del>-         order = self._mModel['charToOrderMap'][ord(c)]</del>
    <ins>+         order = self._mModel['charToOrderMap'][c]</ins>
    
      # latin1prober.py
      def feed(self, aBuf):
          aBuf = self.filter_with_english_letters(aBuf)
          for c in aBuf:
    <del>-         charClass = Latin1_CharToClass[ord(c)]</del>
    <ins>+         charClass = Latin1_CharToClass[c]</ins>
    </code></pre>
    <h3 id=unorderabletypes>Unorderable types: <code>int()</code> >= <code>str()</code></h3>
    <p>Let&#8217;s go again.
    <pre class='nd screen'><samp class=p>C:\home\chardet> </samp><kbd>python test.py tests\*\*</kbd>
    <samp>tests\ascii\howto.diveintomark.org.xml                       ascii with confidence 1.0
    tests\Big5\0804.blogspot.com.xml</samp>
    <samp class=traceback>Traceback (most recent call last):
      File "test.py", line 10, in &lt;module>
        u.feed(line)
      File "C:\home\chardet\chardet\universaldetector.py", line 116, in feed
        if prober.feed(aBuf) == constants.eFoundIt:
      File "C:\home\chardet\chardet\charsetgroupprober.py", line 60, in feed
        st = prober.feed(aBuf)
      File "C:\home\chardet\chardet\sjisprober.py", line 68, in feed
        self._mContextAnalyzer.feed(self._mLastChar[2 - charLen :], charLen)
      File "C:\home\chardet\chardet\jpcntx.py", line 145, in feed
        order, charLen = self.get_order(aBuf[i:i+2])
      File "C:\home\chardet\chardet\jpcntx.py", line 176, in get_order
        if ((aStr[0] >= '\x81') and (aStr[0] &lt;= '\x9F')) or \
    TypeError: unorderable types: int() >= str()</samp></pre>
    <p>So what&#8217;s this all about? &#8220;Unorderable types&#8221;? Once again, the difference between byte arrays and strings is rearing its ugly head. Take a look at the code:
    <pre class='nd pp'><code>class SJISContextAnalysis(JapaneseContextAnalysis):
        def get_order(self, aStr):
            if not aStr: return -1, 1
            # find out current char's byte length
    <mark>        if ((aStr[0] >= '\x81') and (aStr[0] &lt;= '\x9F')) or \</mark>
               ((aStr[0] >= '\xE0') and (aStr[0] &lt;= '\xFC')):
                charLen = 2
            else:
                charLen = 1</code></pre>
    <p>And where does <var>aStr</var> come from? Let&#8217;s pop the stack:
    <pre class='nd pp'><code>def feed(self, aBuf, aLen):
        .
        .
        .
        i = self._mNeedToSkipCharNum
        while i &lt; aLen:
    <mark>        order, charLen = self.get_order(aBuf[i:i+2])</mark></code></pre>
    <p>Oh look, it&#8217;s our old friend, <var>aBuf</var>. As you might have guessed from every other issue we&#8217;ve encountered in this chapter, <var>aBuf</var> is a byte array. Here, the <code>feed()</code> method isn&#8217;t just passing it on wholesale; it&#8217;s slicing it. But as you saw <a href=#unsupportedoperandtypeforplus>earlier in this chapter</a>, slicing a byte array returns a byte array, so the <var>aStr</var> parameter that gets passed to the <code>get_order()</code> method is still a byte array.
    <p>And what is this code trying to do with <var>aStr</var>? It&#8217;s taking the first element of the byte array and comparing it to a string of length 1. In Python 2, that worked, because <var>aStr</var> and <var>aBuf</var> were strings, and <var>aStr[0]</var> would be a string, and you can compare strings for inequality. But in Python 3, <var>aStr</var> and <var>aBuf</var> are byte arrays, <var>aStr[0]</var> is an integer, and you can&#8217;t compare integers and strings for inequality without explicitly coercing one of them.
    <p>In this case, there&#8217;s no need to make the code more complicated by adding an explicit coercion. <var>aStr[0]</var> yields an integer; the things you&#8217;re comparing to are all constants. Let&#8217;s change them from 1-character strings to integers. And while we&#8217;re at it, let&#8217;s change <var>aStr</var> to <var>aBuf</var>, since it&#8217;s not actually a string.
    <pre class='nd pp'><code>  class SJISContextAnalysis(JapaneseContextAnalysis):
    <del>-     def get_order(self, aStr):</del>
    <del>-      if not aStr: return -1, 1</del>
    <ins>+     def get_order(self, aBuf):</ins>
    <ins>+      if not aBuf: return -1, 1</ins>
              # find out current char's byte length
    <del>-         if ((aStr[0] >= '\x81') and (aStr[0] &lt;= '\x9F')) or \</del>
    <del>-            ((aBuf[0] >= '\xE0') and (aBuf[0] &lt;= '\xFC')):</del>
    <ins>+         if ((aBuf[0] >= 0x81) and (aBuf[0] &lt;= 0x9F)) or \</ins>
    <ins>+            ((aBuf[0] >= 0xE0) and (aBuf[0] &lt;= 0xFC)):</ins>
                  charLen = 2
              else:
                  charLen = 1
    
              # return its order if it is hiragana
    <del>-      if len(aStr) > 1:</del>
    <del>-             if (aStr[0] == '\202') and \</del>
    <del>-                (aStr[1] >= '\x9F') and \</del>
    <del>-                (aStr[1] &lt;= '\xF1'):</del>
    <del>-                return ord(aStr[1]) - 0x9F, charLen</del>
    <ins>+      if len(aBuf) > 1:</ins>
    <ins>+             if (aBuf[0] == 202) and \</ins>
    <ins>+                (aBuf[1] >= 0x9F) and \</ins>
    <ins>+                (aBuf[1] &lt;= 0xF1):</ins>
    <ins>+                return aBuf[1] - 0x9F, charLen</ins>
    
              return -1, charLen
    
      class EUCJPContextAnalysis(JapaneseContextAnalysis):
    <del>-     def get_order(self, aStr):</del>
    <del>-      if not aStr: return -1, 1</del>
    <ins>+     def get_order(self, aBuf):</ins>
    <ins>+      if not aBuf: return -1, 1</ins>
              # find out current char's byte length
    <del>-         if (aStr[0] == '\x8E') or \</del>
    <del>-           ((aStr[0] >= '\xA1') and (aStr[0] &lt;= '\xFE')):</del>
    <ins>+         if (aBuf[0] == 0x8E) or \</ins>
    <ins>+           ((aBuf[0] >= 0xA1) and (aBuf[0] &lt;= 0xFE)):</ins>
                  charLen = 2
    <del>-         elif aStr[0] == '\x8F':</del>
    <ins>+         elif aBuf[0] == 0x8F:</ins>
                  charLen = 3
              else:
                  charLen = 1
    
            # return its order if it is hiragana
    <del>-    if len(aStr) > 1:</del>
    <del>-           if (aStr[0] == '\xA4') and \</del>
    <del>-              (aStr[1] >= '\xA1') and \</del>
    <del>-              (aStr[1] &lt;= '\xF3'):</del>
    <del>-                 return ord(aStr[1]) - 0xA1, charLen</del>
    <ins>+    if len(aBuf) > 1:</ins>
    <ins>+           if (aBuf[0] == 0xA4) and \</ins>
    <ins>+              (aBuf[1] >= 0xA1) and \</ins>
    <ins>+              (aBuf[1] &lt;= 0xF3):</ins>
    <ins>+               return aBuf[1] - 0xA1, charLen</ins>
    
            return -1, charLen</code></pre>
    <p>Searching the entire codebase for occurrences of the <code>ord()</code> function uncovers the same problem in <code>chardistribution.py</code> (specifically, in the <code>EUCTWDistributionAnalysis</code>, <code>EUCKRDistributionAnalysis</code>, <code>GB2312DistributionAnalysis</code>, <code>Big5DistributionAnalysis</code>, <code>SJISDistributionAnalysis</code>, and <code>EUCJPDistributionAnalysis</code> classes. In each case, the fix is similar to the change we made to the <code>EUCJPContextAnalysis</code> and <code>SJISContextAnalysis</code> classes in <code>jpcntx.py</code>.
    
    <h3 id=reduceisnotdefined>Global name <code>'reduce'</code> is not defined</h3>
    <p>Once more into the breach&hellip;
    <pre class='nd screen'><samp class=p>C:\home\chardet> </samp><kbd>python test.py tests\*\*</kbd>
    <samp>tests\ascii\howto.diveintomark.org.xml                       ascii with confidence 1.0
    tests\Big5\0804.blogspot.com.xml</samp>
    <samp class=traceback>Traceback (most recent call last):
      File "test.py", line 12, in &lt;module>
        u.close()
      File "C:\home\chardet\chardet\universaldetector.py", line 141, in close
        proberConfidence = prober.get_confidence()
      File "C:\home\chardet\chardet\latin1prober.py", line 126, in get_confidence
        total = reduce(operator.add, self._mFreqCounter)
    NameError: global name 'reduce' is not defined</samp></pre>
    <p>According to the official <a href=http://docs.python.org/3.0/whatsnew/3.0.html#builtins>What&#8217;s New In Python 3.0</a> guide, the <code>reduce()</code> function has been moved out of the global namespace and into the <code>functools</code> module. Quoting the guide: &#8220;Use <code>functools.reduce()</code> if you really need it; however, 99 percent of the time an explicit <code>for</code> loop is more readable.&#8221; You can read more about the decision from Guido van Rossum&#8217;s weblog: <a href='http://www.artima.com/weblogs/viewpost.jsp?thread=98196'>The fate of reduce() in Python 3000</a>.
    <pre class='nd pp'><code>def get_confidence(self):
        if self.get_state() == constants.eNotMe:
            return 0.01
      
    <mark>    total = reduce(operator.add, self._mFreqCounter)</mark></code></pre>
    <p>The <code>reduce()</code> function takes two arguments&nbsp;&mdash;&nbsp;a function and a list (strictly speaking, any iterable object will do)&nbsp;&mdash;&nbsp;and applies the function cumulatively to each item of the list. In other words, this is a fancy and roundabout way of adding up all the items in a list and returning the result.
    <p>This monstrosity was so common that Python added a global <code>sum()</code> function.
    <pre class='nd pp'><code>  def get_confidence(self):
          if self.get_state() == constants.eNotMe:
              return 0.01
      
    <del>-     total = reduce(operator.add, self._mFreqCounter)</del>
    <ins>+     total = sum(self._mFreqCounter)</ins></code></pre>
    <p>Since you&#8217;re no longer using the <code>operator</code> module, you can remove that <code>import</code> from the top of the file as well.
    <pre class='nd pp'><code>  from .charsetprober import CharSetProber
      from . import constants
    <del>- import operator</del></code></pre>
    <p>I CAN HAZ TESTZ?
    <pre class='nd screen'><samp class=p>C:\home\chardet> </samp><kbd>python test.py tests\*\*</kbd>
    <samp>tests\ascii\howto.diveintomark.org.xml                       ascii with confidence 1.0
    tests\Big5\0804.blogspot.com.xml                             Big5 with confidence 0.99
    tests\Big5\blog.worren.net.xml                               Big5 with confidence 0.99
    tests\Big5\carbonxiv.blogspot.com.xml                        Big5 with confidence 0.99
    tests\Big5\catshadow.blogspot.com.xml                        Big5 with confidence 0.99
    tests\Big5\coolloud.org.tw.xml                               Big5 with confidence 0.99
    tests\Big5\digitalwall.com.xml                               Big5 with confidence 0.99
    tests\Big5\ebao.us.xml                                       Big5 with confidence 0.99
    tests\Big5\fudesign.blogspot.com.xml                         Big5 with confidence 0.99
    tests\Big5\kafkatseng.blogspot.com.xml                       Big5 with confidence 0.99
    tests\Big5\ke207.blogspot.com.xml                            Big5 with confidence 0.99
    tests\Big5\leavesth.blogspot.com.xml                         Big5 with confidence 0.99
    tests\Big5\letterlego.blogspot.com.xml                       Big5 with confidence 0.99
    tests\Big5\linyijen.blogspot.com.xml                         Big5 with confidence 0.99
    tests\Big5\marilynwu.blogspot.com.xml                        Big5 with confidence 0.99
    tests\Big5\myblog.pchome.com.tw.xml                          Big5 with confidence 0.99
    tests\Big5\oui-design.com.xml                                Big5 with confidence 0.99
    tests\Big5\sanwenji.blogspot.com.xml                         Big5 with confidence 0.99
    tests\Big5\sinica.edu.tw.xml                                 Big5 with confidence 0.99
    tests\Big5\sylvia1976.blogspot.com.xml                       Big5 with confidence 0.99
    tests\Big5\tlkkuo.blogspot.com.xml                           Big5 with confidence 0.99
    tests\Big5\tw.blog.xubg.com.xml                              Big5 with confidence 0.99
    tests\Big5\unoriginalblog.com.xml                            Big5 with confidence 0.99
    tests\Big5\upsaid.com.xml                                    Big5 with confidence 0.99
    tests\Big5\willythecop.blogspot.com.xml                      Big5 with confidence 0.99
    tests\Big5\ytc.blogspot.com.xml                              Big5 with confidence 0.99
    tests\EUC-JP\aivy.co.jp.xml                                  EUC-JP with confidence 0.99
    tests\EUC-JP\akaname.main.jp.xml                             EUC-JP with confidence 0.99
    tests\EUC-JP\arclamp.jp.xml                                  EUC-JP with confidence 0.99
    .
    .
    .
    316 tests</samp></pre>
    <p>Holy crap, it actually works! <em><a href=http://www.hampsterdance.com/>/me does a little dance</a></em>
    <p class=a>&#x2042;
    
    <h2 id=summary>Summary</h2>
    <p>What have we learned?
    <ol>
    <li>Porting any non-trivial amount of code from Python 2 to Python 3 is going to be a pain. There&#8217;s no way around it. It&#8217;s hard.
    <li>The <a href=porting-code-to-python-3-with-2to3.html>automated <code>2to3</code> tool</a> is helpful as far as it goes, but it will only do the easy parts&nbsp;&mdash;&nbsp;function renames, module renames, syntax changes. It&#8217;s an impressive piece of engineering, but in the end it&#8217;s just an intelligent search-and-replace bot.
    <li>The #1 porting problem in this library was the difference between strings and bytes. In this case that seems obvious, since the whole point of the <code>chardet</code> library is to convert a stream of bytes into a string. But &#8220;a stream of bytes&#8221; comes up more often than you might think. Reading a file in &#8220;binary&#8221; mode? You&#8217;ll get a stream of bytes. Fetching a web page? Calling a web <abbr>API</abbr>? They return a stream of bytes, too.
    <li><em>You</em> need to understand your program. Thoroughly. Preferably because you wrote it, but at the very least, you need to be comfortable with all its quirks and musty corners. The bugs are everywhere.
    <li>Test cases are essential. Don&#8217;t port anything without them. The <em>only</em> reason I have any confidence that <code>chardet</code> works in Python 3 is that I started with a test suite that exercised all major code paths. If you don&#8217;t have any tests, write some tests before you start porting to Python 3. If you have a few tests, write more. If you have a lot of tests, then the real fun can begin.
    </ol>
    
    <p class=v><a rel=prev href=http-web-services.html title='back to &#8220;HTTP Web Services&#8221;'><span class=u>&#x261C;</span></a> <a rel=next href=packaging.html title='onward to &#8220;Packaging Python Libraries&#8221;'><span class=u>&#x261E;</span></a>
    <p class=c>&copy; 2001&ndash;11 <a href=about.html>Mark Pilgrim</a>
    <script src=j/jquery.js></script>
    <script src=j/prettify.js></script>
    <script src=j/dip3.js></script>
    ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/about.html����������������������������������������������������0000644�0000000�0000000�00000005647�11773544727�017624� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE html>
    <meta charset=utf-8>
    <title>About the book - Dive Into Python 3</title>
    <link rel=stylesheet href=dip3.css>
    <style>
    h1:before{content:''}
    #belong{margin:0 auto;width:558px;height:738px;background:#fff url(i/openclipart.org_media_files_Selanit_8331.png) no-repeat;border:1px solid white}
    #belong div{margin:375px 30px 0 40px}
    div p{font-size:small}
    abbr{font-variant:none;text-transform:none;letter-spacing:0}
    </style>
    <link rel=stylesheet media='only screen and (max-device-width: 480px)' href=mobile.css>
    <link rel=stylesheet media=print href=print.css>
    <meta name=viewport content='initial-scale=1.0'>
    <form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:l5eihuescdw><input type=hidden name=ie value=UTF-8><input type=search name=q size=25 placeholder="powered by Google&trade;">&nbsp;<input type=submit name=sa value=Search></div></form>
    <p>You are here: <a href=index.html>Home</a> <span class=u>&#8227;</span> <a href=table-of-contents.html>Dive Into Python 3</a> <span class=u>&#8227;</span>
    <h1>About The Book</h1>
    <div id=belong>
    <div>
    <p><cite>Dive Into Python 3</cite> comprises original prose and graphics licensed under the <a href=http://creativecommons.org/licenses/by-sa/3.0/ rel=license title='Creative Commons Attribution-ShareAlike 3.0 Unported'>CC-BY-SA-3.0</a> license. Illustrations from the <a href=http://openclipart.org/>Open Clip Art Library</a> are public domain.
    <p>The <a href=case-study-porting-chardet-to-python-3.html><code>chardet</code> library</a> is licensed under the <abbr title="GNU Lesser General Public License">LGPL</abbr> 2.1 or later. The <a href=advanced-iterators.html>alphametics solver</a> is a port of <a href=http://code.activestate.com/recipes/576615/>Raymond Hettinger&#8217;s version</a>, released under the <abbr>MIT</abbr> license. Several chapters contain code from the Python standard library, released under the <abbr title="Python Software Foundation">PSF</abbr> License 2.0. All other original code is licensed under the MIT license.
    <p>The online edition uses <a href=http://jquery.com>jQuery</a>, released under the <abbr>MIT</abbr> and <abbr title="GNU General Public License">GPL</abbr> licenses. <span style="color:red">C</span><span style="color:aqua">o</span><span style="color:plum">l</span><span style="color:gold">o</span><span style="color:blue">r</span> syntax highlighting is provided by <a href=http://code.google.com/p/google-code-prettify/>prettify.js</a>, other parsing code is adapted from <a href=http://code.google.com/p/javascript-search-term-highlighter/>highlighter.js</a>; both are released under the Apache License 2.0.
    <p>Corrections and feedback to <a href=mailto:mark@diveintomark.org>mark@diveintomark.org</a> or <a href=https://github.com/diveintomark/diveintopython3/issues>on Github</a>.
    </div>
    </div>
    <p class=c>&copy; 2001&ndash;11 <a href=colophon.html>Mark Pilgrim</a>
    <!--[if IE]><script src=j/html5.js></script><![endif]-->
    �����������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/advanced-iterators.html���������������������������������������0000644�0000000�0000000�00000135402�11773544727�022262� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE html>
    <meta charset=utf-8>
    <title>Advanced Iterators - Dive Into Python 3</title>
    <!--[if IE]><script src=j/html5.js></script><![endif]-->
    <link rel=stylesheet href=dip3.css>
    <style>
    body{counter-reset:h1 8}
    mark{display:inline}
    </style>
    <link rel=stylesheet media='only screen and (max-device-width: 480px)' href=mobile.css>
    <link rel=stylesheet media=print href=print.css>
    <meta name=viewport content='initial-scale=1.0'>
    <form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:l5eihuescdw><input type=hidden name=ie value=UTF-8>&nbsp;<input type=search name=q size=25 placeholder="powered by Google&trade;">&nbsp;<input type=submit name=sa value=Search></div></form>
    <p>You are here: <a href=index.html>Home</a> <span class=u>&#8227;</span> <a href=table-of-contents.html#advanced-iterators>Dive Into Python 3</a> <span class=u>&#8227;</span>
    <p id=level>Difficulty level: <span class=u title=advanced>&#x2666;&#x2666;&#x2666;&#x2666;&#x2662;</span>
    <h1>Advanced Iterators</h1>
    <blockquote class=q>
    <p><span class=u>&#x275D;</span> Great fleas have little fleas upon their backs to bite &#8217;em,<br>And little fleas have lesser fleas, and so ad infinitum. <span class=u>&#x275E;</span><br>&mdash; Augustus De Morgan
    </blockquote>
    <p id=toc>&nbsp;
    <h2 id=divingin>Diving In</h2>
    <p class=f>Just as <a href=regular-expressions.html>regular expressions</a> put <a href=strings.html>strings</a> on steroids, the <code>itertools</code> module puts <a href=iterators.html>iterators</a> on steroids. But first, I want to show you a classic puzzle.
    
    <pre class=nd><code>HAWAII + IDAHO + IOWA + OHIO == STATES
    510199 + 98153 + 9301 + 3593 == 621246
    
    H = 5
    A = 1
    W = 0
    I = 9
    D = 8
    O = 3
    S = 6
    T = 2
    E = 4</code></pre>
    
    <p>Puzzles like this are called <i>cryptarithms</i> or <i>alphametics</i>. The letters spell out actual words, but if you replace each letter with a digit from <code>0&ndash;9</code>, it also &#8220;spells&#8221; an arithmetic equation. The trick is to figure out which letter maps to each digit. All the occurrences of each letter must map to the same digit, no digit can be repeated, and no &#8220;word&#8221; can start with the digit 0.
    
    <aside>The most well-known alphametic puzzle is <code>SEND + MORE = MONEY</code>.</aside>
    
    <p>In this chapter, we&#8217;ll dive into an incredible Python program originally written by Raymond Hettinger. This program solves alphametic puzzles <em>in just 14 lines of code</em>.
    
    <p class=d>[<a href=examples/alphametics.py>download <code>alphametics.py</code></a>]
    <pre class=pp><code>import re
    import itertools
    
    def solve(puzzle):
        words = re.findall('[A-Z]+', puzzle.upper())
        unique_characters = set(''.join(words))
        assert len(unique_characters) &lt;= 10, 'Too many letters'
        first_letters = {word[0] for word in words}
        n = len(first_letters)
        sorted_characters = ''.join(first_letters) + \
            ''.join(unique_characters - first_letters)
        characters = tuple(ord(c) for c in sorted_characters)
        digits = tuple(ord(c) for c in '0123456789')
        zero = digits[0]
        for guess in itertools.permutations(digits, len(characters)):
            if zero not in guess[:n]:
                equation = puzzle.translate(dict(zip(characters, guess)))
                if eval(equation):
                    return equation
    
    if __name__ == '__main__':
        import sys
        for puzzle in sys.argv[1:]:
            print(puzzle)
            solution = solve(puzzle)
            if solution:
                print(solution)</code></pre>
    
    <p>You can run the program from the command line. On Linux, it would look like this. (These may take some time, depending on the speed of your computer, and there is no progress bar. Just be patient!)
    
    <pre class='nd screen cmdline'>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 alphametics.py "HAWAII + IDAHO + IOWA + OHIO == STATES"</kbd>
    <samp>HAWAII + IDAHO + IOWA + OHIO = STATES
    510199 + 98153 + 9301 + 3593 == 621246</samp>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 alphametics.py "I + LOVE + YOU == DORA"</kbd>
    <samp>I + LOVE + YOU == DORA
    1 + 2784 + 975 == 3760</samp>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 alphametics.py "SEND + MORE == MONEY"</kbd>
    <samp>SEND + MORE == MONEY
    9567 + 1085 == 10652</samp></pre>
    
    <p class=a>&#x2042;
    
    <h2 id=re-findall>Finding all occurrences of a pattern</h2>
    
    <p>The first thing this alphametics solver does is find all the letters (A&ndash;Z) in the puzzle.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>import re</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>re.findall('[0-9]+', '16 2-by-4s in rows of 8')</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=pp>['16', '2', '4', '8']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>re.findall('[A-Z]+', 'SEND + MORE == MONEY')</kbd>     <span class=u>&#x2461;</span></a>
    <samp class=pp>['SEND', 'MORE', 'MONEY']</samp></pre>
    <ol>
    <li>The <code>re</code> module is Python&#8217;s implementation of <a href=regular-expressions.html>regular expressions</a>. It has a nifty function called <code>findall()</code> which takes a regular expression pattern and a string, and finds all occurrences of the pattern within the string. In this case, the pattern matches sequences of numbers. The <code>findall()</code> function returns a list of all the substrings that matched the pattern.
    <li>Here the regular expression pattern matches sequences of letters. Again, the return value is a list, and each item in the list is a string that matched the regular expression pattern.
    </ol>
    
    <p>Here&#8217;s another example that will stretch your brain a little.
    
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>re.findall(' s.*? s', "The sixth sick sheikh's sixth sheep's sick.")</kbd>
    <samp class=pp>[' sixth s', " sheikh's s", " sheep's s"]</samp></pre>
    
    <aside>This is the <a href=http://en.wikipedia.org/wiki/Tongue-twister>hardest tongue twister</a> in the English language.</aside>
    
    <p>Surprised? The regular expression looks for a space, an <code>s</code>, and then the shortest possible series of any character (<code>.*?</code>), then a space, then another <code>s</code>. Well, looking at that input string, I see five matches:
    
    <ol>
    <li><code>The<mark> sixth s</mark>ick sheikh's sixth sheep's sick.</code>
    <li><code>The sixth<mark> sick s</mark>heikh's sixth sheep's sick.</code>
    <li><code>The sixth sick<mark> sheikh's s</mark>ixth sheep's sick.</code>
    <li><code>The sixth sick sheikh's<mark> sixth s</mark>heep's sick.</code>
    <li><code>The sixth sick sheikh's sixth<mark> sheep's s</mark>ick.</code>
    </ol>
    
    <p>But the <code>re.findall()</code> function only returned three matches. Specifically, it returned the first, the third, and the fifth. Why is that? Because <em>it doesn&#8217;t return overlapping matches</em>. The first match overlaps with the second, so the first is returned and the second is skipped. Then the third overlaps with the fourth, so the third is returned and the fourth is skipped. Finally, the fifth is returned. Three matches, not five.
    
    <p>This has nothing to do with the alphametics solver; I just thought it was interesting.
    
    <p class=a>&#x2042;
    
    <h2 id=unique-items>Finding the unique items in a sequence</h2>
    
    <p><a href=native-datatypes.html#sets>Sets</a> make it trivial to find the unique items in a sequence.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_list = ['The', 'sixth', 'sick', "sheik's", 'sixth', "sheep's", 'sick']</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>set(a_list)</kbd>                      <span class=u>&#x2460;</span></a>
    <samp class=pp>{'sixth', 'The', "sheep's", 'sick', "sheik's"}</samp>
    <samp class=p>>>> </samp><kbd class=pp>a_string = 'EAST IS EAST'</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>set(a_string)</kbd>                    <span class=u>&#x2461;</span></a>
    <samp class=pp>{'A', ' ', 'E', 'I', 'S', 'T'}</samp>
    <samp class=p>>>> </samp><kbd class=pp>words = ['SEND', 'MORE', 'MONEY']</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>''.join(words)</kbd>                   <span class=u>&#x2462;</span></a>
    <samp class=pp>'SENDMOREMONEY'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>set(''.join(words))</kbd>              <span class=u>&#x2463;</span></a>
    <samp class=pp>{'E', 'D', 'M', 'O', 'N', 'S', 'R', 'Y'}</samp></pre>
    <ol>
    <li>Given a list of several strings, the <code>set()</code> function will return a set of unique strings from the list. This makes sense if you think of it like a <code>for</code> loop. Take the first item from the list, put it in the set. Second. Third. Fourth. Fifth&nbsp;&mdash;&nbsp;wait, that&#8217;s in the set already, so it only gets listed once, because Python sets don&#8217;t allow duplicates. Sixth. Seventh&nbsp;&mdash;&nbsp;again, a duplicate, so it only gets listed once. The end result? All the unique items in the original list, without any duplicates. The original list doesn&#8217;t even need to be sorted first.
    <li>The same technique works with strings, since a string is just a sequence of characters.
    <li>Given a list of strings, <code>''.join(<var>a_list</var>)</code> concatenates all the strings together into one.
    <li>So, given a list of strings, this line of code returns all the unique characters across all the strings, with no duplicates.
    </ol>
    
    <p>The alphametics solver uses this technique to build a set of all the unique characters in the puzzle.
    
    <pre class='nd pp'><code>unique_characters = set(''.join(words))</code></pre>
    
    <p>This list is later used to assign digits to characters as the solver iterates through the possible solutions.
    
    <p class=a>&#x2042;
    
    <h2 id=assert>Making assertions</h2>
    
    <p>Like many programming languages, Python has an <code>assert</code> statement. Here&#8217;s how it works.
    
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>assert 1 + 1 == 2</kbd>                                     <span class=u>&#x2460;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>assert 1 + 1 == 3</kbd>                                     <span class=u>&#x2461;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
    AssertionError</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>assert 2 + 2 == 5, "Only for very large values of 2"</kbd>  <span class=u>&#x2462;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
    AssertionError: Only for very large values of 2</samp></pre>
    <ol>
    <li>The <code>assert</code> statement is followed by any valid Python expression. In this case, the expression <code>1 + 1 == 2</code> evaluates to <code>True</code>, so the <code>assert</code> statement does nothing.
    <li>However, if the Python expression evaluates to <code>False</code>, the <code>assert</code> statement will raise an <code>AssertionError</code>.
    <li>You can also include a human-readable message that is printed if the <code>AssertionError</code> is raised.
    </ol>
    
    <p>Therefore, this line of code:
    
    <pre class='nd pp'><code>assert len(unique_characters) &lt;= 10, 'Too many letters'</code></pre>
    
    <p>&hellip;is equivalent to this:
    
    <pre class='nd pp'><code>if len(unique_characters) > 10:
        raise AssertionError('Too many letters')</code></pre>
    
    <p>The alphametics solver uses this exact <code>assert</code> statement to bail out early if the puzzle contains more than ten unique letters. Since each letter is assigned a unique digit, and there are only ten digits, a puzzle with more than ten unique letters can not possibly have a solution.
    
    <p class=a>&#x2042;
    
    <h2 id=generator-expressions>Generator expressions</h2>
    
    <p>A generator expression is like a <a href=generators.html>generator function</a> without the function.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>unique_characters = {'E', 'D', 'M', 'O', 'N', 'S', 'R', 'Y'}</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>gen = (ord(c) for c in unique_characters)</kbd>  <span class=u>&#x2460;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>gen</kbd>                                        <span class=u>&#x2461;</span></a>
    <samp class=pp>&lt;generator object &lt;genexpr> at 0x00BADC10></samp>
    <a><samp class=p>>>> </samp><kbd class=pp>next(gen)</kbd>                                  <span class=u>&#x2462;</span></a>
    <samp class=pp>69</samp>
    <samp class=p>>>> </samp><kbd class=pp>next(gen)</kbd>
    <samp class=pp>68</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>tuple(ord(c) for c in unique_characters)</kbd>   <span class=u>&#x2463;</span></a>
    <samp class=pp>(69, 68, 77, 79, 78, 83, 82, 89)</samp></pre>
    <ol>
    <li>A generator expression is like an anonymous function that yields values. The expression itself looks like a <a href=comprehensions.html#listcomprehension>list comprehension</a>, but it&#8217;s wrapped in parentheses instead of square brackets.
    <li>The generator expression returns&hellip; an iterator.
    <li>Calling <code>next(<var>gen</var>)</code> returns the next value from the iterator.
    <li>If you like, you can iterate through all the possible values and return a tuple, list, or set, by passing the generator expression to <code>tuple()</code>, <code>list()</code>, or <code>set()</code>. In these cases, you don&#8217;t need an extra set of parentheses&nbsp;&mdash;&nbsp;just pass the &#8220;bare&#8221; expression <code>ord(c) for c in unique_characters</code> to the <code>tuple()</code> function, and Python figures out that it&#8217;s a generator expression.
    </ol>
    
    <blockquote class=note>
    <p><span class=u>&#x261E;</span>Using a generator expression instead of a list comprehension can save both <abbr>CPU</abbr> and <abbr>RAM</abbr>. If you&#8217;re building an list just to throw it away (<i>e.g.</i> passing it to <code>tuple()</code> or <code>set()</code>), use a generator expression instead!
    </blockquote>
    
    <p>Here&#8217;s another way to accomplish the same thing, using a <a href=generators.html>generator function</a>:
    
    <pre class='nd pp'><code>def ord_map(a_string):
        for c in a_string:
            yield ord(c)
    
    gen = ord_map(unique_characters)</code></pre>
    
    <p>The generator expression is more compact but functionally equivalent.
    
    <p class=a>&#x2042;
    
    <h2 id=permutations>Calculating Permutations&hellip; The Lazy Way!</h2>
    
    <p>First of all, what the heck are permutations? Permutations are a mathematical concept. (There are actually several definitions, depending on what kind of math you&#8217;re doing. Here I&#8217;m talking about combinatorics, but if that doesn&#8217;t mean anything to you, don&#8217;t worry about it. As always, <a href=http://en.wikipedia.org/wiki/Permutation>Wikipedia is your friend</a>.)
    
    <p>The idea is that you take a list of things (could be numbers, could be letters, could be dancing bears) and find all the possible ways to split them up into smaller lists. All the smaller lists have the same size, which can be as small as 1 and as large as the total number of items. Oh, and nothing can be repeated. Mathematicians say things like &#8220;let&#8217;s find the permutations of 3 different items taken 2 at a time,&#8221; which means you have a sequence of 3 items and you want to find all the possible ordered pairs.
    
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>import itertools</kbd>                              <span class=u>&#x2460;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>perms = itertools.permutations([1, 2, 3], 2)</kbd>  <span class=u>&#x2461;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>next(perms)</kbd>                                   <span class=u>&#x2462;</span></a>
    <samp class=pp>(1, 2)</samp>
    <samp class=p>>>> </samp><kbd class=pp>next(perms)</kbd>
    <samp class=pp>(1, 3)</samp>
    <samp class=p>>>> </samp><kbd class=pp>next(perms)</kbd>
    <a><samp class=pp>(2, 1)</samp>                                            <span class=u>&#x2463;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>next(perms)</kbd>
    <samp class=pp>(2, 3)</samp>
    <samp class=p>>>> </samp><kbd class=pp>next(perms)</kbd>
    <samp class=pp>(3, 1)</samp>
    <samp class=p>>>> </samp><kbd class=pp>next(perms)</kbd>
    <samp class=pp>(3, 2)</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>next(perms)</kbd>                                   <span class=u>&#x2464;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
    StopIteration</samp></pre>
    <ol>
    <li>The <code>itertools</code> module has all kinds of fun stuff in it, including a <code>permutations()</code> function that does all the hard work of finding permutations.
    <li>The <code>permutations()</code> function takes a sequence (here a list of three integers) and a number, which is the number of items you want in each smaller group. The function returns an iterator, which you can use in a <code>for</code> loop or any old place that iterates. Here I&#8217;ll step through the iterator manually to show all the values.
    <li>The first permutation of <code>[1, 2, 3]</code> taken 2 at a time is <code>(1, 2)</code>.
    <li>Note that permutations are ordered: <code>(2, 1)</code> is different than <code>(1, 2)</code>.
    <li>That&#8217;s it! Those are all the permutations of <code>[1, 2, 3]</code> taken 2 at a time. Pairs like <code>(1, 1)</code> and <code>(2, 2)</code> never show up, because they contain repeats so they aren&#8217;t valid permutations. When there are no more permutations, the iterator raises a <code>StopIteration</code> exception.
    </ol>
    
    <aside>The <code>itertools</code> module has all kinds of fun stuff.</aside>
    
    <p>The <code>permutations()</code> function doesn&#8217;t have to take a list. It can take any sequence&nbsp;&mdash;&nbsp;even a string.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>import itertools</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>perms = itertools.permutations('ABC', 3)</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>next(perms)</kbd>
    <a><samp class=pp>('A', 'B', 'C')</samp>                               <span class=u>&#x2461;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>next(perms)</kbd>
    <samp class=pp>('A', 'C', 'B')</samp>
    <samp class=p>>>> </samp><kbd class=pp>next(perms)</kbd>
    <samp class=pp>('B', 'A', 'C')</samp>
    <samp class=p>>>> </samp><kbd class=pp>next(perms)</kbd>
    <samp class=pp>('B', 'C', 'A')</samp>
    <samp class=p>>>> </samp><kbd class=pp>next(perms)</kbd>
    <samp class=pp>('C', 'A', 'B')</samp>
    <samp class=p>>>> </samp><kbd class=pp>next(perms)</kbd>
    <samp class=pp>('C', 'B', 'A')</samp>
    <samp class=p>>>> </samp><kbd class=pp>next(perms)</kbd>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
    StopIteration</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>list(itertools.permutations('ABC', 3))</kbd>    <span class=u>&#x2462;</span></a>
    <samp class=pp>[('A', 'B', 'C'), ('A', 'C', 'B'),
     ('B', 'A', 'C'), ('B', 'C', 'A'),
     ('C', 'A', 'B'), ('C', 'B', 'A')]</samp></pre>
    <ol>
    <li>A string is just a sequence of characters. For the purposes of finding permutations, the string <code>'ABC'</code> is equivalent to the list <code>['A', 'B', 'C']</code>.
    <li>The first permutation of the 3 items <code>['A', 'B', 'C']</code>, taken 3 at a time, is <code>('A', 'B', 'C')</code>. There are five other permutations&nbsp;&mdash;&nbsp;the same three characters in every conceivable order.
    <li>Since the <code>permutations()</code> function always returns an iterator, an easy way to debug permutations is to pass that iterator to the built-in <code>list()</code> function to see all the permutations immediately.
    </ol>
    
    <p class=a>&#x2042;
    
    <h2 id=more-itertools>Other Fun Stuff in the <code>itertools</code> Module</h2>
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>import itertools</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>list(itertools.product('ABC', '123'))</kbd>   <span class=u>&#x2460;</span></a>
    <samp class=pp>[('A', '1'), ('A', '2'), ('A', '3'), 
     ('B', '1'), ('B', '2'), ('B', '3'), 
     ('C', '1'), ('C', '2'), ('C', '3')]</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>list(itertools.combinations('ABC', 2))</kbd>  <span class=u>&#x2461;</span></a>
    <samp class=pp>[('A', 'B'), ('A', 'C'), ('B', 'C')]</samp></pre>
    <ol>
    <li>The <code>itertools.product()</code> function returns an iterator containing the Cartesian product of two sequences.
    <li>The <code>itertools.combinations()</code> function returns an iterator containing all the possible combinations of the given sequence of the given length. This is like the <code>itertools.permutations()</code> function, except combinations don&#8217;t include items that are duplicates of other items in a different order. So <code>itertools.permutations('ABC', 2)</code> will return both <code>('A', 'B')</code> and <code>('B', 'A')</code> (among others), but <code>itertools.combinations('ABC', 2)</code> will not return <code>('B', 'A')</code> because it is a duplicate of <code>('A', 'B')</code> in a different order.
    </ol>
    
    <p class=d>[<a href=examples/favorite-people.txt>download <code>favorite-people.txt</code></a>]
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>names = list(open('examples/favorite-people.txt', encoding='utf-8'))</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>names</kbd>
    <samp class=pp>['Dora\n', 'Ethan\n', 'Wesley\n', 'John\n', 'Anne\n',
    'Mike\n', 'Chris\n', 'Sarah\n', 'Alex\n', 'Lizzie\n']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>names = [name.rstrip() for name in names]</kbd>                             <span class=u>&#x2461;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>names</kbd>
    <samp class=pp>['Dora', 'Ethan', 'Wesley', 'John', 'Anne',
    'Mike', 'Chris', 'Sarah', 'Alex', 'Lizzie']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>names = sorted(names)</kbd>                                                 <span class=u>&#x2462;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>names</kbd>
    <samp class=pp>['Alex', 'Anne', 'Chris', 'Dora', 'Ethan',
    'John', 'Lizzie', 'Mike', 'Sarah', 'Wesley']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>names = sorted(names, key=len)</kbd>                                        <span class=u>&#x2463;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>names</kbd>
    <samp class=pp>['Alex', 'Anne', 'Dora', 'John', 'Mike',
    'Chris', 'Ethan', 'Sarah', 'Lizzie', 'Wesley']</samp></pre>
    <ol>
    <li>This idiom returns a list of the lines in a text file.
    <li>Unfortunately (for this example), the <code>list(open(<var>filename</var>))</code> idiom also includes the carriage returns at the end of each line. This list comprehension uses the <code>rstrip()</code> string method to strip trailing whitespace from each line. (Strings also have an <code>lstrip()</code> method to strip leading whitespace, and a <code>strip()</code> method which strips both.)
    <li>The <code>sorted()</code> function takes a list and returns it sorted. By default, it sorts alphabetically.
    <li>But the <code>sorted()</code> function can also take a function as the <var>key</var> parameter, and it sorts by that key. In this case, the sort function is <code>len()</code>, so it sorts by <code>len(<var>each item</var>)</code>. Shorter names come first, then longer, then longest.
    </ol>
    
    <p>What does this have to do with the <code>itertools</code> module? I&#8217;m glad you asked.
    
    <pre class=screen>
    &hellip;continuing from the previous interactive shell&hellip;
    <samp class=p>>>> </samp><kbd class=pp>import itertools</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>groups = itertools.groupby(names, len)</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>groups</kbd>
    <samp class=pp>&lt;itertools.groupby object at 0x00BB20C0></samp>
    <samp class=p>>>> </samp><kbd class=pp>list(groups)</kbd>
    <samp class=pp>[(4, &lt;itertools._grouper object at 0x00BA8BF0>),
     (5, &lt;itertools._grouper object at 0x00BB4050>),
     (6, &lt;itertools._grouper object at 0x00BB4030>)]</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>groups = itertools.groupby(names, len)</kbd>   <span class=u>&#x2461;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>for name_length, name_iter in groups:</kbd>    <span class=u>&#x2462;</span></a>
    <samp class=p>... </samp><kbd class=pp>    print('Names with {0:d} letters:'.format(name_length))</kbd>
    <samp class=p>... </samp><kbd class=pp>    for name in name_iter:</kbd>
    <samp class=p>... </samp><kbd class=pp>        print(name)</kbd>
    <samp class=p>... </samp>
    <samp>Names with 4 letters:
    Alex
    Anne
    Dora
    John
    Mike
    Names with 5 letters:
    Chris
    Ethan
    Sarah
    Names with 6 letters:
    Lizzie
    Wesley</samp></pre>
    <ol>
    <li>The <code>itertools.groupby()</code> function takes a sequence and a key function, and returns an iterator that generates pairs. Each pair contains the result of <code>key_function(<var>each item</var>)</code> and another iterator containing all the items that shared that key result.
    <li>Calling the <code>list()</code> function &#8220;exhausted&#8221; the iterator, <i>i.e.</i> you&#8217;ve already generated every item in the iterator to make the list. There&#8217;s no &#8220;reset&#8221; button on an iterator; you can&#8217;t just start over once you&#8217;ve exhausted it. If you want to loop through it again (say, in the upcoming <code>for</code> loop), you need to call <code>itertools.groupby()</code> again to create a new iterator.
    <li>In this example, given a list of names <em>already sorted by length</em>, <code>itertools.groupby(names, len)</code> will put all the 4-letter names in one iterator, all the 5-letter names in another iterator, and so on. The <code>groupby()</code> function is completely generic; it could group strings by first letter, numbers by their number of factors, or any other key function you can think of.
    </ol>
    <!-- YO DAWG, WE HEARD YOU LIKE LOOPING, SO WE PUT AN ITERATOR IN YOUR ITERATOR SO YOU CAN LOOP WHILE YOU LOOP. -->
    
    <blockquote class=note>
    <p><span class=u>&#x261E;</span>The <code>itertools.groupby()</code> function only works if the input sequence is already sorted by the grouping function. In the example above, you grouped a list of names by the <code>len()</code> function. That only worked because the input list was already sorted by length.
    </blockquote>
    
    <p>Are you watching closely?
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>list(range(0, 3))</kbd>
    <samp class=pp>[0, 1, 2]</samp>
    <samp class=p>>>> </samp><kbd class=pp>list(range(10, 13))</kbd>
    <samp class=pp>[10, 11, 12]</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>list(itertools.chain(range(0, 3), range(10, 13)))</kbd>        <span class=u>&#x2460;</span></a>
    <samp class=pp>[0, 1, 2, 10, 11, 12]</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>list(zip(range(0, 3), range(10, 13)))</kbd>                    <span class=u>&#x2461;</span></a>
    <samp class=pp>[(0, 10), (1, 11), (2, 12)]</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>list(zip(range(0, 3), range(10, 14)))</kbd>                    <span class=u>&#x2462;</span></a>
    <samp class=pp>[(0, 10), (1, 11), (2, 12)]</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>list(itertools.zip_longest(range(0, 3), range(10, 14)))</kbd>  <span class=u>&#x2463;</span></a>
    <samp class=pp>[(0, 10), (1, 11), (2, 12), (None, 13)]</samp></pre>
    <ol>
    <li>The <code>itertools.chain()</code> function takes two iterators and returns an iterator that contains all the items from the first iterator, followed by all the items from the second iterator. (Actually, it can take any number of iterators, and it chains them all in the order they were passed to the function.)
    <li>The <code>zip()</code> function does something prosaic that turns out to be extremely useful: it takes any number of sequences and returns an iterator which returns tuples of the first items of each sequence, then the second items of each, then the third, and so on.
    <li>The <code>zip()</code> function stops at the end of the shortest sequence. <code>range(10, 14)</code> has 4 items (10, 11, 12, and 13), but <code>range(0, 3)</code> only has 3, so the <code>zip()</code> function returns an iterator of 3 items.
    <li>On the other hand, the <code>itertools.zip_longest()</code> function stops at the end of the <em>longest</em> sequence, inserting <code>None</code> values for items past the end of the shorter sequences.
    </ol>
    
    <p id=dict-zip>OK, that was all very interesting, but how does it relate to the alphametics solver? Here&#8217;s how:
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>characters = ('S', 'M', 'E', 'D', 'O', 'N', 'R', 'Y')</kbd>
    <samp class=p>>>> </samp><kbd class=pp>guess = ('1', '2', '0', '3', '4', '5', '6', '7')</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>tuple(zip(characters, guess))</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=pp>(('S', '1'), ('M', '2'), ('E', '0'), ('D', '3'),
     ('O', '4'), ('N', '5'), ('R', '6'), ('Y', '7'))</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>dict(zip(characters, guess))</kbd>   <span class=u>&#x2461;</span></a>
    <samp class=pp>{'E': '0', 'D': '3', 'M': '2', 'O': '4',
     'N': '5', 'S': '1', 'R': '6', 'Y': '7'}</samp></pre>
    <ol>
    <li>Given a list of letters and a list of digits (each represented here as 1-character strings), the <code>zip</code> function will create a pairing of letters and digits, in order.
    <li>Why is that cool? Because that data structure happens to be exactly the right structure to pass to the <code>dict()</code> function to create a dictionary that uses letters as keys and their associated digits as values. (This isn&#8217;t the only way to do it, of course. You could use a <a href=comprehensions.html#dictionarycomprehension>dictionary comprehension</a> to create the dictionary directly.) Although the printed representation of the dictionary lists the pairs in a different order (dictionaries have no &#8220;order&#8221; per se), you can see that each letter is associated with the digit, based on the ordering of the original <var>characters</var> and <var>guess</var> sequences.
    </ol>
    
    <p id=guess>The alphametics solver uses this technique to create a dictionary that maps letters in the puzzle to digits in the solution, for each possible solution.
    
    <pre class='nd pp'><code>characters = tuple(ord(c) for c in sorted_characters)
    digits = tuple(ord(c) for c in '0123456789')
    ...
    for guess in itertools.permutations(digits, len(characters)):
        ...
    <mark>    equation = puzzle.translate(dict(zip(characters, guess)))</mark></code></pre>
    
    <p>But what is this <code>translate()</code> method? Ah, now you&#8217;re getting to the <em>really</em> fun part.
    
    <p class=a>&#x2042;
    
    <h2 id=string-translate>A New Kind Of String Manipulation</h2>
    
    <p>Python strings have many methods. You learned about some of those methods in <a href=strings.html>the Strings chapter</a>: <code>lower()</code>, <code>count()</code>, and <code>format()</code>. Now I want to introduce you to a powerful but little-known string manipulation technique: the <code>translate()</code> method.
    
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>translation_table = {ord('A'): ord('O')}</kbd>  <span class=u>&#x2460;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>translation_table</kbd>                         <span class=u>&#x2461;</span></a>
    <samp class=pp>{65: 79}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>'MARK'.translate(translation_table)</kbd>       <span class=u>&#x2462;</span></a>
    <samp class=pp>'MORK'</samp></pre>
    <ol>
    <li>String translation starts with a translation table, which is just a dictionary that maps one character to another. Actually, &#8220;character&#8221; is incorrect&nbsp;&mdash;&nbsp;the translation table really maps one <em>byte</em> to another.
    <li>Remember, bytes in Python 3 are integers. The <code>ord()</code> function returns the <abbr>ASCII</abbr> value of a character, which, in the case of A&ndash;Z, is always a byte from 65 to 90.
    <li>The <code>translate()</code> method on a string takes a translation table and runs the string through it. That is, it replaces all occurrences of the keys of the translation table with the corresponding values. In this case, &#8220;translating&#8221; <code>MARK</code> to <code>MORK</code>.
    </ol>
    
    <aside>Now you&#8217;re getting to the <em>really</em> fun part.</aside>
    
    <p>What does this have to do with solving alphametic puzzles? As it turns out, everything.
    
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>characters = tuple(ord(c) for c in 'SMEDONRY')</kbd>       <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>characters</kbd>
    <samp class=pp>(83, 77, 69, 68, 79, 78, 82, 89)</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>guess = tuple(ord(c) for c in '91570682')</kbd>            <span class=u>&#x2461;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>guess</kbd>
    <samp class=pp>(57, 49, 53, 55, 48, 54, 56, 50)</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>translation_table = dict(zip(characters, guess))</kbd>     <span class=u>&#x2462;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>translation_table</kbd>
    <samp class=pp>{68: 55, 69: 53, 77: 49, 78: 54, 79: 48, 82: 56, 83: 57, 89: 50}</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>'SEND + MORE == MONEY'.translate(translation_table)</kbd>  <span class=u>&#x2463;</span></a>
    <samp class=pp>'9567 + 1085 == 10652'</samp></pre>
    <ol>
    <li>Using a <a href=#generator-expressions>generator expression</a>, we quickly compute the byte values for each character in a string. <var>characters</var> is an example of the value of <var>sorted_characters</var> in the <code>alphametics.solve()</code> function.
    <li>Using another generator expression, we quickly compute the byte values for each digit in this string. The result, <var>guess</var>, is of the form <a href=#guess>returned by the <code>itertools.permutations()</code> function</a> in the <code>alphametics.solve()</code> function.
    <li>This translation table is generated by <a href=#dict-zip>zipping <var>characters</var> and <var>guess</var> together</a> and building a dictionary from the resulting sequence of pairs. This is exactly what the <code>alphametics.solve()</code> function does inside the <code>for</code> loop.
    <li>Finally, we pass this translation table to the <code>translate()</code> method of the original puzzle string. This converts each letter in the string to the corresponding digit (based on the letters in <var>characters</var> and the digits in <var>guess</var>). The result is a valid Python expression, as a string.
    </ol>
    
    <p>That&#8217;s pretty impressive. But what can you do with a string that happens to be a valid Python expression?
    
    <p class=a>&#x2042;
    
    <h2 id=eval>Evaluating Arbitrary Strings As Python Expressions</h2>
    
    <p>This is the final piece of the puzzle (or rather, the final piece of the puzzle solver). After all that fancy string manipulation, we&#8217;re left with a string like <code>'9567 + 1085 == 10652'</code>. But that&#8217;s a string, and what good is a string? Enter <code>eval()</code>, the universal Python evaluation tool.
    
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>eval('1 + 1 == 2')</kbd>
    <samp class=pp>True</samp>
    <samp class=p>>>> </samp><kbd class=pp>eval('1 + 1 == 3')</kbd>
    <samp class=pp>False</samp>
    <samp class=p>>>> </samp><kbd class=pp>eval('9567 + 1085 == 10652')</kbd>
    <samp class=pp>True</samp></pre>
    
    <p>But wait, there&#8217;s more! The <code>eval()</code> function isn&#8217;t limited to boolean expressions. It can handle <em>any</em> Python expression and returns <em>any</em> datatype.
    
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>eval('"A" + "B"')</kbd>
    <samp class=pp>'AB'</samp>
    <samp class=p>>>> </samp><kbd class=pp>eval('"MARK".translate({65: 79})')</kbd>
    <samp class=pp>'MORK'</samp>
    <samp class=p>>>> </samp><kbd class=pp>eval('"AAAAA".count("A")')</kbd>
    <samp class=pp>5</samp>
    <samp class=p>>>> </samp><kbd class=pp>eval('["*"] * 5')</kbd>
    <samp class=pp>['*', '*', '*', '*', '*']</samp></pre>
    
    <p>But wait, that&#8217;s not all!
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>x = 5</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>eval("x * 5")</kbd>         <span class=u>&#x2460;</span></a>
    <samp class=pp>25</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>eval("pow(x, 2)")</kbd>     <span class=u>&#x2461;</span></a>
    <samp class=pp>25</samp>
    <samp class=p>>>> </samp><kbd class=pp>import math</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>eval("math.sqrt(x)")</kbd>  <span class=u>&#x2462;</span></a>
    <samp class=pp>2.2360679774997898</samp></pre>
    <ol>
    <li>The expression that <code>eval()</code> takes can reference global variables defined outside the <code>eval()</code>. If called within a function, it can reference local variables too.
    <li>And functions.
    <li>And modules.
    </ol>
    
    <p>Hey, wait a minute&hellip;
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>import subprocess</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>eval("subprocess.getoutput('ls ~')")</kbd>                  <span class=u>&#x2460;</span></a>
    <samp class=pp>'Desktop         Library         Pictures \
     Documents       Movies          Public   \
     Music           Sites'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>eval("subprocess.getoutput('rm /some/random/file')")</kbd>  <span class=u>&#x2461;</span></a></pre>
    <ol>
    <li>The <code>subprocess</code> module allows you to run arbitrary shell commands and get the result as a Python string.
    <li>Arbitrary shell commands can have permanent consequences.
    </ol>
    
    <p>It&#8217;s even worse than that, because there&#8217;s a global <code>__import__()</code> function that takes a module name as a string, imports the module, and returns a reference to it. Combined with the power of <code>eval()</code>, you can construct a single expression that will wipe out all your files:
    
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>eval("__import__('subprocess').getoutput('rm /some/random/file')")</kbd>  <span class=u>&#x2460;</span></a></pre>
    <ol>
    <li>Now imagine the output of <code>'rm -rf ~'</code>. Actually there wouldn&#8217;t be any output, but you wouldn&#8217;t have any files left either.
    </ol>
    
    <p class=xxxl>eval() is EVIL
    
    <p>Well, the evil part is evaluating arbitrary expressions from untrusted sources. You should only use <code>eval()</code> on trusted input. Of course, the trick is figuring out what&#8217;s &#8220;trusted.&#8221; But here&#8217;s something I know for certain: you should <b>NOT</b> take this alphametics solver and put it on the internet as a fun little web service. Don&#8217;t make the mistake of thinking, &#8220;Gosh, the function does a lot of string manipulation before getting a string to evaluate; <em>I can&#8217;t imagine</em> how someone could exploit that.&#8221; Someone <b>WILL</b> figure out how to sneak nasty executable code past all that string manipulation (<a href=http://www.securityfocus.com/blogs/746>stranger things have happened</a>), and then you can kiss your server goodbye.
    
    <p>But surely there&#8217;s <em>some</em> way to evaluate expressions safely? To put <code>eval()</code> in a sandbox where it can&#8217;t access or harm the outside world? Well, yes and no.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>x = 5</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>eval("x * 5", {}, {})</kbd>               <span class=u>&#x2460;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
      File "&lt;string>", line 1, in &lt;module>
    NameError: name 'x' is not defined</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>eval("x * 5", {"x": x}, {})</kbd>         <span class=u>&#x2461;</span></a>
    <samp class=p>25</samp>
    <samp class=p>>>> </samp><kbd class=pp>import math</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>eval("math.sqrt(x)", {"x": x}, {})</kbd>  <span class=u>&#x2462;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
      File "&lt;string>", line 1, in &lt;module>
    NameError: name 'math' is not defined</samp></pre>
    <ol>
    <li>The second and third parameters passed to the <code>eval()</code> function act as the global and local namespaces for evaluating the expression. In this case, they are both empty, which means that when the string <code>"x * 5"</code> is evaluated, there is no reference to <var>x</var> in either the global or local namespace, so <code>eval()</code> throws an exception.
    <li>You can selectively include specific values in the global namespace by listing them individually. Then those&nbsp;&mdash;&nbsp;and only those&nbsp;&mdash;&nbsp;variables will be available during evaluation.
    <li>Even though you just imported the <code>math</code> module, you didn&#8217;t include it in the namespace passed to the <code>eval()</code> function, so the evaluation failed.
    </ol>
    
    <p>Gee, that was easy. Lemme make an alphametics web service now!
    
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>eval("pow(5, 2)", {}, {})</kbd>                   <span class=u>&#x2460;</span></a>
    <samp class=pp>25</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>eval("__import__('math').sqrt(5)", {}, {})</kbd>  <span class=u>&#x2461;</span></a>
    <samp class=pp>2.2360679774997898</samp></pre>
    <ol>
    <li>Even though you&#8217;ve passed empty dictionaries for the global and local namespaces, all of Python&#8217;s built-in functions are still available during evaluation. So <code>pow(5, 2)</code> works, because <code>5</code> and <code>2</code> are literals, and <code>pow()</code> is a built-in function.
    <li>Unfortunately (and if you don&#8217;t see why it&#8217;s unfortunate, read on), the <code>__import__()</code> function is also a built-in function, so it works too.
    </ol>
    
    <p>Yeah, that means you can still do nasty things, even if you explicitly set the global and local namespaces to empty dictionaries when calling <code>eval()</code>:
    
    <pre class='nd screen'><samp class=p>>>> </samp><kbd class=pp>eval("__import__('subprocess').getoutput('rm /some/random/file')", {}, {})</kbd></pre>
    
    <p>Oops. I&#8217;m glad I didn&#8217;t make that alphametics web service. Is there <em>any</em> way to use <code>eval()</code> safely? Well, yes and no.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>eval("__import__('math').sqrt(5)",</kbd>
    <a><samp class=p>... </samp><kbd class=pp>    {"__builtins__":None}, {})</kbd>          <span class=u>&#x2460;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
      File "&lt;string>", line 1, in &lt;module>
    NameError: name '__import__' is not defined</samp>
    <samp class=p>>>> </samp><kbd class=pp>eval("__import__('subprocess').getoutput('rm -rf /')",</kbd>
    <a><samp class=p>... </samp><kbd class=pp>    {"__builtins__":None}, {})</kbd>          <span class=u>&#x2461;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
      File "&lt;string>", line 1, in &lt;module>
    NameError: name '__import__' is not defined</samp></pre>
    <ol>
    <li>To evaluate untrusted expressions safely, you need to define a global namespace dictionary that maps <code>"__builtins__"</code> to <code>None</code>, the Python null value. Internally, the &#8220;built-in&#8221; functions are contained within a pseudo-module called <code>"__builtins__"</code>. This pseudo-module (<i>i.e.</i> the set of built-in functions) is made available to evaluated expressions unless you explicitly override it.
    <li>Be sure you&#8217;ve overridden <code>__builtins__</code>. Not <code>__builtin__</code>, <code>__built-ins__</code>, or some other variation that will work just fine but expose you to catastrophic risks.
    </ol>
    
    <p>So <code>eval()</code> is safe now? Well, yes and no.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>eval("2 ** 2147483647",</kbd>
    <a><samp class=p>... </samp><kbd class=pp>    {"__builtins__":None}, {})</kbd>          <span class=u>&#x2460;</span></a>
    </pre>
    <ol>
    <li>Even without access to <code>__builtins__</code>, you can still launch a denial-of-service attack. For example, trying to raise <code>2</code> to the <code>2147483647</code><sup>th</sup> power will spike your server&#8217;s <abbr>CPU</abbr> utilization to 100% for quite some time. (If you&#8217;re trying this in the interactive shell, press <kbd>Ctrl-C</kbd> a few times to break out of it.) Technically this expression <em>will</em> return a value eventually, but in the meantime your server will be doing a whole lot of nothing.
    </ol>
    
    <p>In the end, it <em>is</em> possible to safely evaluate untrusted Python expressions, for some definition of &#8220;safe&#8221; that turns out not to be terribly useful in real life. It&#8217;s fine if you&#8217;re just playing around, and it&#8217;s fine if you only ever pass it trusted input. But anything else is just asking for trouble.
    
    <p class=a>&#x2042;
    
    <h2 id=alphametics-finale>Putting It All Together</h2>
    
    <p>To recap: this program solves alphametic puzzles by brute force, <i>i.e.</i> through an exhaustive search of all possible solutions. To do this, it&hellip;
    
    <ol>
    <li><a href=#re-findall>Finds all the letters in the puzzle</a> with the <code>re.findall()</code> function
    <li><a href=#unique-items>Find all the <em>unique</em> letters in the puzzle</a> with sets and the <code>set()</code> function
    <li><a href=#assert>Checks if there are more than 10 unique letters</a> (meaning the puzzle is definitely unsolvable) with an <code>assert</code> statement
    <li><a href=#generator-objects>Converts the letters to their ASCII equivalents</a> with a generator object
    <li><a href=#permutations>Calculates all the possible solutions</a> with the <code>itertools.permutations()</code> function
    <li><a href=#string-translate>Converts each possible solution to a Python expression</a> with the <code>translate()</code> string method
    <li><a href=#eval>Tests each possible solution by evaluating the Python expression</a> with the <code>eval()</code> function
    <li>Returns the first solution that evaluates to <code>True</code>
    </ol>
    
    <p>&hellip;in just 14 lines of code.
    
    <p class=a>&#x2042;
    
    <h2 id=furtherreading>Further Reading</h2>
    
    <ul>
    <li><a href=http://docs.python.org/3.1/library/itertools.html><code>itertools</code> module</a>
    <li><a href=http://www.doughellmann.com/PyMOTW/itertools/><code>itertools</code>&nbsp;&mdash;&nbsp;Iterator functions for efficient looping</a>
    <li><a href=http://blip.tv/file/1947373/>Watch Raymond Hettinger&#8217;s &#8220;Easy AI with Python&#8221; talk</a> at PyCon 2009
    <li><a href=http://code.activestate.com/recipes/576615/>Recipe 576615: Alphametics solver</a>, Raymond Hettinger&#8217;s original alphametics solver for Python 2
    <li><a href=http://code.activestate.com/recipes/users/178123/>More of Raymond Hettinger&#8217;s recipes</a> in the ActiveState Code repository
    <li><a href=http://en.wikipedia.org/wiki/Verbal_arithmetic>Alphametics on Wikipedia</a>
    <li><a href=http://www.tkcs-collins.com/truman/alphamet/index.shtml>Alphametics Index</a>, including <a href=http://www.tkcs-collins.com/truman/alphamet/alphamet.shtml>lots of puzzles</a> and <a href=http://www.tkcs-collins.com/truman/alphamet/alpha_gen.shtml>a generator to make your own</a>
    </ul>
    
    <p>Many thanks to Raymond Hettinger for agreeing to relicense his code so I could port it to Python 3 and use it as the basis for this chapter.
    
    <p class=v><a href=iterators.html rel=prev title='back to &#8220;Classes &amp; Iterators&#8221;'><span class=u>&#x261C;</span></a> <a href=unit-testing.html rel=next title='onward to &#8220;Unit Testing&#8221;'><span class=u>&#x261E;</span></a>
    
    <p class=c>&copy; 2001&ndash;11 <a href=about.html>Mark Pilgrim</a>
    <script src=j/jquery.js></script>
    <script src=j/prettify.js></script>
    <script src=j/dip3.js></script>
    ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/whats-new.html������������������������������������������������0000644�0000000�0000000�00000014605�11773544727�020421� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE html>
    <meta charset=utf-8>
    <title>What's New In Dive Into Python 3</title>
    <!--[if IE]><script src=j/html5.js></script><![endif]-->
    <link rel=stylesheet href=dip3.css>
    <style>
    body{counter-reset:h1 -1}
    h3:before{content:''}
    </style>
    <link rel=stylesheet media='only screen and (max-device-width: 480px)' href=mobile.css>
    <link rel=stylesheet media=print href=print.css>
    <meta name=viewport content='initial-scale=1.0'>
    <form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:l5eihuescdw><input type=hidden name=ie value=UTF-8>&nbsp;<input type=search name=q size=25 placeholder="powered by Google&trade;">&nbsp;<input type=submit name=sa value=Search></div></form>
    <p>You are here: <a href=index.html>Home</a> <span class=u>&#8227;</span> <a href=table-of-contents.html#whats-new>Dive Into Python 3</a> <span class=u>&#8227;</span>
    <h1>What&#8217;s New In &#8220;Dive Into Python 3&#8221;</h1>
    <blockquote class=q>
    <p><span class=u>&#x275D;</span> Isn&#8217;t this where we came in? <span class=u>&#x275E;</span><br>&mdash; Pink Floyd, The Wall
    </blockquote>
    <p id=toc>&nbsp;
    <h2 id=divingin><i>a.k.a.</i> &#8220;the minus level&#8221;</h2>
    
    <p class=f>Are you already a Python programmer? Did you read the original &#8220;<a href=http://diveintopython.org/>Dive Into Python</a>&#8221;? Did you buy it on paper? (If so, thanks!) Are you ready to take the plunge into Python 3? &hellip; If so, read on. (If none of that is true, you&#8217;d be better off <a href=installing-python.html>starting at the beginning</a>.)
    
    <p>Python 3 comes with a script called <code>2to3</code>. Learn it. Love it. Use it. <a href=porting-code-to-python-3-with-2to3.html>Porting Code to Python 3 with <code>2to3</code></a> is a reference of all the things that the <code>2to3</code> tool can fix automatically. Since a lot of those things are syntax changes, it&#8217;s a good starting point to learn about a lot of the syntax changes in Python 3. (<code>print</code> is now a function, <code>`x`</code> doesn&#8217;t work, <i class=baa>&amp;</i>c.)
    
    <p><a href=case-study-porting-chardet-to-python-3.html>Case Study: Porting <code>chardet</code> to Python 3</a> documents my (ultimately successful) effort to port a non-trivial library from Python 2 to Python 3. It may help you; it may not. There&#8217;s a fairly steep learning curve, since you need to kind of understand the library first, so you can understand why it broke and how I fixed it. A lot of the breakage centers around strings. Speaking of which&hellip;
    
    <p>Strings. Whew. Where to start. Python 2 had &#8220;strings&#8221; and &#8220;Unicode strings.&#8221; Python 3 has &#8220;bytes&#8221; and &#8220;strings.&#8221; That is, all strings are now Unicode strings, and if you want to deal with a bag of bytes, you use the new <code>bytes</code> type. Python 3 will <em>never</em> implicitly convert between strings and bytes, so if you&#8217;re not sure which one you have at any given moment, your code will almost certainly break. Read <a href=strings.html>the Strings chapter</a> for more details. 
    
    <p>Bytes vs. strings comes up again and again throughout the book.
    
    <ul>
    <li>In <a href=files.html>Files</a>, you&#8217;ll learn the difference between reading files in &#8220;binary&#8221; and &#8220;text&#8221; mode. Reading (and writing!) files in text mode requires an <code>encoding</code> parameter. Some text file methods count characters, but other methods count bytes. If your code assumes that one character == one byte, it <em>will</em> break on multi-byte characters.
    <li>In <a href=http-web-services.html><abbr>HTTP</abbr> Web Services</a>, the <code>httplib2</code> module fetches headers and data over <abbr>HTTP</abbr>. <abbr>HTTP</abbr> headers are returned as strings, but the <abbr>HTTP</abbr> body is returned as bytes.
    <li>In <a href=serializing.html>Serializing Python Objects</a>, you&#8217;ll learn why the <code>pickle</code> module in Python 3 defines a new data format that is backwardly incompatible with Python 2. (Hint: it&#8217;s because of bytes and strings.) Also, Python 3 supports serializing objects to and from <abbr>JSON</abbr>, which doesn&#8217;t even have a <code>bytes</code> type. I&#8217;ll show you how to hack around that.
    <li>In <a href=case-study-porting-chardet-to-python-3.html>Case study: porting <code>chardet</code> to Python 3</a>, it&#8217;s just a bloody mess of bytes and strings everywhere.
    </ul>
    
    <p>Even if you don&#8217;t care about Unicode (oh but you will), you&#8217;ll want to read about <a href=strings.html#formatting-strings>string formatting in Python 3</a>, which is completely different from Python 2.
    
    <p>Iterators are everywhere in Python 3, and I understand them a lot better than I did five years ago when I wrote &#8220;Dive Into Python&#8221;. You need to understand them too, because lots of functions that used to return lists in Python 2 will now return iterators in Python 3. At a minimum, you should read <a href=iterators.html#a-fibonacci-iterator>the second half of the Iterators chapter</a> and <a href=advanced-iterators.html#generator-expressions>the second half of the Advanced Iterators chapter</a>.
    
    <p>By popular request, I&#8217;ve added an appendix on <a href=special-method-names.html>Special Method Names</a>, which is kind of like <a href=http://www.python.org/doc/3.1/reference/datamodel.html#special-method-names>the Python docs &#8220;Data Model&#8221; chapter</a> but with more snark.
    
    <p>When I was writing &#8220;Dive Into Python&#8221;, all of the available XML libraries sucked. Then Fredrik Lundh wrote <a href=http://effbot.org/zone/element-index.htm>ElementTree</a>, which doesn&#8217;t suck at all. The Python gods wisely <a href=http://docs.python.org/3.1/library/xml.etree.elementtree.html>incorporated ElementTree into the standard library</a>, and now it forms the basis for <a href=xml.html>my new XML chapter</a>. The old ways of parsing XML are still around, but you should avoid them, because they suck!
    
    <p>Also new in Python&nbsp;&mdash;&nbsp;not in the language but in the community&nbsp;&mdash;&nbsp;is the emergence of code repositories like <a href=http://pypi.python.org/>The Python Package Index</a> (PyPI). Python comes with utilities to package your code in standard formats and distribute those packages on PyPI. Read <a href=packaging.html>Packaging Python Libraries</a> for details.
    
    <p class=c>&copy; 2001&ndash;11 <a href=about.html>Mark Pilgrim</a>
    ���������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/strings.html��������������������������������������������������0000644�0000000�0000000�00000134151�11773544727�020174� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE html>
    <meta charset=utf-8>
    <title>Strings - Dive Into Python 3</title>
    <!--[if IE]><script src=j/html5.js></script><![endif]-->
    <link rel=stylesheet href=dip3.css>
    <style>
    body{counter-reset:h1 4}
    </style>
    <link rel=stylesheet media='only screen and (max-device-width: 480px)' href=mobile.css>
    <link rel=stylesheet media=print href=print.css>
    <meta name=viewport content='initial-scale=1.0'>
    <form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:l5eihuescdw><input type=hidden name=ie value=UTF-8>&nbsp;<input type=search name=q size=25 placeholder="powered by Google&trade;">&nbsp;<input type=submit name=sa value=Search></div></form>
    <p>You are here: <a href=index.html>Home</a> <span class=u>&#8227;</span> <a href=table-of-contents.html#strings>Dive Into Python 3</a> <span class=u>&#8227;</span>
    <p id=level>Difficulty level: <span class=u title=intermediate>&#x2666;&#x2666;&#x2666;&#x2662;&#x2662;</span>
    <h1>Strings</h1>
    <blockquote class=q>
    <p><span class=u>&#x275D;</span> I&#8217;m telling you this &#8217;cause you&#8217;re one of my friends.<br>
    My alphabet starts where your alphabet ends! <span class=u>&#x275E;</span><br>&mdash; Dr. Seuss, On Beyond Zebra!
    </blockquote>
    <p id=toc>&nbsp;
    <h2 id=boring-stuff>Some Boring Stuff You Need To Understand Before You Can Dive In</h2>
    <p class=f>Few people think about it, but text is incredibly complicated. Start with the alphabet. The people of <a href=http://en.wikipedia.org/wiki/Bougainville_Province>Bougainville</a> have the smallest alphabet in the world; their <a href=http://en.wikipedia.org/wiki/Rotokas_alphabet>Rotokas alphabet</a> is composed of only 12 letters: A, E, G, I, K, O, P, R, S, T, U, and V. On the other end of the spectrum, languages like Chinese, Japanese, and Korean have thousands of characters. English, of course, has 26 letters&nbsp;&mdash;&nbsp;52 if you count uppercase and lowercase separately&nbsp;&mdash;&nbsp;plus a handful of <i class=baa>!@#$%&amp;</i> punctuation marks.
    
    <p>When you talk about &#8220;text,&#8221; you&#8217;re probably thinking of &#8220;characters and symbols on my computer screen.&#8221; But computers don&#8217;t deal in characters and symbols; they deal in bits and bytes. Every piece of text you&#8217;ve ever seen on a computer screen is actually stored in a particular <i>character encoding</i>. Very roughly speaking, the character encoding provides a mapping between the stuff you see on your screen and the stuff your computer actually stores in memory and on disk. There are many different character encodings, some optimized for particular languages like Russian or Chinese or English, and others that can be used for multiple languages.
    
    <p>In reality, it&#8217;s more complicated than that. Many characters are common to multiple encodings, but each encoding may use a different sequence of bytes to actually store those characters in memory or on disk. So you can think of the character encoding as a kind of decryption key. Whenever someone gives you a sequence of bytes&nbsp;&mdash;&nbsp;a file, a web page, whatever&nbsp;&mdash;&nbsp;and claims it&#8217;s &#8220;text,&#8221; you need to know what character encoding they used so you can decode the bytes into characters. If they give you the wrong key or no key at all, you&#8217;re left with the unenviable task of cracking the code yourself. Chances are you&#8217;ll get it wrong, and the result will be gibberish.
    
    <aside>Everything you thought you knew about strings is wrong.</aside>
    
    <p>Surely you&#8217;ve seen web pages like this, with strange question-mark-like characters where apostrophes should be. That usually means the page author didn&#8217;t declare their character encoding correctly, your browser was left guessing, and the result was a mix of expected and unexpected characters. In English it&#8217;s merely annoying; in other languages, the result can be completely unreadable.
    
    <p>There are character encodings for each major language in the world. Since each language is different, and memory and disk space have historically been expensive, each character encoding is optimized for a particular language. By that, I mean each encoding using the same numbers (0&ndash;255) to represent that language&#8217;s characters. For instance, you&#8217;re probably familiar with the <abbr>ASCII</abbr> encoding, which stores English characters as numbers ranging from 0 to 127. (65 is capital &#8220;A&#8221;, 97 is lowercase &#8220;a&#8221;, <i class=baa>&amp;</i>c.)  English has a very simple alphabet, so it can be completely expressed in less than 128 numbers. For those of you who can count in base 2, that&#8217;s 7 out of the 8 bits in a byte.
    
    <p>Western European languages like French, Spanish, and German have more letters than English. Or, more precisely, they have letters combined with various diacritical marks, like the <code>&ntilde;</code> character in Spanish. The most common encoding for these languages is CP-1252, also called &#8220;windows-1252&#8221; because it is widely used on Microsoft Windows. The CP-1252 encoding shares characters with <abbr>ASCII</abbr> in the 0&ndash;127 range, but then extends into the 128&ndash;255 range for characters like n-with-a-tilde-over-it (241), u-with-two-dots-over-it (252), <i class=baa>&amp;</i>c. It&#8217;s still a single-byte encoding, though; the highest possible number, 255, still fits in one byte.
    
    <p>Then there are languages like Chinese, Japanese, and Korean, which have so many characters that they require multiple-byte character sets. That is, each &#8220;character&#8221; is represented by a two-byte number from 0&ndash;65535. But different multi-byte encodings still share the same problem as different single-byte encodings, namely that they each use the same numbers to mean different things. It&#8217;s just that the range of numbers is broader, because there are many more characters to represent.
    
    <p>That was mostly OK in a non-networked world, where &#8220;text&#8221; was something you typed yourself and occasionally printed. There wasn&#8217;t much &#8220;plain text&#8221;. Source code was <abbr>ASCII</abbr>, and everyone else used word processors, which defined their own (non-text) formats that tracked character encoding information along with rich styling, <i class=baa>&amp;</i>c. People read these documents with the same word processing program as the original author, so everything worked, more or less.
    
    <p>Now think about the rise of global networks like email and the web. Lots of &#8220;plain text&#8221; flying around the globe, being authored on one computer, transmitted through a second computer, and received and displayed by a third computer. Computers can only see numbers, but the numbers could mean different things. Oh no! What to do? Well, systems had to be designed to carry encoding information along with every piece of &#8220;plain text.&#8221; Remember, it&#8217;s the decryption key that maps computer-readable numbers to human-readable characters. A missing decryption key means garbled text, gibberish, or worse.
    
    <p>Now think about trying to store multiple pieces of text in the same place, like in the same database table that holds all the email you&#8217;ve ever received. You still need to store the character encoding alongside each piece of text so you can display it properly. Think that&#8217;s hard? Try searching your email database,  which means converting between multiple encodings on the fly. Doesn&#8217;t that sound fun?
    
    <p>Now think about the possibility of multilingual documents, where characters from several languages are next to each other in the same document. (Hint: programs that tried to do this typically used escape codes to switch &#8220;modes.&#8221; Poof, you&#8217;re in Russian koi8-r mode, so 241 means Я; poof, now you&#8217;re in Mac Greek mode, so 241 means ώ.) And of course you&#8217;ll want to search <em>those</em> documents, too.
    
    <p>Now cry a lot, because everything you thought you knew about strings is wrong, and there ain&#8217;t no such thing as &#8220;plain text.&#8221;
    
    <p class=a>&#x2042;
    
    <h2 id=one-ring-to-rule-them-all>Unicode</h2>
    
    <p><i>Enter <dfn>Unicode</dfn>.</i>
    
    <p>Unicode is a system designed to represent <em>every</em> character from <em>every</em> language. Unicode represents each letter, character, or ideograph as a 4-byte number. Each number represents a unique character used in at least one of the world&#8217;s languages. (Not all the numbers are used, but more than 65535 of them are, so 2 bytes wouldn&#8217;t be sufficient.) Characters that are used in multiple languages generally have the same number, unless there is a good etymological reason not to. Regardless, there is exactly 1 number per character, and exactly 1 character per number. Every number always means just one thing; there are no &#8220;modes&#8221; to keep track of. <code>U+0041</code> is always <code>'A'</code>, even if your language doesn&#8217;t have an <code>'A'</code> in it.
    
    <p>On the face of it, this seems like a great idea. One encoding to rule them all. Multiple languages per document. No more &#8220;mode switching&#8221; to switch between encodings mid-stream. But right away, the obvious question should leap out at you. Four bytes? For every single character<span class=u title='interrobang!'>&#8253;</span> That seems awfully wasteful, especially for languages like English and Spanish, which need less than one byte (256 numbers) to express every possible character. In fact, it&#8217;s wasteful even for ideograph-based languages (like Chinese), which never need more than two bytes per character.
    
    <p>There is a Unicode encoding that uses four bytes per character. It&#8217;s called UTF-32, because 32 bits = 4 bytes. UTF-32 is a straightforward encoding; it takes each Unicode character (a 4-byte number) and represents the character with that same number. This has some advantages, the most important being that you can find the <var>Nth</var> character of a string in constant time, because the <var>Nth</var> character starts at the <var>4&times;Nth</var> byte. It also has several disadvantages, the most obvious being that it takes four freaking bytes to store every freaking character.
    
    <p>Even though there are a lot of Unicode characters, it turns out that most people will never use anything beyond the first 65535. Thus, there is another Unicode encoding, called UTF-16 (because 16 bits = 2 bytes). UTF-16 encodes every character from 0&ndash;65535 as two bytes, then uses some dirty hacks if you actually need to represent the rarely-used &#8220;astral plane&#8221; Unicode characters beyond 65535. Most obvious advantage: UTF-16 is twice as space-efficient as UTF-32, because every character requires only two bytes to store instead of four bytes (except for the ones that don&#8217;t). And you can still easily find the <var>Nth</var> character of a string in constant time, if you assume that the string doesn&#8217;t include any astral plane characters, which is a good assumption right up until the moment that it&#8217;s not.
    
    <p>But there are also non-obvious disadvantages to both UTF-32 and UTF-16. Different computer systems store individual bytes in different ways. That means that the character <code>U+4E2D</code> could be stored in UTF-16 as either <code>4E 2D</code> or <code>2D 4E</code>, depending on whether the system is big-endian or little-endian. (For UTF-32, there are even more possible byte orderings.) As long as your documents never leave your computer, you&#8217;re safe&nbsp;&mdash;&nbsp;different applications on the same computer will all use the same byte order. But the minute you want to transfer documents between systems, perhaps on a world wide web of some sort, you&#8217;re going to need a way to indicate which order your bytes are stored. Otherwise, the receiving system has no way of knowing whether the two-byte sequence <code>4E 2D</code> means <code>U+4E2D</code> or <code>U+2D4E</code>.
    
    <p>To solve <em>this</em> problem, the multi-byte Unicode encodings define a &#8220;Byte Order Mark,&#8221; which is a special non-printable character that you can include at the beginning of your document to indicate what order your bytes are in. For UTF-16, the Byte Order Mark is <code>U+FEFF</code>. If you receive a UTF-16 document that starts with the bytes <code>FF FE</code>, you know the byte ordering is one way; if it starts with <code>FE FF</code>, you know the byte ordering is reversed.
    
    <p>Still, UTF-16 isn&#8217;t exactly ideal, especially if you&#8217;re dealing with a lot of <abbr>ASCII</abbr> characters. If you think about it, even a Chinese web page is going to contain a lot of <abbr>ASCII</abbr> characters&nbsp;&mdash;&nbsp;all the elements and attributes surrounding the printable Chinese characters. Being able to find the <var>Nth</var> character in constant time is nice, but there&#8217;s still the nagging problem of those astral plane characters, which mean that you can&#8217;t <em>guarantee</em> that every character is exactly two bytes, so you can&#8217;t <em>really</em> find the <var>Nth</var> character in constant time unless you maintain a separate index. And boy, there sure is a lot of <abbr>ASCII</abbr> text in the world&hellip;
    
    <p>Other people pondered these questions, and they came up with a solution:
    
    <p class=xxxl>UTF-8
    
    <p>UTF-8 is a <em>variable-length</em> encoding system for Unicode. That is, different characters take up a different number of bytes. For <abbr>ASCII</abbr> characters (A-Z, <i class=baa>&amp;</i>c.) <abbr>UTF-8</abbr> uses just one byte per character. In fact, it uses the exact same bytes; the first 128 characters (0&ndash;127) in <abbr>UTF-8</abbr> are indistinguishable from <abbr>ASCII</abbr>. &#8220;Extended Latin&#8221; characters like &ntilde; and &ouml; end up taking two bytes. (The bytes are not simply the Unicode code point like they would be in UTF-16; there is some serious bit-twiddling involved.) Chinese characters like &#x4E2D; end up taking three bytes. The rarely-used &#8220;astral plane&#8221; characters take four bytes.
    
    <p>Disadvantages: because each character can take a different number of bytes, finding the <var>Nth</var> character is an O(N) operation&nbsp;&mdash;&nbsp;that is, the longer the string, the longer it takes to find a specific character. Also, there is bit-twiddling involved to encode characters into bytes and decode bytes into characters.
    
    <p>Advantages: super-efficient encoding of common <abbr>ASCII</abbr> characters. No worse than UTF-16 for extended Latin characters. Better than UTF-32 for Chinese characters. Also (and you&#8217;ll have to trust me on this, because I&#8217;m not going to show you the math), due to the exact nature of the bit twiddling, there are no byte-ordering issues. A document encoded in <abbr>UTF-8</abbr> uses the exact same stream of bytes on any computer.
    
    <p class=a>&#x2042;
    
    <h2 id=divingin>Diving In</h2>
    
    <p>In Python 3, all strings are sequences of Unicode characters. There is no such thing as a Python string encoded in <abbr>UTF-8</abbr>, or a Python string encoded as CP-1252. &#8220;Is this string <abbr>UTF-8</abbr>?&#8221; is an invalid question. <abbr>UTF-8</abbr> is a way of encoding characters as a sequence of bytes. If you want to take a string and turn it into a sequence of bytes in a particular character encoding, Python 3 can help you with that. If you want to take a sequence of bytes and turn it into a string, Python 3 can help you with that too. Bytes are not characters; bytes are bytes. Characters are an abstraction. A string is a sequence of those abstractions.
    
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>s = '深入 Python'</kbd>    <span class=u>&#x2460;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>len(s)</kbd>               <span class=u>&#x2461;</span></a>
    <samp class=pp>9</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>s[0]</kbd>                 <span class=u>&#x2462;</span></a>
    <samp class=pp>'深'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>s + ' 3'</kbd>             <span class=u>&#x2463;</span></a>
    <samp class=pp>'深入 Python 3'</samp></pre>
    <ol>
    <li>To create a string, enclose it in quotes. Python strings can be defined with either single quotes (<code>'</code>) or double quotes (<code>"</code>).<!--"-->
    <li>The built-in <code><dfn>len</dfn>()</code> function returns the length of the string, <i>i.e.</i> the number of characters. This is the same function you use to <a href=native-datatypes.html#extendinglists>find the length of a list, tuple, set, or dictionary</a>. A string is like a tuple of characters.
    <li>Just like getting individual items out of a list, you can get individual characters out of a string using index notation.
    <li>Just like lists, you can <dfn>concatenate</dfn> strings using the <code>+</code> operator.
    </ol>
    
    <p class=a>&#x2042;
    
    <h2 id=formatting-strings>Formatting Strings</h2>
    
    <aside>Strings can be defined with either single or double quotes.</aside>
    <p>Let&#8217;s take another look at <a href=your-first-python-program.html#divingin><code>humansize.py</code></a>:
    
    <p class=d>[<a href=examples/humansize.py>download <code>humansize.py</code></a>]
    <pre class=pp><code><a>SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],         <span class=u>&#x2460;</span></a>
                1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
    
    def approximate_size(size, a_kilobyte_is_1024_bytes=True):
    <a>    '''Convert a file size to human-readable form.                          <span class=u>&#x2461;</span></a>
    
        Keyword arguments:
        size -- file size in bytes
        a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
                                    if False, use multiples of 1000
    
        Returns: string
    
    <a>    '''                                                                     <span class=u>&#x2462;</span></a>
        if size &lt; 0:
    <a>        raise ValueError('number must be non-negative')                     <span class=u>&#x2463;</span></a>
    
        multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
        for suffix in SUFFIXES[multiple]:
            size /= multiple
            if size &lt; multiple:
    <a>            return '{0:.1f} {1}'.format(size, suffix)                       <span class=u>&#x2464;</span></a>
    
        raise ValueError('number too large')</code></pre>
    <ol>
    <li><code>'KB'</code>, <code>'MB'</code>, <code>'GB'</code>&hellip; those are each strings.
    <li>Function docstrings are strings. This docstring spans multiple lines, so it uses three-in-a-row quotes to start and end the string.
    <li>These three-in-a-row quotes end the docstring.
    <li>There&#8217;s another string, being passed to the exception as a human-readable error message.
    <li>There&#8217;s a&hellip; whoa, what the heck is that?
    </ol>
    
    <p>Python 3 supports <dfn>formatting</dfn> values into strings. Although this can include very complicated expressions, the most basic usage is to insert a value into a string with a single placeholder.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>username = 'mark'</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>password = 'PapayaWhip'</kbd>                             <span class=u>&#x2460;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>"{0}'s password is {1}".format(username, password)</kbd>  <span class=u>&#x2461;</span></a>
    <samp class=pp>"mark's password is PapayaWhip"</samp></pre>
    <ol>
    <li>No, my password is not really <kbd>PapayaWhip</kbd>.
    <li>There&#8217;s a lot going on here. First, that&#8217;s a method call on a string literal. <em>Strings are objects</em>, and objects have methods. Second, the whole expression evaluates to a string. Third, <code>{0}</code> and <code>{1}</code> are <i>replacement fields</i>, which are replaced by the arguments passed to the <code><dfn>format</dfn>()</code> method.
    </ol>
    
    <h3 id=compound-field-names>Compound Field Names</h3>
    
    <p>The previous example shows the simplest case, where the replacement fields are simply integers. Integer replacement fields are treated as positional indices into the argument list of the <code>format()</code> method. That means that <code>{0}</code> is replaced by the first argument (<var>username</var> in this case), <code>{1}</code> is replaced by the second argument (<var>password</var>), <i class=baa>&amp;</i>c. You can have as many positional indices as you have arguments, and you can have as many arguments as you want. But replacement fields are much more powerful than that.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>import humansize</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>si_suffixes = humansize.SUFFIXES[1000]</kbd>      <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>si_suffixes</kbd>
    <samp class=pp>['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>'1000{0[0]} = 1{0[1]}'.format(si_suffixes)</kbd>  <span class=u>&#x2461;</span></a>
    <samp class=pp>'1000KB = 1MB'</samp>
    </pre>
    <ol>
    <li>Rather than calling any function in the <code>humansize</code> module, you&#8217;re just grabbing one of the data structures it defines: the list of &#8220;SI&#8221; (powers-of-1000) suffixes.
    <li>This looks complicated, but it&#8217;s not. <code>{0}</code> would refer to the first argument passed to the <code>format()</code> method, <var>si_suffixes</var>. But <var>si_suffixes</var> is a list. So <code>{0[0]}</code> refers to the first item of the list which is the first argument passed to the <code>format()</code> method: <code>'KB'</code>. Meanwhile, <code>{0[1]}</code> refers to the second item of the same list: <code>'MB'</code>. Everything outside the curly braces&nbsp;&mdash;&nbsp;including <code>1000</code>, the equals sign, and the spaces&nbsp;&mdash;&nbsp;is untouched. The final result is the string <code>'1000KB = 1MB'</code>.
    </ol>
    
    <aside>{0} is replaced by the 1<sup>st</sup> format() argument. {1} is replaced by the 2<sup>nd</sup>.</aside>
    <p>What this example shows is that <em>format specifiers can access items and properties of data structures using (almost) Python syntax</em>. This is called <i>compound field names</i>. The following compound field names &#8220;just work&#8221;:
    
    <ul>
    <li>Passing a list, and accessing an item of the list by index (as in the previous example)
    <li>Passing a dictionary, and accessing a value of the dictionary by key
    <li>Passing a module, and accessing its variables and functions by name
    <li>Passing a class instance, and accessing its properties and methods by name
    <li><em>Any combination of the above</em>
    </ul>
    
    <p>Just to blow your mind, here&#8217;s an example that combines all of the above:
    
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>import humansize</kbd>
    <samp class=p>>>> </samp><kbd class=pp>import sys</kbd>
    <samp class=p>>>> </samp><kbd class=pp>'1MB = 1000{0.modules[humansize].SUFFIXES[1000][0]}'.format(sys)</kbd>
    <samp class=pp>'1MB = 1000KB'</samp></pre>
    
    <p>Here&#8217;s how it works:
    
    <ul>
    <li>The <code>sys</code> module holds information about the currently running Python instance. Since you just imported it, you can pass the <code>sys</code> module itself as an argument to the <code>format()</code> method. So the replacement field <code>{0}</code> refers to the <code>sys</code> module.
    <li><code>sys.modules</code> is a dictionary of all the modules that have been imported in this Python instance. The keys are the module names as strings; the values are the module objects themselves. So the replacement field <code>{0.modules}</code> refers to the dictionary of imported modules.
    <li><code>sys.modules['humansize']</code> is the <code>humansize</code> module which you just imported. The replacement field <code>{0.modules[humansize]}</code> refers to the <code>humansize</code> module. Note the slight difference in syntax here. In real Python code, the keys of the <code>sys.modules</code> dictionary are strings; to refer to them, you need to put quotes around the module name (<i>e.g.</i> <code>'humansize'</code>). But within a replacement field, you skip the quotes around the dictionary key name (<i>e.g.</i> <code>humansize</code>). To quote <a href=http://www.python.org/dev/peps/pep-3101/>PEP 3101: Advanced String Formatting</a>, &#8220;The rules for parsing an item key are very simple. If it starts with a digit, then it is treated as a number, otherwise it is used as a string.&#8221;
    <li><code>sys.modules['humansize'].SUFFIXES</code> is the dictionary defined at the top of the <code>humansize</code> module. The replacement field <code>{0.modules[humansize].SUFFIXES}</code> refers to that dictionary.
    <li><code>sys.modules['humansize'].SUFFIXES[1000]</code> is a list of <abbr>SI</abbr> suffixes: <code>['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']</code>. So the replacement field <code>{0.modules[humansize].SUFFIXES[1000]}</code> refers to that list.
    <li><code>sys.modules['humansize'].SUFFIXES[1000][0]</code> is the first item of the list of <abbr>SI</abbr> suffixes: <code>'KB'</code>. Therefore, the complete replacement field <code>{0.modules[humansize].SUFFIXES[1000][0]}</code> is replaced by the two-character string <code>KB</code>.
    </ul>
    
    <h3 id=format-specifiers>Format Specifiers</h3>
    
    <p>But wait! There&#8217;s more! Let&#8217;s take another look at that strange line of code from <code>humansize.py</code>:
    
    <pre class='nd pp'><code>if size &lt; multiple:
        return '{0:.1f} {1}'.format(size, suffix)</code></pre>
    
    <p><code>{1}</code> is replaced with the second argument passed to the <code>format()</code> method, which is <var>suffix</var>. But what is <code>{0:.1f}</code>? It&#8217;s two things: <code>{0}</code>, which you recognize, and <code>:.1f</code>, which you don&#8217;t. The second half (including and after the colon) defines the <i>format specifier</i>, which further refines how the replaced variable should be formatted.
    
    <blockquote class='note compare clang'>
    <p><span class=u>&#x261E;</span>Format specifiers allow you to munge the replacement text in a variety of useful ways, like the <code><dfn>printf</dfn>()</code> function in C. You can add zero- or space-padding, align strings, control decimal precision, and even convert numbers to hexadecimal.
    </blockquote>
    
    <p>Within a replacement field, a colon (<code>:</code>) marks the start of the format specifier. The format specifier &#8220;<code>.1</code>&#8221; means &#8220;round to the nearest tenth&#8221; (<i>i.e.</i> display only one digit after the decimal point). The format specifier &#8220;<code>f</code>&#8221; means &#8220;fixed-point number&#8221; (as opposed to exponential notation or some other decimal representation). Thus, given a <var>size</var> of <code>698.24</code> and <var>suffix</var> of <code>'GB'</code>, the formatted string would be <code>'698.2 GB'</code>, because <code>698.24</code> gets rounded to one decimal place, then the suffix is appended after the number.
    
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>'{0:.1f} {1}'.format(698.24, 'GB')</kbd>
    <samp class=pp>'698.2 GB'</samp></pre>
    
    <p>For all the gory details on format specifiers, consult the <a href=http://docs.python.org/3.1/library/string.html#format-specification-mini-language>Format Specification Mini-Language</a> in the official Python documentation.
    
    <p class=a>&#x2042;
    
    <h2 id=common-string-methods>Other Common String Methods</h2>
    
    <p>Besides formatting, strings can do a number of other useful tricks.
    
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd>s = '''Finished files are the re-</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=p>... </samp><kbd>sult of years of scientif-</kbd>
    <samp class=p>... </samp><kbd>ic study combined with the</kbd>
    <samp class=p>... </samp><kbd>experience of years.'''</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>s.splitlines()</kbd>                     <span class=u>&#x2461;</span></a>
    <samp class=pp>['Finished files are the re-',
     'sult of years of scientif-',
     'ic study combined with the',
     'experience of years.']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>print(s.lower())</kbd>                   <span class=u>&#x2462;</span></a>
    <samp>finished files are the re-
    sult of years of scientif-
    ic study combined with the
    experience of years.</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>s.lower().count('f')</kbd>               <span class=u>&#x2463;</span></a>
    <samp class=pp>6</samp></pre>
    <ol>
    <li>You can input <dfn>multiline</dfn> strings in the Python interactive shell. Once you start a multiline string with triple quotation marks, just hit <kbd>ENTER</kbd> and the interactive shell will prompt you to continue the string. Typing the closing triple quotation marks ends the string, and the next <kbd>ENTER</kbd> will execute the command (in this case, assigning the string to <var>s</var>).
    <li>The <code><dfn>splitlines</dfn>()</code> method takes one multiline string and returns a list of strings, one for each line of the original. Note that the carriage returns at the end of each line are not included.
    <li>The <code>lower()</code> method converts the entire string to lowercase. (Similarly, the <code>upper()</code> method converts a string to uppercase.)
    <li>The <code>count()</code> method counts the number of occurrences of a substring. Yes, there really are six &#8220;f&#8221;s in that sentence!
    </ol>
    
    <p>Here&#8217;s another common case. Let&#8217;s say you have a list of key-value pairs in the form <code><var>key1</var>=<var>value1</var>&amp;<var>key2</var>=<var>value2</var></code>, and you want to split them up and make a dictionary of the form <code>{key1: value1, key2: value2}</code>.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>query = 'user=pilgrim&amp;database=master&amp;password=PapayaWhip'</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list = query.split('&amp;')</kbd>                                        <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_list</kbd>
    <samp class=pp>['user=pilgrim', 'database=master', 'password=PapayaWhip']</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_list_of_lists = [v.split('=', 1) for v in a_list if '=' in v]</kbd>  <span class=u>&#x2461;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_list_of_lists</kbd>
    <samp class=pp>[['user', 'pilgrim'], ['database', 'master'], ['password', 'PapayaWhip']]</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_dict = dict(a_list_of_lists)</kbd>                                   <span class=u>&#x2462;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>a_dict</kbd>
    <samp class=pp>{'password': 'PapayaWhip', 'user': 'pilgrim', 'database': 'master'}</samp></pre>
    
    <ol>
    <li>The <code><dfn>split</dfn>()</code> string method has one required argument, a delimiter. The method splits a string into a list of strings based on the delimiter. Here, the delimiter is an ampersand character, but it could be anything.
    <li>Now we have a list of strings, each with a key, followed by an equals sign, followed by a value. We can use a <a href=comprehensions.html#listcomprehension>list comprehension</a> to iterate over the entire list and split each string into two strings based on the first equals sign. The optional second argument to the <code>split()</code> method is the number of times you want to split. <code>1</code> means &#8220;only split once,&#8221; so the <code>split()</code> method will return a two-item list. (In theory, a value could contain an equals sign too. If you just used <code>'key=value=foo'.split('=')</code>, you would end up with a three-item list <code>['key', 'value', 'foo']</code>.)
    <li>Finally, Python can turn that list-of-lists into a dictionary simply by passing it to the <code>dict()</code> function.
    </ol>
    
    <blockquote class=note>
    <p><span class=u>&#x261E;</span>The previous example looks a lot like parsing query parameters in a <abbr>URL</abbr>, but real-life <abbr>URL</abbr> parsing is actually more complicated than this. If you&#8217;re dealing with <abbr>URL</abbr> query parameters, you&#8217;re better off using the <a href=http://docs.python.org/3.1/library/urllib.parse.html#urllib.parse.parse_qs><code>urllib.parse.parse_qs()</code></a> function, which handles some non-obvious edge cases.
    </blockquote>
    
    <h3 id=slicingstrings>Slicing A String</h3>
    <p>Once you&#8217;ve defined a string, you can get any part of it as a new string. This is called <i>slicing</i> the string. Slicing strings works exactly the same as <a href=native-datatypes.html#slicinglists>slicing lists</a>, which makes sense, because strings are just sequences of characters.
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>a_string = 'My alphabet starts where your alphabet ends.'</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>a_string[3:11]</kbd>           <span class=u>&#x2460;</span></a>
    <samp class=pp>'alphabet'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_string[3:-3]</kbd>           <span class=u>&#x2461;</span></a>
    <samp class=pp>'alphabet starts where your alphabet en'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_string[0:2]</kbd>            <span class=u>&#x2462;</span></a>
    <samp class=pp>'My'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_string[:18]</kbd>            <span class=u>&#x2463;</span></a>
    <samp class=pp>'My alphabet starts'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>a_string[18:]</kbd>            <span class=u>&#x2464;</span></a>
    <samp class=pp>' where your alphabet ends.'</samp></pre>
    <ol>
    <li>You can get a part of a string, called a &#8220;slice&#8221;, by specifying two indices. The return value is a new string containing all the characters of the string, in order, starting with the first slice index.
    <li>Like slicing lists, you can use negative indices to slice strings.
    <li>Strings are zero-based, so <code>a_string[0:2]</code> returns the first two items of the string, starting at <code>a_string[0]</code>, up to but not including <code>a_string[2]</code>.
    <li>If the left slice index is 0, you can leave it out, and 0 is implied. So <code>a_string[:18]</code> is the same as <code>a_string[0:18]</code>, because the starting 0 is implied.
    <li>Similarly, if the right slice index is the length of the string, you can leave it out. So <code>a_string[18:]</code> is the same as <code>a_string[18:44]</code>, because this string has 44 characters.  There is a pleasing symmetry here. In this 44-character string, <code>a_string[:18]</code> returns the first 18 characters, and <code>a_string[18:]</code> returns everything but the first 18 characters. In fact, <code>a_string[:<var>n</var>]</code> will always return the first <var>n</var> characters, and <code>a_string[<var>n</var>:]</code> will return the rest, regardless of the length of the string.
    </ol>
    
    <p class=a>&#x2042;
    
    <h2 id=byte-arrays>Strings vs. Bytes</h2>
    
    <p><dfn>Bytes</dfn> are bytes; characters are an abstraction. An immutable sequence of Unicode characters is called a <i>string</i>. An immutable sequence of numbers-between-0-and-255 is called a <i>bytes</i> object.
    
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>by = b'abcd\x65'</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>by</kbd>
    <samp class=pp>b'abcde'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>type(by)</kbd>          <span class=u>&#x2461;</span></a>
    <samp class=pp>&lt;class 'bytes'></samp>
    <a><samp class=p>>>> </samp><kbd class=pp>len(by)</kbd>           <span class=u>&#x2462;</span></a>
    <samp class=pp>5</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>by += b'\xff'</kbd>     <span class=u>&#x2463;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>by</kbd>
    <samp class=pp>b'abcde\xff'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>len(by)</kbd>           <span class=u>&#x2464;</span></a>
    <samp class=pp>6</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>by[0]</kbd>             <span class=u>&#x2465;</span></a>
    <samp class=pp>97</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>by[0] = 102</kbd>       <span class=u>&#x2466;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
    TypeError: 'bytes' object does not support item assignment</samp></pre>
    <ol>
    <li>To define a <code>bytes</code> object, use the <code>b''</code> &#8220;<dfn>byte</dfn> literal&#8221; syntax. Each byte within the byte literal can be an <abbr>ASCII</abbr> character or an encoded hexadecimal number from <code>\x00</code> to <code>\xff</code> (0&ndash;255).
    <li>The type of a <code>bytes</code> object is <code>bytes</code>.
    <li>Just like lists and strings, you can get the length of a <code>bytes</code> object with the built-in <code>len()</code> function.
    <li>Just like lists and strings, you can use the <code>+</code> operator to concatenate <code>bytes</code> objects. The result is a new <code>bytes</code> object.
    <li>Concatenating a 5-byte <code>bytes</code> object and a 1-byte <code>bytes</code> object gives you a 6-byte <code>bytes</code> object.
    <li>Just like lists and strings, you can use index notation to get individual bytes in a <code>bytes</code> object. The items of a string are strings; the items of a <code>bytes</code> object are integers. Specifically, integers between 0&ndash;255.
    <li>A <code>bytes</code> object is immutable; you can not assign individual bytes. If you need to change individual bytes, you can either use <a href=#slicingstrings>string slicing</a> and concatenation operators (which work the same as strings), or you can convert the <code>bytes</code> object into a <code>bytearray</code> object.
    </ol>
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>by = b'abcd\x65'</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>barr = bytearray(by)</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>barr</kbd>
    <samp class=pp>bytearray(b'abcde')</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>len(barr)</kbd>             <span class=u>&#x2461;</span></a>
    <samp class=pp>5</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>barr[0] = 102</kbd>         <span class=u>&#x2462;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>barr</kbd>
    <samp class=pp>bytearray(b'fbcde')</samp></pre>
    <ol>
    <li>To convert a <code>bytes</code> object into a mutable <code>bytearray</code> object, use the built-in <code>bytearray()</code> function.
    <li>All the methods and operations you can do on a <code>bytes</code> object, you can do on a <code>bytearray</code> object too.
    <li>The one difference is that, with the <code>bytearray</code> object, you can assign individual bytes using index notation. The assigned value must be an integer between 0&ndash;255.
    </ol>
    
    <p>The one thing you <em>can never do</em> is mix bytes and strings.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>by = b'd'</kbd>
    <samp class=p>>>> </samp><kbd class=pp>s = 'abcde'</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>by + s</kbd>                       <span class=u>&#x2460;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
    TypeError: can't concat bytes to str</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>s.count(by)</kbd>                  <span class=u>&#x2461;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
    TypeError: Can't convert 'bytes' object to str implicitly</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>s.count(by.decode('ascii'))</kbd>  <span class=u>&#x2462;</span></a>
    <samp class=pp>1</samp></pre>
    <ol>
    <li>You can&#8217;t concatenate bytes and strings. They are two different data types.
    <li>You can&#8217;t count the occurrences of bytes in a string, because there are no bytes in a string. A string is a sequence of characters. Perhaps you meant &#8220;count the occurrences of the string that you would get after decoding this sequence of bytes in a particular character encoding&#8221;? Well then, you&#8217;ll need to say that explicitly. Python 3 won&#8217;t <dfn>implicitly</dfn> convert bytes to strings or strings to bytes.
    <li>By an amazing coincidence, this line of code says &#8220;count the occurrences of the string that you would get after decoding this sequence of bytes in this particular character encoding.&#8221;
    </ol>
    
    <p>And here is the link between strings and bytes: <code>bytes</code> objects have a <code><dfn>decode</dfn>()</code> method that takes a character encoding and returns a string, and strings have an <code><dfn>encode</dfn>()</code> method that takes a character encoding and returns a <code>bytes</code> object. In the previous example, the decoding was relatively straightforward&nbsp;&mdash;&nbsp;converting a sequence of bytes in the <abbr>ASCII</abbr> encoding into a string of characters. But the same process works with any encoding that supports the characters of the string&nbsp;&mdash;&nbsp;even legacy (non-Unicode) encodings.
    
    <pre class=screen>
    <a><samp class=p>>>> </samp><kbd class=pp>a_string = '深入 Python'</kbd>         <span class=u>&#x2460;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>len(a_string)</kbd>
    <samp class=pp>9</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>by = a_string.encode('utf-8')</kbd>    <span class=u>&#x2461;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>by</kbd>
    <samp class=pp>b'\xe6\xb7\xb1\xe5\x85\xa5 Python'</samp>
    <samp class=p>>>> </samp><kbd class=pp>len(by)</kbd>
    <samp class=pp>13</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>by = a_string.encode('gb18030')</kbd>  <span class=u>&#x2462;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>by</kbd>
    <samp class=pp>b'\xc9\xee\xc8\xeb Python'</samp>
    <samp class=p>>>> </samp><kbd class=pp>len(by)</kbd>
    <samp class=pp>11</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>by = a_string.encode('big5')</kbd>     <span class=u>&#x2463;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>by</kbd>
    <samp class=pp>b'\xb2`\xa4J Python'</samp>
    <samp class=p>>>> </samp><kbd class=pp>len(by)</kbd>
    <samp class=pp>11</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>roundtrip = by.decode('big5')</kbd>    <span class=u>&#x2464;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>roundtrip</kbd>
    <samp class=pp>'深入 Python'</samp>
    <samp class=p>>>> </samp><kbd class=pp>a_string == roundtrip</kbd>
    <samp class=pp>True</samp></pre>
    <ol>
    <li>This is a string. It has nine characters.
    <li>This is a <code>bytes</code> object. It has 13 bytes. It is the sequence of bytes you get when you take <var>a_string</var> and encode it in <abbr>UTF-8</abbr>.
    <li>This is a <code>bytes</code> object. It has 11 bytes. It is the sequence of bytes you get when you take <var>a_string</var> and encode it in <a href=http://en.wikipedia.org/wiki/GB_18030>GB18030</a>.
    <li>This is a <code>bytes</code> object. It has 11 bytes. It is an <em>entirely different sequence of bytes</em> that you get when you take <var>a_string</var> and encode it in <a href=http://en.wikipedia.org/wiki/Big5>Big5</a>.
    <li>This is a string. It has nine characters. It is the sequence of characters you get when you take <var>by</var> and decode it using the Big5 encoding algorithm. It is identical to the original string.
    </ol>
    
    <p class=a>&#x2042;
    
    <h2 id=py-encoding>Postscript: Character Encoding Of Python Source Code</h2>
    
    <p>Python 3 assumes that your source code&nbsp;&mdash;&nbsp;<i>i.e.</i> each <code>.py</code> file&nbsp;&mdash;&nbsp;is encoded in <abbr>UTF-8</abbr>.
    
    <blockquote class='note compare python2'>
    <p><span class=u>&#x261E;</span>In Python 2, the <dfn>default</dfn> encoding for <code>.py</code> files was <abbr>ASCII</abbr>. In Python 3, <a href=http://www.python.org/dev/peps/pep-3120/>the default encoding is <abbr>UTF-8</abbr></a>.
    </blockquote>
    
    <p>If you would like to use a different encoding within your Python code, you can put an encoding declaration on the first line of each file. This declaration defines a <code>.py</code> file to be windows-1252:
    
    <pre class='nd pp'><code># -*- coding: windows-1252 -*-</code></pre>
    
    <p>Technically, the character encoding override can also be on the second line, if the first line is a <abbr>UNIX</abbr>-like hash-bang command.
    
    <pre class='nd pp'><code>#!/usr/bin/python3
    # -*- coding: windows-1252 -*-</code></pre>
    
    <p>For more information, consult <a href=http://www.python.org/dev/peps/pep-0263/><abbr>PEP</abbr> 263: Defining Python Source Code Encodings</a>.
    
    <p class=a>&#x2042;
    
    <h2 id=furtherreading>Further Reading</h2>
    
    <p>On Unicode in Python:
    
    <ul>
    <li><a href=http://docs.python.org/3.1/howto/unicode.html>Python Unicode HOWTO</a>
    <li><a href=http://docs.python.org/3.0/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit>What&#8217;s New In Python 3: Text vs. Data Instead Of Unicode vs. 8-bit</a>
    <li><a href=http://www.python.org/dev/peps/pep-0261/><abbr>PEP 261</abbr></a> explains how Python handles astral characters outside of the Basic Multilingual Plane (<i>i.e.</i> characters whose ordinal value is greater than 65535)
    </ul>
    
    <p>On Unicode in general:
    
    <ul>
    <li><a href=http://www.joelonsoftware.com/articles/Unicode.html>The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)</a>
    <li><a href=http://www.tbray.org/ongoing/When/200x/2003/04/06/Unicode>On the Goodness of Unicode</a>
    <li><a href=http://www.tbray.org/ongoing/When/200x/2003/04/13/Strings>On Character Strings</a>
    <li><a href=http://www.tbray.org/ongoing/When/200x/2003/04/26/UTF>Characters vs. Bytes</a>
    </ul>
    
    <p>On character encoding in other formats:
    
    <ul>
    <li><a href=http://feedparser.org/docs/character-encoding.html>Character encoding in XML</a>
    <li><a href=http://blog.whatwg.org/the-road-to-html-5-character-encoding>Character encoding in HTML</a>
    </ul>
    
    <p>On strings and string formatting:
    
    <ul>
    <li><a href=http://docs.python.org/3.1/library/string.html><code>string</code>&nbsp;&mdash;&nbsp;Common string operations</a>
    <li><a href=http://docs.python.org/3.1/library/string.html#formatstrings>Format String Syntax</a>
    <li><a href=http://docs.python.org/3.1/library/string.html#format-specification-mini-language>Format Specification Mini-Language</a>
    <li><a href=http://www.python.org/dev/peps/pep-3101/><abbr>PEP</abbr> 3101: Advanced String Formatting</a>
    </ul>
    
    <p class=v><a href=comprehensions.html rel=prev title='back to &#8220;Comprehensions&#8221;'><span class=u>&#x261C;</span></a> <a href=regular-expressions.html rel=next title='onward to &#8220;Regular Expressions&#8221;'><span class=u>&#x261E;</span></a>
    
    <p class=c>&copy; 2001&ndash;11 <a href=about.html>Mark Pilgrim</a>
    <script src=j/jquery.js></script>
    <script src=j/prettify.js></script>
    <script src=j/dip3.js></script>
    �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/iterators.html������������������������������������������������0000644�0000000�0000000�00000076475�11773544727�020535� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE html>
    <meta charset=utf-8>
    <title>Classes &amp; Iterators - Dive Into Python 3</title>
    <!--[if IE]><script src=j/html5.js></script><![endif]-->
    <link rel=stylesheet href=dip3.css>
    <style>
    body{counter-reset:h1 7}
    </style>
    <link rel=stylesheet media='only screen and (max-device-width: 480px)' href=mobile.css>
    <link rel=stylesheet media=print href=print.css>
    <meta name=viewport content='initial-scale=1.0'>
    <form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:l5eihuescdw><input type=hidden name=ie value=UTF-8>&nbsp;<input type=search name=q size=25 placeholder="powered by Google&trade;">&nbsp;<input type=submit name=sa value=Search></div></form>
    <p>You are here: <a href=index.html>Home</a> <span class=u>&#8227;</span> <a href=table-of-contents.html#iterators>Dive Into Python 3</a> <span class=u>&#8227;</span>
    <p id=level>Difficulty level: <span class=u title=intermediate>&#x2666;&#x2666;&#x2666;&#x2662;&#x2662;</span>
    <h1>Classes <i class=baa>&amp;</i> Iterators</h1>
    <blockquote class=q>
    <p><span class=u>&#x275D;</span> East is East, and West is West, and never the twain shall meet. <span class=u>&#x275E;</span><br>&mdash; <a href=http://en.wikiquote.org/wiki/Rudyard_Kipling>Rudyard Kipling</a>
    </blockquote>
    <p id=toc>&nbsp;
    <h2 id=divingin>Diving In</h2>
    <p class=f>Iterators are the &#8220;secret sauce&#8221; of Python 3. They&#8217;re everywhere, underlying everything, always just out of sight. <a href=comprehensions.html>Comprehensions</a> are just a simple form of <i>iterators</i>. Generators are just a simple form of <i>iterators</i>. A function that <code>yield</code>s values is a nice, compact way of building an iterator without building an iterator. Let me show you what I mean by that.
    
    <p>Remember <a href=generators.html#a-fibonacci-generator>the Fibonacci generator</a>? Here it is as a built-from-scratch iterator:
    
    <p class=d>[<a href=examples/fibonacci2.py>download <code>fibonacci2.py</code></a>]
    <pre class=pp><code>class Fib:
        '''iterator that yields numbers in the Fibonacci sequence'''
    
        def __init__(self, max):
            self.max = max
    
        def __iter__(self):
            self.a = 0
            self.b = 1
            return self
    
        def __next__(self):
            fib = self.a
            if fib > self.max:
                raise StopIteration
            self.a, self.b = self.b, self.a + self.b
            return fib</code></pre>
    
    <p>Let&#8217;s take that one line at a time.
    
    <pre class='nd pp'><code>class Fib:</code></pre>
    
    <p><code>class</code>? What&#8217;s a class?
    
    <p class=a>&#x2042;
    
    <h2 id=defining-classes>Defining Classes</h2>
    
    <p>Python is fully object-oriented: you can define your own classes, inherit from your own or built-in classes, and instantiate the classes you&#8217;ve defined.
    
    <p>Defining a class in Python is simple. As with functions, there is no separate interface definition. Just define the class and start coding. A Python class starts with the reserved word <code>class</code>, followed by the class name. Technically, that&#8217;s all that&#8217;s required, since a class doesn&#8217;t need to inherit from any other class.
    
    <pre class=pp><code><a>class PapayaWhip:  <span class=u>&#x2460;</span></a>
    <a>    pass           <span class=u>&#x2461;</span></a></code></pre>
    <ol>
    <li>The name of this class is <code>PapayaWhip</code>, and it doesn&#8217;t inherit from any other class. Class names are usually capitalized, <code>EachWordLikeThis</code>, but this is only a convention, not a requirement.
    <li>You probably guessed this, but everything in a class is indented, just like the code within a function, <code>if</code> statement, <code>for</code> loop, or any other block of code. The first line not indented is outside the class.
    </ol>
    
    <p>This <code>PapayaWhip</code> class doesn&#8217;t define any methods or attributes, but syntactically, there needs to be something in the definition, thus the <code>pass</code> statement. This is a Python reserved word that just means &#8220;move along, nothing to see here&#8221;. It&#8217;s a statement that does nothing, and it&#8217;s a good placeholder when you&#8217;re stubbing out functions or classes.
    
    <blockquote class='note compare java'>
    <p><span class=u>&#x261E;</span>The <code>pass</code> statement in Python is like a empty set of curly braces (<code>{}</code>) in Java or C.
    </blockquote>
    
    <p>Many classes are inherited from other classes, but this one is not. Many classes define methods, but this one does not. There is nothing that a Python class absolutely must have, other than a name. In particular, C++ programmers may find it odd that Python classes don&#8217;t have explicit constructors and destructors. Although it&#8217;s not required, Python classes <em>can</em> have something similar to a constructor: the <code>__init__()</code> method.
    
    <h3 id=init-method>The <code>__init__()</code> Method</h3>
    
    <p>This example shows the initialization of the <code>Fib</code> class using the <code>__init__</code> method.
    
    <pre class=pp><code>class Fib:
    <a>    '''iterator that yields numbers in the Fibonacci sequence'''  <span class=u>&#x2460;</span></a>
    
    <a>    def __init__(self, max):                                      <span class=u>&#x2461;</span></a></code></pre>
    <ol>
    <li>Classes can (and should) have <code>docstring</code>s too, just like modules and functions.
    <li>The <code>__init__()</code> method is called immediately after an instance of the class is created. It would be tempting&nbsp;&mdash;&nbsp;but technically incorrect&nbsp;&mdash;&nbsp;to call this the &#8220;constructor&#8221; of the class. It&#8217;s tempting, because it looks like a C++ constructor (by convention, the <code>__init__()</code> method is the first method defined for the class), acts like one (it&#8217;s the first piece of code executed in a newly created instance of the class), and even sounds like one. Incorrect, because the object has already been constructed by the time the <code>__init__()</code> method is called, and you already have a valid reference to the new instance of the class.
    </ol>
    
    <p>The first argument of every class method, including the <code>__init__()</code> method, is always a reference to the current instance of the class. By convention, this argument is named <var>self</var>. This argument fills the role of the reserved word <code>this</code> in <abbr>C++</abbr> or Java, but <var>self</var> is not a reserved word in Python, merely a naming convention. Nonetheless, please don&#8217;t call it anything but <var>self</var>; this is a very strong convention.
    
    <p>In all class methods, <var>self</var> refers to the instance whose method was called. But in the specific case of the <code>__init__()</code> method, the instance whose method was called is also the newly created object. Although you need to specify <var>self</var> explicitly when defining the method, you do <em>not</em> specify it when calling the method; Python will add it for you automatically.
    
    <p class=a>&#x2042;
    
    <h2 id=instantiating-classes>Instantiating Classes</h2>
    
    <p>Instantiating classes in Python is straightforward. To instantiate a class, simply call the class as if it were a function, passing the arguments that the <code>__init__()</code> method requires. The return value will be the newly created object.
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>import fibonacci2</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>fib = fibonacci2.Fib(100)</kbd>  <span class=u>&#x2460;</span></a>
    <a><samp class=p>>>> </samp><kbd class=pp>fib</kbd>                        <span class=u>&#x2461;</span></a>
    <samp class=pp>&lt;fibonacci2.Fib object at 0x00DB8810></samp>
    <a><samp class=p>>>> </samp><kbd class=pp>fib.__class__</kbd>              <span class=u>&#x2462;</span></a>
    <samp class=pp>&lt;class 'fibonacci2.Fib'></samp>
    <a><samp class=p>>>> </samp><kbd class=pp>fib.__doc__</kbd>                <span class=u>&#x2463;</span></a>
    <samp class=pp>'iterator that yields numbers in the Fibonacci sequence'</samp></pre>
    <ol>
    <li>You are creating an instance of the <code>Fib</code> class (defined in the <code>fibonacci2</code> module) and assigning the newly created instance to the variable <var>fib</var>. You are passing one parameter, <code>100</code>, which will end up as the <var>max</var> argument in <code>Fib</code>&#8217;s <code>__init__()</code> method.
    <li><var>fib</var> is now an instance of the <code>Fib</code> class.
    <li>Every class instance has a built-in attribute, <code>__class__</code>, which is the object&#8217;s class. Java programmers may be familiar with the <code>Class</code> class, which contains methods like <code>getName()</code> and <code>getSuperclass()</code> to get metadata information about an object. In Python, this kind of metadata is available through attributes, but the idea is the same.
    <li>You can access the instance&#8217;s <code>docstring</code> just as with a function or a module. All instances of a class share the same <code>docstring</code>.
    </ol>
    
    <blockquote class='note compare java'>
    <p><span class=u>&#x261E;</span>In Python, simply call a class as if it were a function to create a new instance of the class. There is no explicit <code>new</code> operator like there is in <abbr>C++</abbr> or Java.
    </blockquote>
    
    <p class=a>&#x2042;
    
    <h2 id=instance-variables>Instance Variables</h2>
    
    <p>On to the next line:
    
    <pre class=pp><code>class Fib:
        def __init__(self, max):
    <a>        self.max = max        <span class=u>&#x2460;</span></a></code></pre>
    <ol>
    <li>What is <var>self.max</var>? It&#8217;s an instance variable. It is completely separate from <var>max</var>, which was passed into the <code>__init__()</code> method as an argument. <var>self.max</var> is &#8220;global&#8221; to the instance. That means that you can access it from other methods.
    </ol>
    
    <pre class=pp><code>class Fib:
        def __init__(self, max):
    <a>        self.max = max        <span class=u>&#x2460;</span></a>
        .
        .
        .
        def __next__(self):
            fib = self.a
    <a>        if fib > self.max:    <span class=u>&#x2461;</span></a></code></pre>
    <ol>
    <li><var>self.max</var> is defined in the <code>__init__()</code> method&hellip;
    <li>&hellip;and referenced in the <code>__next__()</code> method.
    </ol>
    
    <p>Instance variables are specific to one instance of a class. For example, if you create two <code>Fib</code> instances with different maximum values, they will each remember their own values.
    
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>import fibonacci2</kbd>
    <samp class=p>>>> </samp><kbd class=pp>fib1 = fibonacci2.Fib(100)</kbd>
    <samp class=p>>>> </samp><kbd class=pp>fib2 = fibonacci2.Fib(200)</kbd>
    <samp class=p>>>> </samp><kbd class=pp>fib1.max</kbd>
    <samp class=pp>100</samp>
    <samp class=p>>>> </samp><kbd class=pp>fib2.max</kbd>
    <samp class=pp>200</samp></pre>
    
    <p class=a>&#x2042;
    
    <h2 id=a-fibonacci-iterator>A Fibonacci Iterator</h2>
    
    <p><em>Now</em> you&#8217;re ready to learn how to build an iterator. An iterator is just a class that defines an <code>__iter__()</code> method.
    
    <aside class=ots>
    All three of these class methods, <code>__init__</code>, <code>__iter__</code>, and <code>__next__</code>, begin and end with a pair of underscore (<code>_</code>) characters. Why is that? There&#8217;s nothing magical about it, but it usually indicates that these are &#8220;<dfn>special methods</dfn>.&#8221; The only thing &#8220;special&#8221; about special methods is that they aren&#8217;t called directly; Python calls them when you use some other syntax on the class or an instance of the class. <a href=special-method-names.html>More about special methods</a>.
    </aside>
    
    <p class=d>[<a href=examples/fibonacci2.py>download <code>fibonacci2.py</code></a>]
    <pre class=pp><code><a>class Fib:                                        <span class=u>&#x2460;</span></a>
    <a>    def __init__(self, max):                      <span class=u>&#x2461;</span></a>
            self.max = max
    
    <a>    def __iter__(self):                           <span class=u>&#x2462;</span></a>
            self.a = 0
            self.b = 1
            return self
    
    <a>    def __next__(self):                           <span class=u>&#x2463;</span></a>
            fib = self.a
            if fib > self.max:
    <a>            raise StopIteration                   <span class=u>&#x2464;</span></a>
            self.a, self.b = self.b, self.a + self.b
    <a>        return fib                                <span class=u>&#x2465;</span></a></code></pre>
    <ol>
    <li>To build an iterator from scratch, <code>Fib</code> needs to be a class, not a function.
    <li>&#8220;Calling&#8221; <code>Fib(max)</code> is really creating an instance of this class and calling its <code>__init__()</code> method with <var>max</var>. The <code>__init__()</code> method saves the maximum value as an instance variable so other methods can refer to it later.
    <li>The <code>__iter__()</code> method is called whenever someone calls <code>iter(fib)</code>. (As you&#8217;ll see in a minute, a <code>for</code> loop will call this automatically, but you can also call it yourself manually.) After performing beginning-of-iteration initialization (in this case, resetting <code>self.a</code> and <code>self.b</code>, our two counters), the <code>__iter__()</code> method can return any object that implements a <code>__next__()</code> method. In this case (and in most cases), <code>__iter__()</code> simply returns <var>self</var>, since this class implements its own <code>__next__()</code> method.
    <li>The <code>__next__()</code> method is called whenever someone calls <code>next()</code> on an iterator of an instance of a class. That will make more sense in a minute.
    <li>When the <code>__next__()</code> method raises a <code>StopIteration</code> exception, this signals to the caller that the iteration is exhausted. Unlike most exceptions, this is not an error; it&#8217;s a normal condition that just means that the iterator has no more values to generate. If the caller is a <code>for</code> loop, it will notice this <code>StopIteration</code> exception and gracefully exit the loop. (In other words, it will swallow the exception.) This little bit of magic is actually the key to using iterators in <code>for</code> loops.
    <li>To spit out the next value, an iterator&#8217;s <code>__next__()</code> method simply <code>return</code>s the value. Do not use <code>yield</code> here; that&#8217;s a bit of syntactic sugar that only applies when you&#8217;re using generators. Here you&#8217;re creating your own iterator from scratch; use <code>return</code> instead.
    </ol>
    
    <p>Thoroughly confused yet? Excellent. Let&#8217;s see how to call this iterator:
    
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>from fibonacci2 import Fib</kbd>
    <samp class=p>>>> </samp><kbd class=pp>for n in Fib(1000):</kbd>
    <samp class=p>... </samp><kbd class=pp>    print(n, end=' ')</kbd>
    <samp class=pp>0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987</samp></pre>
    
    <p>Why, it&#8217;s exactly the same! Byte for byte identical to how you called <a href=generators.html#a-fibonacci-generator>Fibonacci-as-a-generator</a> (modulo one capital letter). But how?
    
    <p>There&#8217;s a bit of magic involved in <code>for</code> loops. Here&#8217;s what happens:
    
    <ul>
    <li>The <code>for</code> loop calls <code>Fib(1000)</code>, as shown. This returns an instance of the <code>Fib</code> class. Call this <var>fib_inst</var>.
    <li>Secretly, and quite cleverly, the <code>for</code> loop calls <code>iter(fib_inst)</code>, which returns an iterator object. Call this <var>fib_iter</var>. In this case, <var>fib_iter</var> == <var>fib_inst</var>, because the <code>__iter__()</code> method returns <var>self</var>, but the <code>for</code> loop doesn&#8217;t know (or care) about that.
    <li>To &#8220;loop through&#8221; the iterator, the <code>for</code> loop calls <code>next(fib_iter)</code>, which calls the <code>__next__()</code> method on the <code>fib_iter</code> object, which does the next-Fibonacci-number calculations and returns a value. The <code>for</code> loop takes this value and assigns it to <var>n</var>, then executes the body of the <code>for</code> loop for that value of <var>n</var>.
    <li>How does the <code>for</code> loop know when to stop? I&#8217;m glad you asked! When <code>next(fib_iter)</code> raises a <code>StopIteration</code> exception, the <code>for</code> loop will swallow the exception and gracefully exit. (Any other exception will pass through and be raised as usual.) And where have you seen a <code>StopIteration</code> exception? In the <code>__next__()</code> method, of course!
    </ul>
    
    <p class=a>&#x2042;
    
    <h2 id=a-plural-rule-iterator>A Plural Rule Iterator</h2>
    
    <aside>iter(f) calls f.__iter__<br>next(f) calls f.__next__</aside>
    <p>Now it&#8217;s time for the finale. Let&#8217;s rewrite the <a href=generators.html>plural rules generator</a> as an iterator.
    
    <p class=d>[<a href=examples/plural6.py>download <code>plural6.py</code></a>]
    <pre class=pp><code>class LazyRules:
        rules_filename = 'plural6-rules.txt'
    
        def __init__(self):
            self.pattern_file = open(self.rules_filename, encoding='utf-8')
            self.cache = []
    
        def __iter__(self):
            self.cache_index = 0
            return self
    
        def __next__(self):
            self.cache_index += 1
            if len(self.cache) >= self.cache_index:
                return self.cache[self.cache_index - 1]
    
            if self.pattern_file.closed:
                raise StopIteration
    
            line = self.pattern_file.readline()
            if not line:
                self.pattern_file.close()
                raise StopIteration
    
            pattern, search, replace = line.split(None, 3)
            funcs = build_match_and_apply_functions(
                pattern, search, replace)
            self.cache.append(funcs)
            return funcs
    
    rules = LazyRules()</code></pre>
    
    <p>So this is a class that implements <code>__iter__()</code> and <code>__next__()</code>, so it can be used as an iterator. Then, you instantiate the class and assign it to <var>rules</var>. This happens just once, on import.
    
    <p>Let&#8217;s take the class one bite at a time.
    
    <pre class=pp><code>class LazyRules:
        rules_filename = 'plural6-rules.txt'
    
        def __init__(self):
    <a>        self.pattern_file = open(self.rules_filename, encoding='utf-8')  <span class=u>&#x2460;</span></a>
    <a>        self.cache = []                                                  <span class=u>&#x2461;</span></a></code></pre>
    <ol>
    <li>When we instantiate the <code>LazyRules</code> class, open the pattern file but don&#8217;t read anything from it. (That comes later.)
    <li>After opening the patterns file, initialize the cache. You&#8217;ll use this cache later (in the <code>__next__()</code> method) as you read lines from the pattern file.
    </ol>
    
    <p>Before we continue, let&#8217;s take a closer look at <var>rules_filename</var>. It&#8217;s not defined within the <code>__iter__()</code> method. In fact, it&#8217;s not defined within <em>any</em> method. It&#8217;s defined at the class level. It&#8217;s a <i>class variable</i>, and although you can access it just like an instance variable (<var>self.rules_filename</var>), it is shared across all instances of the <code>LazyRules</code> class.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>import plural6</kbd>
    <samp class=p>>>> </samp><kbd class=pp>r1 = plural6.LazyRules()</kbd>
    <samp class=p>>>> </samp><kbd class=pp>r2 = plural6.LazyRules()</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>r1.rules_filename</kbd>                               <span class=u>&#x2460;</span></a>
    <samp class=pp>'plural6-rules.txt'</samp>
    <samp class=p>>>> </samp><kbd class=pp>r2.rules_filename</kbd>
    <samp class=pp>'plural6-rules.txt'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>r2.rules_filename = 'r2-override.txt'</kbd>           <span class=u>&#x2461;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>r2.rules_filename</kbd>
    <samp class=pp>'r2-override.txt'</samp>
    <samp class=p>>>> </samp><kbd class=pp>r1.rules_filename</kbd>
    <samp class=pp>'plural6-rules.txt'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>r2.__class__.rules_filename</kbd>                     <span class=u>&#x2462;</span></a>
    <samp class=pp>'plural6-rules.txt'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>r2.__class__.rules_filename = 'papayawhip.txt'</kbd>  <span class=u>&#x2463;</span></a>
    <samp class=p>>>> </samp><kbd class=pp>r1.rules_filename</kbd>
    <samp class=pp>'papayawhip.txt'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>r2.rules_filename</kbd>                               <span class=u>&#x2464;</span></a>
    <samp class=pp>'r2-overridetxt'</samp></pre>
    <ol>
    <li>Each instance of the class inherits the <var>rules_filename</var> attribute with the value defined by the class.
    <li>Changing the attribute&#8217;s value in one instance does not affect other instances&hellip;
    <li>&hellip;nor does it change the class attribute. You can access the class attribute (as opposed to an individual instance&#8217;s attribute) by using the special <code>__class__</code> attribute to access the class itself.
    <li>If you change the class attribute, all instances that are still inheriting that value (like <var>r1</var> here) will be affected.
    <li>Instances that have overridden that attribute (like <var>r2</var> here) will not be affected.
    </ol>
    
    <p>And now back to our show.
    
    <pre class=pp><code><a>    def __iter__(self):       <span class=u>&#x2460;</span></a>
            self.cache_index = 0
    <a>        return self           <span class=u>&#x2461;</span></a>
    </code></pre>
    <ol>
    <li>The <code>__iter__()</code> method will be called every time someone&nbsp;&mdash;&nbsp;say, a <code>for</code> loop&nbsp;&mdash;&nbsp;calls <code>iter(rules)</code>.
    <li>The one thing that every <code>__iter__()</code> method must do is return an iterator. In this case, it returns <var>self</var>, which signals that this class defines a <code>__next__()</code> method which will take care of returning values throughout the iteration.
    </ol>
    
    <pre class=pp><code><a>    def __next__(self):                                 <span class=u>&#x2460;</span></a>
            .
            .
            .
            pattern, search, replace = line.split(None, 3)
    <a>        funcs = build_match_and_apply_functions(        <span class=u>&#x2461;</span></a>
                pattern, search, replace)
    <a>        self.cache.append(funcs)                        <span class=u>&#x2462;</span></a>
            return funcs</code></pre>
    <ol>
    <li>The <code>__next__()</code> method gets called whenever someone&nbsp;&mdash;&nbsp;say, a <code>for</code> loop&nbsp;&mdash;&nbsp;calls <code>next(rules)</code>. This method will only make sense if we start at the end and work backwards. So let&#8217;s do that.
    <li>The last part of this function should look familiar, at least. The <code>build_match_and_apply_functions()</code> function hasn&#8217;t changed; it&#8217;s the same as it ever was.
    <li>The only difference is that, before returning the match and apply functions (which are stored in the tuple <var>funcs</var>), we&#8217;re going to save them in <code>self.cache</code>.
    </ol>
    
    <p>Moving backwards&hellip;
    
    <pre class=pp><code>    def __next__(self):
            .
            .
            .
    <a>        line = self.pattern_file.readline()  <span class=u>&#x2460;</span></a>
    <a>        if not line:                         <span class=u>&#x2461;</span></a>
                self.pattern_file.close()
    <a>            raise StopIteration              <span class=u>&#x2462;</span></a>
            .
            .
            .</code></pre>
    <ol>
    <li>A bit of advanced file trickery here. The <code>readline()</code> method (note: singular, not the plural <code>readlines()</code>) reads exactly one line from an open file. Specifically, the next line. (<em>File objects are iterators too! It&#8217;s iterators all the way down&hellip;</em>)
    <li>If there was a line for <code>readline()</code> to read, <var>line</var> will not be an empty string. Even if the file contained a blank line, <var>line</var> would end up as the one-character string <code>'\n'</code> (a carriage return). If <var>line</var> is really an empty string, that means there are no more lines to read from the file.
    <li>When we reach the end of the file, we should close the file and raise the magic <code>StopIteration</code> exception. Remember, we got to this point because we needed a match and apply function for the next rule. The next rule comes from the next line of the file&hellip; but there is no next line! Therefore, we have no value to return. The iteration is over. (<span class=u>&#x266B;</span> The party&#8217;s over&hellip; <span class=u>&#x266B;</span>)
    </ol>
    
    <p>Moving backwards all the way to the start of the <code>__next__()</code> method&hellip;
    
    <pre class=pp><code>    def __next__(self):
            self.cache_index += 1
            if len(self.cache) >= self.cache_index:
    <a>            return self.cache[self.cache_index - 1]     <span class=u>&#x2460;</span></a>
    
            if self.pattern_file.closed:
    <a>            raise StopIteration                         <span class=u>&#x2461;</span></a>
            .
            .
            .</code></pre>
    <ol>
    <li><code>self.cache</code> will be a list of the functions we need to match and apply individual rules. (At least <em>that</em> should sound familiar!) <code>self.cache_index</code> keeps track of which cached item we should return next. If we haven&#8217;t exhausted the cache yet (<i>i.e.</i> if the length of <code>self.cache</code> is greater than <code>self.cache_index</code>), then we have a cache hit! Hooray! We can return the match and apply functions from the cache instead of building them from scratch.
    <li>On the other hand, if we don&#8217;t get a hit from the cache, <em>and</em> the file object has been closed (which could happen, further down the method, as you saw in the previous code snippet), then there&#8217;s nothing more we can do. If the file is closed, it means we&#8217;ve exhausted it&nbsp;&mdash;&nbsp;we&#8217;ve already read through every line from the pattern file, and we&#8217;ve already built and cached the match and apply functions for each pattern. The file is exhausted; the cache is exhausted; I&#8217;m exhausted. Wait, what? Hang in there, we&#8217;re almost done.
    </ol>
    
    <p>Putting it all together, here&#8217;s what happens when:
    
    <ul>
    <li>When the module is imported, it creates a single instance of the <code>LazyRules</code> class, called <var>rules</var>, which opens the pattern file but does not read from it.
    <li>When asked for the first match and apply function, it checks its cache but finds the cache is empty. So it reads a single line from the pattern file, builds the match and apply functions from those patterns, and caches them.
    <li>Let&#8217;s say, for the sake of argument, that the very first rule matched. If so, no further match and apply functions are built, and no further lines are read from the pattern file.
    <li>Furthermore, for the sake of argument, suppose that the caller calls the <code>plural()</code> function <em>again</em> to pluralize a different word. The <code>for</code> loop in the <code>plural()</code> function will call <code>iter(rules)</code>, which will reset the cache index but will not reset the open file object.
    <li>The first time through, the <code>for</code> loop will ask for a value from <var>rules</var>, which will invoke its <code>__next__()</code> method. This time, however, the cache is primed with a single pair of match and apply functions, corresponding to the patterns in the first line of the pattern file. Since they were built and cached in the course of pluralizing the previous word, they&#8217;re retrieved from the cache. The cache index increments, and the open file is never touched.
    <li>Let&#8217;s say, for the sake of argument, that the first rule does <em>not</em> match this time around. So the <code>for</code> loop comes around again and asks for another value from <var>rules</var>. This invokes the <code>__next__()</code> method a second time. This time, the cache is exhausted&nbsp;&mdash;&nbsp;it only contained one item, and we&#8217;re asking for a second&nbsp;&mdash;&nbsp;so the <code>__next__()</code> method continues. It reads another line from the open file, builds match and apply functions out of the patterns, and caches them.
    <li>This read-build-and-cache process will continue as long as the rules being read from the pattern file don&#8217;t match the word we&#8217;re trying to pluralize. If we do find a matching rule before the end of the file, we simply use it and stop, with the file still open. The file pointer will stay wherever we stopped reading, waiting for the next <code>readline()</code> command. In the meantime, the cache now has more items in it, and if we start all over again trying to pluralize a new word, each of those items in the cache will be tried before reading the next line from the pattern file.
    </ul>
    
    <p>We have achieved pluralization nirvana.
    
    <ol>
    <li><strong>Minimal startup cost.</strong> The only thing that happens on <code>import</code> is instantiating a single class and opening a file (but not reading from it).
    <li><strong>Maximum performance.</strong> The previous example would read through the file and build functions dynamically every time you wanted to pluralize a word. This version will cache functions as soon as they&#8217;re built, and in the worst case, it will only read through the pattern file once, no matter how many words you pluralize.
    <li><strong>Separation of code and data.</strong> All the patterns are stored in a separate file. Code is code, and data is data, and never the twain shall meet.
    </ol>
    
    <blockquote class=note>
    <p><span class=u>&#x261E;</span>Is this really nirvana? Well, yes and no. Here&#8217;s something to consider with the <code>LazyRules</code> example: the pattern file is opened (during <code>__init__()</code>), and it remains open until the final rule is reached. Python will eventually close the file when it exits, or after the last instantiation of the <code>LazyRules</code> class is destroyed, but still, that could be a <em>long</em> time. If this class is part of a long-running Python process, the Python interpreter may never exit, and the <code>LazyRules</code> object may never get destroyed.
    <p>There are ways around this. Instead of opening the file during <code>__init__()</code> and leaving it open while you read rules one line at a time, you could open the file, read all the rules, and immediately close the file. Or you could open the file, read one rule, save the file position with the <a href=files.html#read><code>tell()</code> method</a>, close the file, and later re-open it and use the <a href=files.html#read><code>seek()</code> method</a> to continue reading where you left off. Or you could not worry about it and just leave the file open, like this example code does. Programming is design, and design is all about trade-offs and constraints. Leaving a file open too long might be a problem; making your code more complicated might be a problem. Which one is the bigger problem depends on your development team, your application, and your runtime environment.
    </blockquote>
    
    <p class=a>&#x2042;
    
    <h2 id=furtherreading>Further Reading</h2>
    <ul>
    <li><a href=http://docs.python.org/3.1/library/stdtypes.html#iterator-types>Iterator types</a>
    <li><a href=http://www.python.org/dev/peps/pep-0234/>PEP 234: Iterators</a>
    <li><a href=http://www.python.org/dev/peps/pep-0255/>PEP 255: Simple Generators</a>
    <li><a href=http://www.dabeaz.com/generators/>Generator Tricks for Systems Programmers</a>
    </ul>
    
    <p class=v><a href=generators.html rel=prev title='back to &#8220;Closures &amp; Generators&#8221;'><span class=u>&#x261C;</span></a> <a href=advanced-iterators.html rel=next title='onward to &#8220;Advanced Iterators&#8221;'><span class=u>&#x261E;</span></a>
    
    <p class=c>&copy; 2001&ndash;11 <a href=about.html>Mark Pilgrim</a>
    <script src=j/jquery.js></script>
    <script src=j/prettify.js></script>
    <script src=j/dip3.js></script>
    ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/dip3.css������������������������������������������������������0000644�0000000�0000000�00000022620�11773544727�017163� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*
    
    "Dive Into Python 3" stylesheet
    
    Copyright (c) 2009, Mark Pilgrim, 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.
    
    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.
    
    
    Classname Legend
    
    .w = "widgets"    = wrapper block for hide/open/download links dynamically inserted into code listings
    .b = "block"      = internal block dynamically inserted into code listings
    .d = "download"   = download link for code listings
    .p = "prompt"     = command-line or interactive shell prompt within code listings
    .q = "quote"      = quote at beginning of each chapter
    .f = "fancy"      = first paragraph of each chapter (gets a fancy drop-cap)
    .c = "centered"   = centered footer text (also clears floats)
    .a = "asterism"   = section break
    .v = "navigation" = prev/next navigation links (not breadcrumbs)
    .u = "Unicode"    = text contains Unicode characters (requires special font declaration to accommodate *cough* a certain browser)
    
    .nm = "no mobile"     = hide this section on mobile devices
    .nd = "no decoration" = hide the widgets on this code block
    .pp = "pretty print"  = apply syntax highlighting to this code block
    .pf = "padded frame"  = black border with internal padding
    .fr = "framed"        = black border, no padding
    .ss = "screenshot"    = image, floated right, with margin
    .hl = "header link"   = auto-inserted pilcrow after h2 and h3 section headers
    
    .note = "note/caution/important"   = indented block for tips/gotchas/language comparisons
    .baa  = "best available ampersand" = wrapper block for ampersands
    .ots  = "on the side"              = an aside that is set in normal type (as opposed to a big blue pullquote)
    .xxxl = "ridiculously large"       = text sized 1000% larger than normal type
    
    Acknowledgements & Inspirations
    
    "The Elements of Typographic Style Applied to the Web" ... http://webtypography.net/toc/
    "Setting Type on the Web to a Baseline Grid" ............. http://www.alistapart.com/articles/settingtypeontheweb
    "Compose to a Vertical Rhythm" ........................... http://24ways.org/2006/compose-to-a-vertical-rhythm
    "Use the Best Available Ampersand" ....................... http://simplebits.com/notebook/2008/08/14/ampersands.html
    "Unicode Support in HTML, Fonts, and Web Browsers" ....... http://alanwood.net/unicode/
    "Punctuation" ............................................ http://en.wikipedia.org/wiki/Punctuation
    "Google Code Prettify" ................................... http://code.google.com/p/google-code-prettify/
    */
    
    /* typography */
    
    body, .w a, .inherit {
      font: medium/1.75 'Gill Sans', 'Gill Sans MT', Corbel, Helvetica, 'Nimbus Sans L', sans-serif;
      word-spacing: 0.1em;
    }
    pre, kbd, samp, code, var, .b, pre span {
      font: small/2.154 Consolas, 'Andale Mono', Monaco, 'Liberation Mono', 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', monospace;
      word-spacing: 0;
    }
    .u {
      font: medium/1.75 'Arial Unicode MS', FreeSerif, OpenSymbol, 'DejaVu Sans', sans-serif;
    }
    pre .u, td .u, pre .u span, .a, tr + tr th:first-child {
      font: medium/1.75 'Arial Unicode MS', 'DejaVu Sans', FreeSerif, OpenSymbol, sans-serif;
      color: #222;
    }
    .baa {
      font: oblique 105% Constantia, Baskerville, Palatino, 'Palatino Linotype', 'URW Palladio L', serif;
    }
    abbr {
      font-variant: small-caps;
      text-transform: lowercase;
      letter-spacing: 0.1em;
    }
    .q {
      text-align: right;
      font-style: oblique;
    }
    .q span {
      font-size: large;
    }
    .note {
      margin: 3.5em 4.94em;
    }
    .note span {
      display: block;
      float: left;
      font-size: xx-large;
      line-height: 0.875;
      margin: 0 0.22em 0 -1.22em;
      color: steelblue;
    }
    .c, w, .w a, .d {
      line-height: 2.154;
    }
    .f:first-letter {
      float: left;
      color: lightsteelblue;
      padding: 0.11em 4px 0 0;
      font: normal 4em/0.68 serif;
      text-shadow: steelblue 1px 1px 1px;
    }
    p, ul, ol {
      margin: 1.75em 0;
      font-size: medium;
    }
    
    /* basics */
    
    html {
      background: #fff;
      color: #222;
    }
    body {
      margin: 1.75em 28px;
    }
    .c, .a, .xxxl {
      clear: both;
      text-align: center;
    }
    .c {
      margin: 2.154em 0;
    }
    .a {
      font-size: xx-large;
      line-height: .875;
      color: #82b445;
    }
    form div, #level {
      float: right;
    }
    .todo {
      color: #ddd;
    }
    #level span {
      color: #82b445;
    }
    .pf,.fr {
      border: 1px solid;
    }
    .pf {
      padding: 0 1.75em;
    }
    .xxxl {
      font-size:1000%;
      font-weight:bold;
      line-height:1;
      margin:0.7em 0;
    }
    .ss {
      float: right;
      margin: 0 0 1.75em 1.75em;
    }
    
    /* links */
    
    a {
      text-decoration: none;
      border-bottom: 1px dotted;
    }
    a:hover {
      border-bottom: 1px solid;
    }
    a:link, .w a {
      color: steelblue;
    }
    a:visited {
      color: #b44582;
    }
    .c a {
      color: inherit;
    }
    a.hl:link, a.hl:visited {
      color: #fff;
      padding-left: 0.2em;
      text-decoration: none;
      border: 0;
    }
    a.hl:hover, h2[id]:hover a.hl, h3[id]:hover a.hl {
      background: transparent;
      color: gainsboro;
    }
    
    /* code blocks */
    
    pre {
      padding-left: 2.154em;
      border-left: 1px solid #ddd;
    }
    .w {
      float: left;
    }
    .c, .w, .w a, .d {
      font-size: small;
    }
    .b, ol, p, blockquote, h1, h2, h3 {
      clear: left;
    }
    pre a, .w a {
      padding: 0.4375em 0;
    }
    .w a {
      text-decoration: underline;
    }
    dfn {
      font-style: inherit;
    }
    mark {
      font-weight: bold;
      display: inline-block;
      width: 100%;
      background: #ff8;
    }
    pre span, .p {
      color: #667;
    }
    
    /* tables */
    
    table {
      width: 100%;
      border-collapse: collapse;
    }
    th, td {
      width: 45%;
      padding: 0 0.5em;
      border: 1px solid #bbb;
    }
    th {
      text-align: left;
      vertical-align: baseline;
    }
    td {
      vertical-align: top;
    }
    th:first-child {
      width: 10%;
      text-align: center;
    }
    td pre {
      padding: 0;
    }
    
    /* overrides */
    
    li ol, .q, th, td, td pre {
      margin: 0;
    }
    code, var, samp {
      line-height: inherit !important;
    }
    pre a, td code a, .w a, pre a:hover, td a:link, td a:visited, td pre {
      border: 0;
    }
    
    /* headers and pullquotes */
    
    h1, h2, h3, aside {
      font-family: "Book Antiqua", Palatino, Georgia, serif;
    }
    h1, h2, h3 {
      font-variant: small-caps;
    }
    h1, h2 {
      letter-spacing: -1px;
    }
    h1, h1 code {
      font-size: xx-large;
      line-height: 1.3125;
    }
    h2, h2 code {
      font-size: x-large;
      line-height: 1.167;
      margin: 1.167em 0;
    }
    h3, h3 code {
      font-size: large;
      line-height: 1.556;
      margin: 1.556em 0;
    }
    h1 {
      border-bottom: 4px double;
      width: 100%;
      margin: 1.49em 0;
      counter-reset: h2;
    }
    h1:before {
      content: "Chapter " counter(h1) ". ";
    }
    h2:before {
      counter-increment: h2;
      content: counter(h1) "." counter(h2) ". ";
    }
    h2 {
      counter-reset: h3;
    }
    #toc + h2:before {
      content: "";
    }
    h3:before {
      counter-increment: h3;
      content: counter(h1) "." counter(h2) "." counter(h3) ". ";
    }
    #appa h1:before {
      counter-increment: h1;
      content: 'Appendix A. '
    }
    #appa h2:before {
      counter-increment: h2;
      content: 'A.' counter(h2) '. '
    }
    #appa h3:before {
      counter-increment: h3;
      content: 'A.' counter(h2) '.' counter(h3) '. '
    }
    #appb h1:before {
      counter-increment: h1;
      content: 'Appendix B. '
    }
    #appb h2:before {
      counter-increment: h2;
      content: 'B.' counter(h2) '. '
    }
    #appb h3:before {
      counter-increment: h3;
      content: 'B.' counter(h2) '.' counter(h3) '. '
    }
    #appc h1:before {
      counter-increment: h1;
      content: 'Appendix C. '
    }
    #appc h2:before {
      counter-increment: h2;
      content: 'C.' counter(h2) '. '
    }
    #appc h3:before {
      counter-increment: h3;
      content: 'C.' counter(h2) '.' counter(h3) '. '
    }
    #appd h1:before {
      counter-increment: h1;
      content: 'Appendix D. '
    }
    #appd h2:before {
      counter-increment: h2;
      content: 'D.' counter(h2) '. '
    }
    #appd h3:before {
      counter-increment: h3;
      content: 'D.' counter(h2) '.' counter(h3) '. '
    }
    aside {
      display: block;
      float: right;
      font-style: oblique;
      font-size: xx-large;
      width: 25%;
      margin: 1.75em 0 .75em 1.75em;
      background: steelblue;
      color: white;
      padding: 1.75em;
      border: 1px solid;
      -moz-border-radius: 1em;
      -webkit-border-radius: 1em;
      border-radius: 1em;
    }
    aside.ots {
      font-style: normal;
      font-size: medium;
      line-height: 1.75;
    }
    aside a {
      color: #fff !important;
    }
    aside code {
      font-size: inherit;
    }
    
    /* previous/next navigation links */
    
    .v a {
      text-decoration: none;
      border: 0;
      display: block;
    }
    .v a {
      float: left;
    }
    .v a + a {
      float: right;
    }
    .v span {
      font-size: 1000%;
      line-height: 1;
      margin: 0;
      text-shadow: gainsboro 3px 3px 3px;
    }
    
    /* syntax highlighting */
    
    .str { color: #080; }
    .kwd { color: #008; }
    .com, .traceback { color: #800; }
    .typ { color: #606; }
    .lit { color: #066; }
    .pun { color: #660; }
    .pln { color: #000; }
    .tag { color: #008; }
    .atn { color: #606; }
    .atv { color: #080; }
    .dec { color: #606; }
    ����������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/������������������������������������������������������������0000755�0000000�0000000�00000000000�11773544727�016040� 5����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/win-install-3-customize.png���������������������������������0000644�0000000�0000000�00000036147�11773544727�023202� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������|��PLTE���333�}�<tL}___|s]eedqodspgyyw�����%�(
    1	:���%�(�:	@'M"T?o?q;u9{�BAC	JU�H�YRj1j3fCi@nKtW|L|U}nvM}����3�33_Rbfifv~fkhhf}i~|}f̙f&5*03D(K0zZ*�;/�6=;CF$J&R.S2CKPM$T(Y7b:_@fGnRsY|bWvZoΕ:Xʹmjr{8?fwKHPsjvWgwրőʒ՗˖ԉ䍶▶蛽ԬƠױȶڪ̩۹˶ަź»̙˗DZ̿Ьоӑމߔڤܶ#zEf�U+17�Jr�K�c�4=?��9(IDATx^I0CQX;\	J,Uo2wI,V_k.9ђ@-h.Aӣ#>S##7{tl P	"G;H;A%BykK7%�	_p;f!VeL{	䧱^8q^x!] מA,R
    6rGv5?$~ۀwI.WE`Jabf"[q߁L󰳛9S+=ُEa|c
    vQܸßhXvlCg)DhnUq^2aeeHoWŇ07hؑMa^s^ -yl^,+741L›6s|r
    07Nu=$4=̉2]`_\>_kFBn|
    s/y2m.0\|{3~r5e`蒼8|O{@qڜ?Cr/.vx�9	lrd[$VB,2WB˸%fk�Q5�S~A&x0L܍AT)a>ٲr&ϻd>%L>	>fiNs0?`"̎Oh�γjy?8WW\;stK=xS:OK<
    0RPŸ&7O$i2ݥ$['{a0
    57?A
    pqVXXLqA[%l8$'ivyZhruGfQH0[V~S/�9.sӁMFQ �5;{
    |v.Ӕ$I)j�!_W:宱״):; �|1};عJQ+]Wi8]
    Q|"
    "Xc?}�8d]VidȒGtbc3XᐓGBDLdBX5e)d6!^t&<0s:];Ktf*3r47�|%)3_
    wJ|Q{2:|f[jh}srm4pgɸ>bhnCC7WcoP,o~׌cp	Ɋk<,
    >ϦKѫKu8:mj6*&e4L&%C<KhNIz~|đC
    r?`Q3YrULJSs25Ө:
    "W$.sYm_+vYZ-W_YHO<\Kl4#fq� rHX9?OETh$}S5OQ{-H \RKKsح 
    @Cz@\j6雸MCdmͯ'DX=ŐOny|rueݗx}~|}J)9-_7y7/0GB<)艛,c $a1sc7e~腧o0&2o#Ǥ=|5\vNjn=gX3&<`Q˜5s/0@fΠA7jNE:Anչ06s,Mesv?իa^:Tm
    -^Ž0wUvvv<oN5~lsvs#w7횇nE?:9O<MjL` Y>9^XL6&0a`V:@QR1BtڲCUWw&bqT׉[4\c{gs9 4ռVVZBHoCZ
    ϦȜ:ikT6,Ls~͗~.<&'JvRNi�B/)ܠOBKzeyq	/a[׷Ρ'G><bѠ
    ތj7۲p&HO~2o汇4st
    =%v7B%8ZRqT=WmC$OjSAgG^myύ\'j$0+iAn_ `^z9.k>*XXCOz!ϛknP)<f_#eknd8%aF!lL:j7G	JL]T>l^76sjU8"Wڍ|5ΟkuEliEOS뙆O!n0?Xjyʩ'nOX٤y50҃~FYi$d^[z0Ԏs,Iw<ӈ\|Y]Mn;va^A+FssUpnjjiFO^Mz[*,N̫)Z	!IxLAr{0槿r.n$[f]s{5/WCFsQ\'.r{5x$\ZahsAwJ.a
    IArPuҔ9o8C&BC|Gu{cAZG[f?M7/:Wv;0߂xȃ9}fgV6`<F-GLqDő'7g18;k%;WѺ| ޷%s<&כ&<@StSgK]$ԛ$/
    |l>D2/)CEA%Q>~5ifrB#߻y$Ux?]�Wq2~)T~9|mg7B.̷;}'cgs}+t`4Ɍ S23y#\f<6x-2N>sag^cޮUsȝ,őztY^V
    qeG="|v'~ėx>rօ5Ӽyk?
    <S5A|F
    KP)BaD:Qc (Gxr}3g7UD3k2JyE5@\ba
    $z?68>?_7\Cx290 	T4#3f`A}8sCAZ.Et""gd^EbbnSs	&tH0u8-KēȷyT'n76"V[yȼ}ll߇5
    ]6SɜfNMR7eu$kV�~JVS3d.El;O=*'YMfծk\@X5j0+rs|}0Β-&LavVBb_Q	D,yZX<l`7SǕ?Yc
    t-sQY]\V[Řjh58*X~$ܷ|'OP
    w,˩d|>$&s4LɘXFrƣLsX7/Lo-;7*pE.F7C�sa#VB sf0Oo4-]Ʌ;
    WT<Mb"|2ogf=a#Μz:Wƕ
    (cB'Q|lW鶾5MPM
    NY&[o:f
    cm݃
    v͞JyDmips(>+oQYm2D/~j'8NO0]oKj` 8,^g2'ddA2i>F
    b.X1+�f<m\oz"q\RD\YE1~7.&7b&W=b4cER!ǀp\j房zV+1'W/xO4'69g`nl`VŬ=|tlGpc;03#ftc`aCK^dE6Q)}=oͪy;։ɾJs
    @T_J+scdaeFdde
    <*//%yNc;xN|m~m_z[xa%k$$ 㨰;ZAx˙9ѽG:z%rFTǦ\0Y;yN�kviّyn>v$3$=؂G=Ra)1kj41"@~yͫc=D}u
    (�o	27053l	 8Kͫc0)'Iq72dTζcdcfN`$t̩mW\̜g|X܆�p}̉}pUI~љټ:fcf<ulM1!7s=Fe掙;fc掙;fczoܟ힛vɟwǪmqoPtࡣa<y;&أ'c(384E<y8~RB>ڐ*p~I@Hw$	UIۥxŅ;3s>o,S*r`N]C<
    76`ǝKMT6]ۛSV[il#GqJɖ2_޵9wQ7h4l9ȷȁvN~&po"#9z$rj}꺖L{/Dy,œMs4Ug|uj;0u>I`%5{sM26ᐷT[Ƀ)zC7\Χs=3Yc0Py$<dxH/no
    s&c2G͝k
    ~|wn%<[y%<1ye|ZeN~.2g\&@~4 <̱g	i~z*\νy.Hfs_S3Cb^s;\w%<%FBLp=r7]Gdعv%LEν&d\�6rQgͻ;kr9#犜Aj;!n4O'±
    �r76
    Dq�	.HP10V
    B|$:8jvAX,—h)H	<+z#ޝrV6Ktq9?åff''5yWr9ü[8
    dgin)ɟܭ嚙މPy'WYS麬*6^M)|ixɵR1@v94P;n<X;x-G\z#:l<'ȵY)c[M%]rys/Qn 'L5Ā\oo3;Zda\kz*,.=_o``AEߔDW45y$N@57/�C6-]l+5=~D:FZ=Qw_G;W2>sK̹׼'M`'0R͠.q%09A$"C̋Y70Z޿
    ]sx\1ض9iq<3Ȉ
    b橙|&p*s%9\e┚f;Lh)X�tyoesSMr\?%ݼ'g~P GkC|N(>sSs076:X@BqB	(rt
    Z9eYj#in^#Cb\8I|7<n~'YedNK5?_Ry<ܩnչg)-3?GN,}<ss; 1_lB-}ى9a.0x<!hKɴs 񙋸_x|bn%l2Q2%uv^Ȯ?ΞVW|.fIOY|cjy\c3_GO<Gdu%a뼒rw^?
    b8O|}=!1Ꟈͣ\`
    +r-lR
    sp񘳈佟lB3o'!7Ms/q(]Ҫp&~&OR7Py\5Uw<A��	V"Ud,BRH{	VRo*diw[35F{7nGυގȟ/D$ԌL]&K4䷚GBUO9Aش5󌜇d3Ub,+7fi	d90~v;yԹҨ}*SSsU*r,>bRu)[jJ%81'~S/3ygQBTL\?Z"07h=
    y&ظَ&)\sr G29A;YHJ?w,-QN˪5{8)P/rˇ/J:,EakT]uKE3'^Cn?bs}t'wvr/|(x8p( 'q111es@q́ĩӣ萃r긛y'œ"Awrh7yf cOnB?x	 oK=91|B h
    tsz<E8ysy?̵~RmN"ϧ	@."?t[vr5zf֦9'^03渞Dz|jp18yG3 g.ZAtțw3ʾ<2,勫J0[WCm#g#CP	U;n6`ݗ?`T1'O4,*^6ȭB3%)d~As<J`&†8JTBt{| sIBK@ᵨyNWXˣ69v
    59ClICOs{9GʋwT5I<c
    ]	Lk#<UFg{d{#E2$͔ID{n*0`
    Bٴk a1O_b
    $\Eo`zr0 ޛ9ϝ@pK{JlȌ0^5`N>GLOicjrI\
    NV952t2@ޕKMkU-0$nV99�1K6ˎJΟ[LlPxo2=)zKm2YΟW48!jWϏ-[%8ӿb̘]s|ʚ\$A7'&K</W"M
    ݉J.%rnMd=:9w[DW7MZ@2scMhΟOK(SU'rƕvgr|:'r|
    Q"nvhq"~@!{b
    *ȡWӷ0fySa6C-Su}9t}
    J[Vh=pDT@ \%O_X}Q5&
    J/ŝߎzHT]q0~*Yvi]ޟB&!sAX5>9A	mRy6	AV%+yTq88@X5R߭i0&\~#o9TvCiEEEW>˗7~Q6-hrv~{uysB!''y.Ѭr`//7w
    liTS%!	;]oʷaUb0�L)y<_׆4u2y7Fpjnn/%+סMNI0+RKwhVo[9`|"h?pPSo\%_r^őa^sf`7rXn9uǑI:Oͫ=JGV$?.w&F0/s#iԂ0kWh
    p{?"8Bv)ɼ!8HW,X|V41S\qH2/sfRN]sZm>wR̫_0
    pۜ8:
    m>~BR\ 9ܾ*x;.2V=x(C8u<?t|9s.(7r`yA x)y1ި	�}?Ǽ!2^'|\7..�ǸZyC\~Cz]=+<avI<7껜PJ~eX]23#ռc^.~e7מ ~y~.5{C.ft垖,C$U8>ȼ+)x<b:qjzv2ʥ9	N�Uɗ,ˏ@.}3jnm^s{'7xtM:F٥tzfɵԾR<xy?,[Ï(yy|\ݼ21gue.
    KHtS|:SO65OdCm='e^߫I$7Dݹ/a\\%eV|/rTM]x@"/6;;|Tg'jc㑗!ӁQI|iyFQLQt/4_ga p@|
    +4{[q^ev:FnOca~\F(~"3'BΒ]p[wo]@;yk(؅=!Y
     يq\0GHC[�ܷv;qm0-
    tV6sY
    ..m^Eu9\waH#Lx+ɣ`p!4@c:釷PiX/Yp8KsS
    Oެk<ghmށ._nn0֔8'	~6Ov=yZ<9P%,.8?
    ^%W1sXVcbwЎ"ȟ
    7/P$^݊TřT+_/.tqm͋ΕXU./РPuo{6s&Ms.O<q7YfS]-kȢoU2N:пpe#+X'7
    ?8GWhD>>4Pǂ�d.渂údvks9[[:ם{"(]Wb'#b!WpfWPQs-YӹDN<p9m&~R;Ge|Fao93!'mȑIl!r{cipkb^Ao_˼43Ŝr;,:'/ʢ71hjj3R!0[vwؕ<yW>4q=og[5oO%Oj	L4$Na
    F&4q61Zs0ڈ 9_ߜJm)
    úPC N#x	MU#c'r	rQs@>"WQ4&ɏ�MY3o(~rCPc6 hi@N;Q|m
    #BۃU^3>@LBz.)	`"| @MCQq!4Bng8:29)f^][ocV!7ܙM�%7sY%r̝yGA4q&&!䆙Y
    !Y@>13HHA%l2woL^RxRP憙%ϔ`ܵ\̝SF[SG$Dn{;+ޤH>hݐyW(sg%/24syyPސ;'՟2Fu]iV5ޫ	t&nUSY޲v=i햙\4.29޶v6sg"+!:K9BC䠟Y"a.k{)]瀭G$󩽀00Yus@.2P%Ώ/xxBtR^jHv~GkܙN`$=~O3mϝ9ߨ	gSqH?z(o$!VLҘɜ'NH}Eڧþ!oh$€&ga-eW>n;E7mtP<~j'MXp,<FBY`%XnONN^˛hǎ(Ig H6E!M_3OtnO3?$_0<=oDU3rTCE;ͲrmE0%^wz](B\On*eiqڬl+=Cf/#ܤh
    2.`)CW]s2pO^{BO6!y.sgvZ4@aN	󬀤ԈŅڑط_!뎚
    3�89ʢEwsٍbdL#a̍O\7r3 n\T+\Q~e>Qa1#g*e[JzՊ4?;cnҬQgvtS\!p@JAx7!.`MS:sqxtfw._3FSAlȔR=S]JK̗1OxB\ɜ]}i{8>'\9[96!�-}WL
    3o}oYJ)shy`L2[]3M9zWbeU+ϜT2ORvA֨j9'oZK]R1/ukSo3zNEM]qʚGL$K|;/ox'N}@\?bPaKāf~$$|sm?Qbp#C̕:+avw<ׅP2d3UD<ƨ8l1/<0^GfKrM*`籀9:5c}8Bzk&N`yfZB0'Y^ ǧg&C2"|X\Hf^s3qUI@<dKS̥.$@Oװ~\&ZYT?42\ȇ\RaJM~"PC\ʜ;2Ms91r"`~Wć3e̵r鑲w}@,NQqGʘjYSs=
    Û+s_ŦKz2*?ځxcq9\GB9#y:8G0}̙//a#qTfچKX"DU	*'
    `GWY#nX!!M)9в?/l=`.]ȫB9܆sH599aw_Q"`vo͠L˜MQ‹
    1 2l>Μ\c7<_x1φc
    ;4%zX;15kdX?)=
    )9~_bZ9[$ƀ.aC$zGm˹r){ߞQgj
    ;O&ݾlxzGL ? 7FN
    0ٹ1rk3`Ν)#4|15
    ߻`ԅ{Qg~ٖqy}`Uow-$m%~tױsS2rk"?[H2'S0sW3i=4k'S1gލKX(Fm	L3-%}"&=d)QlUy@#ߎ$s_xb'5ti2J248Ŝ6FNƉ8̷e1V>	+6܄KL%2oFIf<6"^d\VL3z3GR5s7'ɳGcܽnL`q^F(t_E,[ڀb0+ܸFf|%>?Ƒ@)<ΙI==<'=~\+	砯d<p:m+zWf97T7<?WFJ<e!E_taG9uEW.E7Bod#&E>4rܲV	n]Vk)y4IkyD?0zf@'JyvuussKFϰ,{$0w֝N;xh>hŷ")Eȩ/N
    ΡfOsc›Gs1rҙJ17C	Z;cɷT&6y̎D-zo}s76eݙ9ien;2piW$oo&[؝|nW,mnԋ[Au1ķUM_7K@i>ʼ1Ѿ�G
    4'ukQ<y4=]O(6u{ΛٜM"{*7*GsmLMͽC9W9|ר?Oz,>ZN`hdgJ繠yAMO%|mrzu	oKb|-32vwb8 _!WyۖwXe\|`}潞y]	2}	N�r"R7oqۜhau82yav`y(A|
    \l4'1;!k㜂ťwf2taJsKgS{&-X6n1	~Ѩ`8pUz6o2ei/i@PMjϖ.In^|v:13Q CjXnMֻyvxvPhT)
    J,*!
    `^"`=8I\H2\=Q'ȸkEvaɪfۿyIa֏�@0'!6D>zȥyKS9w<ˊܴzA._Z!AJ=Pwj-;7@0Zn
    `?<rsC<O4�� @P[,DVmB];� �*(/��tTL&7b.b.b.b.̯/Gw2FA K�;	r᭦
    Bt=2X4=#J4(KHsYP7s1D/7ֺlD_ <<o^T(Ӡ
    0|VcJ4(jmJ+0s
    1*Ӡ$lsPy2HanKOExv]@f|"V{w:�`gŹ8ܦlН%3?k(H$ȺztFT|W̢Fj3,:G:'Gwnskuss:΁-}΁`]VNbH89jr|&Źs<F-iιqB9`G]]ιX"p⅜?(979{TL}ΕR+a  StCr,t` Ɍ[+A+"?h;Gy,EJXg+]R_q/GTcaL(7<;U(<[
    2'רd,DpBuƃ=1ſ̳"k+{m	*Ef,f}rsY1!]g_֐\䒿"i{g:/[3K:}\&Dg=|Aʛc^UyUμj8QmҕQ"AqB
    MRؤkdEMvmƮ݀a|77ms$lIX
    y;6/oXkT72Z;y`
    /9PRo@|o4<AT/(a׎i�A�V�AE+B3/'?v�`tMH�Ɨ/XODϵyY6łcŶA����IENDB`�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/ubu-install-2-search-python-3.png���������������������������0000644�0000000�0000000�00000057231�11773544727�024076� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������ԍdo��PLTE���
    '"*�($7-�� 7��0&(&&&,9-.3422+7774V8l(6F!?z7M�Cx:CM7Tn;`{LLX��UT5N5+j�o�hww�~p*
    v-+DWHG4Tj�tIoW2dxPQRAKaFUhC]vY]cT^pXcZVcs`__{XZmkVmno;OGji-T,X6k5uI;pC[SoNvmsb{Oy+&TT+YE*vv,p1YO[nNN}T~uRllt#97]SskNKVhwyno-54&3,TK(eg,OC8e
    s/Y[XZvOxmMHLneY
    *-'\�J2lw(rPLOgUpjjhgQg{�7((MtTdVsIo04Q|؋̉/δͮ2*/ЏMӚfйLөpQl
    *6:SpKqWjŐ҈崺Īđ¯܈˳ՏМгƺⳋ紳ʾǕϱΑӰ+.2U;3��[WIDATx^1��@k`ȇ9Bo}:&�A Va`!�Ec�4O&A"l\
    B XdG6	\"!_msO>PǑk9)F�Mmv2YuLUU;�|rLü:DZU-}"9M3Q:2hi#eU@Q Z,`_94^z%OAX[^PtLDMj{<0;B�WXz-_rv']0{L6�<9MyLEh 0"#}rX6NMN7,M%0&Ք3&3
    K(4>?^L1^IbZ
    6F9f.Ius.eaI7Ť2OLYaB~+-kGYh/FcAyrrR'鹘HVL0z"2RLWp)O.ݕw j𼂨B w9H]1.Q&ƤXߏ"r9PRՎ\#yZ�`1)|XXp{M�RSv D^<Q:s=%y]|dP3<9n
    L*qI'{Ԑw}UFZ8IleR)oJe)%4R żc1}Iy'^;e>L)v(Pܐt8t
    \OuѥBo<rQw*3Ozu#+LJLQIY8b(LPl) _,ÊYy\i(B(bb.IЛj)VEz1t2OD%^
    +fN-&(WY3V賘?,2fE~Ubbc08t#B߼2hps3W&�NOzWE1YŲ Ay(ꀖ)( X.gBڢ#4d5^`t"?[RV9{S>0LCGr	 wBotbV<4}}waZPqc)A/dk\[2~6A ,#:k�E3lic1bX0E#s'9Þ6Qx&R
    !dTisk4b3UDHTL&!$)W(z]E!گy4ֺyKi:\'_j
    ?v
     LԂBMgJW*-~ZuXoeK݀;>I>C#76TIcڃ`Zk
    9`_,ӜHI&\yzFi6D[DdՌV*[:GpM}F1(#Pzx9QgRyXLoC~@uVOۺop2_E@9!f#^]9X_i
    pFtM\0?٧Ca Yɰ :cTJ5,3dhd1	
    꺕UJ~?!@}UU	89kjp['62L=_D#?ԤT]'h8n.ݪЫtMb_3>�@Ұ
    "P(TPYf>&sOD�� �
    hl&Øp_Ҥ'8c.tH���E,zKL@L11AL@LO&�0�Х`acA+pnL	O^׍]ep bnaøgz+Se%-8ЭwA!J45cUN|8cs-s�cB.iȬ~̣Nc9<,X֘cq?3ޗA>Č1Kd!گ|VˀKc't!a}]RSXلdvD4Z(.<	eG4@3\Kw[0ɤiv`fϼnM`
    LI+L�/8
    [ǪpLwȢ P!x)]y>
    }79K,x˝H;Cbn/wiVHNө_*mKUYt0ʋ9*o;.կ+0X0m
    /;F@KaEzN"NWS`r"-g`}`y,Bˌq7`(z1䱬K}$L}ac0z0I¼5)u明2̵	O\wS&"+
    Td@$ԓX
    16lam#0}>5,aF0o0ё뎨\JUׇNDLHdU0Q*e1"_|mkGGB z0D9_`rj!{QO.Iɒ)|K2Ň[w㭪 ;|(6ĩuy?Lօبg^}
    0B�_wлSh	 q1Y<S|
    	7@'W
    @vY� uB`NJv']'�A4h4U'/'m#L&ح&d	`J�gs42};4EYKu<0	":2"m3aDO"8>8ەج`i`i!�;{[9-J8WL#{[�d@µ@$5S>eJ8*(rja1"u@"&{Je;NF`rr#\86UEZ߼Pgij0j/fR$٬z`
    A.w<n=;%z
    `D9r%I4ni eutZ"1?t*@' $FOȮ'L1IT9
    >CI6ˍu8p|衪	?
    7L[)[`ѧ)LRv3k
    <y&Ev?A?fo~=sӱ71Y>f˴XJ3ie ˫
    (05a@0i
    AL
    q@b1ih~9fg[JZ7ɟnX
    9̡>,0gt,
    +sYӧhx.jys?'noۛO($OXrׇ�	&L &! syKY/(eb�WƓ[	]Isa/㮨*%[-\dn4\m s&LQdI;EQf]0___x~8.nNe殉 L&mɊI@%<V9BLd@:oZ&R`ҔQ-0YTK˗/_\?`pip>4y`4Xa0yFPH_$.jTPH`�qU,)os0mO)E7.:KYv.�&n,�&7bWJѯ�`^0{G9n0_K)-$98Ƒ$O nI5^쁙*XkmyYf `Z\O.Caw204H/',7bpzËqm)`�s.ߊv~'W PR`:LEt<`@8<4\
    &.e+&2!
    b`R0t>#^Z\Oi;N$ͅlp#vlH-%{_WW
    QS\ySɋ`F/~Yk0;\;+D;b%SKhu[43v-	y`\ONh?u*I6ˍub-L6abK`˦n0@8ks376,//2
    {Q}0&ۏ>@ש~|X\|0YM?1x>v0fq�a(spIL&`U7Ē~Nj<9Ō(MI;L”	AJ?0;L¬A av:E"p,p6"j!ZB1y~ۼa?0xf_Y:0I!֝lPBɜ7TN)LHjlQcE<P[M'Ia2<
    }@)v0H7Ll%¼).1GǧÅ/0!"2dTNpg]v2	bmҤH~/nv'퍑N!?jޏv.[UQL9s{{D�@QT̎5XP1W?$XhoEż��NDgӡq:G	yTGXo!}'Q1Z+{8圐
    .DdKbz,fiRSQ1?bO;n,&%&lC^BU`F5[607"3@y,MZ{%b~&bubFiӆpB`ko8 |�n1C8i}bF(bb8»wV"q,B'CcuIFe.CqŤMBQż%Mx엻"�؃',&B%S&
    ZLENL]|bŽÿ(+X	(MYtNTTEBaǴ@"O$06]CiOg,Lzb"([&3&%K%3b&
    ^LED\ێ)gVn`<YB'faTTLW1gTTL|`1.WTsy.ØDHKiUzA)Әbfb3Ọoá1~*f_ZZL5ޕHCLm@̨le*X&fɞ9ccFunR'&~%GYXF>TLYB)HEH!?\&*35-Ѝى&r7vGJĔB$`zkŴ?Eژ{m aEb>:M^CoJ,WhT1},\QL'^=nd	fvVhmCJJABC9EQLs'(5/JL3J,¢brNj%1UG)Ĵ#o1UL)%|. BL&yәQVlkeVLGY$;C5g$f01hJw|vػ#0q6bVRJ2]<X
    A&KU[L|ʄzb֦&T&A>}tl*fq	EY4X
    A&KU[LjqŇ4@1"C!I,5S쭤EkKEH!d5ac?"Rb:k?Qb
    bDE`RXG
    ՈL	H&&*IILrľ2bT@Q1Ǐ PW>(1O+MSQ1l?a;wzQL`?!aVBs!ESʕ&0nLaBƪ'tb]B/19+z8͛wKb6&/%1ͅm!6|1e~@6bs8J&V"M+-qhqSD:	Kxי=a&„_<{em+!nnYbA}\|/}`!:ڐQ.fLH"&,?a]&{1XN‚(a쌷)mn~5Rm	eZJWmP̰VZ!s{7	&&i*K&}\B*;L[{}Ϳ>Z
    &-uZiƍ\P-}\L*K`{߿q=>Y|\2,tZ%̪q1{7?n}<'`il0Q#hl01h5<Sd<F׮]|<8gy0<$x<
    5҃fk8F./ �XR`)".9	�$SLc@#<Ly0I<J` Z
    L:KHF7ULJ2&q%?&Af,!dD`z0Q
    L
    &�&E1eJELfa0#a<FƂ>dɴK
    }q;wd)7ALfsjL[΂)4WL<qXKee84Bf_	(iIqcez0=nݺj;Ե?)΂	ޙHD2k<Dio;:+)k/M"sy0f_Uf'X8	S;}sj6G0gLd,reT
    &(4Z!Q<RYQO0V_皦2v0ov: L%)C.{
    ^|UBƛfEڷJҏK{LR{�&T6$1P0TZ+<.pui`&@2TF1*`0[@j77KsۧOu`@E:2Ry`rHYRx)`{\Gfn0
    
    ^zOE"Rd}`O -yZF|ɰAPLRhBQ_qk 9і
    1vw9c_!/NlfOI\*_?]`Z;2�҉7`R+2L``=9
    JQSZ	I3(3&MWP㰢V+thQ&*);soKf%�`7JpYAT=vZ&N\C+XC횂HE`d[1ns.>c:z$y8OfvlN~T
    f@)vvfrxz7,:}~Ub`_LdIWvX?0R
    ̗W_/Lz,)(4jXbTk9O>Q̋*S
    RA&>j:Mc3AX!:0
    1nCk@2n0ŕOvQ?k	f*x'Pe0,Ձf^
    h(LF\>D.Za	[C0!\/`l
    2ʝ@bLeY.
    /pT^dRiRfC`w	Z;An{e;]�Up�
    []sI^!|eA5A%A}
    ²]猙*!ws.Jf<.1a灉,	:/v[X 蝷lM`Q]͠j-cYd8W{-b^ڭ1X*2%LUH
    Vf^L=[b^0QyX'~MfWLdd)\?%og@
    DKAYi̇JX`B3H#LBǐ"P`KpqCN{o-Ƶ6NӴ͆>qwOdBJb'yGM1Bb]
    `ƐeD`�Y`V\VfPG0>>ς)�<Xw;Gv	n:ФQL9@$`kYȽ ,$/J2NI8PXe22a$hF&IJf	%֛7oe_)K5Q"¹@H`NtIPJTCҋeJ&iڋ?LNɇª0u7Q=2s
    $KPU
    7L,̃3z\>oTZ
    E@L9yLLI8"TrU}l%#OT\LESUM3xF�k51eT6#UDU(R`Ռ�f8T0W'ᖁ	*ăsYh/9)yJgLTu0ɉB
    W3bN.-4Fc`}k[{L=?^6e=	W(|(0v-wIfq2?S,9y>]ibb6-A&!E
    UY{ń)dF/Ǫ-򡰪>ddcs 9i5I,x. ,(SLU
    JŦdz$3c�bQ%bvqds̞&IV(j&'|(0.0pdzҗ0BT3~0wn@K^[S|`ʚw&t!&₁<�b6N0o=^^frttrrׇG%=+/f<>g''G	Ώ˃秇}'wSL/f~';eAJ�|t!مP;062ȑNCrlRIYBv )Ӧ:́b)\Wa߈`;lM@؃Nߙ7ήoO쮞+>73guGMbʓ[_w+G%	EG#b_oN
    zE#Tm0n%G;WڰYRi1-RW|0`&e+*' 6n޼bq绿J_TV"qenӈD%,+_e(b~qڵ$+	VC
    qBS\ȆH-'JW
    bɵׯ3yxs	zpPzŅ $#aӲBu%*C+&Aڬ>)�Qq*Ilo=V{huf$Dl24bY	Qlp	a'Iz_Jb
    +.6Zk4	br`9Jh%)W1e<P2ŋ~hWTX\*CS.&8CyDAOQbϒ_Ke.K&moT[q*Uv13PD2b)%Qnb2	[ &34:#TK06x=B#㉉?Xehbkr~T,{GLKÔ.$}uf44P"W3�A̔eQq
    c_`Q!W\v+&v*Cy5M?vȤDS(S|K	AI"+acI"5@<b,P]m~B90$V1Y)]b\evi.oJ;nab*b
    В_<s&!fM8lR\$ A 
    c*d!SYb2 $Ibݮzx鉉0}ּ?S0b,*{<m19r8>b
    B)ɇSY7c!)?]2w@*J:bLvPsJΰ܉soՁ0w<1_H~1q
    oFR&0U�%b|)	䌈~suov;N!Z@w1E#HN#yƲSQ1[*z|l6O\1'<1?i^ՎD<>?/;u18`.j'M`W
    <e<Yـ DIY"vb1+}&|$%RB`r.	\d),\ny/R5!9s%b/fh9DL&U	do%bcϮPݩl
    wh(I@rDlb^]lzXş˝f fyTkO{wttvMUs'˝ K&ZZl|y|:nZOT%lh1O�8\xTh׺?6kG fScl^2<)3:ro	le|QQ0KÙz}.zzcOVڗ/w;N["Јb=FךGzKwΈ@Ƅ.%bbO̻Mr/2Ebi,\v<;d4]bJ
    Reȵ<KF*O@He%bcrbq^k͙UbtBQ{zmKz
    cƊ~*cT)1I脡9YDYL2sU-Bqŋ7*nsi6�Oᩄ8(o{eN>
    H<r*mI-,+FTDOZ1gj`]\Iڬ+[-Q4l!fg.~njDZ1S;,11ӏyNm�op$�FyLAs|WLhf"fa󴉩:'륳*kwŊ)
    ch#p-?rwHQꉩ#	܁K2?[WLZ HIf	adW`$f"n|gC~+`[3,Q`IyS
    Ĝfϣss~ AH",5iNYST	<1у)OnDVK#z?ʆwLS:jcbCN|Ĕb1?NLizs/a&([C,cvIKVL4b.}b*)nOp*!1m?	\qWeM�|H{*B<`
    W ә9~9
    b<.&Ne-nPKD+"=/�&܌.qUAS->p:�b.bR?`fcR:DOR#yAxv̳#fմ)OWCAL4g4f
    ܒ&&#@1{
    1	ejbDZ/KyvU	ALkf^O f Qf|/Y[8P݉1%f.\XX:2bi6^tDfq-c#rpKrI 䶋63@280|0$CodtI<MU1ޮ~~~*:B¶_�RI!{'M9?o&& 1NLLA1?G|bb
    yx;b
    "f
    zfČ_|;SYAD?W'1ySpܹBejm :Dƃw6P!_]:1_|b찘ܡր bnG3=6Z;bV6"Zei
    "&*l3W?w"fb2AiZI^{&^_'O,<%hVWvWL
    )u LͿg	~tALhU <Rӥ1PZu77bfX.hM"f��K/O>%UG
    y=ݼ#15КDL
    Vi
    .ƏON#OP
    e*%c-Bf5ЩDLBH7˂QR;ŴK+&{|⏦Fifjm%/ZQ=}J@oڸbte<.?e1ƈi%C^.拥n1]` Xs|STCL6W¦<?|8:88[
    ;%OTL/O@6cgbs8 &{yp8=@[�6<9&:@{\2<e6 f 
    Cb|~p4?b3!]<.峟|`̎
    ?
    _9 &{ypϏ5+]&'u>4i6kK^-f$3=1y=pqzXqLY&˾Mb~dŤbzyX;W?K^湩EB2t1/M@1^|⧭	#gEMR,|?Ǟ
    욘lxѣǟ킘	;'&fOˌ�?0 n{ev=R;DMkV+xnl>᯽/ByF9ybfӥBʰh/V1U\GL-2ob5χ5>A뒟6,~3@.f5n^̇`b2A#epbx1b*j2Lj(745@ʓRbsXZ@Q`@sllΒzYRTpVW>)'쟘lf/+1!B*=m9Pm(�)&֞plC^c&Q`k1c+.C{t6 .ϠmvQ},fLvآ
    tWX5(b:bLoa4l_zDX%NWQ`xuڑ9Ắߘ=0./br[sEP,Rҵ4J%ƨ%\V�.[Li	ls!=2T=ܮUԑM1߾
    f\5KKe~@�8T1ԭ	8ngLU8KAR9׌D́SEL]
    !Pc[wJǥecr;fZ犘:(f~\55jYnǥecrߘbI5Ĉթ"I|Vr0Tv
    \Cd!ZJ+&[ecrU^16(;*f0B̡S
    1JޔǓUxcvnrQ,GUylpوUL5| Ά`h1SO0I14Kn5<uZSTǮ3YL@"o91saݧ<g饈W.੎&qtD6+h5q1 bXb*H-MX*"DS]�6UC1sTa1&v{1O̿~b8RѪ7;c [xsymL#AIaRP&hP	݁eWd?1xI+j_j)NPc_L�P>n S:n1�ĉlu&dAIBP5HbŔ+y0>2C3&#i(\J
    NS:.gC!fMb
    8V@L}jRB hu3>,?(3huT%�%OX5B 
    h Obm܇VLeBҤJX^$\D	$ #*a2/+"!
    0`nk#`"t%0`-`"tu0�?LDi`Iܕ 4̡\'u9lf
    ҺX{|
    L6i.-`Žˍo&L;s["xPv=0f$.Aؕ՚,usdRY>&L{5qA%ٛ&LVLDuRS]&<c2\.3e\O0c(W3hqvx/Oe!->聁,drSY^[{@JV<8Mb)9Ķ^ϓ_қmkm[/2A-BBr/Ld�TLR쩴Y{Eܳj*`EQ*Eە	+4KV"q	YeT0&Ct1%k/)MĖAB}ZDCDm^Ӯ`8̟`iXb#)XS/R<DL*ype5X3`Ƈ$Iv$alI^=,EH$Enէ5W
    p(ϋ0&Si|0s
    x3`1P:UB4Ff~%Lk^;-d@B	d¶+kHtNv(@0K7j.?Lc($~d95cqǵ&ּC#\CSq®`H�鑩4acV:r	P+9n=$kE0q	33׬	fZ2ʁL[ܙ9O{w@C6;Ϙz(0	4%5[k]2zIЄ9^V^=LkciͦL18LpC
    IB&jDqǫ_ʆ,QD=B_a-IXJԡ,cVʷWI^'X=lR,{Đ&d?bg?'HS(ʦD
    z&RsrkS7fuSj`վd-0׌N0Qv)f_&p9:P7(p
    &t~+[=`bh`'tiĒkɟ&ëm\ZZ\SF4CO/l0=kHܰcUN&/QRyy7DSs咦qd-.X%?Rt,ԕX`6L~
    f?k-+^	Á߽awGYZ3JYke_"lqr?3_ET/^T(w`qk. wf'7
    o1j~Z~EJɟ†[
    /`V|_ZU\Fi5I0fu05\-yng<lmD]`rnt	i@<sX.q3&VK
    3-˟wzxn0Asptn;d]y[	wyV$@e|~nb%ol^v
    ǫu`8M,[s?_:L4.G24$蚕ZH?px!|l׾V-eU0�{!nQ=wP)h[pХ.%!u`_],<0�3Vyro`Զ/$tT2L70L҄Im[?oH_jcwFE0rw	TbKc0	N|>۲4zpX
    LŒ隤'r`2I>^0!qZ�´Sa2̂`TMjLA3(a]
    �l2ଈ%Lf2,4Lo�M;zIŸu|0>M@}Wtȉh L\Xʊw</
    ';1aMLD!L�8`w]c҆xk@ٰ-;8r$%D#=KAS\'!=REFقw=�*rYaf*SRֈd~15w}03P5̗5&nɛu7LV]1tASm20u.0RmhBsFLCt6pu<	dRke!>Af6L\s4I>!D*0ehR|a'}Ϧcń�hM %YVḒZoXq*@s`bkkScR0huz=zK\bBLQ!ݐ5.8E.`nlҰ|3^!0aG	&&yL`J;	>F/{,#Xچ"&H7EXǂZ"+&sZ7xzӠz=Qi9=U&&=4Qi4d/
    >8(uAJUw[`D8F
    $^)k[	fp&V"'45H-ͻ虎pemqCEXx$G:֐ĹtQפMwC1ãGcc`uu{g
    `PNVKY}|.&4:"c3Ku.8o%j+o
    N>fEqO$PQ)ސ1G~p0G FeF$Rī>>xhҬPd\hM C;|ݒZO+
    wp0KZ"he~<=1Y{Dm
    9y،x4|T}bDp[fD"EL^0f	bsh.hPƖKYMzdpQv
    ]qg9=KYOi""?cǃQɏAưЈx
    Y;:Diq_>,$qtMY6|DZVd0&r{oKyGQ-	&e0o`=9f_Ul05r)K1'=0
    cRd0Ĩ$4FSLfš/~
    Lk&,ngc4#r<9IBCJQC;?tGb cɎQ	0ňЈxuZ[Vo_V~%--ZB_%"Ǩg<y%rfRWJ)G#)Vf6
    /0L۲:(;Lg:r{̘pF'/Q1@dĨ$rD,1"BY+H*qu`LYԝSD}s5V`7jY`ZY`VV`V`Zk+jL@i]jLvhn7uX
    ZΆ~wp`R4%EoBIh+sL^s1M8�qzl3[$3D]I:˺*Ψ=&Rx``Ο!zJ0>|fs=TTh7T
    ޕ,aCPx8c*J,yͣSv>F0!fqx0ۻ]ڇ"Z-.XLWS``z"Mk.w>5	gb&f,
    Sv>yZ D(ˢPڋѬuY/k61gOg2JS,KrʬRSr>y!Ύ	^Wvp0;{]';EL\1ݟL,38oߠ+(e53>7I
    S(9>e %JNhkiT?A]
    bcM޿zqM6,*dAU)Q0J(
     #K{i>0D\\`ڋֵC?&#Vk~S"UF 9")JMJ#P>1Q1QO-`ge`~xLeQ!M>5|aDP.QvLL.|W'AD~%ڋĖT5ٸU"e2V6ȏpLMԸzw"T	*w]/N8,*ԓJ>(.ELP(iwDǿZZAL.;%FQMĵU\(kbmmX(f9W7ȏpL"}"D;9–.fo_%i޷VJLONm:g
    Y7UL
    ev	0}6^If.^	7-,	9!kIuDD0iL`&Ɉ-9هI7f߽J`5]07]DQ|l&c:L$Pva0CCMO,&ߘ^fKZX^!7`>2W+Ӗ]&s\s^?6q0ed]ڏWhZY$]2=5B,
    &.'RwcEDyWڋY6t/Xָ&FG&owA6Xe09.->`\LT
    |sCd.^ʮ?]W�'Րg'R6 Vvc.fP%R:dϘd~A]`bdDV	Մ%0BahAs]mh_Vʫ9դjja7!`3JYMo@{ʉĘ\0ouaa*``&2}",2?;*xo޼HBhǔ 
    vH3Z30rV[̫`Bg1$.
    f91E?OU
    fm:lzfC1*D+A*/W`&|]іs쑂ՎO}VӿJT`mmܖԮyV\U0U0+vg7
    fr۷ϗ#Y\^+ϋe8U0+h?J0ew/a߅c
    fz?pX`ߘˀAksK~yj0+w?2;=f09QMj"G^ې3t'`45K_驗̻r*`JBD)"PאP'WDT1*4͋\D,V<uۼons`J(BH�PMa79FU XӤR.2/ߟ<V1ܪʂ˓cSJ6eB@hj>p@.n
    $kك5<Ƭ`F,ퟷSM^L.6E) e	0X|2]$./ޭ
    6!|:[4fKDO&1]3'.+
    Fo2PKvT)qp)+UG20*4M!7̟׳`n6aÁ#u?aVJD烉8GŚ&Ɛy.+;$w%sS3=kIYV5`B?=v3qѠRâ|0181*4M!?Nەc+;.>ofE%x҉
    %Wb1H"  ! 8ȐN-�j"w
    CĨ418kyNRܲtsf�ޤZ& Sl5A@B10 ?'`n-ϟnΆ	(Ȫw;/+DiyAV7Dh/js0NX>ysvVDץkKP#O
    pC\WE
    NXӖϿ|""؞$X)S|&V<=γ&[Yz_3Kex=tli()/eY <ij77oo?4deY!Vzօn4y(<0U0],R^HS,+Am
    <.!BV<qgg&#DdYV(x�7Ysw"Py`VKY+*_VO~dU0تU0ss9YZUɫ`V`V0�	6YaؘS
    =G6D#ck}Z͏J5jU`f�s!#XdVĘSW+OP!씛f3uUW
    &T`CLP?jҏӨM{DIeU0AU/GYn)1Fp$0q_328,R%
    i/8	DuAK&;Ds@ײ|^iq]s
    lO>'9tHiXwCҰuR2m=EhW<�L�&Pu C09| 4ظݮckǂaC`O槿tNrr)[V2cS=,`R#DvfQA9kY>"u;IS5&!?*>[m<7O.Cگ1
    a%:L)$\`
    (/p񆲨^oe&# 15ٝk˃a#`̏FEȾD3
    b niXcJ92%0ÁY\!A(/PJ"Cq)C2_&!gKF90tl=65l fWHb`"$01t|ēk3h0L4bJ++o̺bv9M>.A#Y&^KYkY>zl)+ـ0{!:79Bٓj,
    11%~cvJul)[{�\!A(/ab:M]K?
    y(^ː"Ha,]wee+
    	ByaL#`kI>B>.l7~ZңFE2]d14,SAΟr߲/)8bbV+e ċ#/H6&1&ңMF"dL?g@\;+7ck;9V0S̞⥡v)G	fT[[5d纪nCQY7
    >vn$0=S)CXS>?�:36T
    !ư1wb"7gp5l@ ڳ\`\"f԰{~|c~uL0&`L0&`L`L`L`L111٢ދ}lܫ8عcb=`/T
    st!kUd("%?80P-I(2hJȈaNMxJ!!YBx4M[UMO)2\4SBf\G~PmxN!0n#ޢ}ZCKP	OZ<$lN$RaweNbeqi.34[IM'TM\M_mӟ&?a^?,_~0Lia&!t89i&ﶟD|C.[Ȝd$3\>C�s9=`,Lե5@ǓAS]!rc$K&a=qI<u|6Sx*X`"RuoF"=^i6iC¼svs˪L΄i.0oNS"RL$P0|~}Gi
    sm	/MQPB�JL9lHäsÌh4a�sxq�"�5´YݜdJlG{tV̓X>ra=RQƵ5ƥdFWOIX">j$+
    S
    EOi|y,@ՉZqHҹd^巰Jd#6ps`9i#OFԾ$UGP]aꍤf3֖%Bܾ@~kQ˰.
    `ّ̲,+K6o_Z4̪/1
    L"'�Sb)Gnz2WxDqlJ҂Kˤ_$l^2Aл.H:&23B	t3Ӭ6Nq@/z,0 TSp*cq&E*/ĵou,[D1s+~/$
    z
    `2a,LRtneW&X+6sf�n!G*t}Sy#ne;ËO<yRϟ.´YBBz
    6w|_E&K$͗0rd&̻0
    K
    `[Ys̤p؂P=F%V|ÔX$w´-:niy-ivIksW\"ftK|�L=!\sR	p&1r#F
    s"tZD4îf&f,T[0kRim	W~r5/Gu쁮lzY%tʼnU5+K(3璵<#0OVykN=P;?_cRL.}l`oY[cĞ<a#D&0ʣ%v@2f
    LW(>Ar�vg,$U%aCG$>&ÿ0ppTrRIyI*GiK.vÌ8Ζ{4r')dw^30[c"cBSt_ds_m10ḙ3_\O3=U0P�"
    =4<R[C%A_b6Zb]sVpǬ>G$Ɍ1~c>iERsRÄyKKcj1g5Uw6QMx:5PA׬ 05$k;wZxG}㴖q_͛g/\tI%I}5;:L@0A0A0A0a0ag\!��@EBe#�wLl,tL��0ҐP(¡C%cqc�@Ͷ��0/
    [{zGCMTImU 8[����IENDB`�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/win-install-2-destination-directory.png���������������������0000644�0000000�0000000�00000032754�11773544727�025502� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������|��PLTE���333�}�<tL}A.)F+6[$*P<-dD<vV4___|s]eedqodspgyyw�����%�(
    1	:���%�(�:	@'M"T?o?q;u9{U�H�YRj3fCh@nLuW|L|U}nvM}��3�33_Rbfifv}fkhhf}i~|}f̙f&5*03D(K0zZ*�;/�6=;CF$J&R.S2CKPM$T(Y7b:_@fGnRsY|bWvZoXʹmjr{8?�fwKHPsjvWgwրőʒ՗˖ԉ䍶▶蛽ԬƠױȶڪ̩۸˶ަź½̙˗ǷЬѼӑމߔڤܶ#zEf�U+17�Jr=�C�c�4Ćt��2IDATx^90CQWPp2yVߚ9dXJ3\D;c>%;Z\jGGz<WGG4$o@(C0C;)
    (+\[@mY�&|MX
    ʃl%PbRƺ-ü$ꀠΎ8q^Mㅸw\+]@%h`8%)oa8hRI",ZX۬S$X;d9Hw.[|4;l_LO.8Q2oCj)7ǣ8ޱss2Yg
    <uVI5LoY8RAu3̍yk<u%zKKsJ
    07-h>&pz4\F|̍8F	q]|q|.o)s s"A�8wךPow�ry4d޶Lg%b m"힁Y.c8:fMs:$90I6O\&'	vh۬%c.^�$y6g6B^(13}^!<,uīmQGȩQ|e	L7z7|˘|S|Ӝ`4<T,�k1s9-^}&2oHs82Ks/s^BY<y/PxD0RPŸU3B6b2ݡ$['{ nB,BR	;Xsr�6v%M:6ZA*gW'T̃amb>E@{.8/rGP N[Rq~G0:\n[@:8u$<^@vy/�)e]Q�vhv192KLE@|CDao>9Wy(
    <ٵ{(ef1ׄP؀' F1+/
    XÁ<.t6a�	:]8]8<ۦ:ArI;tMA3
    a
    ħTllC^۰MsMxs;]ovR0dy99ld>́/
    7J|S-bl2:bf[jh}s?X:8&Fw
    |{`^rkXf,gLxfbM3f3W!xt2V٨9�-L(J\%2x^pq"oyP\`I/vTk2V.רzJA˜}!Alq2_hoI}ђqEE/Ć|)]'{t �o�GrkN	4{YV֛Kh�iH[ĨbR0�{S=n@I\H)tfd^,Bk߾m?\mǧ:?x}~|}Wlo{w1ofd53dO̸4oɀI[l:s<mWn[雧d=o|5gwMf=ZC*Ӽ=>$=F[Dq3t:kQ2@n7Q՚y"$`(yi%X?]pqlA
    ꃸ^żTmyy=OsGVxy"QF>yߜjO)vZ#̃|o5O}>zBc:iι
    aXg9C99^fQ$!fV=,KvB*Y3WUWyu{2o*\euưf�|~<cƼ
    :C79th!rDXt!fQ.ذI><v9\2u8Nीg}DESo0>poe;3CDNog4|pbppR|	/2FgtāR̛> yrS2?~Ebn6c%,Jw~˘c]ө)nzSc.egέװFn8q gl9=f3ga�P_yj_<lQ)'Pq#Z\9|weq.-0Ȅ%zDM'slq|8ũq8U|>R>YÇ%o{c.tN`(<Qt(,#E)*D(kuC;w4[ :sy:
    n#+r]Vތa)dsDw-;>vC9o%2A=810nļ2率22߬$3E֣s,ΙH߉s+s<lIBB	"ye2]N|y4`!,;¼2\+Jm.ӀBWe!snxk	+Cˇenmd#sC^Dlӊ}ka6\;Z�;K9mm.f6ⶁ
    *sm�y'9ClFpTxygypt$&xj^Ќa*Ⱦ&X)jʮ�xCd?bi*	yH3
    y*gO&s׿QJtBWEvFe^Hw"m+@k݊yeν
    a�!AH&1HF]H�Wn|�ǯY
    Ad,`ƄC|I>/UM]pkra~ީj!_W|lOg12y7%c9[CUĻ5ϗVg_m[Se|5˭l
    ?~Gy
    ęD|W
    ɿ?L+y܈=ioqw-60W<AhZ-5㫭|>	'p]Y|-r3püDu
    p琏EBN u%Eüje۴|p{a4urAVx[eXΐaάWU!"~ˉ}54Bnt5*pFa3{[ʚ*6ۦi[/꓉+WK	j<dOzZ[ҫ;ʶ{zo??.za8/.,szq%'t|.7W!eRη7sO^(SgnrrÖ%u5IA
    y!QY4'?"\qe;NaN&&f;ǁ˞a?{C t_)hD`d֣"㖭rBxpHR\o寬6}꼙-\	yռ
    u)`u޽LG
    V/jԠ#a,r/͍Z嚛]/%17_H(+~=q-@e.JeffCO(Y#F>ki"xonaĜ[>W1?_0:zy&\VbU2G}d6IyĆ4X=أF԰w|Wtp"G$zi9e
    a1%3L2"<]2ޜ9NZk0H ~Yosl&sb=2w0 Zg9GmDΆ[�a=?
    X2_9q܌1 Ƴu>/DJyoea9-:>ΖJL`~\ֽ3y2eNn7h7j@]55Yygb*Y̳aDHL2!J(B!sa9t#zDRKQʩ7Gu _aȿY�zG^$gA^?y3Ww oHxfn[x40owryg1o>U%y{&f/滢fQ̛y]ͼy?Pͼ�mعܴ(�#T@�wQAl*Vł+q*Rd"x
    Q]T!QXɶz
    O31d1!.3Tk
    Ç0qxQjϽitng^t>5Ax|tncӾμYiC?~l7)zYCsb>6`R7oz/͹\&M,p]=]yӋ~Üru�2_)bay7K[61QWsad.DqnnOGCQ
    �N[|2c(_ܻSw5i>hCgQy`\`�^tϣe1b z~/2as"ss r5r-7d.8RigL3't$gs	)D$&s;-sYMjF�a.9Bc52GtͥnN'.�0Z/9fs1L~IS<LGzk?.{)ܹ-9ǏEK'òfs	Ǫ9�.+ɛs�sn6 
    VGsR-,1i2ߤess(Ƽ*yk
    zsoF@M&dNe%S;UMVK5jsNl89L�1摃yΫɻs7O-?ͷ/<ъ\Y5w2"{Ig&sdԯdOM,=挛.^_LFg <-\IsA6vWsŐcCN1׋c@~}ӹM
    0` +n^$n%[5c^"
    n6ʼJy˟=
    xOhd|#CK{佧᧴1▹.AHN%|c>ӥק9
    n,s(Ϗpw}\rX0=h&߿̣9z=ٻ' >A4xDăod.3&9ɾClhP%'1;KM1J]=LdK}!1ClgB9m0
    bCݘW>U317U>7vZWb2zO<79gqCn9oȭuL/
    ə#9|;7[z
    ̈́{=?heܕ6F6Wsu o0|6'Mgru&oҙ 7}l?c-Pr/a,[1;Zlr`'cDs59oK,sgqAgNdg]a!4MBhjrHs7|\ϻtg
    @can}zH\ͯAh)2CnnjMcQJD:˜{r4c\8(򜫹^~z"%щ0VCNx\1܁YA<(e& '?_v#%ApFߺ G E@]>%\zCd򰙈hGGLEts5u; RNk NFϹyw\d;ukqGɨy+y|Zqg\k_D7Wn)ȼ|U5:;"xg2j|ⴭBLYp1WZהgjN>x#Z[Mbȭ9o^7W|]\\Isb"UH4\1lUlq&~!;:Ssc\D֋^*8πx@HR0+'P"z)0-
    -zI%{>,z8CmW|ݙm;P9sBP^ԍj<霽D?->OщDzn^&#"^J>[
    0:91țo!Hr
    Ͷ6pRiK{[3<ǒ7'$yK$k~Ѯf޻{5-N0y=Kmϩߪwͩ!_07#~%:Ys_ɩBժo}rĂ;Y}NJA>^GAܤfͩAtyۨRd9bF?2za/tc1_|.'̍zQ"rt99kE&9:nkw;͹򕼆BŜ|A澆CMϺ`ϝ[8M?i0u}3*7s7wS"2RܵjW37ws\D
    O7:37o~LN5ׅ~.ټd*h_66wLL0Ez{dLbWc ;enN[4DWwfɗ9@_'](]09\Q8&p~D>mE:Mh"\-.O!UUךG,uV҈ѣ> 89EU'V%ϬIF1sH͑_ثk"n<f@<7:Bq2HcxO@:X?<d
    cqPɦTr\%S yqԻ≼siЁ9#"~:ɵ9Jiܦ͑m+$yy+rPVrseO@0T1dM䂌Y)곗ҝÂCe"
    I?53sBx!Wqa̽fӀ͑\vSyWn}iyd:^ܟ-BMGamQ0ž/3%vu,N`
    1@25>7T]ؕo2>ݬ�1ȉ\	9RӻyZRq|GɭJelUG#›69bלgh;@'Ó!P"䈕UtDz2ed9?EPc�}g?ws]PT֩m/,n:h]`jmjHnNj
    q)-与%I<ߒg2E7'FbIuVMs">1)qs?ov%*tZ]г6vZ-k }
    kS|ZX#5wMf=
    P�!E4
    !!NL蓔0H_;45�
    x\[5²M=׼KÆgnB۸+@k2˜Z|"ir|=@#s)܋JGy;`ނE$ǘVw(-
    I-׻}3Rx-5֛J,	{5Gy2'9Lq%-Z۠5ݥ$2`!g9_wQʸVyđ -˼Ѧã-ԗ>q{yni}؜8
    bWHyZ"=s
    ~_Ar?\Vu\!WuxWw<]XC`W24ʋ?zA6�瘗9D֏l|Ê_|| {~m.-󱮖d^Vvlτ%!UWݥ ׼KrB):gBGv	%-ռcd>n >ͫ^g%Fww~1iqsu|s
    #sMI85oYK	N�U8g><쨳j؍m^(NH!CWVݥt3A02!N[q?O6/sg-%g39ٹf''m͏9cȓͫ"b|'fE4O6g8Oc~{OȼWH>IrrƸDK0/!SP߇Sp.ż]x!o}þj=&WEtˋnR~:il6i}Wjd/"ż:0Y.ѩ<h[q
    O`sw<#
    doL;.he^wb(,޼6{,xI,͂NJ8
    k$LER%8㛜IGT)q姿N�D́<"k�P}f׫yuCs3i#OGr=_9_#L
    y|1=]�ڏ?g+s=]-|jus3:2|yjrkms3w	:tGv1s\99T<Gqyx[P`nϫ!H
    򇙵\c!y-Y0HdsqDط67s-!vS<uͮYD;}f"=6KsreşB['Z		Yi9N9Ļ]v1&#ExqYM!^z]0ގH3^,R59A{$ϓ7I'Bp" %g>@3!،9BqWdn߷{IGD+':DSȻ}/`ne9J`z%yWGܫXrCT4r2<fnLx[/eHg91{&ԌGWcnv.Wͻhgo@WcnNH81ލtv=RZrfp
    e:Vo=<F\Qi0昳Kg/ɫ45rK@:xD4n՚9ę$?OG0ż^40ӏDa%|F5}Cysbr)4{=+N{1~?H,ܪ}ԇ}'ͭf:'I#1ob^CK)1Lnhw rC;=#GfpMӔ}Ź-pא3IÎv6^]Br9)1uC;/ɿѹyj;1.3*zϒ6f07sr;U{y[{s 2 井
    |7涎n/Ծ~Kg9}z,JK	-=I&m]s͜8C >!?wR՚91\*ǂ?Qt;Xm#�Ogpcrn&zfLZ7΁:{.Vn:ư̐Ǭھڃy A:*C^j9mY:k,μZ=73"BZ:bpB^ےbG1_"ټ#�:E䣭N
    jڔ-`t2H~=WYDy6o\Da_�oGEϿLܬU~gܺA<Pb.ɏ]eS0T^gs)F꼡�,Ωzsl1_�;MzkRC]SbN<5Yedoo͓OD<i,v[J0쒈{0战430<v']]%0?|OC
    M@.]8s<02ۓ�:C1p9tU�M%3wE2'=aNG9_8lN��mt
    ܓQ@2
    ÷a{:>4_<vt(չ/mI{]2^l<x'F
    \4TeGOM4T%[նhipm_59\q+yVU<"3;9+>%sڧoy4gsn<>%OlU<߻dd-.?1@`/F<>^'x=: �2즛İar?j[!]0o7星'Ksn9/?waV^ȵ/uAP7An�7E80V*P<_m̩	9wwȕ1Crַ-5w,9w+]3sA81ڞqď..0O|(9vҫ�nnpuѷ^K0`7vxGLZp�44<31wSo~0ξB:@O:j)86mohGs#\L,0z|r+S}3K;%Iy.e.Ul?p̯`,9mͽ5=瓃ܛCk{,78=Ǚ1퀟pU$e7ӚnaV0�D|=޴ī 
    q\1ųNb71	BhMx9APh;Ke2y\@F݂~;w<�{/gZ2	k5H�<lsֹj]sFlṃlıG}̥	Jl͋Y94	|\	ͽjY~Ȯ{g$̑hY`]\m1WkNjͽ=`\gzgfTr |Ĭ+kX vgY
    ~uDɴ:HC(󀹭ʫ4&\Ù3.0>h+h!C5*t2 ꧇<! Lj0`^ޥRi!fHly0(ߓdl>LʎqN).ɼI7;w:EQJ50`?YFB0YKYY@O<~2	,Or(	h-v\קN+j
    `Rm@lX̦sAj !CΊmK^zyO
    Oqye֢^Y~|X7Kqᢸ^):؜F7FC =HKs|l{`Z~>JC~y{JcSjZќK_:7If1OE٫/�0\M/GsK lnz@=P| owbm+oS$Ќo͹o�\@vb^r0٢=ac-js7Wu?4A[Gs.K'܂#jMh^wfn֝]Az)W\7\܏iiX.yqsw<o0	2.o)<[Jqn~~s?"Aݼ='m}%s<o}Gz<sgk5}{XݰeRnsq7{�)Q2y/f>ǚoY|c1JMr/-_7rzq}85NP�\[m'Ȼ<p\i85.@4ߒZY7Hz=ziˀ:l�8v'QM0.@4ߧUh=e6VVTCbݎ,VEl6M	0IxZB+m`$G=ܯ4[4WnFݛď:G8C؃y/qWhw^;im|hn2ko<C.9'.dbr�ĜKf<wrZՃ<#Q̣<cEh7tL���
    
    E"*^NDl&!,أw�a̀CxOAh(I(+-7,sb.b.b.b.#sEf̣ɪnv혵m XC5[)JFh6
    סOkZY2zIUWrkdcdyBNXpW֔@5de!nmżj̼(&<b>rT9d[>$ńR	�I͑*Vs17IQ]&1sb^4skSSm6Q7s1.7U7JQ`Uu.Xs1H+z=l{8\cQxN?ChW!󐴩;\puG*jގ{{8kӹPslk<>f\usKHuߡePP	-{ż!
    's
    }7rI#CYWcsqg9e\9P=砂{;?w[`{|owiޞ1sז"#}+z{s5561'b[j2|jC<ͧ[FoO4w)<3}B>4_|jqU˳QԸ&>C]pVK\{tL��߇v`o=g~s89qsoj��a�VCׄomD\{eZ,`1vEUc1����IENDB`��������������������diveintopython3-20110517-77958af.orig/i/mac-install-6-custom-install.png����������������������������0000644�0000000�0000000�00000040247�11773544727�024100� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR��n�����1:��PLTE'%4...1P8e$9N1=rDt0CX0NnSXZ/](*[=&j
    gtn!c2
    e6s$r:t=e(%r-/r.0~57TA3zByG"JJJGYnLcyxTUzgXeeehltnpwwkbwww;O$[$V/c4kr:zGIHoJxo{hkA~?8XshOY\j`rp!.8(*:135'(IS2p4NS"_5Z#_8l.k9`:q=HJ]SDFUNWXhMrcrqWXuJrm')01?@p1|Hz{dfQQpp/\{yjvgyMdNl͝dž6Ѱѵ(9(̎QeԋiݕiݜyǴQdzfĺuԵzGcL[DUT]ov*,1/2-3(7<FlFYKTGVHWoQsҍ䥵ƚָ֚֜̀Ǫľʽݢ̺ýѸňȖljʗуЕɥ̨̱ѭӹ܅ڲ÷!\7S��=eIDATx^� Ao_g8k2AU_v��a 57\]03RʈԔgY	�:0C& b J\PR*a]8U!&M;f AF-RfYn	j.y;F<	Y.EXf<TP."Ņ&1^nc]ZzP9,tTʧհdʘLH0z}w~BaͤOWS3LX2oاQjfs˗X
    ›F?xVz(e5bP/sw笘q&8{otw߲u^]
    <#T0.>QnqnY ^!P\͚m^n5S_%c|"puxtOx*7
    >V67O*>d~Ηbllo76ZDTrzlmj=
    T
    N
    "'
    ܄{ybA!\ޱ1k@7.5h&!NR&.qh AR4CSk;LnyCHC>C|>*ω~g<~ЕܰO??PȑÄ"BmoLAD�->ݧ;,q{f6M\ɖ[[nuC+6L>H@�
    7HQ(¶~NC r8II+B]-}Ul7_:b-;=Թ0JE[^"
    _4	[.skłM"}ylYoǾdp=N;s3vb֋!n~2"S[qx&ڞїLYo`.`^vNo
    X*Ϭ6(]qZ[
    M]Wv3Jz797pHyҤ"ҍBb�T
    ]iC.0Ca:wtlq]Cx\,o]ɳ>B%"!tS@qGDuCS `D\/*6RN2&h&4FYޡX?P{iMl;Ƙ*"mEdҀ?İ,*@Y9Ǖ#OeF>1���0'-XO$ح7b 
    
    Ejn:WUi8LH҄1mUZ|XTknYr˲%,KnYr˒[T[ܲ,e-KnY"PtV~kiymN+Voo6߬.8e|xŁ
    _֡Z�lrS]7E-Xxue$|Ծm@[0�_Nݴ'
    Yg5B\7̩qY\eV	.Q�l 	)NnnkqSv8ԇzr;iG\u(aj.LsP!x@uך+XT>rSH3BmZzz\zs[Mg.u7\藣#74nFpٱ!y嶗qnS*t<um�Oq(Cj&LP7n^`
    57nRJ5)eu<{m>rAnnlYnNh}6@a7q}]\/p3'
    *WL�mojs]r�ۨl&P6P6KD3zLm
    /pۛv�a
    Ы@{nH1*@U+�ܢWMmn{`r;{>a=}Jq}_=0ee-KnYܲe-KnYr˲]:( (zZbr_SP(BF�.l�}aeiCK76"Mnuk!;u0Ca Et1|.Y3hYr,SPBC
    -Aɿx{?׊59ѫgxuےC7[M)4E#7l黩]U
    ݆sFnAܔٸM"K# ē2F+@PQA7I
    HOlpl0GpKt bR?BEJ6%*uI~q'^N	ko"¯W}Fe"$mF+I#/%'6iw9�iQ6Rs'^vvQ+	/&hԭoV5H+`<6NYuZ�)ZPbbSVī�kX
    qs?Z9/N@l-*{>ShH-NY)%Ύp/n.7n:6qK
    *V@yfX?8Upkc"6nwq;s�㙂q+('#�
    }p+)HN-AOXb\O?q{&^M7\'a\~|񅸍͸;m#G�\X`߂s8Z{pL/\2r+ yTV2H-Hf
    	"Ëexv/ei?_|xrJYd~uX,3mf:s픙")o_7?'sfn(|̙l|̙fsV~XV;Ew3sC6!`e/#sT
    )bǞ
    ɛC^,RٲMYQ&rk=g-ù@eaac/[ٷR)jFD8@2%$c+0+
    MтMHI)s4kHn58ڹY}:n)$aα/2ȖBC9xJ:ƍq)Q!ұP|
    'p"徭n
    cAe#f#aiYU[XX+т}O-	Fa$\+|99FI9
    s,
    1QiG*JrAvopc!*s,{(LqC�qs+]jAVb3byu,r̘mL)ƭ~diCԍ&sn1$=
    7̨ïR:?X*m6bHr! Ķh2^4ܸf-n&΄tVnżSj7Slef7>oSY6Ȟ[1AM+]2-3[qx
    #[ꐈK_E]�apn|HHH fj(UNq0Z7Ǹy7_WπKJ[DqH+O01i[܊d@QW3TR0Cg67hܒD*;l)síf`2qOM)5$`0{l&w䦐&nrndV{Tp۴vDsS�t&*Zns9č+">nhqABa^cٌ=9b"2B CQHs10fNܸh-zr~4%km
    ͝&/ 25GS>Ī]JUP,�]b  31չ9L#r*nC<3Sܙ>P;&}�Fdsɸ6sj=;&NWf꼼r7.QtwwTmμ�Wr\^nnn׃<grH<g|F[WWrZkY}ryX,..^߬Tq�:}O=ޙC^}hv^:gl\~^nϖ_3s^5i|Ha`{-n?y
    .]z5o翚ws5޽_6j#Y߾^6X-928<
    <&MNx'
    |@p5KPVzjo&rPnW=C՛Ǐo^	{ranCɇ
    XM%>jޓGozl>}<<>]^>7_no!͟PUr%or2BjܒmĒb,\D}rvbxO{5.ߣ=Bm؎n7op̀pVA֔24L1V%8Aq;)P>Ly+翚w?=mt?;g㶭IN6h)؃
    DH[AW}/O6"Et8#k[ma/,MEHmoMo:a:]*fe\*>ܜb+,ş{q,LHV;˶a)ۼ+m\S80^T}I6eYX 	]qS[2sDkkA.ր)ʌ*ߦ;6Ō4nK|N٭H@7UQM1cmETδF�,&Xynym=:l7\uģ
    mZa,o-6Rz_6L7ZP7,<97v�wYPApk?(Et)1QmT6[6f}:6oJ@){�wvwVZ|$ܺ|.Oq_,Rb͛2杧�vf%N[i*&˂4@GI⒓pi9qښ}Ќ�:.n	)2|fVrjYc6Ss5[lhJiڙ9Z?1"轿Yef95ZAm;3uR9w1W
    mTߪB�vm�#
    r9ԖⅪ;ТVaB|01/է
    VrRV{m	cHehk;9@yrv5M-|y3{mͶl|N'h<n0a]S交B+bosжfŠRUW7�]Μp]{qgp_	,6#&Dm^gSyf>Uܝ*B2ogN3ngJ޷|ky^4C~tRB*N|̇>97IOe'etmmkv.;.}RHݳŽvBm]GJVW\7}4l^xcT'NVa펢ʔ=뉸ۼ	kl%]u+[Tv#v"&AUn;)Bv[8�;x7=wۻ=}׿	ܘ;a-u:ȭ#rӄvlfQg|I	j46t{MiټI	kyOۼC:"n-b%D]-^c{FgAyBl-NjoSy+JpC$}5mq,pGy6=n5*)펨=n6KQ2-CI71�͛$qp+n=26oNrJnVlZݢ7znt[�wD1}8e&Wb{g6qdjNž+M~\%~CI	7E˲#bTFC}gH09mvHad5CHJIonk)BUYkqwo-="znz>#73&1VMSCjݼo8Pa5%Ϛ滺y�BRy36q^K}-tKH g9ybYB2ȭ6CP(hݼJ[`]Uwͫt[W[?mdp]V7ilp-jdPI}،[8=a(#Gѐ͸up+Y
    g3,kQhmupc"$7(0e<KآR;lƭsvj}g/LR9b`9p{<}n<nJڜ$U$QM_tF{nN'<y3M,pr_k{F8ĭ{ͫZ9fq0VXV�׎ێn^58`c޵yux/hh=iͨD,Ogwrx?ߣ_l0Zg	\+nn^k(MӸ<ڼ2R
    QX'*y-OVץ57`msuQL)ݾZ>Yu&[ˆS:`Lgd}~vZ$;}sAޚӗ|Fy5̚Ď϶6/[SX56o3/lO_*_Snjxk!5ݼlX g2m4p#H"r-ƥ7M}v(Ϛiϲ6/N">Dy]Zs7w`d 2l	 7mG7'<0X7mNd+zF8ܜO4<+O9nL~y(M!nnVOUץ5oncn<FcQq{25[spF[p-I P
    :2nϳ62y+Mj6ӚQ.'2l+܊4=ZugVm�*nhBE;r.5&?ڼl+4ƚ"?UmfZ3)%843^;䔺*
    뼝٭u0&mq˅]3@iQm,Íf%#gX7rm\Plo{Ӛv]iwcU,9m un
    7ŭ qF:n�@PZ+AdugSUxbϱ6e"r߬*Қe5=�*5EY[WmלHU.kӘ_1֎^n^1grzAvH[R[[IŭS[[۟?Snup{RT07n׹m
    /<cfhSV#9	yK):*nc!5_-Msjءd˫HSˑ'UXa(luoM6Vp^]sY%')\lM%ϊۗeZ,mG-馦bQsU9Jp3+"+=	xB2`Z.Mv˶Yvr_?+nFJuǙ<+,Yx1jºfJߒD/+q69[2GE-u<Q_sk	C~^ypkx1]g{BͦϺfIθe$SyrS	3S'yCg99+6ܴ*	7RZnYVIøY߮Í
    6U}UdVFc%PvZ:/?1x`�fOp_nm1[8¡Wi1Mn)sn|IA:ܬof
    6پᙥ7r!GniuJMMfیq?i |ڂq%MLHrsH
    �MF0|nipc%^:w1e=7TzEb攢[rVDܴI-ůRYvH&,T}4dmy107@c]Sne܆0L56\W:w17uodMv˶YB}_�7
    'YFeiױ
    n,)6!4N|?pr"bxy|}|
    @?cʻ>zLWLzoJ܂>\RFW�d9ǚUtn
    7_x>g1T\k
    6[x}ftY3QN%MyN4̚N0?A䆸vރ1~\o~^BoXn
    7#ng†3ڇFE8t'l:W^ۈH'Ξ&!ąp#Jw0[
    #�>,n|FaƼ�@BQ8�-3׬g;v	Cl$85 �zq3o�%q*9RP@U4h*^L+
    nђoDn܄,n}m&Q=G8p0P̄6 u50
    {Пг[O˻錢ِpOᒞԐ4p<bܸpA] T+Bڮ$qĠpt@ٙ]w6gh�Q.`dp8MJ7O
    e3u8ׅ֜[5x"(hQ^vU#ZM*nM*5a-ğ
    k­ӚkֶSҗܾ;7oua&R}wbZ핧Rrr;72\'AA+hUYS0;yzyzܼhgFtmEŸy᱋R;nHpN[uOnN?=l^ynؐ,D0-8{s!B-ub\;޹y)Z'Q!1/nn^/s$,CmCoGdQdT>C|mܿnPn⮫+DG<Y=74VaM⶛jD_	m8T 4W[VՠuD~:7[KG
    &ryĺʠUDž-Mnq+tU7]JKݏ[u4i*VE!oa͊65EOfMܴ"�4Q73@C}p
    ֹyN+
    ɡ6EBf$[HBҜM0[A07{,:74'ȚKy/ڠ	A<aBٙb{n4YܸAunG&p
    Pю4CMd/@(&qU-4>hF07<.Mz-2\~qg|2(Ϳד'v\}J/ƚG7݁οv߸׍Tmޮ|9L]q7j[D[rMpq6uv3p,qۃɮ_%Pjk'4氘,6>+ͥ>mW߽>b2he۔[G=/g)pDTN\is~]rKJ9MSI&Fny\JnF)3(T)5RT)ڤQnj^n#ؘ+]n9#Eiމ
    ۬$_iA&ݡT(2`8 mx^S	EC[0_ؾؤr`bI-JZ"]}n,7$bxUDNjrq^~sk7!L,{n%8f=7i1:T)-7mBܴn
    Mܸ{a"^=5#7NXn!Ѽp3<p&#
    }PŶzn}5T`tYz9-@M@RS=v!@WgiRcmarm_b_t+Q1m0"90-]3;VԺN>PLU-`ngvt-CW:#ćߥܸFm#I[lk~lg'j~ng{p5,mxeL49>VsZW0ֈ|O™ڔ8En/nAJ"7-N)_ x6xnۨMɪMzEEn␽u>.>gYO%*MӅ5h#gs
    fs&MFQf<ow_81;7ps߾n/ʖ<-S;sn-u6s$SjM"xq"|F6b:rNzƩrӁs†oRKrC~Z1<ng
    >K
    &莡"嶙ѿٻնa0{Jz}{-}Vz($AZ0TF	d\F]/͎Y`%JrI.l|vogA@wrCm#쵊Ĕ0-#o\v,7&!7LA$&#rdݲOAݍaHuQrInqv1|:d4cDBU4喩
    a*B=~YM?t*kJr;H7NV܎oQZl0>v#4ZIi冼W?La5O(h[$:lw棂F0ܪon2ӌ-ӧv(zczn싐"'&/]o8n钱;M`0V0;͡j5"\T99EQlf 7-0m$jڢɢ8Lf<7/6~Ymil4,#(%ﺓIh5f*7mjj
    @p4#0ݦ6a@=cYnG69͹6ھĻvֆLfeު6&Sk&]Fh`gsYnX{Ze	pWsVhn
    و
    [P
    7t.�|nihӀsYPh.רK�>WW
    36u4nso۠ϗhJ\0`U5y
    m?sׂVgim37om_`.7M>+j3vqm8̍YJB,`r<,T(EW]Tʆ=9�N*޼t:눝$3+zȍы7
    #<t3>(UbL=n\oS8L47SمRS(ܘ]ܬ5?ƎuT&mqe^G.S@nC/koUtDfeF[7&(˚-6q,q<{1hחt8rSr2N
    l˚7oH77s,6p?\\MaOT[Zk({ύ
    %\nhfB	[e4ǓVkX8�_|}lbx6in[6d],d$p9VPqkn>Anх0459ܐp'!I=ez̍5?*6�+-I؛*rmdyv4Gl^s!u}
    5md5
    p;SEC[r;URm2we0۠"S7s`"hQklQ;'ZpxYyonr5vi*hS]Zϗ07Z
    ΤN68srKܔwhܖ7hnԛl>bP@m`n}bRTYhܘ[}Ы7z&,,gwǛXܙ['mm]_]m-fgٹ01?ZSl#ڧk|eehs7r+A%j,�17Mjv3zFYeqcn>Fm{Ch[B[}�)j.&nZ켳(717
    6
    !	a~a�Wȭ&=srDv;sVU~fGroQۧ͛Y%9{a r4=-wk @DDPqh
    !MG9ƙtKtsU6Oiʲ8LT7!
     Xn@M{M3tH7gK7n$03
    `31g^V"	{Nl˵֡TLsBFv[
    )K8>
    ɵn\v	]ʴ$6SnLj;
    >'uǺ]m7n�)$DmCv	Ƙ5YA�F̬s#ݸn˜׀n�QG6rE�ĊK7WV_hbӍwI7qiIbK_͕J`%aI6nT@ZeG]?.6ͮ Cqh=PCț!"ZXG!CVhK%غǟ@({jʍ7ǮьF�c@\Y>Q=o&!,#%E:7mOmRʦ@J[\ʷs_J>Y7H_PJ;ABXoaikJs=ٹƍ("syÒ]Fy
    Z
    ]kw+V7ՃRhd!K3#z|0VpK?LsL~>G!oEqqͷq{s8:ʍ!@m%q֖Uձ-78ᖒ/"ynXn)[ebpqsg[Jv)[�q2a$nu5#,YiQxo[K?Pcx֛ϭX
    ;2Zӥg:R񷢢Ϝۋ	7xp.�˥cGvL»٣sztp3%0W#̖6|Z�%UF1gV�qz Κj_;ZwUĭ@n[\QSuG7nZO[+9_M/mVFn- MpT֙
    #Cqݾ.q7>no(>D9˕:F"1Rr#-`n/:
    *Sqr6
    <H3Ю6Z:LU<Tbgs,2ud]ynN۽rM4PCV\U!#=rc䣨=u|
    ̴\-(=G:
    qjni̔bτӌV\Tjt@6]qϡ?aJ'ov'ܔU|yo )P7e2pf2"GFrc~/3GȘƨTm|u+(Vs㬥$Lgԧ\儌8aQU&FN;yw͔D|./f)m?3Gk@ T֏vCE.> B?i{ZFApiivQ|5^Zsn"3ߝD37joo0(ԛ(+3(/ȇE(P s{s.5ҡ#VFSn"7n2NZ77Uk
    Tzn9m[߂7V7{l"pɕC8�b`3x4�Mg=p[0ݫq[=O8Y禄4n=7cg�a*?M	Ї)mU]e^9a*/6a6xӲi&)isʵQ^RكV-#E[MҠ&2/~鹑~D5с{lnљ!ngZ!׍boV`RņۥV'Hg!JS(m;L۰[eY_eІ2%}DoEY1Dm>O/l(8I1^2%q󹍽aZ{7􂶲Ii1{<ZFH|WSo.AZo_u[]SX\-fSUEղV%nMy"vlg4cq8jx7'n= cveouz$Q~)}߬Nl6p'Uy:$n+
    l
    ZʔmefM�&!h6v6VZ_O׆њ|oUr ꈦ
    s>vUa 
    è߈LAS
    کC"X@R_9a00c+~3ҽ
    JAfjnNnrA7;vp[VnRWR
    e;v^Ϟn+n	7n	7pM	7pMn
    7pn
    7pnᆛp
    &p
    7n	7n	7pMnMn
    7pn
    7pnᆛp
    7܄nᆛp
    7܄p
    7܄n&nᆛp
    7܄n&܄n&p
    7&p.�Pd4.=E,f}
    :@n
    ܐ
    ܐreڋs1.]kr{1u
    m{m~%Gҝ+fp"S3ÓF>C뷂&ӭ;~+h\(Lڷ&I+m}/ҤwyMbY|`j8p9iS=IƊG;@35e2cDmg
    |F#R&9M�ȸU4Ê9R	2;[ԍ�X*h,pe)49&
    J2Ձ*LҦI}Ϩ~=hyteVOC!DQd`݁6ǖݲE\p9(6@U@$B	q$m!(<167EA3E΃rbh'~(MPőIu[.tˎ>4 
    4^ediNcݣq`oIJqq56estÏVЭpy`&"Pnh6f{O*I7j+88RpY7LYl[6S	[e@S7qN
    @%M*
    ̺N';vڍ,-WYaO^Awn0]CrW~_
    8")whЌHn!
    1*Bʉ癩i7z&	Xm[6ms>J7BIc}QSt0s;va&|34B,$}g%7?Fg`ݱ&t:Fʼng~Αųsmq̑ɻ Xt,ects3dV$9!چ~GV$A!ŷ&%
    aZ^
    WtǮ�P8)}/2l^dz{Aˍr{Z*|h%-7ssCn 7@n
    ܐ
    ܐ|1��A8:@GJs~֝����IENDB`���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/win-install-3a-disk-usage.png�������������������������������0000644�0000000�0000000�00000013520�11773544727�023343� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������|��PLTE���333�}�<tL}___qodwww���
    �������$�"
    ,�"�*�-
    1	:��� �,�#�)�.�7�=	?�61�=1�:	@'M"T�BAC	J�@L�R�ZT�H�T�Y�[R�aj3fW|nvM}����3�33_bfiffifflfhi~|}f̙f&16:*03D(K0*�;/�6=;AECF$F"I#L*L(R.S4T1CKPL#N)R$R+[,U#Y$]+U2Z5\;b<a4_@cCfHhCiLnRqUrYqVuZx^|bjr{fրΒՉ䍳▶蛽Զڪ̦̙ƶѼ##Kz�T�L�TK�Y1+1r�=�ED�XdM=j�K�c�E�1j��IDATx^ч
    0DQ?&;%t 23=p8=%$VϼkUD}WgU_Sꈶ�rC�>)o_U�Cn0`
    B:tޡ�EjHLPI![mg5wə_5oR9Ơj]L
    5_.^T"Fn?ΝtOV1ܩ9t"5
    5v(hAM$ 
    b!2`![mlEnLpd&argneiY*.XY42d2#).ỷ9Sݎփ҉(
    G7-k.6:/dI}[PͥUJYJގaYщдGrO۟Z),XiϜMۜ:>7v4U+,IbI_IOidn>')ȵYw7dөDh&�ԟ�#.4m{->^@j*�Pẉd]&sSz0w6-@|@H14:&gf梪2(
    |*60ׁpr;�	ZHrTKII$ɡkQ`{cnj]ҋ8nADNQDBP:JSmoijA_I4ߤD
    aD'RB\Mr)~?s~^8g=� /]W's+vnεfCdt]0P@SslgyFh9in]cK'cyms!Z7ry7sJ#X-|cs{|s~ro4C2>Q*>̚QplL	pV(w99kD<MwH<R6!@з9=kF%c^%{씱K@_FK8zе8O~KS͞q.]'drpL:	g|x/rGup>{[)o .bxяAk%l|RZV[07g+<qǑRw؊b72)IӔHL|;g"iطeYWfܚܛCOs4`2BdMyQYf/vDpx{x![ѳ=HYH2QX"֘6	TLRL[QVRP<xK~i=	==C/C?٘xlffyM+19ZpCp!;с%7u]S4VsùsVVýg_XQcX+<)4?uB)͍O?5%J9o�|cFf/~S�./܃"x2l拰oнPk~1�
    <h>|i6<ܽ]VD"L+F:3dórTB>Rj؀FT�cEd.z1Tfr\*,<Ԃ3BR~+7bt
    {2_
    M!8?.;!{yDΓ?[TR^93p&[-?
    ܱ~#l6@x'2!Km,pPK>cY^ɝs[=k$"dbH9Ν>n Yn[wL2lϲo9TێOI&F9V	R�zI_kY덙[fne料[fn[fn~n5_i;f;4�	爵y̼I	f?
    0'Iލ+d[،M#Q<HOڽeym(9xJs3gni%aN%cJfN#1\uPEaJ5i
    Ѣan}I'2s32s-37s-3WǬ)MOD@c뛎J:(o'5\O^w*Qd>::\R˒_mV9'qE1)zHZ0%)G?Q'
    /xb.Ɗ0[Sl8is8}wU_@ym!^<zqcy;b~zװN(0o۫3gƂ(fkS)T
    05xD9t9H
    ^L9d9Т
    +ʽP5<մ4C*8k7U9.yz9sB{9o|c23O<Ң	gICR+(HL?S&0*8.2ǢVOf~$32s-32s-32s-3-32s-32s-3Q[fnefneZ~':W{VO52%cGO:g^[scW,f%
    ;j](Ҡ}4n�]_0JZHWL$:W+l=41%<s3h4W憊xn//DlcYU1*WLyg3I`=K|y{=󇦘?4PR\e̙'Bc-}5s
    1'R\׍s<SK"s̩qp>+uvqt[s3gr
    s}
    t԰+^=v(Qu!b#K\6ƧW̗h)P@U2R�%k1\mV/ 	*呤553_FIt޹XD*3׵w^&ILș*z!߹r
    xF_;jMp	Ckr
    Y4$<PKIzN2A1Nh-O%rcΙąտ79q(똷S歒CgJ|D1g.lV1L(J9~E/ 3Wf0f}9:8Gsv/ _9vہKw0-}!K΀�feӀ1G-[Ö H95
    ~cױ[f~sy\ziuy[2ꙫS|ֺA潘8=stWy6A94ji"Gx/B&7ms=Ui	Ķx[i*wr/bL{9*H`^*
    mmcޮgHy9'ƙ0oٚ&fK:c.B6y0E2Ηz8'*ׯJ<s-1pBo9>bUiqEe|-e(4Imc<;ܟxC8�3Ǫ4YqBWAxUZDni	s,+T0<b/8cLGy-:�
    8sCJװq
    ^$heGŸ4E
    nӿtT<}y˘sLG
    Ef}4kΜ|0MG>s|=!̼?k|ny`N<wj$XB(8OGEǕ?7n料[fn9ne料[fn料[fne料{۹R,*QX4`ױEŚ|wE
    u.fK
    {P|ӂs_?;L	onL8g YY5\a+UaޞZo0-9P9Ϝ@|ܔpPc_&NЇg$M#6ǜ3o2
    Ih$]8+0j9Nb(l̉9<$!T1"V\{6Qw?!8_˿"ܾ<Zyn{sgG`U_=gnWam��a �H0L,P�,saOV\}ތ	=;i&0
    S�z>PA9e(YIof-k]rR/{μsT.%:Ў8˪-/mnؼ)twnuĨ5L(�+-"X0A_Hy!Pk	~ޘܦe{Y�4"/چoؼ{|(X$^vbN1嚷˖mJ6?&q搇Ny>LyV?zsݯܸ}˯}~''b.b.b.b.b.b.1s1s1s1s1s1|\\\\\|>b.b.b.b.b.b>s1s1s1s1s1s1G̙3fΜ9s\\\\\̕a.b.b.b.b.b.1s1s1s1s1s1+\\\\\̕o.b.b.b|s1s1s1s%G4��!`	اE5".8؜FsiٳC $`8G@/9S5QkTL%=Kf_<=4gXVHs4Gs4Gs4Gs4Gs4Gs4ǮhVin>999cWCs4G}y1]Sm{}g}X@ۿм+4OchJҼ5"ja׎q87S	n8j<bnjz`K*a#t`1?12Ǽ{┙c~y7A9>1v׽|\&O1w.
    G43$u=\F79
    泎]Dn~s̫eyagYcyM_yn0,F]RҫiXKsœ0'	sœ0'	sœ0'	swtl�Ж|4q�]�+K>1h\k*)dQnT�R����IENDB`��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/mac-install-1-welcome.png�����������������������������������0000644�0000000�0000000�00000045652�11773544727�022555� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR��n�����1:��PLTE #' &#+++,v1=pE~.SzSXZ/C>-@=1](*[=&j
    gtn!c2
    e6s$r:t=e(%r-/r.0~57MH6zByG"KKKPZpZepb[C`^SxTUslSfffclwnpwsmezwixxxP$Z!^/c4kr<}IpJxp{@?8XvhOY\k`rp!.8(*:135'(IS2p4NS"_5Z#_8l.k9`:q=HJ]SDFUNWXxX{curWXuJrm')01?@p1|Hz{dfQQpp/^d{gviyPpNzĜdž6γж(9(̎QeԋiݕiݜyƵLDzgĺuױ|GcL[DXT]ov*,1/2.3(7<EhEYKTGVHWoQs͎㥸˝ԯ֚̀ǪƸĹݢн½½ѸÖŋɔујŪDz̧͵Шչڏݥĸ^_f��HnIDATx^ű� 1B"M8k2AU_v���a%s0 f)^
    -X6fh߰-l<x8$d:TIe1[`,[,}COlY<Tmtz|'\
    TKn,JK({JB@،J5[j4JY5*2&c"L>~>�"aeOO;Z3»Ϸ[t(?h8w|w<./Py+In#1.62p4E<{|mq&8{:XM|Y(tEЂ
    @--Zj.i;ιwfHxbpm: e"妃%TU%mq+�7YI8vDTG}ٚKߎdU(�Ф ?OܥrD\z
    >=;fm�2tDS>H'K8HC騖6͐.7<|#
    =U?>n:e!\a9ޮO_�9LnJnL&�ĂB@6K>F.5d:$irn7+͏_,d
    LQ8L(�Un
    
    m[H4(
    ʸO
    ~qQ )祷\a|3Xkq	C+nZ)-"ҮFr[|/ls_6vKo�뭭n$}y&'<$/L\)n-b
    |9H$K#mG
    Ⱦ2en}ɒ*ŬpzeYoWu9unu	ۍWrϫO
    4'EI5r0e"#mإc	a(irQd'=bn.`gm#EQ{ySj>Tg]*5+B%Pqä,o` ׇ:dtL&iv&mʦ5M*
    H5{Qza
    b6_.榰,AqIW+KHb$,sc>
    ���ZD":u#(|>;6ztdXH	.`pʲ[ܲ,e-˒[ܲQʲs˒[ܲ,e-˒0Ra
    vׄ^1A{=U3%$V(wW5}S5|&qn1:.nW)~ּ-Y8\Խҟ>p^e
    _	H_
    bSYxbQb#వN5^R&$:;R`>uТc"_u 	jHp
    R4*F -<XS
    {іn*
    =8\^(n<\0ӝRT|OذTx3z^A,/+c-Wrq}Jn
    UHT}pcS0Ӌ[
    *'7DqqӍ?zT[-7*M Y{嶀o?ffvď0?s.P-Wo5` ܞ-w	n~g�Xm޼KnKaxýR0&ukH݀6C"Yn;[,~(9mh'Kn"׏`,/�rNwCó%txf~MHpyNO{1GK97ޞi߷g{-S-3Gܲe-KnYܲe-KnYr˲tP��@]x?ksgG߅spNJ�1y\SoĆHJ]JS[ݽNCd}$f~Pz'Sm65qM&nSm6qMOW|%MLj$t_/srtJ`49�"I*EZ`2tKD&[DygڈXwq#jnjKKHF)"n_"Dqi@9�fH(
    :urIRY$�2B`D9o!,R7)$Z卥RFPI&p],(H R)PJdB
    d+}<I\L4	CO=9-75C7ʼ|
    Zm Z`*QRj$FHQ(׉ U`ܘWgC],|`@PgRP*@cxiMҧO	+�N&ega[Gi�VVe\bM7٨b급(Dhd,RK#f"(
    \IZqj
    HF̦N~4Ą,W)nEZH^p�I!�<ǭ[Gi [s7tQ=yyV/*@,c
    -TI"LDFs8ꖧД`I`jޭ"^�!H67VInh:ŭco!:7_pct<h⦪ʊAL2Kbkus'Ay܆<-RBHJ{L@	-6_|jx+}E$"	,;Ҹw[GiHnt$eqCY&\:;5Tz."<ny\1h*h
    [FpNpGYF@̄ h[>77q3V܊Asw#-wbDhDP$�e#	:dç¤G6Xq@Z	l|a$�n�4܄AJ.
    �h|~F�wYu-p,IoϪBf"-:,+e9CX/uL.JF?%2BE,߷&n5ߊ|mj6q}.&n˶)
    <qݼǻ;f/vˈ:qۯ/?߽uÍJ FFA{+�Һ9
    6.;M&n^޾xF�4-@1%bBB
    ܋U#(l.Zڀ@:\&n&n뻻?Im;PqcĞheoq3M;qw'9<\&n;M/t6v7nf8%u&nonpSB3_!QDҚ6Pu
    eNhf7/lv$_*fQ�$G%UT'nZ[v!y<T:[QL>}g'
    ۷gs~۷o޼z??W޼}ߝ<{xr<}M춭$Q0b+Ehe^IP@tuy%Kn󧺺K">aEwrz|X.jlvQR
    Vr|xx|֞p,c{3ԔGŲv߉fz
    χ[e9gz0ʲ,Oyw/!nO&AOH,k֏W
    I[8n1]> »[n'vdq3Υ-LLDLoό#
    3f>pO)kUaaBg	eἡ#YD79O,E_[>}~Z1j[<7oخSiy/ubGf [풊M1
    qpH7B²1,LCij2]h,:q0Cc'
    I#i>h
    7[]qb1ƭNm$>&FmˑDL7.X>#5IݘxPFUI#xpz`)Ԓh]xqţk(zfZMbAAϴWStC\p90HRsggư0if}w,ib C#,Ŵ	ng=QI+1nՁ`Í-:jC=-{+w:WGܸio$tC3r]cX)2&%r70C\Ϧ=QB$͸qw,mϿFqG9!(2>BkUeV't#3M9n+n\4@7X902_pò1,L.pWpzMfCwS(!nVMqۻyE;進%
    U7;2qcy"\praN
    F
    7,+„1,|IM'
    C<hRn.61״ϙnH9ҰA
    <?n%.k=QjIQvwmq;U]
    f#"x!$UCtp;K6ۀX߸#<KP*[Ӷ͙!%R"|w~.Uϛ??z7Ma%ZnVңGiK:ur!P;GŞ\
    *_>;h9E[޺
    niqsҔKe>&TEA‘t&Bʎ72aBo1)ba'n:rP
    1sRyvY$Uuܭ<pmڰRn1-k۝P&-8	qC{wfUMݸndjJ-|vL;:jMq'Q/z7zR7ʎh@+q9	n>#ݥL`OERηl<|	.DDd.,]L(Rq=nqSJ5)k.Çi:o檯K[Ȳ/4P&^Ћ7DS7ʎ}7N-4n̶j'C[-5j_/3-14yp"P\XW6"CpViQOKe!nm6ZsUw6.74֋7DS7ʎ[�ouA7M[h\Hw)5X5P4Zp(9\ɘEȃ#nON+lzf+W=m,u".89tBuօ̿zApWU
    Fq$Ot]x
    V`2)©
    fvQ&c	"tN:IPмn՚�c*k5pse	7zr!V'DE~ɾ_d1nV"Fp)eǍ⌾n]d
    R`2Ok5V
    '[7dۤLƌ/D&spa\7(R>!k+9SZ+Kg�7ԄU}:`x)7`+?p;0}bH^U7ʎ]ZIэq4BBKaE#7vXOlz23HyHb;EʻWvb�8Anee0<k BX L!Pv&J\nPpw)֘XB[St7\ɘ"An~.,�7N"pCX/EOۿcq៲,TA qogA-a2Yc,z)["wWypEsdg')w	pLv2};n%fMDĉ3U#4p>
    n-,MDĉ3U#4ppezU;Ѕ-&p*uqۆL%a+P@XQaa@z/
    N^(	V&g%QI@8n>	-~F7`n'U#|%a@JB~et[i|ac3g,K-V]t#R+ȃڼia8hnnOl
    {_),'CsJ8&`2]c|tyZFV4݊Z-vTśfS%#x94D6Ƙ66˖ԀC#<>s}FV+-
     >]|+t
    >3ݎywxcL_T gOr
    n@DdjR&i4۹p&ӻ"ŶZ$Rrf3t=_
    MiT]OGxc_D gIAPyz)L|bBӀn%Dm02{zuLLN`Pm+I#9xc_J9QQj*Ik #P3mg
    YHcn|2m7thڒzon¥
    }P}W~*
    st{ޟ`0m|<SCqjޕi@DF>ΤWRЭw4ݶ 鍎݄l}xmW+;/d81m|<SCq?G)LFr¡4JtgѲ,PбlA+2ЭVU;}2>݅юa+!p|)31:$i>TOxjl>$t^!injAбlA\intl0KQۀd|:E'\J7҅\r&
    4ިGЗi4l $_pYsa.Dl	JKHMo
    tNk[GV_umAPZP_IP\Z9^~Y3n݁?Y=yDlv*jõI­]߱fЭkM?hUL3D^묫G`$XN)\<$hb;0VjPoͪgN.ӭ<1Ft&Bǖ>rH<X\n-jKt;0\
    .}t[cnaT#F>rы"̀}CWzfAIsny{24'd@!X`ºt=bZ(,RD.B'a40ѕ=7>KZ3E>NNnBhfFYl9ݭOgu<a'~w6M+5G|.#%ߴZCƥUIJ[.	H;(zn{}חr|&9Gp\gf&{l_4	rYK^[
    &6E(/zkt8(hpn#%۴Z2t3.fJRU!ҰَC Ey#zuS&wC})ʐ?6Jfp�:{!m+V(8Cm-TYiT%*ElyM*6T)	tׇU!H}N)bsD(c9xt{=.kNlk#`!Fƥ
    k"<L9$,09L7n{}dO
    A7XXS!l!kL	Q:9&!уf\:1P^aa4pɔ^<CIA.KRĚct>L7{y_T1I7De}a\:1PijUdZͧailǁɔ^VB%MrC7XXS!{lN7c4 
    K$H3	c,œ/Eimɧ97E%]
    q=X_X]Bq.5}Frt8aWB[
    Rar\P9^ ^!K̴E(ʉ5n{VO_uiY'zbMAFW{LJ9r{;\}R|0
    I>7ɟ}*xA4:c`R|㳌n
    )RhtÕ$F~Et|`>K6DuJ_?iY@njjaQz4L⤺]\&D/EllTFfB:d.Ӭ~U۰SIT+Oʖ+b~p9Evk	srxS )	p~Kqu]3&tj4L}s汀?3uxTb
    jYHvH7fCΡw8?ί0)ɥ5;|0oc|/!A[0+)mLQw8}k[,ث5{nfQz
    =hHӚu5do`d/:xinmfYcUU4mJ|udnwf5z
    L۷Į57$qmYܤٖ%mF7ӴJK"D)q�Ag['M4ع8Ta0%k^T"	>TF9I-TIvNHE6
    q�@ƅDjMӕDZD*pJG\H:$8?!ɢL#s?DʹΩrbMv@Bp_n۳]>b^oiZMP^Ht>[ugx*9JSجgj#jf�["9#,tvשּE[˃톸g ZiB+ą|{9VmP&lN5V	>ۦ2kNkg"FB7n?+}?ߞ[o_jOA.[�p	!	ܣї\"fiTOҲmH&ZJ)3n,Б=B7
    !gyn2@qb/`lԞt:DØ=b"!:nts;ͭ\sg5l9QcA"cS-
    cGLİ2
    wnnH1g?BN;3
    s>
    sR8s0@5FM8+֚[.k^kRA%I(ϞPv9:#i{Kw#\fM3˛]|U=i)Iki͉[w,Ls#fK{U7v;c4zp+p[
    vsQQ'QSB\!l[6n깩igV
    njUqzo[
    9i7
    k-]6ͩuiviM^8(ҙ[1dnG3JmGfӸvJJn;o<7zxfrƢjFǧ-+.\hE6%pߠO$4vQB6^pͅ4Ldso{[G]th>dYrCQjg9[GڀH[ɾ06XzDkhk5B.\%~WlN6@ڲkBKHLRpnݘۛ0v5ins8%kNr:k[
    Oz6.r.eZ7
    y3ti{{]ThB`aNvMt;Ҁ5TZȴ,Hy6<1V5-Eㆡf0mw\8nYڢeZPfvB	vyc@FsF$Dž\8CC591=Zsʽq!	\zxqv6Å5ܮ&b%g-6lFA	msV|~1
    '!)z69\|<B2?#h8i0.p/0h)B`"qÐU2x=^նʅٵf}tKKZ8-j"
    Qk\gқפx!0]L	g{\
    yP?R{(ãE;pB+th0
    {
    ]h<]kk>kpSx-eT6(kP.G
    @Ό$c!ˋeEbf*ǀxʅٵdqKB
    $acT?H!t&&Tfi[ 8LV5p;Tz?b㑘/0h)&n2lT<ܪƭrqmv-O0C1D,̈
    T18rq|eSxԆ6K~:%?S)4ns#vʘlF^/M/-bftz7\an\h|hq`ƼE0b
    OΜNR7e(3@
    mp9"Pw>&{da:R#2TK`2_0hQ)nvlT|8Gܬm]-TE*h+DE-39SV9&K&Jqbε:bJyJbY9VP
    ;}S[Np-E2
    L0٭m&7o-zf鷏$-,tNqn-iqV�,mhk|ܰ+2I*ąmnаܠiܰmxM!C[31;&_{f<k%ɍmo`hk>-�
    }T�s9D8Viմ݄٭7n~VXͧ
    BڰnnnǑO[h6͚ NL;;+!o[s)5,jHu_ܔ%^6n/	n-DEBLmH{􃉬S[6	13!7"mppeqyŚ`'I[ni�7<AD5FU!lܴmiMQ76T-j:9_ݖeܦ<nnQHb<|W7Kw
    a ן2)Rm(M˜|ecq[հuč!9rPã[3oG
    `%C1}Z_+ɗ)7qWu"W^p]>~*Twl[^"k(B`E0J0eWw6-ra`
    2)QYu/05=8t@Be	b̬xl2UoWW'¬a^yiQճt{nlDz%#2vx&mDT/<hB*XɃpB_In PCb(O[ۚVq9U'Qof=|Mqwd'*'6$DヸM"Ǵw%nVpSze@ "ԥ1帅yp�7?(>c5~1zv`jZܦDVbmzf<}bq+Pn*JKQ]%IG5Dd$!	Q,Rf31s>5AtLNID]tjEKR4Y;#f"8CAA4.O{ۚod[ߪּnyۚ3yS}�>3L&Yg"#2 -dvli7ȆtRnN*MY.-JHVJHJ[LGHG)GB`bb c29%TC,\]y%yY
    b((Eoq[MJv157*ckֵ̕O+4}G?ܮTݜp3ÖFӧ9l!a^eɴR]l&	*9܌
    #Na:C&$:)!QrI>
    5"A]x-tn%-5vݶfӤz&oܨXf!͸BCF_LkOvޛ9N/ u.O%DY&O8!G(R-
    pCgD\'e5ĺl	EvDT"=@p
    
    "h:m3uu57np3nW3KR|r,
    ^B9Җvθ=؄bWmjp3V4^.
    Õ$�O%Dt%4BZ
    *
    J7Ka:C&$Ruju)2!;"f5vnCAA@_6n2b]|7h7{B[o2[*&ϝM)>?BdI1ĻvkŭqnF&J-'<yz!di2TB:)71	(RM;4Ơ3dB|]2[)#o$H.Nۚw}ܰzw=܌*5ik7[/\FC6g۴MD;k?tCBWbªy\u$DES	
    �n:_`qa*SIni0!WXٚ]ԛ1PP)Eoq[s.-2r[s!V
    n*gGݝ<֦l8P.xt4^Ga4~E;~泈Տ&q^
    f!r|o9QuQ#,h%okp[o|-=Nl
    km1ͦ)ZjZnOr2U-oӚV)rܫ6glmst�y')cXVLon
    "&7`o+n[Knn5\w&soGl
    Gh"J˸Z3}\^,#l٤vrrbl2hZ &%Q.PϗaH^"c`adS4j	.kJN9zZWQMI`@`p;kmrܞ�e$qlڥ�EF(9<#V)(]7č"/H-MȎ J捸,OҰ&7Gۗ'+Bmg
    >'8XmC9L+6S}psH.H'όf+0=~so)c-#Vq{;_gj7%
    Z.WגԎoXhY"W#`V z%QQ)Q;,REv!BIdH|4*1nVZUȴ4Q%F`֔RנUOUۨM\ͽ̽
    >ޜVG(aBY6P\{Z1;őv~c'B
    AԘpbV$ R[rV!f4qԥ%!Mx1MTHҒ*]"}fMqfUdF:i6AI.'38CuFECǫPvYLSmW,3Q#6W#جHwAQ8uK=rvxDg$wV0nVblfDLK2wTRp#P[xmr1?Ii{~-i{-z<fȑDPu=p;Ҟb$qc!UD7Q#جHG@s\@q1,xy88D(	uMDUIqHRk"(-\#7oEpm,n=N[چi!p,y[:N1&9nCj&jsI퐺U?4q+$Q2	㖨*@5tU=C#+2pa~^F&t1e
    7i#eqC6<܇Z:0n2o}BqvQ]kwtw]nS1nBu'G-S#^q+0nJ&4ab]3CDɐ&[OLjM@Vml�")[a*Wl7_8_M&%bof1W.<3m>5^q$X
    )EOƸiCbVqC[9bXYҟw4F88D(IiqUh"գ\RiyUs7	nRΠmpm"%R/o9mM^o~3Xm܊Z	O7m%y;`gm`j*e(v7f(nZw9:JKCw6::e13&|nĔ<0Ue=(J=K6/8&
    FKeF76JMٶeIyY"m62y3ߺ}AōOҀpVA-|jLܞRG4
    y[	k[;
    >qH/z0܄MgZ󺯐(	n%6`vAMHP};7Yы%.7JxU5@'6yB_tGЦj$\g{x5O4>J.JO|CUuuc9K5\7|A}aH!GT27xqk8-W;y˳L>
    Zqۿ7s
    t%RS7\wI	<DH}iNg)uzL+^I|C-=2XuuC)8BbmQ&H6ى$rOȁ$:lИ_4% 2#:j;.6Dj\pʉ pI!l91n|fQOKc0%F{]?ȉT4Z5y9BfK?:M$UH"hE
    轄8Yfo`z[\P	,7	2HXKlԎި¸-'8Cv{[NGR7F/7Brqk,_hEÊ,hIXDcѩB0mwJ:H%)d^@.zr"
    Hpى}$ӚWLH6Cq	+]<CqK	ko&K[G\\8~4cܚ?Wj!!3+nvFDcpɴP!
    AxD3QSM!!byCܾBς2|[HZC*yθoch܎Yq;v
    7	X:aGR犸sAl	w"\Sm5+Z1,s$2C%J[Ps*h帑٣5�.nmJ>6nM 8QR&nʊި"(PVD6Qu֬tߔq{f&b܄7*0neׯB[MQyG	-q_dj&nI}#n{0g/fNb7 {X!ꅛpC4Q�k q�dW8E!?B`QE
    gHAD"uavynH)RfF|ɹ]vO::Նr33T斟$8.Fť³:(=Ā9r}�߫9D{U:~&77s^AD
    kx`?>qkqo'fj>hT[f5[:
    2o>xܸjpFv_4Pn͎ܽCnDik0z6t�[:޴7̚hۄ׶[aqRǭq7qnxD@mbM8
    Y:n/}_vS*V"6-fR긥x jm"'ȭ6f6MyLm[Lvm2΍J%lY5fz+pch۫M渥@i-تii90nu&�pdAUҴLnn
    ]PN͹=�7  ʸCBxzcI9nilE[":*U71T
    u^e.Ί
    jm
    q{wo7X*F!)([S6Qmi	X^E>972�kMjrwOqCn$:7">^0HSlts	nMt+r	n)}.r[6374[Jjs-fpx;poҏw
    {Z<�hM|?
    rȪbJӴ/97qRnrnTnne8<,Wn3bDR	7N"7n6Vզ܌z{Οb$Ī7-fۤNr%VndqGVn͛<ֆ>\[
    n;BH&xSo2txn6vћjkqSo];mkH	7nxu
    mxSp\fMsnD\,fܛ6|RjՇ�g
    [~_Vf[اv7oL�'+sC6>(r#ݿEm3D[#
    [ա[V*.cm7wrkӍo5r!VR͟ݒ~w+nPn@6E:n'C4JY	U9X$ApCJ&k6Y4{p6p'AfMVpp.ƅs]fo67^xãq{+VU*x_
    8EmgA.zB݊
    +s�t*xܶ%'۟o7��Kr;7*|})]
    nq}1v>޶B1ϦuD#w3Eo|˼m\ԍlRnþ)r
    obJ黒==tT/̍*';_H;7p+6]QÛ`oR)):斬RnKǛ{֛))RRp;R7p>97ާ!IXhJ[8yEo1|o9p|[d
    j}8zͼq,Yo.&n7hdžsը-K1mDVԫ\V8b[ˁ[kK2Eq7,Rp[pQNY`Vg4:r';"p[n=8SzSnty'"EϧuM{k^0	nv2innErژEuFs[7p[#SJOMGگ!
    @Q1˂
    	Ĩlz?LߚqJ
    wy6qE]ش2jksJSD,u-7nU7pn
    7pnᆛpn	7n	7pM	7pMnM&	7pM	7܄p
    7܄n&܄n&p
    7&pn
    7pnᆛppnᆛp
    7܄p
    7܄n&܄nMn
    7pn
    7pnᆛpnfJ���ٿg
    ac]طwIr A䥣G#0Cq1vS]Yy2? CV7
    7
    B
    B
    !pC-TL
    V'&p)nSC%զVVMqUM'Nֶ*7h%7m[Kq<.q&>w,ۂi}"3.
    #2[yv5gIh3\wDΒI"lgn~6,-ܾ{kTh(mܖKoX>7BMΗEj#d{Hsp[,Sf}-f*CcsnOۺcǔQT-ĖDTmT1j7O.
    nLXDEn)j:gwoB8sC|0LLŬЖ6k^˅[�cQ99ID8y`cOR6&74]L:`ڹ=H")N=
    ܒ_IszYnӲxlC53M;y>7p;x-TEIK	?st~[+zEnE7n.:~-ŅX1N{„s({ֻPﵚо?`cܖ#~b,~AYb!&S]ԇwQP7"+$
    *(7|cqt+:9nkN[^o}]^.}/
    yI+-
    rˡM!(7xI^M&1Iah:i2ßMK&Mtus2+"'MKsC
    !pC
    !pC!pC!pC!pڥc��avT<T'tE3f+oˉ����IENDB`��������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/identica-deleted.png����������������������������������������0000644�0000000�0000000�00000012476�11773544727�021744� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������15q��PLTE�����)�''*��+�+)'�'((/00677��M��U�'t)�M/Jy2Ly:S{T��R�'|'�FFGNOPUVWBW|_`aeegnopopqqrs�+�M�U3O;V+U)t)t@WE[A\UULbKfVkRjRl\r_xawfzl}}~d{++Ulpqvr{yURU|��+�%
    )4""**88U�W^$a!M�U�t'OPQRMMVWklopwxt'xx.9>+UCUKV`elxԀ+ԪUMUtȘ•͙Р¬̭ͮҶѪԀ̅ϐЀۿõ۲ٹպ޻۷۶ɉʓӛϟȨƿַȨԩԭչطȷ۾΍ΐщԘا¸ݨܷřԀԪԪTM��IDATx^
    ���0f`|%.9tl�2DhxifnϕkÞ6REq|(SI|
    RʾEdS՗.
    KSևJV
    .Ȱ
    y؇%3%;,,NcsޙsùtewӧfrQvSN";SN"cM|wJ�frYD?+$$N~=Apvɹ]$LٲjS(m]IuPmFѬ4vYHEcQvGᾥIDW*~v3KmS}J)Ҵ#mK\T{3g3wʎ 2 8\~Wr<??XFqb
    `/:o]2M["WY4vXXZ\	AsuoҚ$忤ڡ!sAme#Q;䬨^ίTWJʛuኙ?Nj[#9^dd2.zy{<Ňl];@5ĤGvi:ʑ,~"IDyUwsj7\0̍S`&q-Pe9죣4UV4pn<Sq#')GQ塴ڒ{yrʣ|�8 MGy{&1 MlKRYf!f&WáZyt� CevCy.Fdy:E#
    (_dB<0? 'Ea fj?h+<8X$r.>\.Tvb_Rު,$ݴJ~ZKMRt_qTO3ʳ#M3./^0?;}Zӻ7;)_&AV\RLDkj텕Z{@Ptk6n}($(>7ܿ4U-PQoZqe$\,&ܢ@@(^H~p_H}Q5d;ʝ_iɑ$R27^^zkL\*)-9DJ@FHODNy� T'�H@y/wx~OoD9;�zg�P=C_+ڀ.���zV12|u`9
    ���@SZs6ٹƍ0pIH{hcdw@H1C!lJ![nڬ@{zPX6d]kw)
    fF&|1~='Tu�%�r�T�r�TP9�*@P9�*@��~i&l_P�*:cu)U~D�\6s�@Qh;@sr-PLIWʳ-&"]*y\/HO3xN;�G6n&W4cX(~�<6K:,R7)iPy3clj{*oq<.}CzT\|6.H+}.9b?
    *o=ʓ&�*驼dF�,;-,\#�*X.$
    87I#M-KX9C*+JTi?`by\�;X�ߗ**'ChyP95x
    ƌv4"=�*
    ,Cdg%ƈt�<,`<TNNUmHL&T^M]{ݽ$@%Y<g-1Ѝ9rkneŮn!X,'-WHz"W<7D_6Kոv~T#)[=u_i=kzDnpÔ1kG+lfTn3khwq8zqBxKJDKGLc&mފ9LzFڪBW~exV2yȒ,OQF{&!ODW2s13E娼\mœyDt)}Z/@/I{"I,%f+YyT16.^mbuQQ,W;/eر�*ySGsҭLk2]`d6(ݮZ*U͉. كZ"cSm_H``Ae#6r5tl,荻H{Bk<2MǏhLi[Lz(M<DT@TcH3eDiʵ`vrMI<pt|d08UK/v2mW9P>{+*u)Ů	PyRr(ޒ�ӵRNξ\{tH4P9j,^=Ti=@496XF#"Py5j,N\B?v6`\-$	�	QF
    22M^BztS\h4UXbV?6c#Clr!eC(﮽!˽;<?FP8m<ͯeC(Go!ݮOYHUI?G?&)sYSPٹyrcǯUJ5z򸇝>O
    PPed}C(]~9.!'.h۪έLrSj*Uٌodd:Hb5a.x've[WያVD~gYWYdy4UnqGyByC>݋C(D7F#^(v~ZyGDNh�,+H
    'vußb]۷ϧýU]+/?=ڠ\9IP"JZ,z2'kYLDYʏa甋+RN(wQN(G9<S	?}6es2W*̣oUYߍʍ4('_$(ˮ2{bib0qKb9YJ9(<w:C4ykrB$`1*H4(/[mR	؉V^^eQngƽs	MُCsr#uY[<wKvUn]uUU	#PNr"D('B9D('B9ʉPNr"ʉPNr"D('B9D('B9ʉPNr"ʉPNr"D('B9D('B9ʉPNr"ʉPNr"D('B9D('B/Dn 
    `)rB]�G92\%܀
    q&[HYy|0̾rArP9T*)rP9T*ArP9T*ʩrP9T~m�M/-CU#ڬAgLJa+Gm]y|[\S_f.o%nތQy&?"~[oz?Xi|{|;\_y*qYߨ<s̠e?Um]}9*ۼVfknx]^9*%7}?W~QyT߮P9*σ|</}9*([wr;c?+G5ߞK>Z~.6&k]屘ŕLxg\S}FmJ/O1UcArP9TNAr
    T*)rP9TNArP9T*ʩ_Oj0Gô Mx2Wzz.BƟ&3L;@C?y�ru�=�`9�`y�|+�`g�k-T"�Muq.:cLim(~轈ةJ=s(]%hyk%S?7S庥r;;/usQJXSˣJ\ڤdR>*Z7لA/jpKML\cO ؟psu,r%Xw"#HHhe(�˽OH7H+y)՗M3?$lXٗġiŻJTy%c;f��v�`9�Ds4��/w:wP9A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A%T*P9T*DsdB����IENDB`��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/mac-install-9-succeeded.png���������������������������������0000644�0000000�0000000�00000033333�11773544727�023047� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR��n�����1:��PLTE
    &%4"2-
    ../z1O:d%9M1=p{"*|1Et/DY/NnSXT2](*[=&j
    gtn!c2
    e6s$r:t=e(%r-/r.0~57SK
    TA3vHyG"ymyq1GGGGZpCHMcyxTUzgXfffdlunpwwkbwww1>'1PF$Z&Z/c4kr;|KRFpJxfxiuC}%(%/(56A +94AOT\aJS]dy{agJT\dpv?8XtgPY\j`kp}ʃ!1(*:135'(IS2wp4NY)k7HJ]SDFUNWXhMrcrqWXuJrm')01?@p1|HqrQQpp#%Z}k}kKNĜdž6ϲж'9(̎Q֓mȶNDzgĺuױ|GcNov)3<EjFYKTGVHWoQs̍楸ˑΔ֡ѯ⶙ԭ֚̀ǪȾʽݢ̺ýѸċǗljʗуЕ̩ѭԹێݥڸ
    ��3IDATx^
    � :rqg\AA218&�A)WLyŒ2"5+cց8�ߒGi"jBS
    mЧtK7`dTppC{£#]Ź8M(]:mq7;E2"- ,em(Rܩ61-z		&7m
     睚Th%5R"I4h,6.0?L	h)9io%m%fCh%w5Ӽ|yMmw%)&E1J2𞎗YV0I(I*JS@�]tdQ7v6]cy^6XBu, 8&TEnMjcTʱ7lwX'3rN_<VIeC@�S|ȍ1P'BR)_"ʽr٩ն sطRAV!Np"0qLG^RZ_B{,/!yG~,>s:Tg|;oW.]=z2kDN&\7(%~IXP}eiqpZ׹d^^[Q7ƾgZ
    QGo+)m)(2(ܦ$I_&xʋemmn &^ZͶLqRoi.@+P(mЈ02Rgfc}6mh8d&eCh_z2i뇼Szn[z>rIM|	Fp8:>?>gȽ2QL
    nPY)tpjr<L�zTqw_:D8O($- vV+Y}@.0CattmK=`* <J#TBH~O"_yu][ `DZ/Ϫ*
    )X'4tC,oЁ?
    =J9Ko&6jRD5{Q=o.8dpDB#�PBd)eN>1���0-XO$+UIbލE>U$_f^5Rz5/MTJ%n-JR[*q	@Tn-R[*qK%Mʸzn}ј5&%n۱]KlKq}RVx-SעϸO-q^u-/p[[֨t"BgT)nST=HU~L]@˫NK骝�j%Te0 tE3 8qj֣A%@FJ�WF4T'
    S'P+`f6H*axx	
     7qL-*ܴFzŢD¨^
    0vx8W0 "Q{p=pc=$nX'`aZQ<<mX%]`m`363b|>i+{Xzȋ{ϸuXjƪf;ܖ0A�Fq8nqjmX$3zLb(L`3=ps8רy͚w#V%nZ�I@ru*MD䁛]!pskDq$n:)xǁ[۲	79iyMǮs1iX}.@WY:|ufh%mmd)P(\;<sg
    {Z^trUbXf8nq
    T[]n
    vj7�.,lnTLu4ZMKS�T70zyZp	jNx;"|:N;X.]s\u1y M~&ݸ	-R-R[*qKTJRĭ;Vq0<e-ȋ8vgFvdLi5FՇ]#=DpFp#FpFpFp#
    np#
    np#Fp#
    np#
    np#}ֵ:^77f1aUpb>܊?ssYIMon[+Vڝ.q۠#KNz5-(c%ENYP[
    nZwnbXE':mcjJ&uOUo?!bEenpsm=kn}Ti<UJľF4CpŜ3쁛vIӜ#7GnW*Vgil7o;v,}m=oeHQ$7Ge&(<jpۆD-5g%XxrO$=,3O[|Vt
    nv\~}wnc5*|M76(�sK#{DA+#rqWj,Fe2)!vD|H"e2־f"x`3roWP.
     Ӫ0-v^^"ͣ]ԍ8p|2J:ݶJ2iea&ȧ5-0L(]ҍ'x<'s-nA41,`zYnGt#j2gӭ)Jq(Lx>*#\Süƥ헭k2PN7:jQXkjhn p- \/Cs4m
    B.rIt%(l,MߧckmPϟwmN mzsB:JxmShhmvr':--]
    Rp+Ce	tۈR[0N,\=
    |`(m}t5u 6i}U<ɷN7U}E[ۼDfnuJSVOUΞ>	N7qPYJGIF[ѭȹom:oU{޿ϱf
    &zi!H,Gu)QIG('{ea$P-b֤}mQj_,mBry9-ucKM꫺őe[85!-‹]{q<Tnc̈́k)N~#"c8퐩J"`E1Ml.\sݦhK@K@4wx>DZf:4J ɸi=R3AGY,P	
    vy%@0ƺaԞr9M)?t}kB-=mLjvM?t=;胮Ǐ�|I;rSʘ=k^«[)guPZA7u;m0kx2G)ddƚ3+{A-zn\[vs(`A/^cQ|"HW<on=%>=<U]iX3hw
    Vkh9\61G,^bK
    d$'bW$nUl/t7o)bϠM(Ǚkxu#bZ"gGT"~)PcԊ^2qTRy3!;Liu*QUQ
    1𛷍md'k^K__!X%|nҷΙ>I7[2֯놅n}hJ3n[Sfo]o7DSM.ð6i)W 䋧֔3QzU"曚qA�2ݨ5x>U׭ME
    0U'�\/8m[EZنۡ@)@d醤ШuLُD@mMnJްnnr\M4+d@7ZNSg:m-wm@�w!K!PC9H\h0<c�C`p}i1J2 @H;+fi@74ưtA7NpUطzo{ .2N6yE)mVP&e2)Py餙n^WEP!fh$qtO7} }%^sA&#2l{f]nHqS:lQJ$yV
    2
    ^|OC%(@8K-44-8mӁ4р_7ɜ=Lnn7
    8[T5"E
    hO;L̵-6U(JqnCmf6�fatс4u@t+?A$(ߪl#w
    p[sU}
    Kp8#r]kầ
    E)V٦gC,h
    B�\GWķ%S"SR0myQ8H'c,y{v/^w1Rǰ-M]PvZE7x`gEQJg$l`c͐LҪ8ۗZGs5nSSv
    q:n8\[0'6fB/pۗH.]fcV7%9TPƚA7g0R~x'cЭ·
    [tEɉ=\clpۚ!]$n7+Mua~F%.[2'5
    6f(ǕnOz8r셬OVO{݂VW!S`KjZ16fEt{l6?LIխ\zLzmӭ\,@I
    =B
    z[wSKne9Ymp[R?֌3*m@^FXEvh%YL78Tzm^79o_S)y[TzxGۼn
    =ԍ[@`^7ۙ}v[}s6?`m	^ȇCws0;|t1R:حS&ȵ:ySN"J--goۆoԶM(c?7j2nՌ<$n7#Ề[%N0ݛ^Dtj�@t漏sL[*bou6q;b4 y-mEJaA\čiXnĹm܎Db]	\9]jzqc-U2fR8B= L5@E!oSsˊFvHYaSo۱$-^gA:w$v⼕(okrڜ�ٺSyfOZ0_P9rԄ3d=u")Fy[s"k*?LTifX~wwq3`&Qtu-DL5-x{,tYh$5^ЃWo$'v"J@#.?2brljƟ57#qn'\|s|;>xH`XT	@؄[-d1_1)GN˒6EVŬ(N)NͻwTZNܴ�sFP:4q/`-cͷ6	k>L\Loe9�vV̊I1p?Π\R3^RJK|m"�rq(
    uMl)l91l1,
    r@</"i�ҥHT!L~]�Ԃ:lM)6r*nKܦry.:�'<5#S=؊/cGG19MYRENnDmƤ*n*լ}7\i;O
    n/cͿJ)@xr*lsϊfs-N"4sB9anjn1bR1 8"#*RQiJkh{	^Dǚ.�e@▯Ajk-W�ynΑ[ԣLq�dZKc?B?OlofEt^]]Mᦞh$k򯽽joY??|&[Ŧ&f
    il4vx)[;7l
    v,m4zn)tgi{v+p{7eɣLgjޘl#r}fx5=?e#C--䧷I橴Z+d79Gns[̭9Kv׽=o^ǚ;[iϭ2cΘ٤ypkvͺfVM{nfl[jxgZvڸuwӞ[Lwø;vq[}ͩ^i_`qx9`9$y
    |	i0ҧymz,Y+#)
    ^H
    w%}!6JAr{mwzhwQ\l7fknTo^luk&'X#o}wN�>>mjsaͥf7~⭈JK(;un?wmek9aFe_)(Rw\R�L/XȢ;�wۚK7!yx?'K@Ö4
    5
    M'Ąw綅sζq`m6c:z*TwW"a^w-,m͛29�`n>>)ņ[M{4]w'i:d
    �Ye�`cnZ�!ܨč9&8 a	Mnm+M
    Q0wrsi|pݶ@nY/ H,P-wU<�e^m̥MoCqnfN{6s۝)$/v2XRm+GV!|VH.S$+|po_�Jj~$BVQ`˳Jʐt	lw PԷ5[v;cjr|e3dekn�<Gy>/3iܜm79n$*c*-U?*J$)熈dm	;msmg,FG(np[aCoᦹnsh(R*O%UUKXQ͹lno]*@y̪Nxԗ¦&d;m͋ewt=aFUDҞyYY$
    $kI
    _y[hwɸI6Gs 42p^*Xݾ}ܔU,'zc}	lN|[~ݖ�d @b0`Iܲ5m~n+\L3-)T:lF5r׸E}PUÍс&Xߝ{|ah^s2}w/
    fh햴4-Mlnɳr+7.^cU/X`ʛ-4t@3"cLw9*5(wۚ=ܤ'BV<*k	z~pSHuXinꐼ
    ntiLq;ʀt'͍6a؈4C'Z($\2h*u7sDMp/Pa[Ѵd_Թ}wDI-K5'um/cGq3*ÍxD]̌DܬE*;m)R&w\o{*'6K۾@loJEVPx˭!ĭ0N=7qDt'-]nHʷ	-QS{C2xnmO\2J-@\VQ#N4di*ySv P֢.p
    #
    ;un8Vmԣm1!oimwscCMRBNsSykdn@p8@yn^1]n]oCG1[q2nEk$,/_i|L"aQWhФ0$d@yS)m^~n%ۇ6u#LMM7Ѫjs~kZ@7fwҖ[vLR׷gαێT#=jZ\lJSQs-n}}G;Q;4Y)-Vm0Ir{nN-I܎7i3_njx!6~*46K�nLItٻ40x!#rEd{Q|>FIs\t@K	9krJcM1࡭Yuca?fcfwoflGTn,!u47y7՚܌Q^j[Mbiwۿ=yWjfSDt
    >::VI!min)֜ܤ75mKn\{6i!{Hcjܒ^ky2P@wR^kEVdƓ<y:ݑ축F%	eYDMch~Zs֚Oi*j͒[(Z>PV:݃,!��
    f15%e$Bcj_k1j5c2fZƾtk͆q+}๹PBk$T)禧5{ܸ(,Ǎoۻ)	dJ$%.G&m5l[Bk88M0q㟂;ՍX;pmE/iʭ%uyf";7ʰ7c&x`"}s$՚(M&j-Suk̒<?&r{%%�6L3r󀭬q~p胵inI5_1WQR#XD;gg/Q84pӚg8تƅkK|OgvlhK7=WnV,]SƲ#[-E?ܢm:vd*4|͇*Rq
    TMKIFe˅/j~".4Z@eZh#Lkg՜0k}%Ar馹>F`m/ik#Ãyc8b%6vB͝7D-Ԙ&)zJn0�ۙ
    FI6cE;,
    Ϛ6č
    U[8Ko6}N"/%^冦Msŝ	GD\aPIH\υ)tf�mlfBpR-\5ndXnӁ$͘	Hm`hػ8n(.+66	´]?#,l亹j{LI0&077nAKK)_zΈj3ubͤ`6:G$;Jtnڸ^nO"'D7[Ϣ?lkWRon5[	%6uIڷet͝qqnc�tr;o[bw`]Vۢmն`~r~2?xN7q8w<=0=0X[lhDŭk`S6o`p7S1CW~YOn|�?[w-ZM`/6N{mcneh<s
    W>>r5nb
    U�RjZSvXJ+Ѧ)qm(=ހZ:X@6}֣[ZZiAnYVƮ\!K.wrg17Mڛ2	6\!Fx7B.tp{@ʖGݟYvm'!Dm:n­R"G
    u]HɭІ)~
    3<]Y!PPUJI& 4A6(V2g3s1Z"C5G3`�F9{-2vBY9%w[!0n36#n[	7(�ܸ\r1B[MD8TFRCrSQQ/X2j5If/Eey]Y5;0ƥZA;)QKgT1Z"CuNj"7
    7q>dxM1!Nk4vZ㊋3y:wʥ9օEYѧןnr[U:#9�Uk,Lv:VeVujV (T(,WHDJq3(RmVmrjRoۙ<w5UZϢp[EEjFnLȍü`LN+
    ,dgeyʬ5ʥFnd ܄&nT2rgIYX<\ϸrnmn?7WS[>[PWykv5ؘj:*EKLZݼDHDFnMY0mnuh40A_[۬u=.*:]-NnWss<0.y%>ɜ)[YBqx+YCAi`1Ĉ:~#p`J
    Y\=\8&)ŋnT;%Ԟ9uscP@CڄL7QIIcZxa1@rŸxTD
    7[2ȦW@J@p/7Y(|@4l@ɱsHJuXYd6-ɡҔv)0==n[Afư1gbnT܎!ҕ5gp;~#8l-d_,-o˞ѼY)ȸfΟ='03Y+o͉[n\)_)i7jEOqFS`n{np{_v
    
     6Dͤ8
    7
    ycs#m>o)Ġ-s#oO0Fܙ-sszP
    6#éB}T27\iP8"}l2n.qkljKphPs{LyN
    Q&7㏥FV27ʺ^L`S-dbzv4̍b_Zv"iXYenv0c+HAx7i(iR4"+Aـ	˫(cnvm5�DqO;!L=}!L7p7L7n
    a1}SZ{݁p68�Ve"ry�vD4㴍
    [n{w1fvs۵wCFLg!pqC&4m<4psszWy!^]=N.R9=2dqME-D~X�+i5/bY-׹Ċ*6pCvʷ#�AXg#h7p+_rm]}%s4/7)+7N7nC-uEnK<XL9pSkK:Wrf݂)wom�:="qTyo6s
    ^n=s+x1u5p{{='ebnMv6x�oq*M\'j#j|��nn)-\ȭI9yY��sr
    %|}Kma-7?N.VP_O]5B�3O7n~o|5BQ,ʒ}hy5uMLxOKMܠ
    |oꑹZ;28"2CF
    s?[^Mތ!*xM*2>%E+u2Y7ېzS%e+67p.c&㣢7 rkR-[cjN5Gϥ
    r8o
    k6z֏On."oK	6pgGRgQ[
    Y�/ROdv9o}ޛhbboIGmZNCU2-&*
    lV˾P7ǵ-QDV~pCM9lxmm#ofIpoMUznvߌazn
    ξzqJ]A
    MG5pZ_lvz}Yѱ:43ػc�"w
    P$%nذ0Ϲ18
    n	7n	7pM	7܄7ᆛpSnM&ᆛpn	7u&܄nMn	7ᆛpSnM&ᆛpn	7u&܄nMn	7ᆛpSnM&ᆛpn	7u&܄nMn	7ᆛpSnM&ܔ↛pnً]:(��@ fDv5D\u+waV8ˆKemi1墋u2,{h&3 4HO_?rC(An7n7n7
    7
    y#eܜoQ%
    yFBqܒ3c(vrCkȘ)uQ?G.XǿO<kUQkUܐ0iw[]~l%
    .97uznl7S[^_ۮmYk뿖7)9Vjrw-SyV'jjK2&ޔ	~?xmUUZq5?M%
    QW9,ٓrSV܌	qwIw'4"Bx5/nͨLk"ܼfXWG̐
    8k@L17y'j!*몒2dQW7D~Sȼ]rŒĂ٭f#j
    ͫ{FdZ	?vfZ7n%OE5FF)7|n~8<O7!sS#j]D\|8WU
    Zt/@ȍxKRfw7w쳡.ڦ~br%Ɩ9o]46|7Dt(3#:T1,
    K{^u%D-nv!XC/Ef)Qn5}=mOK<X'ڗkm`m~$x{;;2I?.rr)Qnx{3	Nmm*Ov{XoS$qMr};J/ӍvD!rޛHy(lZg͢冈Eh1H9bm!?!pC!pC!n!n7nk	��`9QS	DC nI$4f<����IENDB`�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/openclipart.org_media_files_johnny_automatic_5261.png�������0000644�0000000�0000000�00000054273�11773544727�030320� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR��:������B4u���sRGB����gAMA��a��� cHRM��z&���������u0��`��:��pQ<��X9IDATxM#ٕ.^ކ)Fx2uE&CIFF$cLPQn`Sz,1L7ŔtjaPRF'Ql:3I8ssA1Ŋ/a>vVACk,)Wa^&<_|[1FD􋨚)<'?_Ϋ#'V<؄w\ׯ]~]�謒Ѵ7^0zӫDWW;^0Gٿſ](]q�puU0h_|w;氭t}�̍l^S"a``L/͗_tտMjEЎdaxϧʲ=x0'"zM$./ٛa9�Bt�\]WEĮϋŊN�]`{N\e3=@T|ק˝Oi8^
    6r"SPZ[?"to!.'?B_3#�uwt̉k~Uu x
    4b=
    }9wCwFy�peCA0/ht;}`{Xx8
    �"`Jtq^%>WyXchzO>{gVԚJkEp`i<lL]H[u=dE�kGy:
    �խxS	A:ԃttnNt{b
    2]hGɊ58l&>yloC,n]=\�(6X%[k[@\l�]5=[q[gd�yklh^Զ)Nк2b"^g~1DS,$+ߺ{/蠳%w`m~itB�	$ɜy,3d1m\m>`5;:~1QEѥBo~p.}	x[-Um"@JD$7
    kyCDILD:AG7kMM?3h4ͭ^y9sj_1&J_-P}TQ@N�c7t%۷fdCk\xa`9'x:]6W1OhjU8l"PW!#ZdQѷDDs�8
    \C\^:4h%o1CBeXc}l!92H'D�*s""vgLe!ZvƗ?%%xyϜ3T3VC�^ frQF,ѰY4r0
    6n럄W�0g�g;2|ibXF%)*X.'"r>BGqZC.+>MG낝]Ot2P]ѵ	|ˣAfMDf(@Dj"*@%ID[l41	<Bwm+}q{ZpHĨh]wDsD`L$)cuUȘy?Z�ګtǰʳC"|m;l!p�ub3g6غ ZXZQ	|	zESWD�
    :;+n2;M.rTkr}trtA-#!-E58�;|�\n4+H&-f+źڠ[G<F_Bkv	GvN,�(~?VoqL6RhKb�1ɳ"7 :	-݋z:\r16�TNMIƎi
    :s0
    Llt20ΌVE@~w7.lˋ�O[E{d>>FQ33x�RQJYNSQ�푂.^ bOIБ`BS4m/(S$	�K(L0v3h^�4De|^i7@@[Q-X*FG6Y%Qu5NH5�*[{MV&&i��xdkŶsKـSG>f1tȁG>;i3Ʋ%`K彪T4DX%;?E1T1�G|$3;WȌUøi{	H"y""5mK",MloVUBȘmY�,~`!pTqƎ*GCZZrDzD"{NE(23K;d&<:7|MK&&�oW8X{Juwm|1Z7v_>||"S[}`	3%.5�;ol
    (u@!SEM-I�iV^m
    ]+;ʏ&{`g\D}DHIlDZ8l�džnK.6Nz	IZZR嫗>
    "}atvh ,`JhnR6^Ck_E�<TЉfJr]^J)*+z�X]
    7˂`U`]7
    m�#@QU2D?[.DP!xlN~�UD&c;i]7	́90�L&z}Ƽ2"tk$ Y�i{�zO?(-$(nyQlYSSN}gϲ7Y;.
    o{"fE[hsd%V*36�D6�0Dû21<թݚ-y!BG!"fXDž_X)HٕKiO^,:-EɶJB�ݵEdzr	ﱠ�KTm˗;D8jH:͂eՆub@}N{;xsS)Wum$"
    5/DDȆ:~(]1%<Yx)]7]WXh\�;V0|hwIvvm7E&f6�+&"y&7F��jiHн8`	^@[	Ԥl`_tܟWlIr3ohG=(9"vS)lT�X8%wC5�xH
    .7RqQVȢI7T{RVl"i*%ˮr>mlDD@/nMŘaz.:<+cg_
    㰕;_pQ+*ayœzQQS?r<=FFfZ6�$5,[{B*(n@V2ZjEb<-&d')f%hm܏H者}kx@dK)_B^(VvP!eI(TABT܈;#Bhoֽ
    �{_�t׸"اmAXKfeOێ21R<qOV \Np.7L<{0.;R-MY$
    un,�/)y�䴾gGTnF;�X.m2<]N蒼аۗ_lWFvUUj�;hܾ5�kl,v}"cpf4E�}bQ+wHέ[ws*|6TK"/]0ӽJ44TЍ\T@*^t᭯nVW6o{ˬث\Z$E3wRNX8ԟ*%Yfd:2;钏sVpL5<}tۊVƥ1H`P~Saiѝfn4t[:\8=GgTU~��\tOEcV
    ЯvIzވzfv~=œC�ph߷hWG+{躧aOLJ�BxYoQ93†yqX@e1vLɬGgk纁ˢHrgPn 8QbpE`uϻ2
    kEJDbYNdF{M6Eu{(Lv#4ӾZ�`z\I_Fiv0\);5ZQrtk/$
    9V�	S{$,NRYyI*.b7tn'? DZUA6#䈗`e8`o5qS�"-ɬ-IG6P1E�.^J4d]=5$g{iSGGx#n[wUslY5/KOCκĀ!d2
    1qDc
    `:ĕ!QjkC5goqxwGWr'r14DpRlmvq*@�s')FfDe
    [*BŸ(̉(l਷;t2bIÂAa&\
    ]^F\]6w"[0iJ&@b~䥻<1ڮ2FZPCWԹmxD3d^,}o@}ޘD83ڭ]:&m˛-))ug/)J5*FsCx4V5
    ?tYIZX
    ADA&k	eM#Nyͺ'*CJf#�'aDsI4N,/D1ztJikR
    @/b߆ z4ŶwwRѥ{Z?j{l&![*bjZnY'C�Flzu#
    ݪVfvN+8B�nܮMAbsXv,~w5�_#nuYZt,>^/B"s&D$\f
    NJwa!E*y79GQ�CNEJQcd$}YHY"q%in�OZjut&:zuw֭V0.oQXr^z?rOQ2
    ]2qDX�8Ύ:l/i4q}yzbtM
    8(cMouWZTkRI=�;q
    NgW<b0�\ж`Z���)1
    n�L*{];FnjۨN"=Dmn6*|f=�
    k{ަSg}tbs|%
    3\V?m9mtyMy#y)ewpݨ?  &*sjt@\nAdX
    "3ʩE]R
    {e	sAK1{s"$;ث~F3Ee/y1D龊b}SDlj�XMEhVa2]UzH
    ͵{C_ѥ_D"HUNY@6TE9bCe:Ԥ{ޔ:Lb1k](r8W~y=);~OgnU/?�TA{ϐOeeqt-X:\cޥ@
    {4
    Av}dha^;fΜioo6`8.gzE0G�]4�TPKEXL$xTc]T=X%)w9cshԗwَu`51̽N)�8cqP_X9{+{�C�w�y@u|ZFWX)[`{D^h`*cNh.k"ܖZ<>
    pprmkk4;X:Ђȭߣ)#Q
    h(HrCl@F/vRT'!#	@q2%v¼"LL9ܠxcsXW9:)M
    "s>kݎ_X
    h[dM’p8WЍb+hjң-Xyxъ)rrss8W7 &"!%mFQ>�|G-͗/�`D$OݜFD$[J;(αnB)NT]�Tv2/Ekmsztp@OG:(%SLۤ^d8',^o󲺶1U8[e8y8tr!4NRY->rשzҦt`;DEh\,0e0F<8wE-H-9�\,joXKF><QԿ
    ,4
    eDXBD6iJ1ۈbh�P0#;WnXj6܊6 zG\ ҋQ0iESnmCU4r4eI4�~٘�N9r67MDLN$MM�*yo[~uJ&&�48[P,c>'/]A"S<ER$d`7tZXD4Ӓ%<"y٭;e�ڹ!#=`X
    Ҫm7"5XOt(N=bW􀟉"${FYv+ ,3@eL^bwBGS|sqSsoz)v,"0afjvȎt#[-x3#[A϶!�Xc!.$(vaBnWO⋩رi)]nw>DyjH25J`�yM�fյ@ӱk
    dž֪Xer�jiaʖ@u@DM][p]%D|@ъvjo! Ѝj@39:B9'Y=G�>�ZL{k-\[7P�+H`I$
    =%saG3{AʬTh-9H}Gg"tCD�:S�i._?tI!n2*@s{iIo>}�oQ\Dd{:n>q2rW3NhR\յ̜<yS-
    GVzQ|3jǃ+(
    
    BbK.iwY6'"loP12xwJ5"ul2De{Q\|=|!5Zg!BkDzN^ʡ{{ob>γ):(5g؂`C*#KO ݸ8
    /P,)E+n.;>�j~OY|o䕵B'p31Fs	%ɐ|З.
    nt@t<u
    KɆw'@+9:q�m^@den#z0tOкT{=*G-%9'M1δ=鱍
    #ZY&I}�d侙t(-be�OE'g&,qM2
    ⵠ�(?5y
    6(+d*b	80{_Gi$ʷ)lGth?t5|h7ݙɏ�'ʜv?sW᪚)VU`
    ]DCэx'yihSOQMZM
    `ax+5�O$vڡ9Um`gz5NДn\"oa'86K|!9lK79|EO`k_}?}7#|Oe.-z|FȆ[x1tͺJ݈e&_麥=%ժk$x$P%9;J֦xĕ|�yauDqrڼ߽tX賛y^@t'ڲ{M:%G{j
    AQS)�tBT
    ֺDr$/k24A}�Ugk4i'{P}]'E%/hnk-U.Lr\Lf2YxZˁxv'/$Gg
    *s.a$&МΈ@@ȼ9\_"1˔N,%DDIE6.{N{t\+9fnkN"˜WD
    ^B
    �ɮı7!G=k>9E<9m9TR<f6]SDLqi4׭xrl&#6wS#@U\PDMVW2!3>Y!a#FYH<VgOVaPX
    T?%l{(tZ{4'�l9�X@0	A^(DI|_<9UYo_7|cmB.ql=>tk)ko!�_8\&=$%[L8R*QWJup@2WeTZfs_=fH(Hz|<cЛZ8u@6(<W3v**/ ia"f,{U`cPo60D1.y~j'Z:~Z2:(4UVr\wP&59IUQMb`DX`*=Lsi#�bV!{$]7^
    xU*aImU='ь�B	N$r�)�K��&I`O\ibq	hKYE@c^iE@kFD}(Yᐷ{sѫ�մ޺_tOix8kbHVJ&tpJJ<Fs�\Y+e`Yi[/8'-aD=jjB{�>TGFCdƻ|~5@7@&~%&
    i=9�GUv�]
    )(q#&쬿w*ހOM*ץò# no
    Э7/\"5�dP�!8E̫K8Z9|;ʔ#Tc<XV'|JjJ�w׺4%~6^?8I:M!U091TV
    0f+!RBc">8eJFq�!
    ٿP*2մC#n_c|rIyX<D�Wd((+&2`7ph
    @x` ¸
    _e<ReEl_#tӭtcގ4:B�}D>vLg"8Eꕔ2#
    {M&P}_09uLE%]:xI7׵îuh)Qcdc/EB5{`�[�@g	a,!]	1	3Q
    M[V�f}<{	RJ~Lv?&tX/YLɺɥ-r|E03`0ܵ-8oVIC´0V"Xd/́�qՖ_2+6gmj}^s<JMMuO+�:4�?|6ƖZkXJ¶6�يj9Q<PU#`ٴL1xrCEX\sjvGUJ�ۺDŽNB\7a zo^>Rx+�1*�p㈙@QtSMՉ:-~OnH}B@s@(p|=ENo7%U0_EW]V},g@0?9,(&ڹ}�Onn^o?%IwU0k.7m'mM4Wic�Xsi}\ ?6`ooʥNn|z #ޗ;Ѱ~+fk=I'̵J60˂f=@TDkt7Z#l8}X"b"؜l?>tWwg4pNjv&籅jr8di08ony~qrg5uQ^zn#B7\]]yg<WP=9JvlaZ:04#(l_ގ+�SR
    OٺbOܑf1L?K2)&*Lu�pc"dSt2
    #Y ndK?t�vE	]?VL̍] ؄p	CR#�i$zjYaꒈ9ctO""y<xCGKacm5x
    
    {8Unwa	*WD;3N9[ts"zr%F}.Ku5v>0<'	eCPi[͔Ȟ:�ءܡDs74-�X;_cC1"z�:4]^i�N0-Ďl*ϼޝuB;+=Fbb{&3"9N9=
    &B$B; )>
    o-,8w_ڳ`('rȜ3g̨
    7@gԓ"?S&-.9%^{d-+ "yHPA٠t*]7W?ME�oYZו>vi°�JřtN*57hX8sqzfvUN@7`8#�IGpc~b"ivp80'kϱX6Cꔆ�f񃳝e?8�sDi`wQg=%u,ݨ|-ikҼ.r_vcE s�`񟧩X?�l_F|ND/}^hbF&
    }LxDaW1S"%qxqLr�<cآ�1jlV
    7o9ޤi+YTZW>Cv}!ͺTSOK"e=;{V;Z
    '@(Ŝ��:eJ6$,n=w,�+<8x˥2"y)Qǎڗ1W29Û=@),x</"߼|&@>lc'2<v7#բ=RkNf)N`KJ,b4mgͥWDD#LNOx*W8z@‘\ZJgO=$-<hI?+d(o;h
    /nf0w8@{cM
    1[&>"te-)^mS<#g)VS5]fNl˽5"x_W@uHT`~%Ā@՜|\b,r>|}~ IV�^&_2qiam@OںBծ}wRvo~NE׉�:ːAEMK=/>,I@a'毉H~Wy@=b,cX׆˽	O_v6tR6X!
    :!")m�E@J'MR<)2S/�L/_p~/Ol.)P͑ӣ9GNwj�/oFEW)0VwO:E˱ ӔO c4W�hRI|%VE?zٹyr<
    r4z,b[�xUXu~p_O-o/P1#穪_hR%{ý4C{y4F>"jZ}$lX]pEh�dի?G [HV:x^E;)!KBtz
    qPaΣAǝL)WW|Rtu磘da.`_'>D⧟u^rA�ߔL7e)F\{64Q3�jP} �jAG" {8z
    j
    V_WC�}Ƭo@Q	gf%3!Xvu}g%Wa~Xܬ	!-2F'M8Pq)~랼,9j&BeKUUTQDD:nއ◿R%šjb?$#v\ÌܾtY)X8ǽWSBs`'4)PF@9?t6m͑WPӘ|�~bK
    TcfR
    IbXitӸWI4t+|FPק$z]HvDcBâIR$bjgB}isgag;HgzuA&4pݽ(&cT,M|:h
    D%)	^JؙDRa~ח8Ϣݖz�.!XJ$ZUV,G*nuL?i魯bdegFDS Z#Agn>Sx^-T?GfJ^pM$ibHK
    ;CCEHcܐ:5/l>)W6j~XשjP! Z�zԲNeZT`X�;XJDR"kpI^'K<efC_fȌ~
    K$92Ÿ}蹽\`lL>TvF
    CDDM#N6K;<TkMzoiވkMJkgDl]s_ȶ�k�9|h?c(|ⶫ|+
    ,%"wGnÔHJK{\AcDc"Ue/z>DP/'Y2bUwûa!k3üyAF5G:�;҄!T9߁yqh~ٽZ򱛢ov0m3ej4!w.KdV)arv^Oeǀ9'M(USg5z|�pIK\N7D$ΎI@x҄v^IXaZ.OϞPtQlY+3DQ`GrG	9V:i"
    #5I@g']ntQWiHfbu.N|w5J�GOJ
    8%֮†6^B|ZVVU16!Iw94gZ,it8P<3
    :Z>NՈ1�$kMy1q'`"[O#KECDpA)L NIaA.=/ih#$
    Z8tXҼyPy|e^iWEP*NClOfϴoUVxlkOsk^vLlQsͣ\KC~FP{ɝfŭml-.ЌQy4ZȏKWluz,rd'cSJp{;E{.C�'+D+ӽfSm}ZGn薶[K|$dDVujAg#L
    D\Рf ȚP4hμ!�.e�r$d3!@5&hWcN.O7G04�U0{$9+zfG@٩>HˍKM7�.0NS-9wӉ�f78IhP!i	R$gՍD^@mIz)ta،ponTgqyox?tyUf\z	H�LM(BRG2ٯf.#VnRDt
    ,YN $殙"<!"zKkSǫ1Q�FNZQM՛B1P9US�
    9dZ�)fme
    .ˆwV5S"<NYH>o߿`Ds^=EQ-K�,qJc.Vc/^31G>Z	Ds৴U͖?h6Iٌ=ZD$|U5I"*Nqo褅w�:{Ъ0AIK~oX\GxX8Nw8
    :/,:(J@eg&fTZdqaA*SH7@y21@:h@�)%`!->u뱸$1Ǚ/8*z}!PD\r,Ѿ0u� JcKy32"X)GHFJI7Rm>.,WtW]OeX4t
    �?[Z${5c8BD$>X3�tg(Y@킷,JKJ6~v]D"%+ܡZ`oyA484lN#ʠrb@3_4M9_IP;!""K*C^3CU~ڟ>E)[޼/d)`cZmׇoƐ6'Dg>z	�<lZT\a}+)GD$FжQ,^'Vq&$"[}lSAn7t<uY^!*]Gd*?Zj8MVg��sB9;SOx
    ;rougƙ$"n{5"`
    ]DGsT7Bn7t*Z5})9l,�WcYJMD+<uI2xŐ
    eX}S_,huͥF3&�o7ytnrqN+]b	�H`cWcrϮ)j�ZµVkM"ϊAQm0D]]Cw58P5
    B�cm	եo}R1TܸXw8VG&Ԝ7*"Slpr|8!{>.p]~,tTŁ_(]N?0�4,fټVDX`J+($$If-5
    7%`^,|Z\Clp䶡[N^=	Bkٖ
    vY.�CfFGwz5'ZBhtVSDX(jXMKqb}<Ϥ:K5X7mV"Z5^nJ$2Yh4
    5߮C�N9P�+Y^u7;{iH}X̀DJLz<	PJ]n^Ҋs-W%/@}9t
    :'S�и_~l,u<��T+L.;Vwfb
    j Z	6j^W/X:?pOډ[tD"�`m,&OVDg:Z[L
    (ZX7wt[P'jHծe tZ~K~<E^1Y@`	р	qQ.Ƭq	EQ8�ķ"Wsm`2nJ$֓X7YıbUTOpv %W	9+#$5~\lzcV]]c叾Kqp[Z@6#wyݬR.Kʎew76k;K*29gY<{�A5씶`霦r${1t\P>*%a%KnIJ=rI`~ϱ7DzπJ4	�5%,,<_>n
    eir+Y>WEEm8/D?~c.pQ(d|�S"-:�gtb�Ղ>/vx~s%BMٽLe/	wGxb-Y%EϺoޟRm>t׼GDKq![H.(a�n98`�SWnU5B%؊>URWְXs,9w_WunIqu6._pH�C_Dt]HDBR(Z>IB3̉|(`�MLPk�4*urmqΘ̵0b2HZ!fw
    |St�ױO͠`JJS}Dx�X.͔0֔,K:`@ 0_=*:Jqr�u[�c@)4җ(@Wޕ'e&YhRon׉:5w_#j{nj3?BZ%
    >1b	!`\Wj*iڨi$rTDfph#;WMafEH}քNJF	]Ed,
    h0.hg 	8OemX5/�^E+}ҒVep%Y1ސ&ДEzȖ]U$Ň1fm붺+ZYobu}
    >BNU*C(%"?�8멦|Od]OcYv&fNM%eStۦaaKLBe.zV	);Ѹ#{Hwfqei-Z]Us9;9^YR`
    "FΕ1ؙ�VG^n4ҥKiK;9gt?,'U͗"Dnpnu3jQlǙQS7|pJ1ﳅ:ꎌlk@twOkPuGwo=afNmvTz-i
    ):[ƂO;o*ELWnmT'{R3g8/2\8ӯo
    R
    �ˁP98*�r̲s:q|${(^&fpxT]iw)T|ɮaJ#G̷u%P`	6z}�;ǝb{9�hQV$e&�C,gCTepRO(+.?ARYlg&�l@4_S:϶S`ZB:42	QY~͗ABhW.E8�k2o<[FܳX@tAf2K?$T'Z=i`#pFc=1߮- Ū*5و:rOÓJ&`Weubdiܐ⧊yb~2Ksн\Y0Zf8ӾSx{~2.�cN`ct{5`)YzHڃ;jl>i|exuw2l':X)ZהWB	i?mˊof(ANaT͹	m:JX
    Z^$={		zy�dKv)DH~pnB*c~mz9p\˻z"�kK_J,:4ÐI7ߔU\œ@e'RobZ!9Z	Li sD<#Lxϰ
    i).B+]�IZtCP(�0"ԯ$[䳮뺒lrxoʹTf#G�2ƈ${=hJ#R
    Y/3vwI
    46*c(IUQN<ɶtl.|p蔑W>:`
    X˩5^4fMA AEdlnTUN?V'قU�6"j<FK@Η$;`'C݆T��qHm_y`@ogOuDU3<ڴpȾU4uI6w5jkrY-Zz
    6IR&Q׃DVRd,:W]GW�d^ũ1b7qzѴ3t~|ݭvM&$SmXp.R-oP9^je .vàӣnh�!\hP}xY!'Fc]ocl'pQNoA~O73�VTᵤ4dU&�н%yP(#rA	8vF'}9}(,�ف
     "+L3}\5]#2;EuSsPK$=rKoW[�v2&yh5A6
    IAwm4�|4>:	@C.օt	K�R#rlBśҡZaSzS�&UhX7d
    'hgU^#5r]~6%jBN#XQ]RGbU?ȱpmg|%�!'od'|vI@}F,p~û~Н�]ˉēgc o
    EɁ1.tLDOrtfat@7h
    \t^ټ3pc$oRw	0,bhR/C_䮖B~CGisJ'11ImE\4FOoPkn<1t*Zn15ZEl\'ǗQj=(VHWZЗ.0>z;]P[xc<vY'y֎outx~[lr"\UB2Za*LdϜݱ%z^h9<($t`Դp|9:"v'`XZdW_`ӎ{؁.BB.tOI4<|x__s99[QM:Iq)OnrrieJ5p1kNľh=iAH|W_@�!0.]*t~_
    !n(n
    c̀iV;֙"Kijj+RK(~\_�3>tXZ
    HWؽ 9 떝na˗[+QW1wi<	;_{4IHָ"!OZԠZn=>
    tL8QNY>tI^m7u]wtFoVjZ*)sbI-aMvZK4Z>dSkT'oZH7;*ז%9"ٔGoNmH+Ō1{]\Iᆟh4O;1
    Wj6Kq?U>ٷmwM9H7->59""*SqVf&ChD
    EЛxq`(.E!FVa+	eYQ&[r,RIU�zN?I(P<5 _]c27N_'M]_.:}$\׽B!t]l_F懲MUEOiSe+mS8j
    =m䔓pw˖�|f)n|'$injo_=Nl%zNOH\}:*bO*M@uz$[׬`<Yz
    @kó0S|GII@I"ʏ.�
    =Wmq잿"PHj#1=ӣfktkh
    89B۹֊*p饍B@֯NV3@AR28|}N7Xb;ޱ ݮUMͳO?gVP[ug	hjYҀ
    Z=Ѽ@.v;"]kSEU[|떾$u&;g
    37}:HD?	!]ωwΥ<^n.9O:NǨ.!6$[$v	"LPGLfa\t>/Un`TA,K5oW\7/bciʭog
    P(
    O)z#|g>OM|߉C`J7�8KgNыRcs^('ցs@R;]~dH-|5Jno"fkL9XT4-!2KLU5.9إ\GyLvCIeUtt	[»t0tK9{jԮKr( WMO~Q2+]R\"9g-G"-WeZ?A�LSwl;|%лM;py-7u`##8{$Qd}Wco;3
    @:{<WEm,kHhOފ0+_[
    $eSwwLbWKanBT_*/!59?lЬ3-[GTB~7.L3vh+ٛeSIm3Ñ0#*kr#VUܹܛqt,?B5n7$p>!⏆N~Go2UTUp+Tf9jǩ?Hjڞ@z$Qt$SRGO*'|25f5>IN1R&o6c2Z
    @-Zi%ЅW_-HvYg[)d4�U~�sOGIޜ!5!5F_!dWu;"FUv`yI͛}:tNŊsZFg(sv7M
    �4D?ل8tF>pHr-C'	7?#f~B
    f^nI"*h4y@XD3�<G݌ƍpY,}^@'I'I}O,a@e3Yd+mI�9QSw
    iN9ұN+׏P<MÍ{^L'//F{8=ZN;ܛ4aH%y"X}ߠ#ya^BUd�6u\rMBtV`RBʚ�5YDAGq[S)H\9+~9~۝dU3tmLmtd,̐mپr]zg3_nBYuMz
    �RZApqmCGW}ˡɨtF{t9K:P34L@Gy�چa-2]b=N^}8ҵsIjF{}>.$!Ū]XYNAW'ia(D}tq>=ߟ^'ySΙ9G'cMP
    ƣ�:]M?�.1G(u2e:my,;d_J9^;	h3h}h;~x$ywtFYUW?s_}Rtr朋x	-:aA	Y=
    9WtM;N>3PB7K`a]vzϡZTɮN	r?H|Z=(JS69Sܪ"xbLJ$8�&,!Iʉ:P.(aC݋+ʗlWXT!{F\vp-=/n;I5ww#yI
    =7(E[#F1U9tkaI(ۄ.F>o)A'bސt;yz^oc\P]a?>a7
    �7Taw7UޕZX|SUu*6IZnLB:ۇ"y?J1.Бojw@w7tl֔M<'{ECoɛҌMnbK5ȴ?Cnm$"�C7s-�:d
    �b�	[~:6#@`RU3to^(J7{#9씞@{+O%sZ����IENDB`�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/ubu-install-1-all-open-source-applications.png��������������0000644�0000000�0000000�00000053767�11773544727�026654� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������ԍdo��PLTE���
    '"*�($7.
    	*/&&&,9-.35:8%7784V4n&5F#?v7M�Cx9CM5Po;`{LLX��UT5N5+j�o�hww�~p*
    v-+DWNL+Tj�tIoW2dxPQRAKaELwFUhD[wY]cS\rXcZVcsvY[jdRmnp;OGji.T,X7f/nI;pI[PmQvmsd|Oy+&TT+YE*vv,p1YO[nNN}T~uRllt#:6]YtkNKVhwxno
    ,65&3+U
    K(ef)PD7e
    s/Y[XZvOwmMHLneYnk'+(\�D5lw({PMOeZpjcUjhgQg{�7*.MyTdWsOo04Q|ڋ̊/δͮ2+5ЏMҙhйMҩp@Pm
    */:RpOsQsŏ҈崺Īđڈ˵ӐМвȷⵍ䳲ʾđ̳̒հ+.26��TIDATx^1��@k`ȇ9Bo}:&�A Va`!�Ec�4O(A		6^ao9/#lH.!)$EBt6̈tRBuUc.7"&n_lvL~R4?<
    žKob8eFG˪{UȂ#
    
    D7{1WAX[
    PyΊФ>KLeL$ӣ&Gdc[;Mw}s8>P!�@&�^~zXNMNTg,~Ѥsjdw
    '%LFL ^s$�'G-&i穨~i?&O<;i/dԒ/fĜdX5�bB]N9/yVT?nov{<>>nQw:=	VLuWX&0RWl@zӕKyJ1p|@ץ}*|:cwibs
    1eSU3Xzϔ,R<ܓN;R*"'yKx{vPS8elBa7,x*
    9zTR}/?#x	(C%tlWNt;8.<FzYe6鬒BFL2y| 1落o䥿UĄbZ1b܀
    ׈�Dn ?r5B<1\<T4߯'Һ	g1IG-J,f 3$"/%jR1uI	k*q2&R�CLG34zӡ�?Ygvr�%V,fJ,恄}1UbbnjU"(,l,!*nXkIN1߼Ʉlb2W&�^wz1^b+wErPTF(cY.�l
    KQ1w+\8G{ac^CL鷏k|$ox1k�AHNCX̊c[^/ia[8njCQR7kd*=כ`x7[A2EGք6&k!ʑU<5]9QL]Sw=3fi8"X9%u	YzCK%ݲ8v;DLKbDw_s]^J/`hЙ{
    %,R2@m>E]#�`
    ކf_F\av1
    †Y$|?1;4JO*%J	/-z`DQGLM&xr驊X
    ,Z{4
    k
    V6iq#ڋ:c)]I!$,RCa	2s(+&M$/6eYy~HUBҼ t/AM DO؄a°'Rkn1uqN;xR\q
    	\Q TA=T&,(ԝmystL!L51îݔfݬ`5}:4� Haq)"D03kSzOaan���`}E D@|F>!s٧C�`�`(`1@l+�_bb & &		bb}:6� z-&'ZInsc?Lxbn*sO
    A}	tbic0)B@t>`"XPHYo{OM6JyIU>{#a>TW[^X$ L-Ƌ0)`nf\w	<f^L?</%,}8qz0SfeJC�X:6/za2fkfmYs0S�8�?w[\1ca0IO~
    =80B6St٠p7]rK(4Qm"GJ%h#*wNˁSYg>lu="U^L>;c~btso~^w4VI1牁;\]S�3@`#5# lB2?u<|w۩ӗmwf];1E>֊+n4b
    �^LP>^bz5vzb]/ۈ9hZ9\k\u7ry/<8@/@ saV"`jw7b=׸nӗaL?}B7`40
    ph~ybt͌CAdK
    `vƍR=#|NML9}j#`ȹky[Yi}I1#hO}#mb~U:1"E`eϚn�47ˠ^L9�vb<#&?@O7׭>m'cPnpIl0–O &@s_rΠq#Xm?@)r[SrݵaOi֫O!McB)Ē[>@UyhFưѳy#~cf>
    Id$ֳ	OhgWeO>b.;@q'
    f`U/FpLIlLO":`<ERzfɌ$*'4Qc{eŮ6&&l'12…XA­{"VFXdt-'v|;dp̯?<3?v	`FDw|氕qi4%1X(~0	dN"'(0)͍)	ky	hLь|g\ nG-ҩrC08.]=Yلܹ]0/L]Rv)uKyi
    )EhLa+I=@Sh
    A_j"JNR3.\ECVTkyUm�O	A0xb9]N//~+Md71gs5�Ln}H-
     ]fJYE֊wAэՄXh\rwEVX[ˊN\,	Av^~u6XS<6=%4$6iUP)j0ۢ$j
    0os0=RLL
    0a`j@--|LLF,_k.ƣ|ݧCs,A-jI}$׀))7Y3 |:0]M&Z(Ѝ)eѧZ]ҫ&-FBvx1~<_VXQد}y*EXE|^ͫ"8�bH&vMJ&(;DPsH	e11A6Ƹp!A}?Sm+`^W]ʖBtyV_&gɥ9j,[]CEl\0gG2='ZSB)50$;@4^] N	uU{6yn[Y-OUkfjwt6OFF,j;7+|wX*\*Dф:mC9qlݭ2t9R7ȁJG@PP;oq"DJ�L(
    yGmʖ,O҅4	b<&GO?`j{>`~>_N��a6Yl`BB.:Օ$"U9W*}>0~	L`];�(1؄XI	g,\%	qOU}w0sWO'yax07uo0a!R,
    
    p6
    "j!ZB1;<ci002_0&0պS]a
    %ԕ@yc@u$!V5Pă@		tJJ&ṣ©a'StϴvZ"̋ژ=QCqO)N.FH-75R*:SD> &(AdMY4]E$NzA?1kϛwG&_{ven<{ps/EOϪb0+�"D̃_z|P�EAdjbKBDO]{`
    D̏:`ȀD4Zд8jHS1?b^wsJ1)sb-̐8$1-�YT"b
    "G
    vOZoA{"!4ȇ?I;sjB37Q̂Ō``Gކ0!�v` gNڝ4)a%&H^$jEM5Pb=0*08CuSBVb^F:n*눘<GW/&/`P:ib
    "&xyS1yrǴJف�z\z0bV'9+wL
    a~BgȸF!x
    91+_L颉Y1)P%IS1sYɁ~�mXC!HIsS1n;&9f! blb^#G+fpfQS�ꁡFb;gS'[}]L#[9#*UJٳ1sfQ-fv$	U b&D\BMZ̒Tz|_F)ekV>ut\%aj1y%PTw@FLӨ6ʄA7f3Xqݘə)XeK$`ELq<lWbYLe؋*u/7)/VE b&{Y?)VB)fDLn&/R.b+^=Qyhz�ʞW
    Fpac1ר)b\RF<Q1Le?JbagbbjeZL9�^LO!&}*ic6.e6Rvb
    u1O(eY<~ps1[Dp|⳧ß@YtES,Vr
    2i0oBL;P訝jƧ&/~\ҨDb{B)baǍPfZL>RxE|f)&W,cԀ2Xg{h
    ZLXq+aG-Kl[Đe9[)YT-|FBH81E1C,eq*:#b
    "f@KDi hpA]`0
    0�NBmYgRb菰\޹՗׫b:l)&Œ/,usJSիwӧX!jA¦s0DW~]S1iũR7o޼_ۘRL2hωY6Blb
    ]_@
    pKgi9D(M<nA(x?xۯb&,%nPJMͷW=?5̮]y`^kǡe@aw&Pz2	KL;qCr
    .!kց-4]}HJG$-O6D=~OߓÏIr1{kT:y�'|4i"o*Kb˅NL0Fm~߿|<|ŤQڧş5ifҋjB['&Tj1ϟ?y
    pDbf.q,귲a!f/]bI!gOɟΜJb8i510<=zg&#X1,&b"ΤtfpMd13/A/SLq
    u~Pf+ Y6Ta1	�d;� vӸAb2,fm�o\.i\$&b�crc܃ -�?b
    {1\� =K@`DekCa1YL^&K%�VNLGMWSLd1Rhf�$µX,
    Ӵ˲MOLd1GG%3@cM&c
    !ɰ@?-dZ% .K2(eq0Lŷ}E*zk$/#bbK$&׭/%b*((bvm^f,
    HZuKSNevX}bF*URkܑD
    ^yZ4Mh,
    Z\a;;Ub)à2W%TI^OOOE3Ǡqv&DB!R6v	iWW1gXZ Vjlb̤i(" .=`r߰F0@6fwggJ61aZ~$fԲ26]Lrs4saT#fh:*ٲ@Z.&yyz_LL"jRAXh˩̿<3fVX
    b8Ĵeh h3ӳ:VLY.&WL6ܪGLż߿B1VvH{:~Ǽ/{0{[JzČ,+>r-jޠ
    6Ձt�dQ"م|^2A~R)VRNm?C%b$5~V59=;;g/sfIJJ&1A&J)bfSYZ jVH?ge
    %O7*'J!JHLzobșݰu}V,]'�D>�uLG18UbUXz/OT.&.)(SYk%n|tcr.&v;-wݝ*Vybfug&MDAe1G(Btfk%&yhޞV3OIWAF{[b5)㤄<
    HHiY)�7$&:^ÊilK9B(f�^W%(MNJӃ\D7NJ
    q9HI74N`$@WV$$&8L07,&H̴e֙IfT6"k+VjuR0!a (f`l3<nD U=c.EKƺE\bB&f5ȷ_t4h%
    ] 4~^:gl\
    \rd1IƤ,|e
    T$.Cs$FSSxcż'%~-`[,?<qx�%)mxEᕭ3Rҙ�:1{!ƒȼ#t@I)Xqojb"Ateh{i
    HByHx4c?Ţ3VI8lYJ!_ BNt-bzE(?C>ŏI<[-B0F+^Y
    ^Stez4Kb.]FИmB!
    WesE(+h
    91$.:"?;yAIL: iRVb#yt,&QJ:*0΍}%
    >s\p]t̢a{Әiγ$&#tteb?za1YXTȪ
    bð_=a1WbF&י?X°Rk'O>N#ӟE,JaXL9_O~sppp<񧓏>5a1+?L&ᓧg^H0wZסwbrM|J!G/#rf,#v!r9źYpLC6!oF`G	÷~)fjW?ѻxQ/&u~0on[9L>%./#g/*S3*9|G`~4Sl;aPT(9?EE0͐)gWѨvQ?̨&Kz7#,p6By**[n_J.((**	BTa@ǐRP3*{iS)ihR�$CϦFU"Q>yʥnrBdaqhTeSfB*We`J9�T	52*>8*ikΣ?0R40ѤBcPD�:`#JE8QOt퓦</?V
    
    6,.DBg,We`*˜d}0h3]QLLI
    K=OY;&(*ZW\.PP8/Ĥ1Dg}0OLu)˗v%!
    *CS4%G	!3IQV+;L!s24L,3UQL
    'i˻˰?Vj
    StGSR͒l$ lʎQR̨f&s)zyC{_tBIL�K&դ.(2g 4(Ye&1e2|0ã %h)@JDZ	MTlT"2הdFf	
    YBn20*
    hP:+Uv�
    3_=j��2J7	HU [X3*	K)>}^*Lk2<8Ѐ0
    ?�1_&ф	$V`JR<NӔpxDȑuxs``L
    /!
    gJl,LA
    o`~",/c-6+?^䁩JM=
    @v'i{~5K"YA
    o;y$4w쫒Sy:Drtooo{`
    @	
    l|։F	^Q1$elL8Lt;\ktTWSڭ6ɁY$^h{v`jHvV<F0s)\uej`%}``}~*2%FTRfff>iEX0g#4_Ls$ff`Dhf/�>"f	&?6]qr,Y|wv`J4W<ʢ[mo`lg76dI1QI"7_0_][?ګjlЏ;*
    yslx4nڝ^c3Jd	qtv|Z홋jX"_	f۷BAY[YyxxﴬڻS`~g\bTӛ#66o{Hվ!=_VEYdhDA	34Y`]F59ym6sq-4̃y$(_dJ1Tas+#9ZF5yAwnl/\L0_Zk7wu$hRGC& #8i҂}\|&)\/b
    ggIzs@5&x%nvV	̊z;Xy1w_/
    $BPd2A|52d.z>(k*JՒE>yˮGQ2`)t%Ԯm*ZT:hd^!vM�T^df8KZvg-#Ly>'JWp`I0L\il-[++m`Ղfuü&i
    DH%8B8.I*6\y6&`Ru`3DҐ(]1!v7>fxu?J"lQ%
    }gސi+Uym8LX8E0;[+c.}0jA$I{-5
    fxsbA,D;fxIT.U+f01c1	L֝;%3�+kyÂƃ.e+3T=+f01cY0iں{f#J·Nʖ	neoFw+p:a^s$9;3N̽rbݽC`.M?ʲB0ƃ~oUH{LxDvQp6C'2NL!0ӟ[$c) ?4�l`RqyKOS%en^0eN\&Ŭ`2qȤ垙H%AU)Hd0]7g\0)q`FE0GX9̯".q()*dH|04fTsdv;Vwk@Z3*92,Z.6fTe%RzwLٻ{8r3n@	).p5U 	�i8H�+N<(`310?%w9BE_6gRIC$=|OFS"0#)3L#)ы)ׯg;3|uIx}C)�Hח뫫`z�#)lꮮ~'�GS"0	ti#^P^O~s0LH`Jf!͙py�#7RC|�4&*eVM r@xr Pi.l?�RL{Ӏ%f	<j$E!=@$�;]}:w�*t}ࢫ-e#'c33(7\D`v><ܰKEFv曦2}sA΁DΨ4n^{HfP
    ]=G<"e'FEh`6I-ĩV�) *jI6zeVs4%CL=m*LRv8W4dxcKUs$P	[+|0yl'OKr)KlQL͵?Ns~\_\2usp]N22<
    *7DNh#0
    rk〹xO2l&U0d[0//dOۓJfjKV*ϮYmW#01{\@ϸas&<:j'Li
    bPejj e668~5K-fNu0=LN&',@#0ɛyVLvgY`"+dGdrrڶyC|?Tm򇾳q5"fu	xa6Ӆ]榡̘!3Xm777χ
    eҼY~^-Bi'!gVa^\yyt֦/L=mۉ1&նcz.S'LjarŎõ-|g)/^	18GILȫJm0=z闯zNGv
    \\L3*-äy
    N¼㷲q?6Sb0j4:K^
    �5cqFq�?⏒ۭɁYIUӞ]yUl
    3hx`\E@żcɛpWr޸hbWWm.$	0TM0DX�E^tCJ˦̹L&*ˮ9ëKBK͊dM%m(;kô|(hwm[N0Ed{aaQIO"0ȪDī@^;0+0ɊyST[$(:ƖeaC|I##0xm0`ױЬԸdI5U
    yǒBd<aNd�6)0e0YwIŖJ&�d?&	&C:<hbP1ݻA䠹&g*s%TtXxdP_M&fL*L?Dule!.͘0欙NفDW,!0ILMujYEvx(S`ҩÄ	9c0ϢԖ0Y&>0z	
    x,<Vvey(!-s[&l'OsB=Q2*0>(PKaV>ɻf6{L
    FL92k'%o$uJ͗3>ՑeG"0;纍aSgSD6f婎[ΕjЮ6#2;v{cmB,0Nu$
    wnGDf̛T4c�؁oaJ$eU0
    |/F']dѥ{A@DV$A79r1kb8w4Khbb2TQpBl�	XeTG)/4{>H^KhmBV6b^bmBQP8(]_J^YQ	:~ٻc 
    6)<}n{le	ll)(f׈HaBd;e/'gb\~ yrl0oB	2B
    &M�]~&!Dt�_�h(`,Z҄ğ nǼev\Π5r
    ha/tI`f{
    q`R;!$c^Rga=bmwjQK+Eb'af %Y}gKiī|% 2l8`𲠘ׯ<Sm<8sA1QL@1
    <,>)	&)yW(f9+^APLUJۋ9fOrدGlZWmyeb8LKjSin^,9B3sյs]/K4!2b$9;;B3nZZLu̱YLl2}Ŝb+q[*Bc1#m37-|91Suղ^lUE&IpbXhbLF4lDLPۡPqP[y+֎z)z%1n P+hlPP]p71I"D/fDY,h-ZO#/[Y+ly_*Jч*B247tF7\7S;\$&^ɵhP̧b~K`+1Wlej\G=\ɠ\" uQE_5b&~G܂齴bt3i)073ojL)l="t1ȨUtRG}%6o{
    hRC㳴ׁG܂;4bq<h4ԩCʿdR3J.CHE?`ȧ(.Wmd~m?ʉvHw{HEKkzlp
    @Aٶ{Vى*tFUx޷d1)1ub1^8mLu1M'fDm	6rwFr)UGժ:ӧTL-l3>"-I+h|OpbJ^Lk[KMퟦٝb"(*bF,t?~4$T<&[18"R2]/]`6g+1ϵ	jOD1ʑTubo:6Ig.f
    !
    BSvtxQ1sn^-tb"(˛*kBa1c[ޜD1$y%']X*
    hПʪgIeS|Ye]՛j9j
    Bt.?)7^LC,G=TDY2^2G
    2geSIkYIjv>ln..Q n (O_63]r$y>
    0o`}6{(ӹ9~eʂ,$'Gܟui<b~81D^b�	gi2`*b53CD0E1Әe#b~1"&,cv@-Le*GZ9,g2վSٜ1J`
    y (fd�(AP?YK.	+rJss (&FO@ATi}3I=wꠤu!PLM(J?c  ߘ,fEsypG;(d1C¤[A1҆7,1?v$Blc$70s3؍G\x${ؙax݃X<NÇwN`)HWW]4kfIi!%u嬵7ӛ#@:OUSR[_d`"/W6,ה5/[(?o6u	Pw	!n٤a..Y`1>XΘ09nv'x�	dTVJY4f<R8uATʾV)L"Dd6"ɒ+3?ޜ\,mI2!)
    本XZFMSI{
    #Ս:erCb`j0QwM0nT07 -MMڤL<6.	L6'QQ~U(!nFJ3io@SJ?
    ?mU3R̗`v88c,Ӟ,RL
    M0$Q
    '+YF#M{a9OkϘ1;
    n*醫ۻّAO0TTJ}?qhfwJ99fCEAG!f=qS]V: ̸33',nXYCX6{tB^ˀY	iL}L{tOiic99͇mkƏ
    ;$%'}&mo%;41Θ.`Y0Ʉ
    p4'Zu7~)KTTA66ʌMYWdvbԹff}ieL9S;I;NucZA_|lVJg@|?⚡4zG"DI/歇5q4c?1MeɄ46H91f)JK?BJô`GG\qU*?ye8ʃ{RY`ҙEl
    
    ʃ“vF+`p>t\h;B]nᢠ0g<6�S{ܝfO
    KeKcUS&4	GXjpmXk~ԓ<S8"Еm͓+ءEAQL[gb)'LSp#n~9r:.ʕ<|0AFצݿL3T2f)R]WSʭ^/Lbͅ+XR dT3"j2[tKY$
    iȱc{Lԁe:WZ疲%Qy~i]y)EA}C^6a ?=7}ЕjyLoy0Ŀ7?5$(n~'mO?qi#Ef5cvޑnᢠȂ>Iιn0|l1r1)DuI)Ly]�=Dk+'%&]#(<V+.K-	}~qP]B"& Š&w*yxI%�.H<{_B#o02ED̷8	N%aI;q7L*`ү >$a8lf_\3E;t䢠ȃj`VJjZ79YQyb}Rn3`V0U0q0+*6YVYV*۰jL@jiS܄U`&߻Z\.t#דax%*a˕16Y>$nOw}`PXK͇*u!`1xwaI*Ğ`V0?jĐ^#Cz]Ĝ)&RUb[�rLW̯_]g;Th!OP{B%k"HY/K_b40@*3Y${x!JIM>m:ɽ#z3fo|?h7wT#B{YHYQ�SLaL^E=w%sF&(7
    Eht~aW\Y0]];XX{(MFUMpZhصZ,R ĥ)*a	G*HxFA/DQXʊҗTl2;${x!m/25	v.f0/P0ϫd2ϓ
    !L,TWdL*;Ӱi&Ab0`Ccp#E&``җ8")
    U;"ɎxMa8{hq6z93=h׃?O*>O48$1A.ODL
    iv1ڣR4Ḧ́/qD�S buy!JLmF3>m}s(fn6>\biRÔU4e"-`"PI2_}&r4ELh,�LYG$0=L5LR|iBh	L,֖OvuF0']z&8e6&(+4p'_
    &Rl(L=^2, /qDPHd&ť,*м=)&Bs`™Ө%8;z0	1ƨD[D`BQzË5z#N%0J$LR0yIBܙ,diI1܄Vx;{7}uOnT$Kd"4)&/]&g."K	Lҗ8)]"8@vI($wx!J^o$"4&u3c0/P0m]g\~=Th>B. L
    .jTb^$LKҗ8*]"4@*3IU$sQ2lpՁF3Jgb涿qC/iR̟S]
    Rn&ɟ}ݶw$P
    r=U0_6zw]|~W›UmU0!o\ع6B|se`j~a0c̚?1>"ժJ^H+ZπiBZ+[V`VV`V`V07j-kU$۠YD͍	5/Y`V0/}0=`._}ܲ`>n.L:BHB.BBSV%^bf]='oYf%IL.(ucQԠMnZ%ESܸWof@=\<tW@QV$GW}$	Ubk7=NB$&7zW1çMnZ%"Qq#a0o_S{W�&d
    
    B('BBWV%/KLP 0=Y.NTmv[ʔ$/!M1^Wss`;ʂáKS-4NT9Q$=x$&i	h1xjƣ^Q:@S2KlHS̸ב4Ka$`.N݌2/C!!)IZk$
    28sE<vpwTp$nV&/y
    gƽLkY)0hOl=LcWv#p32&jf0Lr0[]e)ۋKYFBEu 	7K{$x‘|eLAR^Is`v.z`j)ßsChUDHH"KL45')Jb==M(%5mY+Sbό{	myL;ܱ`,.֕$M+#S0!a	"
    s_b !"&/KL2"bf%IL28s@Šﶬ)I^R1gƽL\~{q<!hV(7K[wC@0D D#!})DHHHѠ⍘xI.T!s'7ˁx0ΎBA'>Q@|eLY"";U$07
    3`6ЗOW(VTJ`nvimF.ޢ?˭UMe냙`ρG %,M+R9i˓EJ""n̢||۳DYɪO~4e7>t\rh
    fS5h$ 
    `ժˀ}ǗS0
    H(B,80#(�!
    [_V%0_�es+˨#K+ɲ	V>BaAj
    b`v?WM<V9Ն5pd\@c  /�f
    f(3e133$foϘBԎ[aCDuIc ^?*ay&`ޗWOpÚuL|�aOC8m@3g;jU$rr_plK`!Ձ@ 䵈/q,\'#<2`g}aε<z;Pe*�d(ĴH<+英F¤£J7]}tZ姥R&	c< 9lJX}dbz]F~uɴjPzi]Dy"I{vOU2
    [R)BHC0KvO_,IH)\a�wD}l8M%@@Kt8>Ь_F{}5+J\Z�\,hE
    Zlj.<Ӓy)Rk
    @n睶:T$bi~�aVFneۍV[ʿd
    aI4?b~%wNOG蛞v_)۾5EC6D>@U"pcqݢF.o7zgSЙh�4H{c'"ۍ5Mp+kNN0CNO$c(aƧ'az&$ ?-0& j8�´}:6��2|ca#`)p)Sdnzӡ
    @�Aڣj9NΞH(35.г|
    111c1c1c1ccccf~_?bcQaz=vS)d!ƒt)CΠ?kBHaseUxC%XM.3M	q߁*ڄ'3$$KH;UEbfJȌ(Uцg3B0[c~VG�D`ff1OQ@qI,O7hބp*"ޝDdqR=Ng['Isr|*٦/O0?´0]|Zf:ǏMwsYQq>-dNTMwg.狧>
    CJT�0m&u5@Ǔ^�Sm!rc$+C&a=rI<U|6Sx*X`"RuoZ"5^i6iC¼Sv˪L΄i.0S"RL$P0|zyGOisȧm	/MUPB�JLLJ9lH{äB9aFh40}jtx�,�5´Yݜd_JI#p
    =:|�],a0	iQƵ5e2#󧧤r,`4`r
    \Pub�VW:lCީ6UldEbU.U`aRWCujV&5,jU{[/Xˌ4]~pT M<c]̎d逧t*ټ]aj0L*2|�Ln]`j{yFL\iG&&szW\Z&}=#D#
     ge.ywN5]
    <tLdfNLfҬlp`
    g@m/,m0 dp*c3L2$QU^ΉkRY*bV0^/Ined/a,LRtneW&X+6sf�#i]ySDBݷgv0y?i0r))xlꀗ30	7v,4_?6üCH"V0o)a̛_X.yI#Bu1Va[b�S&VעFV6R`Ҡ@~k0Wଈ&җ?ki0SO\!uѩœ�(m0Ͱ˟I$)e/Rim	~b%/Fu쁮lzYnc͎U5~+K(3H'jPzv04eCM0y_@[gY2ۈ=>x\@K[
    Lñ _1ʣ;QY~l}&=d$ne)O`%763IU	U7Dt3\`0Կ=x:0m^Ҷʖ:~0c<$}70M$o?J9ٞia(P%0ݗ^pT/62֙Lw(0w 7إƠx0*bǒ=8]E+V4͢4%vZsS4"IR1?úfQ9)R!N
    @
    zww6`FFx6xKPT`HD
    I
    7Nk9zռI}%O.־ĻI}5;ú	(&(&bb	(&(&tH���AzF/ŭ^L�nL�}:&���aiH;A�\Lu�m	��`_
    Л"94 姦����IENDB`���������diveintopython3-20110517-77958af.orig/i/mac-install-7-admin-password.png����������������������������0000644�0000000�0000000�00000032727�11773544727�024057� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR��n�����E��PLTE&$2///z/O8g':O1=rGu.DZ+PvSX](*j
    gtn!s$e(%r-/r.0~57EyE?LJ"{bVpfkd/DDDLLSOW^WTIXWXP[j_`^Qdxc[C`]TxTUolReeefjtkrzumzvvv/)0OQ&Z-N0c4lr:zQ(i?KQBGJnRziFtOozdiN~>8XrkQXXicux!.8(*:135!$12%'P.x{"NS"_5Z#_8k)q(`:w+~1HJ]SDFUNWX}\}its}fWXrm25#%01?@e*v3q/}?~@z{dfQQpp[xnxǕ$**[axgsmtGvTnʞƅ:̤д,9(ԚOÜlܟ}ͰR֬iGMorz.3KmPpyːׇﭓѺ姹β׳֚̀ǫŴźݢճڹĽ㺇䤤ͳĚƦӍխ緷 h[��2IDATx^һ
    � @},#қ@pk�A(ևj$ 	x7Ыp7ef3jvSlfjt0]{AQ!B@
    #[
    %nnp:Y_wRIܻ&
    1K79D
    itݲ8-vtC1aqkyB ؊MFւI{kMrK&^ܯ|L0r[lQsvǹڂIզm1.-|?{v@q`ըy#w&MH+$m	55AxfM&`nO1׳;G#+y'g-AXkR[7-
    %+Μm	, w8#aڢ斸Io긹4lh9jYZsq76&8MU??k5nߗHKdMrہZn,ncؾNEq
    7kagU[8uT<bZJA,1Ρb@P0ņ=5A[s+jRY2�,GLsq<La=1^\O.ňl7=8b~<;b읏󂗏{b0q3BC?,ޮNĸʍ7ָJ4+Wisk/ܰ
    Y!8I4ibeKm[v­K�qC3-:J6vƽ]DR&	XՆXm"
    łyL)H0i75U7ś$7ܿ-X~ʻ*c*)7@K_m>JXDz|ϑ5TyqC $w6ގXblW£yqsܼ-z#;||4PM!6^7s6+9nZo`?]7
    ?B|-ã`G0:L`O06t0Vɹ(pEꋤhg/OpX-M8=Qopk֊WxOg_0uWV.&[toun{MŖwڜ90C7&VbvW"
    .Nb4=&;Nɾ/nE{sWYOb	Bxd
    CnݭWnzcBZ7A^[ML3smur/g6E�$�̲-Z
    VȁfNh{1A,6-)H"HVP�F!YԂe~d`<n	
    svjcKnfΜ3\^Ąn!nTdAv	f0U'lh́6_-Ҏ/ȌMY$/u0ĸVP+R^K#�fnu/WrvVo(huvk"Ķ01&)X_=ҏ/2Ԙ4m&BB\V	-*ocZ7G3tV3Q&r[!|3q?C7Y~nq�nB/&Цn#n5npM
    ZA{yWMxn"v/DRmfrn&	h"+ݬ-ԍ"2Z#
    [# 3a+Z[yۻkIOm&&Ͷ
    M\ݜT(xD[D`ng	P	+zu\.l pH3n02]KznC6l0Kko�i@ĀuupkR9LºH?2/�dl<ZZy-evגЍT^L7}@1VMDvɱHǾ^/:: YwpS	ƶf߈�I%ڥ9
    	7"'KHK3tc7䶉S]DM�J"bTC75Q'r;?]MLfDz	C7Sg"=t)+cƇeb"M0te":.͏F{Xnur>M3D1 #ae"^n㝩2p{؏4lF&LƐ>LU&
    HSN1֭fvc9j2%L^_ЇJU]CDS#!~5Ч)=�Le}X
    �zt}޼yiwGtsOSP5#̊�Ê]7}=
    r|.SOu>!i2XSu, "Bmi~Af`4%Me*m+*6t|w;#)Db
    v^}=?.\ni3QnwD?6/_Ƴs===#ݮ?2w=Iv?'0;?\q7LI[3v
    >_~̅՝qe [Wm1F)-d"|}.UHq.R9O<@=R
    )vof9nbqy7Ǔfn'ݝ
    �?#o|zQSngM76ү!Qs)z>7M}7LQo+Brr!4K1Ĺi~lw[`_+uy46ڻ_8pλcY)n|m[8[2m8v2O(iێ|H閹mǦoB`stmOm Q6YRqnrv݌=ѾN
    Tt)a274gptVI-u[MSn_wz=r;	DZ
    ]GUH{֥hY[ 7MUQ꺎(cCHqfr\onף]m4
    (Nn됹rer)MӜMvviϹ5԰Xbxn7ԧLnrzVʻ.ʪZ.뺬dSVP׾iʍCfvuyy:jih-YuqQ-+8+M~zC#jYbQIŢsitUDᑛܰns4YrcDBsexOMISn#SnlrӔ85p>{ci*g|bᆦL'"IiʭtGn""Cѕ y))3hsEܸ�AOQ7*lٙR2܌7SMa8nX0	7MSn8lf&>46Ɋe'dȍEU9#ܒ,6s+.NJSn%ᆂ,_?[([F_r8?
    I4&1󋜫))74)7)ISnrSnO(G
    '*ſػ6r$_Rlށs.
    `A9s{|X ~AÒ-ٲ#6jMb%
    er43MnNɍ?fW-RͰƉ_ەok=x1�|_*PmPyybE#`pܤ{nYkLbmk&xʭ(9	PܽrlR0	+7%,I\>Q=/[QٶٽB %Yݍ@![%ܔʍsroHVA"0od֋=&2l1[r]Ɇ,a3MNZ7S"1P.xukcTmkV$+רc4"PWfڰ{0qfԎ7S%^aiQ%>p7c1/#7ɶU[sg4`	fJ"ջ3u!7]zZ-hE/T�=emPߙw*b Ȩ#ͅ�33n<΁A
    
    7>rMd#76GneܚHA[@Uȵ[___�4`
    Ax~B92.Y5('[ޝ7/PO@Cz+4[?)	ۚKsK
    x>Wn/DU8/\d2ښU6ث0>uzߙR)/m͟_?7Ș_Onmr&776vmr&mfrP;m׻m;m_nTvoqܾ~7?}(n7
    sflEq_Ponn>NnO֬ӅrNkiA�a%
    BVF@1tn.@i͇4ulNH[�5D1-Ok>p(G4ъ43k a|'!%@	
    ,Nkڍ^up[E鹅+Os܈�vmǫ[ݯni(zNQ4 @!yBNO~ew"پ1
    n4c^呛`2r:%QVSsK[k
    UTmr;$ښGxpsFϾGn�:[a-$/)
    f:U@9ӚU}Dȩ?w3*Ws
    8vZv捞+SA{`hՍW(׫_s+1L`yFl0&v2s3UȜȽ2�7/@N<ScYt-]=tr 6MnF۽	0@4$xq\ywQqx8ܺS+0wsH01U߷qDf/UYKSak Zcd
    %9'u;BOk@'�dVZu-uk[즍a5Q
    S1e'UeWڐCApK2q$Tt.r`8!ŨOVmk%͏15Ǧ37!qMM֍w$7}*״O'9nMqm=̋t_q^
    V%6܎kC5ikVS2ڴfnѢo*-i
    I<	[Z
    `nqH@+<M߈O@TB ułjm`�бI,HO1-:f�ZWjYk(A(i\ۭAq]M5+p!2�vXs7)a錛Xh�F̍17To-!Crsv5ts;byH)aI[v@du[3@92`n5aR)�[
    {=m"n~'j	Dg�Xq�-?֜hU険t:f3:|zȯ:|7Us17j{쫭Z2k6*ܼ]~F7'mJzW*-2lnn"-pv>lKnUNN�s<v]fyo@jnܪ9`ӛ)!<!�MG<5*<7!@FX%Dbnc_=Kk5+ᆄ-ɒM2nNN#6Pmj_4oi-ǭȳ[Þ'zc�e|$bnߵwvq)Җ&e
    ۮڈG3U{ŭƾ56ٓGwdgsVO 6TO|fV(i\[1H=|GpWԳܔ:t1*yzsr㘛.:
    Hs&<SQnsKd8/m�q<dw[RϦ˸[M`onskԚ# $�Kx-nR�U۫yi
    4
    q_Jґ[ܤcA. q[RnϏ4%/=|/F қ8GäKMnᶼns+	 75.57FIK@̶Xs-ftwS%sKz#G,zUw_IϊW|xg}ǚ߆_=�}% \sE_()n45ςG&n~6Fq.=lȆQ|{|
    69^833l0'[J.$xs`
    t^56pj۩!y',qq86C<ܳHSiZDZ:ӯe7n<0<D[~7m_3nMrNsx[	ۃiUI85taMr{/W~4�f̹]
    ·*jZv_X>E{Ɛses^l>y&Jzr+z3M~gQ7?}0hOrPn+wrFX.kY}y04pSuumqjmUw7^͢(y'fWd;jMd/h-wy}aYV.MP;^5z
    ֛ԦB!+qC?ű?;ϭV^v[%lMNT\ㆢ$ύvϭƽ.17=+޲OnMf'ܨFsHXIPmrXNrLMȍj4C#6.c5^/~p˸pɇvl[7h~
    84[
    (Ք›)R{%zu(G_pS,oSz+CJێ,߃�7^x71(
    d07;“G~ւ%\z2qZre\ʹ9ۜwǵIopK-5\F-w7+pcc65JCp<co%O|!z=e.M�Q+"BS4<*cdy@j`
    GAIc[X29	_-@&�*��%7)];^^p![7&?f|FKG\^p}ٮ'4l1p*\iaY |2V7"8>+sc9&qm~H[$_}]01o²mȭrDsE*6GKAvYZ9ڴ|mlj
    ]^O|zd,qZ2n}M<o~?7R#k:g׊g6ZqC6q3$1q	F%JڄVxb1ϾT6SnsǺP�R^]yH.E�utP/zbՅ�(,$Iڂ7
    $H)�!_	
    \!pc,[Lz5vXz|ja>iUyv"pˊ"wQP9f"2=^t7.\LZlmrnN̸N[?pGoznUָܸ3'uvJjtct˹sQ͆G}xƊn5݆ȍ%_s+*nRWsEŭYV>+LSQJ"
    ܶ뵼Larek'JF7u}Bnqgu*eRL?m:*lzkR �ne)ƤD7=ԆB:a1KFY46j6~-79D"ns{z<knM
    k"n–9r#nUnHNoC¸sӣmu
    nsm̍"nfq{Xܬk΍"n}Gm8#$2ŭT	֞9B{(%djArPIv`c0$jy{*|krwWh~-2[10o%Mخ)Uoګ=:4=zgem nrbޞTE81p,7~2ջ" &�M5#j.{rlEmq34oSW{]н`um1mM[!H	(%$F�G_d#iFCGnPطa $N)+'gG1m=*WرG`fHfA؊iƶdAM-݇ʢƼ7ױ1I\ݒy4s)uMؚ{)s?HS%ZƘ&nF~1<\55ిn4јƘ5ܮD3鵵)nT$Knijm*n87l-Bښ1ڽۚXm-^[^2gfOM뿴p2+m,S\Lj3]o5햛/y_k)R3%~q=�-okLD�zk7y'{7'D-xaWrf8Hfgnzrn35n
    ܊�c~zRfϺ_4ufUp]޾p-((W�ԉÏ.4h6Jj^'v0qܳdt*K⤕^I./qjQ{b,ʏo	:a܆{,
    	8͍uZ>[$+s\nXͭ6[>u	$㜋(v!o{Ჶѹ	7&A*[vPƦQ)n.n_pz+L
    \ހҼP:7r\Í@~ Cq,F7X
    ^#UΠuW'_ӭ
    fn)u,ੀf
    3򆉳v
    >mrS
    RL$7	9nEIB\\۶.iqf
    "ǪaEBk& mjnk)qsrucnd~᧨7$
    ԼԻ7r{�rcCj*]EŨeC�/{v0`xS\vtu*LZ@aBv	z)Rk[]@_A%[mѸ9oȭpKSxn7lxZh
    E9G9my]T,fؔ6XmMjV4[xz1m;	
    %kbpnWr+n7e,-h
    V5-1-GɍvQ
    h_-_pqL)bqa�rp2d@bA{ѕ#BPH~`e>Z+7E+87-ֹ{
    ږߩ|$c:xÒl%	hksr?McCkssrY$<7M4g}$ii
    _{uX$87rހiYn"]�=wX4uy/';u0DaqZbIL
    ZvjVXa	w5hܽi)7�Җvڟ13);7–[t�'].kp#lErQ۫ 77V<7T9{gmY+�>!c jpk|BMq#h5pü	M'Fn0}}܍͗nfg
    v|=4vmcF\?"	/_$͇.!p}FW!,Ӝ`q}\
    Ձ@˒uY⺮#?αÆVO7nBE&6*7js+�	IJ
    Io4Uƻ\&snvm\s{8r"p[?d'7jpw+m܈Z5ʌY>?yvN2%k;-\]+mT*q\xOvY-nɭ
    w~<pܢ[&'Tې��Ή22\ɭ[s2��nTrmTky7Wp.Y斳Ni[6ܦ+en7yux)/w)v;<w9bap7)y2MwhJܹ:eY,7fEZQVRnw[z{QkZ&}2Yۀnsg
    GV6pkԯ'Z:[W[rck/zn,/x6p'qc
    ۺ>y߹{"^L$q7-,RpY1JrDM_pԌ3376Mۮ{8f5ݧ	N
    ܎͸k'kn_r9GjS;$bn߯Ftpֺر#)=: $ɉyGPWZI�pm5fFn??7FnFn#7r#7rcȍ1r#7r#7FnFnȍ1r#7r#7FnȍSȍȍ#7rcȍȍ#7FnFnȍȍ1r#7Fnr:)Nn֏
    dNn{<vkrR[Frۯ,6mR3-:aҲCg}`-v7`-hI>V%gv36xDSm0/6V03q|X|XiY	Kf
    m,؝[?$,u ":�?Dv"@;J,TmZ3UEmJZ
    Mh<|(Fn{eܲ▋!
    Vݥ*y~ɪ>U^PaVYGbnh↪z+ssr-;7R2l>O&UT󫧛&�R01Obm+WߏQojL4^n
    @Eo;MMMPvU=qb|q֥?s+rܽz;tX;Omjns.ͫmǍpVhaG#D48U`}!EM<4
    1Kq1JD҅hY݀X!7S*mqeCoܲWXܮ"ү<D2-nӯEhGr+xuSFt́xX;_5-fG߼9fy,݂vZG|\<Лm5n5m;An;VN M}쒻sاxDn?FnGnmȍ1r#7{wh a$[FF4{aGH&h?Yn>
    2@n
    ܐ
    ܐru)=Te|Jms{;Sd{VW0|;H3,Bd=kU]\Fa{N2{®T4.	Th|.*ax!X-	 @lGAeavI�@"(tlz
    ԇ:dmC@׎~ߙˡxGɌ	ԕta=e5[J}N)L8vT{)*'WPbuOid16(=:d>ᦑnX7)%nƶ:V+n5
    @!.4޽T(orp&Kn'2l7ʊ#Tê.SYUzROuK馿YI[@lཛ-f0hBG�/<tUiYg)IiwnB!$F+0,MD3R~	GJYWE#�sf!̉-ef�tn,`I `嫂ft jB`SqFK]U/4&PW2WecWeQLCaۊF%f0$|ttsM({BS-4TJFqWe2bwz
    kLxDbW!r\N&tFz&xbnUn1tt49_
    MA]7{dGzUZ.M	ϟa+U"$ s:n}M407M@]C݄BP64V&Rԓ±2F\F,U2k#L&dߦ%N / dV|2ն2`@.tV`M($PGUNIR^U21_լU
    eKy]][�o.!"s?^tso
    _yr+#UAګ*=!(̹;oMC)qc?6iiet.n/rm*:H=)ԇBϟCaP_ڀϷJ0�a(T?N>j'k[@?ڎ a(w6PE;KaAȼEUϳM
    
    Bク�O.kۏ;mnɭg;룮nʭ'm,{hK̉rCn
    @n
    ܐ
    ܐځc��q t)Q;OgS����IENDB`�����������������������������������������diveintopython3-20110517-77958af.orig/i/ubu-install-3-select-python-3.png���������������������������0000644�0000000�0000000�00000056524�11773544727�024115� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������ԍdo��PLTE���
    '!*�($7-�� 7��0&(&&&,9-.3422+7774V8l&5F!?z7M�Cx9CN7Sm;`{LLX��UT5N5+j�o�hww�~p*
    v-+DWHG4Tj�tIoW2dxPQRAKaFUhC]vZ]cT^pXcZWcs`__{XZmkVmnp;OGji-T,X6k5uI;pC\QnOvmsb{Oy+&TT+YE*vv,p1YO[nNN}T~uRllt#97]TtjNKVhwyno-54&3,TK(eg,OC8e
    s/Y[XZvOxmMHLneY
    *-'\�J2lw(rPLOgUpjjhgQg{�7((MtTdVsIo04Q|؋̉/δͮ2*/ЏMӚfйLөpQl
    *6:SpKqWjōш崺êđ¯܈˵ՏМгȸⳋ紳ʾǕаΑӰ+.2h&��ZIDATx^1��@k`ȇ9Bo}:&�A Va`!�Ec�4O(A`3XWc;�E. 9bM[X$dw6̈pR*Ҏ}nD#my9L<?TJRnl[2hֱ)0+ob8eFexqA
    Y$d^4d/sO#D D,{-B.}3oM*^:?;;5gp|,î`}/~39<Q-o}2YۦQYgXB
    ��zaY=>39^U|$WRIk)#ιN%J@</"HN
    [LR9SQt~Hyhw:Ӫ_hɨ%%r_Ȉ9ɰ$5jfńCs	ݕyU?[9JFM驘HŴbp22	.bdC�#PO>.u=�COG�t]zKЧdCcĞPq\,+󬰘AP; `1t=-b#Oz"񱄈77?h5Ec(*!aX&vcȂ7 pΛG5-G�xr0/0BHs䝿ʉtqŲz'hT6]јψIf$/$SM7나PL+fs~Bkp]Ft
    
     (z
    PzBHu#G8fj
    DZ8<{,&TŬdfD䥤Bm*f.1rM"NawԤ\-aM1Ĉ q&}Bo:׃>W#2K@N �ŠY"LSܗЍэ7;fR17(\$"/W'..-(
    [<I!.u	OC[ YEوb6/$�DZ\eddSdѐ*2ܢB,Mp~Z6KB~/tCs@l軑B"DlxipښQqgIR&GYK2UR[2> 9PQbc5baLƬ?8ntg:As!^=Þ4ax E^A$\7llmLϐ"rpG鮱LZXxگm;Dq0j?כ;X099g�U
    "VOCel
    lO2A'f�IG֤s08+DJ2yPv%!3L|{p/(8{娒j4tV%+dG�`n}RLX"]6<ã\j(Yr'D}Qm-J'S�D61EZ�kMmj}:a0(]xxHus3E	GHDTA=Tו&(}Bv$&yl\59x}651îݤfݬ`5>���Ӱ&HPDwJ/
    9&`L0f	��@�W!Ka81}:$���"xa%& &			bb & &اc�@�Bpobpv87'fFȮ2817t0a3AĩS2ADp; dCPpil-k7ǔq&&Zi6�#:->߅\YGsyX1˗-,~<f/|crU7XC_6ǘO@ð3}]VV+&d0E!3cf(2�:w]uj$fU�;8)0&0	ByqesaǎY8c8PT23uJg.
    Сoc'tR/.푒3g8ij@FzuP`<KsDFV`vu0+NTPy1|?}/|Q)jLF�^>P	Xz~T&z
    PV38]LulԂIȁql=0Յ)SBɌ9_+vQ50�V3ѬK$L{a}0ձ5j0H5a^O'Z0ݡe996%IplL'Ef
    W
    
    .Ie,"Ę0|Mxf{`c}0{bX=B`	
    ,9e
    ׏
    �d0Gj*D Yf2`^E
    ym3!^t@C'kbBN-=z/*BP|7#Y2ܒ
    T=Tozmk#HE(f23NceZm/0Ygb%_xt�u Yw	 '%4O�ӛo@@-20<ҠͅP$�zup9Rz 
    "-vr%\23nP9)@̬&L,ctv}H5)Y|"dLZ'"^tR6p'{۝3yi�hy^l2<UĹ`8&o`*02d@
    0I
    aii`AYʋYtjN`)Ecْz�ڞT	2nY�'y&حj)y`_wMGV
    j+q5JT&NPK/ޫ]Z̓d^0E�Фåx<14ni %&u
    ~([Q�qi\AL..ȓ%i
    3)|N8rfg[�]UM0_fk&ywF4ʖPyl`i v	]ŧ5)N@ݸ.ٗ
    {Vxk11$�%X"t٤5iy^4M�S
    1�j8 We_NFJ�mC6˕e8p
    PX7պLlv[
    &"PŨ)}H|)g삹|px8t3m78o!O(x\0H(w}06	$hBHj0sؖo`*ǁ O^FrTH3gBwE41v;aL_8n̸Z1I00+6IY+[̗燃ϟD6g=K&IdA$XLJ4msV2
    4ϫ3)93en&
    �&m�L+tm0iո./^<G.{;_07|67"DX
    L^TGR<u
    T MΒ`"͋6Э5e)e]Ls\5*/'`)K?
    0y)[	9=C,{xf0D`/#i!N
    l,fgLမ.%yYIB`lE!�)B�m3s^HKqLL�&jaQao%ʼnラn`PS3.‚	V
    is0,9VISB_e	EN$͙>.J2Uؾe3wW_1*3@5a%_;km׺+Do-,ot 鴋&N9?*Eܬ%nݒP4 F~)3̕8eqF[ùʖ,wMG^{t][-w+|ˆ?Dn{'&Ƀ`H?�>`_>5㏧6]/OصC� Svoa3x/=`1ؼKZuAD3>/0T
    u3YXP020E�x|<F.%Oau[&a"ND1 \M2Bl$!Zmal&rx~!<a?0xf0SF&$q&s~Zw*>9L9o!S$""*XPx0c3!NRI	dyS85aJnNKyUS\ػc9&P3t01|qڡq_ eŽ9:$#02-Dā-N`};wݙVݓvC[ifmߥ|wέ?
    S^ij)vvn=ީ$D$)~*0[Th*)]Eb)D`^{@G+pFxvG6m?l&(>냊Lüz򗳺]zG4ot05,4fmFY&
    y{TXl\
    =v:7*S
    ;gm`JI-<){/Os$}=Gi'zMhPK!&.-bu`)Ze
    8.Y*FM
    5FsjY:fu
    ad2yٳES{?E	0C oaV
    D`L4/]|bWoU&!2^0ĥC}fu9)sLq;BNx&M ܝ)`V=L<6wL:5.bcRS.I0kS"0Vvk`QW`@A
    Ƈ_0H0kS"09ZaAS"0I'Gwa0hU~da´P�f8`&^`a�0S`rK8	H\
    �Y
    ihuSY&DhfdXke
    s*|	Lh*䯍[1:O(5FW
    yFpte`
    L
    -؍Yg]l1goLY֮$RfU@?=L!0[{vSj�=MƋ,ٴ?ŕLSYL|t\0L2U]ji0	zi%K+B	y0VqŏM/oL,aV&¼0k0#գST`7L&"0w{DId}{ߝ:s.e6{Rvca
    W/e]	f먫a�&>'v¸|0dy*4Ӆ<JäfM~krb}.l$>\	)ɳb0s!pcF!f^E˾FĹ l,``xa
    J^4#D(a3Z&7~ &]ZlĵS(PO<d%
    LO#r0dL`.ZDnX`J#nooةd	bjhS>Nq@`cD`ֳV0<߹7׫0I`ꬰ+aMD60֩arNQ	Y
    j
    y]l˟|ys!6L<?B&xu5qW?qIc0ͅBl0%嗲}oӃzw(�@Lv?|q`90MY>m1eXB1On(aHA);8+džRG`b`ڋbɄ$@r
    &٣#a	PW
    DYIKB"ݯkR5Czf)uoG`]ά)/N
    e|RTMY޵
    &7e4Ӧ,bL~ҁ5CS65v~?rWw~2
    0	eI 5V'\~Q-\h)`\?wkWMu1Nt.KSM쯈ُݻ6l@$Ϫ`@Q)kt?rg@cY̨&`Z "KӮp`jS]J0h[IH3ЦwJI(u�*)D]ߢL|*2\v0IL#$Y@(DL3`"u^CHQ
    9#b� $ftB5 _'bQAJ
    (`F0m
    w?
    )~#S#TSL4
    jy玳@uh<Ft.h}E0#K+;GDHZT`*
    ŧ.9CF(&;zVK8	0\Ze;f%ҍ`Z-? 
    cn'/>tJ@#ۺJ%ְٰ؎+\uGL`
    `& Un4"K+m]
    
    ɿ|+i,5/Ԕ&X7XMxṃmT⦬
    7e)5kVz}sԃ?JL2œL08^cF	
    &1W9?Z`J7ˋOp2#
    0MYU	
    0ֳO1RM0M^#O)4Cc0xrguuee0/�`6*/MɃ?apdB1׳JmF$FIM0IY<-ef<u7SW+?<zddJW15(	5e%`\ڲ(-%vį?o&m&u=;k2^wNbo
    M0-J!1L#Ygj8RR>zL#iEҍ^q-fϕ͂=RRu/7^6dZ܃z}|Vq7$5zuIVU0!'"}05(}L
    gNc9shEesMY<%,sY�(UCio4I-'swIe%>MP3/�%/׿v})M,(Hی &I*&S$Jz*
    t1"@Yqn6^>BNo,AA[im5Syp@l*I0\(NyoZkVfH8[%;C]^EVkLU[6)p"0,@A'sw,r.,a|^rb"Ϗ�A-`r2wren\z^#\\=Cwi5|v;2`i4_7~2ԽJݬ1J[[K<1lUwpuI]_n1*A~G`B8A	I9d`Ҷ$st`Z(Xޠ&"p2wtey$svWn	dN
    Yo]h-8S	(%
    i8q2wb`tU`Jd.UŀU2<ЧP1(ӳ[k!Jdlf't7>6@vԎ^aR!+P0 6_m$y`ZYޠ};5Td}Ph
    LA)2J5M}Z0qz>j+VWbj/#z&Կq	},^F7+0
    f?If>2u3n 5o07o,.+N>'
    0>QlQYV2"ЧEpkx%Ϣ!wr^(h+Ļf'AXLQGC'%ɖ 5{0N=9&.OlLӧꂡm`BMR`r,Sw0+-_yf'qᰉ|,4.$-ۀwK!f̯1q0ἃirlkl^C
    4e9E=l,iKġPy!J[:Jj8`ZD<c"VXWck8Ԧ	5qd'eǯ1`ƽ
    ނܔ%o1C"+6=ILK8j"㳆1}`T6ġa>a01'!W!6\L0}-7&)k%pLD$YQYl�m-|,.@n@{y~oS("XJL~R7f%Q MLA	cI6IćىcB2A05xz>ZT,A.
    UobHIg|fSaUmḏ5qjf[ncs׃`߿f7u`sl~G0WQL,z{<WEE0ro?Νy*4/?^_or۹Oh[i|PbPKz+
    *ګVJzf<%
    $c=-mÂP[ H\
    Bv33G7_Ld3w1DxI֖=Sh4Ӌ޸~_ry^^(*T*IOSF1ob88e^_BZh1!΃
    CE_F-Fv;[ϾA)*kWQ?l|W]y=BP)P=b7vJ޿ʐSM'2&}!刷Rw!-F\r?w6YwKP@_).!\Q]݉S8wh~2@r4-&Dɕ~wIb Je'D"RYL)ПxR'1-&|>S}˟^t8jQ!Ņ6G*C3-&S$M@{ e[]SĒObr/uQz+&&Uu1c 2+�<!kh13y}.!1B4VJUf\Lq"6.ADi1@8Ӓ2bF8~}~Bd$7HLy̈́i-s/\P3a�q@À-fW_@PQ!sPRT1Eg24bm#5y3MƮo77MuD?xUh\/A"**DbRq!倁HP/ie23uWV*/`BZʡ&I8ZC+Rrh1wPO2@䐘9[eHh4Rc`Ĥd5)b
    yi8\LA11p1M{9oBGvw ,7?iYYc96<bi	K]b"&z&&1p<ẺSYUL#ٓ%y15fX#fF5UIŬQˆ�l~c+] wnbP1`ȍyAk~>k,g1Wca!p}IeӧLuȞ-^sUuɄp@*2h*=9?UL"fޭv$/ۧnt1=!
    I4t
    b:!Oh챣Ŭ,
    MybHS)LVcy̬b=vЈ	ZO_`2Z/ȣn1L()K$V56ZZ͕AShٲ/0/=J5
    	#L}Lmf+slz1KT1o&p-'yf2rٳgߞ1%4Ϟ={tti̱||qa`Z?b23tގyѵO/p~9ju;xvu5*Gbv%/166اMuce)flX^yޮzn7y9-IA4suɲ_vlmUȁʚ-B1	˯EpN�B
    ɅE'B`alo5/*ٹbwwۈiZtUò,RJ*M)f+>R>)6Ã.44M>Zż`b޺t/[-*Ԫbh
    k\7bˁ/~Ƅ2!{WMEM~e(&6L4N|!ׇu@`$%Nr:uxJ?`Y!#>Mp6Dv%.5mX^NWOŶϛ_۩b|D?ILɯ<I6(밎�>4x.Zꒁ&j߼e6$\-m˛TjHJf1bZŶOױ,K<%:v'@b0VHY;*]©-2ŵ699ILDaQ;hҨyĴ$^>^?e.$E:W( ?:ϡ	W|^D^#nb"7bkILZS*~&7~}LN4lJ7OULP1GfVta$o(SbŬ,$f-J $VRC&5CLB,료$I([y5"`n"'ŕ͟Nej.p-;DHNBnsXq5fF11Ļ;)P֡iчC~bnh1BL6hb6On^HȘk;[eMHxsĝo]$&&*nbT*&5PL*1�Xk&1Eċr-dP@#^v2Qh1%`џ[kMs?;RŤfcT9J|ՎV#yZLت+	8~V0>I:.xZY1˕- 㲱صQs{\1f4YLfRPOG,F	>3n'b~)zk_'S^C}ݞ
    /-&D[Kfvh1!Ks疚[yhٴV[a7R`ffv9 ?c~B"	*|Hv݌cbCeLZEf1$xCn]U+[.)^5TB"1r1>+=_੡v~R)i=10U*31R)_2910U*S`Ɛ
    ׯ髯g(R0ǚx}\X܄um%@
    (Y
    O/.^?80_00,kI(\x~_>Q0E$rmfˉ*}ɦZYK߽`I~'xp`p?`6ք0h!T
    Lj$yrOpk5օ`J2tK0+YGLIRC[p߿5pxj%Mu0ٙ$k	)#C1xr.?_pZ26EO>0MLP)!N/<Kng.=iI*S3֒Og!ZrԆ y$g8Eh`^y2:]*S2$7QeN0]ytϞAfx`L낫p51U>
    Ϟ%u2{=Lƀ錗␡I\g [`.09.w|l)HPLkMtLpt~?K%y[O
    dvLLLY>&6h<hsǿTNXz>e7$!0l~8AjG-^Ĵ~'p�\gã|~fR4vU190/[.b&ZWY~.1=01py0?9Rwb__^>oĴ$HL,0)BS.=fA-.///yŒ<6u,wk`b,{4?ϔKRL+.LO?]q)
    e`b4{2;8\\t4K2A0O1L<m PTe.{G3ADNu:01=8Q.UYkl#sx,lc.cY&o5@v?3UxC):GQ>aŋɂK1pGevkV0MQ\M|iJEՠ?67?_h`*7opZl-o̻4F	E+2nL^0ԕH;dg+/`1BId-'$a'9_?B(}D*[6m>|6ges6qai^]�Sw0=0AKp[T*4/4)ADʉ'\!jAڲFƧqbv.+Ɩ`6i#}Ĕ
    7{LJ
    ^]9W	T�̔J^aUԀQ&Xp
    5Hs>36%ʑ`U4m>bw"mUύw`❂ykRdr!.m!㳁L丆Pm}bKªhliCჴQ>bv&ʗ
    N<	wojlܼ!D<1Eۆp)%\;m5neEsi\a9#s`WG=*Pb9q1``u[0T mOc)$8)_wWG c
    H%ȑ`z<5YC~C*|6Ƨ|S韃<rWG
    wOVexJyrD*[	jfe�VEc{؂`H~^.D
    [
    fݷ4̡]C cP'a?c&v.CxQ;�VEca>Cs{O«۟ɚXLbt~4宎;l%0vӁ֏ʖ:v`+#Hr(8rW]vLFr`%ձWo0yiBWf`TsxWr'vihY
    ӄV0U;ٻ%ߊ%RC#NZU5L90uӄ 
    JU_ofϮ
    oǚ669'?Xa.>{etUxK"B88!
    ?HWLF)^bҊ/*JSou?	1 NSiuTK4!b2�ISiu.3&dAB+h;$ib*ڕ<Y?gh)Hj4f$?Jz
    4!?x\2Sku,�4L %1V`iV>{LSp\p\"U~wmP�΅waC^H"gG	DJL�!m
    ("a1Eir~Z[!-ү|*�.0	@I_rIQ<s� 1|�\� &�b2b?LF^l�di@Lx<~U3�1'?fiL]D�1W_^(y1%1'ǿ/W�9_q'SJs]s,ӈyxx(
    �veS:QAs||b21sE-fN~^/=-�1%(+1m϶OLd$(&a1ֽĜfZ1s]wamKeO&	q|x>a$fk,|\:/ow=dD) fvU9y~{K8LF:bjHzGGOl= f%ļrí$g#feP=jBiEͬ &̐W6q߀P^po^Zba|/f:8JD"ELE!T"/KQ*+(//ږA"}uPkiR5եzLwJR@1綾NbQOCLQcڟc7Tn]–3Pqy!9?wiT"O*xQ
    \&c&oӡ,8T)	{Jq#jɄ҉CwQ)j٬,m1VP	Q#{
    dEp.)iSoY@|oӡ,8TLɢP'ft9bƭj#τ3m 1>b=a-K$ϼO	9<<W=?Ѐګg.i'4j4k
    ./{SY_ő;tpO3mTO1j׊߾bHx(ʇ+ve11RubZ-''w5sw'gPGĈe^_;_(!A
    "'wW# &e4lyOLʦN*ۺ&Ypmb"+Rǹ!tӮj̮iu]]\0z4?S_I̵m4^7:J0\1[^[!gQIvO5J/w1AL6!"`b	YI̵ԅG/Ög揅ULvV5liY͟=OeALgW4NFY=bv
    "vUjbvZ˳3縤6#f_*/^8Jy1Ί"$9-t6KVb1wbxy@Ԥt7s\bztI1)0SY=lt/	K
    .8LL1iTZv֦lW̞㒾ԘK#.\ioA)8w_b@)&ZKX(f*w
    <Nv(6nhvJ@L
    R!?q,8FnX9CXL(#Sg$I짾nj"Į")S*
    o@F1AL*5	h2$w &2H<#|	b˹ȟ"&<�	bذggxF�$T<�	bHkY�1S1IwFLg2�@̻Ō	8aƵk�1b1t   @$1/HcT3J1-8UIIt(in1He1KK_D!b&DQ1� i7R6T%xe1}DH{nCT%.ӄ%Ӕ}k%\ϵX=Lj�bVnci8@,%dQn]GH/
    #i6(8˞Ӆ4FSQ~?$oē%Q!OgiWuW]oҽAqN 0'+[UZ٩l72b0{U:<XyRS:5N^wap,ebZ[gtwZKO*Z"NK09'ُ.@$TJ63-ӣUpSE9:;=0Q`?=k
    	_Sq"r+ZRmUݍB0rpV֝&Uc4eFk{!1�ތ6D2!&wxBU<B4NUj20xU_zy>
    `Žf!:8PNL3&{Z,#XZi$^i)Ȏxwvl7cgў�(�
    _pFЮ0 alBI*|⽻qFr/Bh+۩ʃ"CU7qO=8I~5C`z[
    0[&F*oy6:<&FC
    `z<eVE&a=&0QQ0y@,<R#Ȍ}H`{,';f8`^NwDD2!=لx)[m<^PL^L,amDŽnzfFxi_vP6^5Mk:QB[dQ
    4T}VsJȂf7+e*U_MX$ÕqOIN5PlZ?1JdBVƅs9s5āM5?ß֍_i-*UC =ơW�S[Ir$쉡= aE
    3ՌX7FL 2MkHb'x`yqG
    ގ	&̄T
    }Q Mmv&]o�
    ?oT
    �SO6?94@}b)K` U"c0٧
    <xCUl(IrpȓLĆ6+S75 Vj2~:ZL<!Btc1<σd9j
    0c$`>0y
    `#|�:X)<Be:2KY3泛ҍut\$htl<K`KYC3Qj̓7Fa[;I&ڌn,!LNJ΁>kUUY�fK0A!54x$?h<	0I~OOv]u֝kYZcm0h+yQMr)%90٧Ǯ�L3d҈Kx`Sj$>;yBOW%cL�Jl#icDΞ`T2C`P%dNIs60:(khF$1{>8{bO&MB~`Xb|s	kfSwB}~	,
    Lz9ޚgYW7f
    _֗V,`+V,`+`ZkĊ0eou8
    {LP\Պ0-^/�3zzg.\>JX|	zբo޼͏20``s9FCym?xӗ_wና
    0KHYoݼCI"T>#yO־xy}}};ng
    -	&YE U$Ŕ࣐VLHyMXd80L-o%4eyIOS.!RDVyȪiKBX(jsl7of(B	&IE cP%̨(ēwASp`tLQ0\gJ&'HtL]�0jf,o|'cFc{vysR!hʎZɵst"piʏB>
    )NS	=ERbdH3T$ü#K+CʻL8p.f#:\3IC!N`B &RTdvRֻ떢b;7/dg(BzzxIaWRJn4Ep;&$z(p3T$ü#!T2RÁlZUݥ42.1pȃa0YhRKbʆSL
    p7gJ,'T5^#\@Lj	MDiv0!Pke"T7|?pqxRBm'وLCKbZ)\zȴF526"
    C-嘩ޡl݋l7
    ML�6k"Дd"0+HS"]LғɃATR^!`*4h#`*LC.�SG2ZT[`f
    Ik_O`mz`ڮB#'"`(
    `nf<dKYyRÁ^KX|%:8;RF,֪@\Vy0KYv5vCq>2	i#D c[P$3`#wED.5\5=jc>#u&yt~&u
    $DtKтbzyOFTU+/
    R6XL+5`BO1Oq%QEZ\ewRI
    &_Fۤf#:\3I3.`%4b	B5'x[XL'le	kKIj}8["PL>܃b^rzf\riGqD	y&,>F*7=7MDQ@t&";iLT &)!R	QFdRYW]rq|"ğ(AlFo
    `)FUJo׾z
    VU{|=~E`�G�E c5o`6v}k{^	Qͩ+䩩E0
    f0>J6W+{`)E0+66EZX#ٻ�S1XtYY,VY,V,`"T^ym#fs
    |gU]0Ѐ*`e<>oݝ6М$uBqAI+Ap1	C£hOFThPE0C!4g*daR3'&QԤ7+'})ќKHXĒeYr1r>)ȃ:,!U&fNM8޷
    վݹ)�jXE$QK:R)ȚEvH,"fSPi97☦&U0_
    `/_
    E'&KJG.�f^D`"%fdDr\—Vv䟪F'"dL'D@#=Ho1MM}` wg�W
    өVz}0Y|WUBeD$̊t`	(#Ÿ˩#T5>$dod0sBoR557f]>2
    L\L ’0YLhL̜ԛDq^S`10W1Q2r)"lL֌dEr)lA&ʸjbp,	
    g&Q,`v.T	IR'\�$jIGf#޲Xr]W+G&%!�]0Db7)̳d]ins!EIirb>vߡOpr풼$jIGf#ڱ"){%!/&I55/|s4
    B#FJ,]=p_0Hu0䈂y<"K.KKrUQI@]9O̜Л9Mykv	0k;I7Ky:V(TE3(VJImu58sG8Iɚ6ۑ']4>0_>ߟPseôBR9W�0C;(zqp89A03	E&_n}<&.NMpKY+X,Of#
    yI@қ,`{\C{~!͂Yi0'y09E07	`zӟ8g0ħ<+
    |Dӵ}�y&pib̷}09O`NյVHUF3<-Y&0G*'ȌH`|�t`zхn#l�b̗&,|w`"OLL2
    <vlo͊T8#$./j_~uS+׷WW]^]~ȒYt7/TJeqᮞH(.//..,W9+́fo0@$魨0f(.Fy(
    -YDԨ\͈B[hA*&L
    ]pHtbTMA),'vI4[cz.mr)[DX\͈B[hAUFPz6Px
    򢓋.ul	t%nm0!(5h3Z�d3wD#9Hc.Qӈ0*D9\}n?7fq0!H4imF.dŤ$ꉎ5.M^9)ȋN.;62f0?`s`~Fd&XmZu>L)=r@ɑ]RtF2_N\^	ƕdŜr0r09H`�)c3/,`D#Xo1os#7}%GǾ;${c7	f^dŨ$n$�Sv!Z9H,8K0)E53}2%Zz`Ũn.G#Ǩ8H,)&~{`9nLh$ʥ[iA6NJԦ9Jz)H6e.I4S8>ɦmUe)
    Jbr0]ۺ泷jӃYK
    ,`0AI,`0+`00;OoŊ?tl�@*q�KCnDGGyōth DQCV`g
    8 \f*⿻G6a0a0aaaa			¬^d1~"a^1
    @DQVJcK-"KN0|p[,P)t0øW˜a
    W	Ӓw
    u>�Q-Wu~B&`Vނ`cj^^R8.5q(0ޚ>Źȅƙ<E;}HRpXp;58XUG]S
    w!D9K·ab6\՝1Wr3q6M03B o'GxyZ?<<ܭn4U0@@Sş2 D{!fx~T|YvMj]NV/ f IBSP5iL4Uv&kW~/.7 rŬ_"EWB	@܏b^sn\4}n&Kks~/zdHYIiKݻ^^yGB!x~ԗs'1UX,V1!f#:1'%v[WI,ښą7rGyHGZV]XvEuc+\b5IFI�]	j7�#>yRJj,dJ(v06nMvFnp4?!!
    _2ِ#殨._ol%` s[)x13.N'wl ҉\
    H}Cl$bQ+zsJqI;#7�PjxCFǂ|+T
    d25/yN'3FȉY@%f 9R~nM1sIb;^@9%oSJ
    _#N1]m?xH3O&O;p
    S@ziukTl1OZaNX枣tK/äs~tv &Y/A#Tb.e6N?$&s 1i71?YA!H$FO֔
    OLwF1	[, 3Fnw( 1ll=LM1>_5DU{Nz$I9""ߎT\́ZqI*+n~T/__ls%6lgIrûbD f̑4e;Q?8(%̝Q]uJ[abV7dX?f$תKL׉Y fl ovcRDv<G@\x#w\5"oh]隗V\)M9&&Wy-˲olfbƢ_9ZB+}FSΓd6*Y[wޏ_V̾OPJ\@eGU.oX |g>+&��G~	1gma0zNRt栒VUx
    \%q`|@"pBqp!
    ΂EBu(YtQn%
    aR9q:hB{UtENI]F.q�W3t_fm�a vroЙ*K&:AKɛ
    Sv3*5
    /
    9T}:��Ɓ=cfg&�Eih_b~		bbb & &		���"	^`[�ܘ6�,tL��0ҐP(¡CrcTD1��0֞zS$0GLvmF����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/win-install-1-all-users-or-just-me.png����������������������0000644�0000000�0000000�00000030466�11773544727�025063� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������|��PLTE���333�}�<tL}P___|s]eedspgyyw�����%�(
    1	:���%�(�:	@'M(Z?o?q;u9{U�H�YRj3fCi@nLvW|L|U}nvM}%#%#85MJB?UQ��3�33_[Rbfinfuwfkhhf}i~|}f̙f&5*03D(K0zZ*�;/�6=;CF$J&R.S2CKPM$T(Y7b:_@fGnRsY|bWvZoXʹmjr{8?fwKHPsjvWgwրőʒ՗˖ԉ䍶▶蛽ԫŠױȶڪʗҞܦ̩۷̶ݦź½̙˗ǷЬѼӑމߔڤܶ#zEf�U1�J7+r�c�C=�4T.V��-IDATx^I0CQY;\AR7ꓗC8%4cE3 3Z%vztsxD|CfQ�zPz5M)/:
    k4L
    �[v,W9{2J_,2>(=jrc,NDQ-R!n ۊ`Z%h`uY2y@),"k-V	RIb1haqfgsg7B5`san0?=#.gEQ7ې괚uM=? ve'<z�Qn\&"m]-U7ܘQ7FoIQaiNyT�s|Ko<1/拀\ov;?!W//b؜o+sp1]LV58|f9۝6p^,42ͳEEDbB
    Rw۬)cDk#d}o1
    MW	'f`۬%c._�bZ-m.U=bsm.*T89kQ5P~1e>Kj}GFnSbog*,1_]c6/cf9K<<”h�Nj�@;F_xؼKtq]{Β٣|bH@i?ߑT3R)spH[$//-8䯂0tPy	q!QW�\}.]f):x7~pwr\9/ǣOP Vgp3~Gj߶4.vA+}`$iY@9W,˄(^H)$͐=k|G}HbNӷ+<Z^=K@t 'ƷnmC?BT/T\\Mg[]P
    Y
    \Bql!<Y~p4X�oM|I8d`
    ۴nⳉ;]ofR0dy99ld>́/]{w%b)1@G6	wQٖ߱ĺWYjD3M&̍''s{`
    ^s/ׄL𜣲4_d04S8i6TǣӶaZFE׼|HndBQ"~c!dW'\țD^90{}̪5^R:uPr͙k:\V|J]Vz-0'EKWStrѱ
    @P?8%3E$shy69ltEo.	KK_1j@ !EnN2qiN"l1qa}>V7LJӧ6"MV/uJI&fwۛwbÜo2k2̭կ<[XL͓=*rV`@gyH=okqa-='aNϓj0E<|]ztt^0 y;FG4s$ݜg;e5)䵚9|wBQ~Wkp^ĩ:m7r&O?ѹ_w<۲J/=UDa~wyW.vY
    =W7wF0~C.e:yY'z1sw7_vXmzС }6͚ ޚnO�ASmՑYDHF@>3/r/LMtNC:oçz'rX9i-2h u}yBkEGuietzZSDϼmcئ7	sRWqV#?	=(
    N@5"r29ќyi{d~yom@/|F809U`
    thRpi9?<갚-)?2gəJ
    e.뛎y;'UprCZCyO:]2C-D1sYl;0G
    Tzmy9YNJbg,3Pl1mǣW{8[Hīu;1?!_ݼ\TܘSb>}V�%e6 d
    ibLKqȜ|u>m%mGYM@<sqNGsz̓I#m?>c
    av8<|w8c+3/>֧tÄcdܤphʣφw(0_XkXΜ1R8 **EFH+u\B{:vDo<iHXAL.<(۶w7T0	
    iZ<@YUUg5d2'A`J^\ZY`GDWܷSh3sVNJ#2́}z|
    zW$s{6䉼[<2˼iʜSue\dn,$l{9v/Ml�`^.Pci⳯"7-.?}U(yȉi{%/+f"w&o/}2Crw20XKwZe拈>c|<QyB\49d.m9I9?v0k?sOcXK[s(mB#;eR5s?s0*Ư|l6ji	ȥpc(K8Ft‘+;g+[caXٟMDK|A]+eaA6s%
    ĨI\f|eNB76~bq|(7h"NP<{&f~7lIk	Mz/ =P&x	̟ŷI+74Q��3PpKI嫑(8w%)h(Ft̲ۙBD 4S}~o|JῨn,o泂\_3c,*Iv|3&p8B{hxn~y8W m<
    5w_kǡA\JzpJM]2z aŷg&'~
    d\!$adr!H1>.CD.̕6wsl59/ 
    !T\C+ZOv%-7T]
    q0N6XD7ҐK{Qs7Q
    &65g !C_I4	NR͗*8x$y|\q)kU~i!*NjQt8ۧ%e|[7a>x-Y퇅sOٵa4g)Ɯd.%K{z (ۼ008^G;q+Yd2Q+s7fp\ےlDءݜӌ2p닽;m�]P"MDS`O&vznt{0BH5,xt4r8?Ρf肺Gg{8	A"aSۼblؠX1Veu-2OIq<\
    2O0I96}KfDPt)0�SJ,x[Cnq׌e@z@}BPK.T݃ZȼvzaIr<l,?\AN_VI.1V90˜CM;$!DEy?4]%�}ϋU-W)%ȫڷxc%\9q|~2P|Z!q y_�T
    2yg^@oȼrNiGl
    [y7 
    ZCM9SgÉ%bks0yROs$G3奍gU-mߘ{Sԋ
    ˼̫|wT}ITx�ky?��?'H<w\e~͵҄s^}<A֛jWOwab?.tr)̻Gᓤ.m܀	iQy/6KUٻ{ƍ ly#E;n!~$TAgX".B;*XBpK(Bف%rI
    Hk]^Wo#9B*Rs�\td#7ut63׼y;@1G96͗K#,S";2`#1~}7u zPk
    hl ,yQ#vv=q3?x<GL"wEoПR;:}]hަx}|}51_1{s/Ҝ/%onܛ4dRv1+6ܛ/U_pPJ:�1Ua|ϑ'l%q޼E-"?y,\vh#yƙ{N'Mlθi65~2kLih#7'ʜI΋f{s@T>n7h.DB"
    Byܛ[!n4Xp['	_#?۽lG?.bAkDNVTxs;9ω\]<C'ڥ'.޼o3WerM%mgsQDKU>,T.Ln2Ux52]5.yϵKAeɠGP\sk@/m䬄I<}2.Rza54̣>͗$0,Vx<+.qcM6*X67c'u4
    [h-6chN4Wr22F%=9
    KOLjjJsM0o~Ww%p`f<_`{\?].lxOY,ҙylY#9t<2O']r|4=H,-F{&P^kjjp*nk0WQhN~vs^`vhg⒰%?m]ZU]ҎX:zG91\z73+y =ߣ+z2j*9ssc<£.&+$
    "9rU]104sm olƼ]Fᵠhn3Axh>v$9\}kr!nbwsGrb:otBFz]^'09=9}MajBgr+qKC=O~soxer\ʫ,S`crD{+Ӊ78\TWI.0;#~=s:#g~�|F)ܽ|7fnix{ .{ݥ|qS_^͛_WĮǓ26&bÄ㭔ˡ1^(q0y䷉oCseqMyJ~1,c:&v�ou#?]=_	IY⚌7(n/ s"ڄk\'Mw?A�y�� ; оT#{q<s+يT
    ҏn3—V+R|NyIL\_E뚇yI 7}w99<] IwG"_7so(D\oO?Vt64AwZ%n><sj?_|(FC{2%6ߎ%&5h'=%	x6fFkrooTĒ?֗?{;w1?pc""$yS>+sBqA\\Ü\V|{v97zR[AN@\9Vc'& t?3m/8
    s+CmcSq0%y{CUJ&_=9Ȭof|_Oj%x1+='kȩ/9&9ycxgan
    grǒOucGkwI|KK9yD&cߊIV;򿙇yyȕc>b^W7sR$/Dt}|cU~$W?9y~i),9rk_<z椎.rݭy=wbc^A7a.PmFNsB쀚mw؇;B+⭀p\bKtO>j/AqbZikVZny;&U_&=P4*)@ls,aN~ABD%ڜU
    rL,WH[ 0$./πc	s5gXxz;$9昭ZyւA!b{F9uE[beHϓܣ2–ԩAfz9fr5Lv^ɋW2IrژglwTuWƔKX$=@.'}|3sUPίe<z&gxqf7&<K|'NQр6qbO	9ݎ
    ~~Ly)<d!1%m,Nyc	BRL<reߪ
    ˚b mA`D-a<oW]]E
    aP<ퟻy3ܒA:91_y"_HN9hDq''uqP̣4]a.ӄxVlK%}˜|s>sFL>epOYc)?wn1o@+LX1sLR7r{>	\P,r�9ļI;~A	6>*n17O`	mo1Ss3ȭ,糦9b7r{g27<@3K4SL] fv>;WX'=YU\mTzggFbtBhۂ@牵_5=+Z|�5N`̯Nzu`hF=՝!Yu{3hNT+eGe4$`s:wPXq62rw5R^Fe%c@Tĉy)Qu8٥"͜`"N3Z􋱼<NyOU1o$c({ȅOe>wa>0k辴4Ĵ̷^!yRSj8 WW�Ոz3x2Oꎀ�You)wvKQ.'SjTPZ0Oۙ‹i%ҀTfNdӀ RjhӐj{U
    ?$C-EWx>%	H#0!?¡1dԉJ<g==.o�0Wfx3\jhu(Ԓy;,nC=ż}	>p	ccJKggsS.aLc镦S>=ra7HC&=YP.3=L~>@<SgʷǘaC
    I-ܾ\>,T2o.ݼ|l0jw
    ,|#r_mCz=K"^˼k8oF�9]OOW,q4!PǼ_+Q#[rD>'6Kưyۨ\hɉ-I4{Qź\0"v%ȼF`a;i7}3Ky֥lof5kff^y?fNq"�g`E))'^PH0zf=[O5L,Gy{qps-GM{�7OK9m=�={gs	=ߞ<�piXuYB=3
    ͱp	w|ݜԾX3,!:nsf�xΉHaUFE#ۂw4.uÍ<3Iw}!+38s0ws,.Y߾
    42�+rb9"یšc\Bkhf�nM\؁FEoL�ݮC#Wq6cݙw7M9{#L3mpI9"v𥶦-v}`&�y=I\My*ZSHjor7fKZv/rd%oer[~-4BN}ɟܒ
    =JTN�9.pf_܏@Xw=ov 7g	?UbLnU	qQ˛7.iN$q
    bn;rcɫG{!n\ST>ڕܾs<jY1s]gbYVScܴk9C!?{w۸
    �LC*@-WQn?XuLK@n]BjfrbMR{<#ʲ3d~vj�1wyPj{M5sr&nü]g?ȭ~M?%5;8f�ueeBݯn57:'ڻo.qnj`'􀹽o`.澨WA~5CSoQoRʼny]d
    [ejr.Ͻ䦦j;8b6iVܿWgN�b^`86ּŁrm؜Nmx<vj$kYjY5̌N~e`pu5}P=0:
    1@kƠmn*( s2`ų
    l0LFے|}pZ|({`.@m9Od_J�%:._t9>dyx&}qs?7֜C􍹦!ܪtgst\]2\8
    k�l^*ϝu\{SvdNEo'bnK\C7s5s:e3^<헹\hhH9‘Ùš"|Xrߏsݳ@s
    !BqNW{564@D	}.|Y_Ŝe:	9�17	??bnEq4+{�q/HBߚ_T&o訹`-<Iangt5eXbN(qsM⼦u9М6ue8T:LS>:WZvͥNQ
    A˩J%s{R!nߜUճJR5
    [6:
    �qMi¢ms娩)@-ۇ{AnMsC?5&,*�B͹ q6nڸgmqۤYyq.uWᾝiq8s}LeTV&PGpHK^An`6y#
    \ީ&Kg+28qq\?NGu	9c*ojnt!>^<4طSynk͗yi ȱο E3?]7&&jn󿆣t:ѼCAUs1_]FWc]\Ndž+;J]NL&Fk
    cOjRLW8vJa+yrŹsZߑxVglMTridNI|GU[]r42/?H^ᨚ+yD-3=3<2g\}.0b,ikNfr~us1`VeҪU2})s77G\-2|u2snVگYOĜɕz=պ8⁎r^Maau\0�#3PP	:*
    ۧ#U;d7aVqeW83sFل"UtgtެY~'n6de]YTS`*鬻ݮmuy2�K}~\yt@4,yJ8r|괢-cKGy27*"G	3wa35ϟ^/O .]΃7ͩ8Q&Qnɚ<{x)]^ܥ[?ƚooy\U+̤24YcL{tJy0Ll;8J
    YՒMlEt{dnU%[nhyJ{wf#9(sFla=cVgϲ`;5UV c oEd*d!y2@؞7!w0W1|󕝧*]kN߈<p,N0O_+ XyswZK_8:p;Lo͓y5빠eA [0-
    Y]͓yxD|K}#z.^98
    y۲G|#>K潞3;1_a?S">[p!\7x{dFeysy㓳ñ7OP#
    &y\DY WB6{6KNr*R+P.w6G	B̉d/v[d>Nn!uC,jM߽߯l6EtQ"f.h9lisr\~̙x50ZR$pj]B5?8ɜK)<YIc�$s=ϼ<LsÕ5Yȏ69q�RCE֋$\CzgQ+!rzdJ��N%K=͓sѡ DPCDo=`31μy;;6Gs4Gs4GsќseD,e׎U�Hq 5W${%	b	ZB"6[xڠe.nubم:FC'ѥ׃t"]/1:w/³ayGDh$|7ӣI>ixMP퓁Iټ_μ1?]jM4D05gs^9*s#5gsl^uhK9!t2g^906VUa`]nv
    6=!W^sFڰy1ܾƆ樂\X-ځDnۭ>`.ܔ5g\eĚk>ms6q{pXf=G"s6Gq9nĿmnI}k0y,j@O,Tn3^s6ϘGnlb\$ڜF$)MJlL?n>͕F$H^`Eלp49M1�0�
    mќ� Z@<#yZ\(D2vRqXK����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/ubu-install-4-select-idle.png�������������������������������0000644�0000000�0000000�00000057527�11773544727�023356� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������ԍdo��PLTE���
    '!*�($7-�� 7��0&(&&&,9-.3422+7774V8l)6F!?z7M�Cx:CM7Tn;`{LLX��UT5N5+j�o�hww�~p*
    v-+DWHG4Tj�tIoW2dxPQRAKaFUhC]vZ]cT^pXcZWcs`__{XZmkVmnp;OGji-T,X6k5uI;pC[SoNvmsb{Oy+&TT+YE*vv,p1YO[nNN}T~uRllt#97]StkNKVhw{no-54&3,TK(eg,OC8e
    s/Y[XZvOxmMHLneY
    *-'\�J2lw(rPLOgUpjjhgQg{�7((MtTdVsIo04Q|؋̉/δͮ2*/ЏMӚfйLөpQl
    *6:SpKqWjōш峺êđ¯܈˴ՏМгȸⳋ紳ʾǕаΑӰ+.2L?Y��\IDATx^1��@k`ȇ9Bo}:&�A Va`!�Ec�4O&A"l\
    B XdG6	\"!_msO>PǑk9)F�Mmv2YuLUU;�|rLü:DZU-}"9M3Q:2hi#ӲZ@Q Z,`OYADzr	'"B"=B.}3oY;c@jh_99rx"/*[^M@řx	3�(U
    *:T:K1vUv b2b�bZ&aQxbY{CCכB8BF'C1i3`>/&4Em(aq*�,ͳ,ݮ[=mTLbj1eJ*"}�%pɆ�W[r!]&C�F\<7f.B
    W𯔱;41D�'E1
    uc*Xw]sn
    'ii1nF-s89eRU	-YF6TQ8͐oQMK{�a
    %ϳЧ9\ߏD~XIѬlwufjg$3$&yl6šZ>0<dD4р++Lh%n _tK6)xT[^~CMbxåt"%@wg:qb1kDy)Q{Yn
    Uڐbvv+׈E)cqo[J0@)G#2K@N`y/B:"
    /3SD옱J0Cޠp<@`XJ^;\|3d(\l䤗pKAߟp-Ŭvzһ*bv/	CQDH	FArPz&TH)!cI+ӐE槍=j.KҗaJ>K�A*}5ٖý;8ւjk7DH	&x&\Sbޒһ|`g)yY(eOяs*)2 $8),;f1m,|r)|{sل4^g^%GB ߥLZXqMºW 3e1Иdv=F)7j*0LĒi)&ݧ�ކf}ˆk3%n`WnQ|otx`bCnN'N14AhFt")#:8E`0<<fx<{A)kUS`h+7c
    f;箠ICewkIRMY$ d%kM)MdD޺~*"}QLdzKRd
    E0@*VJmc~O6@Fe
    oɾ.t;xQ0!0}W}ODx>駆5rWb(Ly9cPcu5q{O췛01a<اC�@a#v
    >^饟14	!��00$@`:|B'O� �Qb/q:W�111AL@Ltl�@]Z6aMNƔuU"fQ8{78u^^"zqh
    !͟r�1ĘD#cDec"2~15&}Ře@܏nje 1cLk+2 >ݛ�av
    *xSXلb&"QPDroq?<vm̈#CK%y?_{	L2i6m
    	ק	L)0iI�\A07Xa o9
    ޡ
    BСdNNu	d>K8:S)�qѣ!UbJQ#BA2\HVOC߿:R_
    漅,]62sR?v0d
    B8WS`rv�X0mnF@{9�ZFzߪ'+Ƕ@%IXɓh<2S*Q.De"i&a*qu	YlL=aR&QY!̫ק>y0Ba*Ģ0mM_s`^j��&b󘀕cÖӺ`N0S2fNʌn
    `ў\JiLY#`|ct&
    HE0G)ep0?98n(?0Gx _؋hL/O{`rj{ٲ,_}rMzLY
    C-!x>LRIox<`|	7JSYv`VLڝ·`~n!;�_H0�Y-|�U`ӫTiVUɅP2:wj0Mip鼑0A1 
    Q }BJx@ـnP�Sd_kS1fͨ`(m
    !MIґŪ	{]=6ltmējZO{?v^
    
    ƽփ
    &N8q.ʒSdBa�OQ`R`XA]Rγ
    3X@d̹Òy� TW!
    P1od2@IMxneͻ
    U^nQzV!!t]Hk.*LT)O(SC-jA.j=xbKf!K")pЈQAy!ȤHDIsʙ?
    @O>b\Xop*D)s
    !,J2dnzjz>0ksͦUqiTC؆`Ft2qKUs&Vp$E'QM`08?h})�?-hmCLҟqi%%\JJͫvsQ`jM,"Hj9@QU*D�+.,V!w+@ߍǺ`U`ƻ`T
    0qh:evMOG`>+ki]ǃQ=ƺ7[
    Gfsb>uS-Lׇ�
    sg Ab\V<myR$\']yP^ ~Wk&!Lj2'q`e2IdIC&燽<`*
    ;cdd1	,�TPi-`	q9$-1sMn�LS
    f8,t]0ݔi0Y]_|a<&jl>6p>4}h`[D*svQ[
    " Tf]6{K;4�{mT_k<RXR2>d{0Yw䗁9{)~J)`lg�s{n<ӹj6׾N즅MǑ@dpNz|]r,!ܸڀ&}D"lod`I%@Sfjd*8j`ۨ}m .0a%07"1EKA=M~"ji‚	J8T�I.<sH}wa+@-tR=Xk
    Q2<.JxE*l�U)s»Gy\!i'`
    <KkoVv
    fi`Ցi&}`0eN`Lh<?kinI$=M<JeLRHfY%Lfb``Ķxgx!Pwt8*&][
    L sbˆNQoO/:�[Z+NoOm\:o6�1`aO p,p
    ,4!qKޯ'שhf(QZ0S02si	F	F~'y|ƲO0[&a"ND1 \M2Bl$!Zmal&rx~!<a?0xf0SF&$q&s~Zw*>9L9o!S$""*XPx0c3!NRI	dyS85aJnNKyUS\;9(GY}xXWO,%/0(^D#iC(xа=\x%YNu/[&30󟙪SUtp~/U/ww󯯊b:p*�X;ٹx$&�E̔Ĭ7_\A@
    X
    pK�'օWC,TuT%tbwkqSQ1b^wA		RJ \d1y'4subXb@6%4PftPHLI`sc!2T휥I+sP:^j8o2,f:m
    '$�V\
    2K
    8fh3'NL^+e&&ȉ~]B'W"-p0VHBrI넢ļ%/wDLܳ{<|tb"d11z^BYQ|Kŷ/&*2@`%tG�'fi9SQ1S<ŋ?qJ#$0 oGwNotp]4ib**&vL9rX%zb&]LEp3DLE'LOp11/v;ޅY<jQ1pa'&$BZHLÎRLiƌHL3Ә<X:+8Y	b嫅Ŕ/,E/D`j*fIh̚YfbN%kb'3gaOTwC[r	H)+Y()I,#LMqDstcvbaɩ؍fQ1s!aSDc0=b@,fm̽ݿkEb>]C/J-sPb>mVG~b7Zi%RbBQLspD2cQB"@b(1U.Wr(f3/T1̣SiG":bRf!BL&yә(+5'e7VL,Q$f01hJl/qp'"G`<R00SŔBe\^4X
    A&KUZL|ʄzb֦&'.L|zq3W]b.iOHUZLjq⽟ć4B1"}!I,gaO-)+/րBR+k0Da,~`"Rz1i[NL�sY}AE\SQ1	1L"끢b;e1[@>VC|PPWP5 bY+1Mw|T!N,LB�\EyƩ|qJ7DL0P!c5S:hs!Η3N-#Ny킘I)q.'氹-/,ӏcC�aI,.QD6I%¥	N.`E<$"q(E&uf0b	y}'g&0IW0WrN٩^waV☆sg|^H8A0HǐQ.fN&$r&,`a	Mb,8!
    M!;
    x3ޢe!z_uJO[QkT_pwuẋz]U>+0;ߏ:�ܹ~wy`R(;TU20Bkl/7>_}g5"&M14Sz5?iNZ;0ʄ޿sעS\{
    =ʃFrMBߥ޿~W׼ZofAQo!'F^z?,[L'&*UK\#�OZ(tb"qPb
    ;7�CXI�PLXJlPmMv4<WULtH	5T;q ք\Ɛt`QE	�-x�:uU]L&݆`b$i(( $ml$.[F
    :{Re8E˖Ӂj]lǭb0C�ۇ`d`.
    S&#găF1
    	PX:07o޼2|'qAl93	bϘ1NYⅮ?8q>],]V' 290:leJ2wxH�B
    ;W[HF)[[eCB0CC*3h,�‹P#KiE5Utj.&J(@of[?f|"IOLäJR)*`6{D4[.gL)&e'� ``懲-gK3RreA_jE+fH
    y`nуv
    |V6"ꨁx-y-C@uM``nD
    #1=ʶ77	'aT2%>QCZ`VĜ-yFVc
    '0懲%5tj)%nsۛ1y)_g(7zCQMM$.̗^>ċb01S-"'+LV;̀&wGL`S#v\ܼTI0a_h0wvvQ3Z90eijzYHΗ8?WL٪#?̺WG�__%00LT)ry`10EHP
    h)O"> s]$5+
    B
    mD+Yh6fCb
    buZ>S1ʅ2F.Mɀ@nx466icL5FԽYD/30GfS=0U*y)wvjg%K2:YI}kꓔ40LneǏR̵SsӨU
    HeϋG(
    fw2Epj>{8ȯ/
    L$s1.tWN?ɸA5wJ^z1RjA ʎQkPꍾ\f"w�Xv`,[5`ڡY
    T 5b;Z,mwWNz*9D0e\>S*}7(L�9nlxm5#iK-RL:F$w*ia+Ųs@9bƩ42`r&$V%f|jی`�iLsL`6Di0}i`1%sLK5 f"11&ezXCx	`vE�쪨P�S,=jIB&%Ĩ}}	^>�}797
    &F/?`@XhnZ=1!� .oC@RL¨P�DĘǠC
    pTk9%u4g2;KF4~Z@b`JHDBL"0{
    zw8!MbU9(-h0d	UTaaem%IUZ=e탃)@Q_Pٹ]2R fTifrW{@^7i9HE!R`R	T<ȯtTL⥝cb77`hU!T`978?&dٜ.%`ǿƔLCޅ~Psly
    J
    @@;Lh
     [#^KSSs
    Ӎ!dt|ا@CZy0#%1|0)U\T	֚,$K.yrAp_Џ0Elh_y0AJ9(r`NGJ4X1cR,ChH(3wPY)UI|ŤyB0"d$)<}2O,8fXT/;CgL5b7P�&%h,TSZ0MalNɟC$]GkP>``W%Vf,cno�ŻN~Ys(㔅˜e풽\W."LNē}t2cWcU4fI
    [P#$T`9%,2X�u钽 HNEu}]	`)aE.J$)BLೌLP�IxF\:0ҍ/2W%Ɂ|asrr`g{Ep?KSu'o)3z~?έO~gBH>erqncS[
    9jHwIb4m	ɷ1ȇc9-m͂>HCۑ`]h1L]CJfZZ[UU~3&D	:;{޽?|WS5
    ܟM&
    S`޿m7.Vsyuk!4B0+
    ]Eݻ(=z͍n/TD!]ЍC峯OUމTR(kwQ`qi.7]4t"Cqi!%4Hy,.eD!_޺uk!yT@+G4h.40*{!(3uOmk._
    
    ]BNs!e+5?-ɾehr$<"ˉVܔ2r%L_^6~rf\zz+Y(
    ]&L+*\$M{KiM`Pi |T>B1DQb
    LN%BHO3{'@!"Pz,E۫W/}ڒqtM46s	pMLE2C!/"kO˥tVuM0	mȺJISIwENl1pB0%?|đXs
    \(q24`tFc82bÒ`r8r2)KlW�(`\6(3d1c|,R/nS!\(B]&�W7R~yTA)oe6I.i/
    ˝b"�&Q	e@II8M�Lh.A2N,#fi	Ƀք7w[aD\QfDc/iKz0
    CcB$0My.i%=g)3`2%JA{{l.5Kb3ha>bJX"d2zٯ7t ::Tj).ǂ))"Bȭ&H7V	1Ԍw^T|DQ	[iThn3v.A;M%s`.|A&.$de-NAYY%lU	mHQZ�Sr;=LY2U}]2|?<(!Ċْc"	E0%%a̎\j-mE0%`[`�GhDjTJ+Aqx	۹D0Ir[5Zm
    /Xյ(3(c!Jʃ`XT5reר%D	D0Gbs*c-R1QI#Cl>~`9
    L8]\o%l˗W~`j2IuIZWޮR
    `~B	RqQV%7[ÓNW7&3)\_r�nU\~qrxtttrrxbzE̾E0;p\k{X~Bqf$J*S.̷޼9:zu:ȬI5
    f˝|bJ20WZko޾]_SZRPԥVbPNelr_.q+U00@B(Aʵ(%B1UT߾T^n_&^z=	"V^VG“Zlw<*-9xrؼyvT	$0mT1#`
    B^F-R* J*ԢJVnhhO`b.RtfÐ#4׵Vəm)a$ʭr&5vQHx#Wuqʚ	[$ܙ`RZ߹`شq
    &�L+9+1_f&FcQ&1;_vPr+5Vj&szHlƲ17| bd;Z
    efLӴNoV# X?*3ΌW{F.樸Q3!Wff.5nA6pg{㝔&�Y|Ie&	34ȏ3
    gdLYK0L1�swY0nAZ?HhܹaEDŽ%JvLrׁQ'`
    B!Ak@wI\^.gf`:݂6iVC0,I"D`IYFHk�L'Z	ϘLR1{1`
    V8c槓HXLg5v"$9	K%L L4WWX0>g0%#/3ցQ'86tz:xAA=_ /4:Tzz1LZ`:i{``Σ)ԂQ&[̧\PWSؼ*h*0H0=O
    f$Jyle/nB0SeTRQ`rx]2f+nQ0N6aGe;)fLYsj03b\0>`zL|b0Qf_h2}O+ť׾.P%_UCߟ.Lٗs
    M13/'4`_rena_|b.L?Φ
    Ծ f1j3',]e@ftbHv|`@Q9uȭVO-Z}=U=[^<tuuQ}B=!`"MݾBv~Ϛ泉)"fsvLLLA1#b b~d{DRƉj{.4@C.s]'C@@1@=b|}RtC><pq_>Q1(`-\J*Kk@1Q̆oN_/6NLߏ	ʯ	JDLJwfB>yV+m=uJR+&E(u d]x߿wF2vEb2"&Zi-"&5.<:|ᥧ(P'7y({sS3>e	A`tx~⾲b^f7IL
    &Tѳ~T[RKP"ZM_̛˗l}k3S1	2"߰	峧-yM>zIZQ9.+B.e;͔%B,?~8
    hV9*>2b1Pzۅ{lf!-0a+fzO򗏵x
    eK1\zJ̳bOۃ9Y_׳Ko-NVfV&&-&:+d/9Y_^7nm4XLPLw)c�dPy�1QX%&{9oqd/#f޽>_z+b{|~pض5*;drb^^~߇F *bKcA{,HS;3SWI׳v;S_$/Qi4eƋcB2Ͽ>i)Hn|xu Y	?Ǟz :61</j-Sc>z06axy�'(f^0 nlf]R{D"5e̚b+!ڍG0|ه"tl
    /jլ=^x!BѪV˯UL5h'2ob"77kCu~Fx`1È9"~1qbUehFM1٩/$EQ&A8mhH5@�ZCpɓok@P'_
    w9bG*:;䟇yes,wwϊ0g1e<Gr &@h\
    jOh|j8"*xJG(+\
    ׀.jkL9)ф`푣&?s^}Ბ9;fL@96!"f3^]!7(&11Z<3?3(.;!'v<_Cj|A|%g}-m\ZC3d*:tǾjZP-,\pY}N0}K}7A]
    99\6*TrV6B>.ݕMb~:G̛37�pea9_^9EETE<._ʄ$\XKX31W(bj^XNp
    نWcb<..S1kbDJ1|pYQGgLbzakkԎZYnǥe#rg̪hRM)fO1]EL(ȓ<
    `U!ہ"UX<vslDN1+[lug7~KL}#ĬX~TQj=
    W~Y+sIאSf=&QEg90?s9\6"븻1jug>VTLgCn宎6^<0Kv4<uZCrWrϟ]'b$Bn0B.y)&Fz)bK2SXW`n8:JׄG1:;4P>-bAĬXvIk$kB1j1kBJyZBDLV̿ĬXMy9w*@]|被`R4K.-DBPlKh8P03m}X)<ձcPL
    �Q>u!%hm&ilu~`0V^0[ۄDuᩛ8 4ձI^&ݑ%4crPj2%=سwy+@0E&`%ehuԤ?c
    0cVGE.\ػcԆa0]|{dq!1_L&ڥSCv_KbQʤ(6ɋ@ÃA]-P{iL㚦
    	Lg{f/Dj	0?[)$�P@x4ٗ	!~$�4'WeRZK,"ke��隺60eֲ^L~oDiGn;KD.ha~0W�yjMq`Rivq930b0+✆OKM
    ӛ%Lf0,adҺ
    fow̑
    3pi(L]]`VTrLsaZ8ދ:c{~.~f{@2Y9,u/fm{@JDK#Ib
    2ga2z}i픀zZ|d3"$9w"<
    CW"(Uh{*@aȵ{~[UVUUu:4?s\iP"N &B٢UqKTM`Z:wj[V}dPsZ#_�jD1-lÞ`d,()"r-`7#e
    &wO4*~Rf	`,
    Yr=92v"+*%\6S`K7aL		)7A0MJ\<׈j�M`~%$0XbQ~;2HFD#TH\4o&$S&&'/56UbD5WL$&QLsKJPQ<u7
    9oQ'߰f"3nؗ&;%XG
    lyw.s%(hc^=4oxx,`0&?.<cY`"Qjsu~"BA)-0}C#s|q;!_ :&0i`F}S0$B ZFcp!2.0Ѻx_UryL	ToA �N4w\P)Gx/&ư~(&6JԱH3
    ]Z?gI&C,`pW	(5>ZT	z+P'o)N.
    s0öL:ͻ(M,0ճ-Rf	&C)eɇRA{ki�}
    	~Ka08|ew�3eY}5&?AɅ*qYwZa0s@@'klBHyϸ6$~c*eGslLަ<fx퐝lW`8CBʉIgvi$*١mj]N`*1lɶ[`mfruư>f%0FHb'"R֛Zkxhd7ʴzuw0'\.\>�3G8u0�3Q0ˮH	h~ND0dSyy6?^e1jOa?0e&dG\Tr0nHvׅf`ÿN3&HJOofϳٛOB8?aϭˇ!ّ<n
    ~<>``$341h.ycK#y`ԣpm<d`e>N`k_G1]WvPҘD"ԕuFa0pFL6qªݱj0`/M1d[ܡy>vT*
    }.B*Qj(	N8,k
    �ar|e/
    |_6km_I阤`aU\Q0	`ZB-Fh$:mÒv1B>6U(i8p/0	3cY!LŒ	]"w3n7u�s0- fŋkf	0&S5$Lg
    �6dPYK3+`B:YS�m7:FD1.uwl#LED~Cd?9
    ɜKYNPeZhG4Fu2faF?7m]B ,eK	p>zx}!aao
    97{glΞ	Y,:+S#t7Ë8w=݃!qUDRtPqY'(e3EC{@c
    pMXCm^_d"d0zqEJOUB'^jNlM%Qq(z*ю@
    `zz"'L4sA'O
    &̼kEf*x/YW2l3!1YfDZCU뜖TxV4g&:&0q0>'/V:+v`:mL`FjHV$1uqF	.X5I:Xy`ev~`&ch`*g]`bؓlzY]42xNbIƪ	śFL
    C)[QeGUy\*^wv=}5b)jX'y
    It)DƋ|KeGqPt*5E-5B JimVLIb2XՂ	w-I?LMTL5I$zpm#`"xͺOBb1^P:k4Ȑ CX%jpHY0Qt*5$#nQ5
    tRR65*&6
    vLeEWuq5cj*fψ.AԄ-�5Xv5Qū<$@3aw`v#_;kN	jz!mweÕ7'̋V95E[46Y퐑$fBN2NW=	kL5Ir.ӘJ�LtNy<H.v#_3
    &Q5cH\#Yy0Qʱ-FߢA^);Sl1|"=PGjBY56DSLeF
    P<`N∑!Ij#?|d0~=hk6m2kS0(Tf[pc܀nWxmDjG2`RLL/04`0Ѫ%C0<˃!zsG1&w/n(=T61Lj̴anxurkc` S`
    "%gtݬd?,Ffb5H+`gS?1Tg`UC0yxZCL-ݶmƭ濒[<ԃ%D=6O<.ׄN=";x~H+b(Z%Z4j0~W32s5ZN(A[gYE<2䨆f~"|;`Z-!V橬HW
    LgA0Wc&aWcfS
    o/`fXfXSk]\+`JoMp00hCsV:mѮ&u&d"ZV]4s(9>	k$r"y)7{`I8LMԤS-W2$
    o8&Bz}`"qa0][ӛw?a{5gS/(4IS1!(<hEsLj&Xfk!	Ӏo}xxvŘTh`B`0MZLi,N2O-`V
    &*M�s񛷷m6bSy`3%Q=RJiDXC4^h	U%j{2?	c%9yԘV'WfMDv'M|Df/Q4歆ݾF~]mSr
    LHɔ"0cڋ
    A)f./smt4Ѕ$.5	mH>Q$*&oD7gfݛ[fo*#Vn]^@DN	a;!:|pzKcʝF0Ìh"F%"~ui8<("35AB*"
    U=fF"QZȀ)=PS>їhVe1xjF]L_7z2'7dg`bz)	ҫ-T̈&i/k+"Gnk
    N) `u`j
    )*3I}Ɋf>Q6f/yځE=T%	ƙ`/L>%MӐ=`d3`#Yڋ}HNe51VTפ4V)(X<*RR_aLoLDbVL4#ɯnEoۋ`xS0dZ<R5zݧ2`u:$"^0_-,	9
    Q;Lʁɣ$0	LLtI0)JLS1]�oa4l*̪Ѩ'ᓁɶ@ỡ`NMd\{&m&LPE?>D=KO6)zH̋Y01ESoOT (p<H`FȈ&UYh/B22DH!
    wB3ii0ʹL)zp.$~xdE0wW&fK"T[LWN}.)ڧtacA[
    7\^^&x80f
    L;٤TvjУBl#y2Rs`u}[�l*fsWr֟ʀ&iȃĆcF!D ({o sqyM
    7NҺ0LDMAUν`2'}ANL4"͓1DOw}w
    a@S]^@/15Ubzϯ?׷�s$&%-,{̿`�˃f>GȶSY[ݺF;ݸV>G6˳MDr\*g36mcmu:H)BWT9v?֦ѣ=ibLgVw40a
    kff?{
    +`0?^\}sd0DW8ȚY>?ܸZÁ�-L^+\Y;0=|0 h`nڏx5sK)	DDUWL5ճ
    D"[g ˣd8*5Me~ZSOelLBP"TQ=pGMULjJu;keNj7ḻa!PMDZFQ1*qU,k.?n>^}syV}Uoq_5hɀ!*T߫pG&A^7gMAMU<,`z aa!t^M\L.6E)1*jbFH`xxXt�2?\.?s&&44?1c7"+`^l-&l>5	RGRbz*SM*f80**dM1>p2X<yqٸ)!q0fӋ?PMdգ
    bYS|D~y.I[27)03S?9VGГ`B?-Np2qUF)qż,0yy*5GKd_<鹼q`*>X˷
    (Ĉjv.@`�ƼR"TYL0y8*5GKd9Is{ùfvF&
    	|[!_A~�4ͮ3LPm
    'pGXL4T\dLr:�YC
    {iYa^p
    'pGX|V|i0qA]Jjc``=Mv4a'QR|5V|lwC"fy10G$YI`N
    
    :~yd3KK2f,5
    z�Tz*H+`~wd=i`j*mGPEqmjh8p,V4O#fGe?bfؾ?0C SGT \`pԟ00ߚ_~	XL'B@TÜ5ly�?y`+SY=Co|剭Xܽٻ;S<+`:c43ck�XW,V,`4(!16Y
    FN,$_E]eV)=]ZI!*jV%z&``.vh`LK`D$KP!lf]@fÕ>
    LwL*j$9L%7i阴DBMs+`-=_0чW&
    `&9k(;p$0q_3RLS0oH:P0`ANT_!k!}Xv1jg~@)Qu`j1VS07Ѭ`
    YǻNI`~]?[L�rځxCBԁNv%1[A#=VƟvm0g>0Qg1x*5>7լ`CǻMYiRYt$^0o#
    EpEnDMvD)3cJ=c#.?m >7լ`2@.ב	iy<0\!񆴨X{AިN$(HZG?=yNM8C?2`;FÃ\%2,TfᏀYkR`:LeBHy^\8THMeQt| LOɫJ!<MnVpӶ0dVD tpƺOeUd**|TYBN'>(#N&¯L's2D-2b6L<.A!Y
    &SYt_6EX^dS16Lxl.ْFL7Rqa
    0s/ +$@y`zt_aN>hJ>?-_j~dDxFⳂsF UY%ٚ6IY^-B0H{?.aNUPWP4.{\"񸄱1ƓG
    ``Q~0t]G4|%Y[)/
    	^1NyB(,7i`G^0`GLG33aM6+x!֢mAAĎ7̢`�픓+RTTZS|;|g
    fST盩HZU47œ5LV=ӪM݁0`mxQVƭ}:� 
    |cac1:!c"o-f7oRZ!0EAȝ1dfo&kf_wwVa~5L& L& L@ L@ L@ L@0A0A0Aߋ6=Ư^dg8̋}:6(z^GA(Rb
    .AɂWH	3s,x#yͷ%a*Ի
    
    Zbaf.FeQbap.XR`a0DŽ9aӡ
    �!+reP7(X�lH !
    l-v,_89/1c]3Zm܈ː[n/b/H)!
    ! SPU\-Tx Xv
    dp| e?1+Cy\.}kWy?bz7՛O	Zkn�33~/x͒C,[/ow4ITCLSZB^NdQ
    8Bݨ &_GI>p4UL/bԐ0T�mԟ/:x4zy4m4ezDw<T~/x.yIbVW᫈y- /n{9	.I<x\M&I*YdȖJvz1g[@wbNWbt>/bFju4'HmWJ6b6Hrk7X
    6)s;rljy
    pk;nY-,FvVยP1uEdMTq`w&(MJ�ϐZJIڒ5-XiBm'3r{Gs2@к%s[2܉닭Zp\1MR㵙i4dޯ.{\bҬ^ȽŔd܈Eyj rV3JqAM�8C9Zǜ;Q|}^/�W�XdqOZZ/.TuQpB`2C61=^̑s-F\،P%b1bJ3$;C̬p&_l$PIQq(Zj6WLS{im903Ljyb9ac:eQ@܉mgx&u/e_NNJbHI_W6,vddlp|6^b29#sX0:b~e{ ih4Z]7pȴ1(b6, 1w:cm[pj:B~ƓwBID#)GDl3FRq.�Wܡb*@[lQ|=Ǖ-Tv|wMߛl~6/̑lY/$6E''d^ԀdDuV¶mpSab7h>_561y/؋>ӪLj䎘<0wF@1k:%(�돭 R&&y-MotzŬM'҅ Xj 1+<ӫ+
    nա#
    lD_%#ȪS͢P%Wbz1,rgb/!!C1a0L4Apjf3ϒ&Ln>U/@�>',
    ΰ(z>_�NVo^(aa684FcgQhhP(Y.%
    Hv=n8bl5]bm�v۠3U'GB[)R&0}8El5vF
    ~3m(ױ	!—}:��Ɓ=cfg&�Eih_b~		bbb & &		���"	^`[�ܘ6�,tL��@ҐP(¡C>f�Sfہc��a==f!H*a  bE����IENDB`�������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/mac-install-8-progress.png����������������������������������0000644�0000000�0000000�00000030544�11773544727�022767� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR��n�����1:��PLTE
    '%4"
    (%//.g1P:d%9N1=rEt/DX/NmSXZ/A=-C>2](*[=&j
    gtn!c2
    e6s$r:t=e(%r-/r.0~57RJ
    MH8xEyG"ymyq1EEEHZoPdxb\GxTUqiPfffanznpwwkb|vcwwwPM$Z O/c4kr<}C^GpJxp|@8:XqgQMXiaunv!.8(*:135'(IS2vp4NS"_5Z#_8l.k9`:q=HJ]SDFUNWXsU{crqWXuJrm')01?@p1|Hz{dfQQpp\bziskwKsPyĜdž6ϲж'9(̎QeԋiݕiݜyǶLDzgĺuױ|GcL[DXT]ov*3<EjEYKTGVHWoQsь㥷ˎԯ֚̀Ǫõƻݢ̺ýѸċØƊʕуЙ§ʦ˸Ѫպۍݦڸ`[��.(IDATx^� 쿱d
    .C@<S
    1��0K8悫a@:.H)#RS2vi[
    Ť i
    zpT:[K]cEQ<9~P.,oM.ސc\(S.rLYf{}3UЂp܄b[-iIԯa`||>]xWlTXKM*}:Y[K$8Nz0˷?L	IDsJJ?Gsm?no=s{}.)&E1J2^gYV0H%1%PU;x�PRɢn탃aʹ]4칶ĒܬcY|1{-7zxzZ*<rhr,
    ~׵X'3r?{Lʆ,�FO'� pyc(Oߥ.RD{͎<SǪmCQr]j-TP8I!%`6T:M3v,!%O#4^
    zHg8*]W^KЕMnX|J~kD2@2@I@,"r?i]>ejnG|,+Yepc{W?|f7 J\FB=&g/~QfJ W鸍aEѿ(
    ؕqYI6M&k-9<rcHfRϹi3@+ZLER6uBz;hoǾdpN;Wh\7ȳXfVM mȥRnq{YmOOїjoȗ`d.`^`SWi\7jrIEU
    J1+n7ܟ^Zm}]Knף؀c7CDVn1�&2nQVHOd?t F8KήGp( <M|CB%-.Ex8ϣv]SITbO*n>5+B%Pqä,/` ׇ:dtL&iv&miTsE ~q~mn
    D엔!q1}I\2eov���Aq0vXUni]Fo.~KEfo&!@?AU>,rrs朹9ssܜ97͙37͙skHiN^JC_I)Z% [/rr}ƭ4r7gn	t߹9sӈ6#RBv9/nZR,bKAV̋qH+zBbK+✼i	RAJ*a\A6-YfnlSχit4)/n E^iS#}3<62scJ |і{/n 48sS['n2t֤͙VP'7Xz-i:qq+Rꄹ=2]c]JjzAAܸ	Au@0.n�JB	71[%i%@;s3{ǹXc-h%ktgM"!Ι2ݕ͙s9ss朹9ss朹`J���?g
    a.w[
    �梻pҢ\$57Eۡ@(<}pOGp#
    np#
    np#777
    np
    np77�5mf)I-
    ]nwsPs%272uma>iI|/Xٓ$
    n##FD)]bC=gcnহYj&|drMtz\Kh[?Crܞ͵YU?qky
    yic^UJyn~7rsҩb.p;R}V-tӱӭN
    np~qul1t"46FK}q%.K/H]GY^ Ov]t}#
    nyw}mjvox<\ʍ;v*؛=2lbQ^qC^q="$bHhn{[:%T8O6}P*e>H3nEy7
    qsaEJfi!R4b
    .H)$Iq#nY5M{5Zrr{׳S4I mnw2R+pD)r\]snh4h?F!nd-k"Oʽ+!nAl6=͞�
    q*m|"m?B^a0-VCL^c$`<A@\^C>SYkF=:Co?�qks\c.Q[!|u53Ovf[,K53=}oIqX[(6$@.E	8C*Ao`mz3,rS[$E怛e[s]xɋG̘k+8<vh!R$kkKsk
    dkؠ;Gؚ-ü[
    oUpy�WNf\Sjk@!a17(k.,opAw/ބʭ1Y>R[oݐpj5[^p󰵮[0o&rۚiPnpqujn~x>`	 
    ]@_7`m
    }P?zPbۙϸ8g|nwpWf=_[3*Nlۙϸ+Ћ9}g4fX3w}>`qgIk�Gö́XokY
    71^17uD8&fn(
    MFB[7'znZ
    O
    g
    q
    ~F<B.Ce~V8wɩeeO+Dn>GH 8Ҥr莼ڮAۇ]GaJ"25A[sCƦYIDB.+]ktCF+
    #"&9kieSF$Rq|.ԯηXm*J
    .rC%B֚(z"ֻڨt
    [ܽUdXkB{se*Ǧ%".R֐Ǧ}Tέ7p8f^[Úֵ!履
    LmhBnkKSe{AS{s;
    ۚW頍]Z	w6ܰybnI:q(q+v)5E݃ir~|6c^"k-
    c2}v0/o%0[OkS<W)7u0֜]A6MtG	K75r_@I#J.צ9o턹a9?.&M~{n7n3aY>
    m5M6d~tӧϫ٭rnaYjv?e;uNG/_
    ۚ1=f6齛-8+{nax0pwgۿɪ!p;$nK
    2t�LJݵt2?lvkneZ7p{C	�β,MI%/U`nػF0ɚXcC{(
    W$,٪ͭ=cF"j.i=l<:1:9;!}4;OZ5ld^cf=
    %r~j_7ecr=5n]ǡ$Ū8h\Rgs8v{ק'*rdV샖ghFYT6CO
    _kMv&fmiH(G\8h&7ܸ5q�ös}تz\ˆ4, 	X�uō^a=7xݒ~7lk^ƀ
    'PDl1f�L,B	)#.r,/D8]}KRnZ�HPP_mscm݇a[*%D(YzT'e92,�JgPsZsBDM)%kq[/߆mͿP�g0
    `QQ#77(J<scj'@8
    @YZC#fQhС>>-xmM)pe9b`Ӛۨ,%
    $@RsO9	|V6�'Z$	PčZx5OpvF6
    .0
    >qs<30#n[n-7-qMBMuO7c6~ϭm|(�TesdyPO3\Hbnc(0vY*RQCJv'<DKdIb5;kmKpBafq�)!kn@�Xi9@Yf-q%(҂/(S�x�dvv{modӜ˲.^]]r9t'Z#1^uwV׭z0ކmKfMhXZ+v(o(n;6p͍]D}3tqܸmV]mKO2]+p;-	E3}gؘkWq+z͔;D-Mw7m+WR=K?6Ңx% W3"0&"^kܕ	&u6qo[D97E[F A~82|!n7My퐟Znf,TK+jͲhKΈ~F+ڝ_ջOr`<R덻r7-|qfżi+֬Lnڛ
    [	TV2
    zd�\'SZn4bFCK-[33E*[}%7ϻki@.Fi6)mUc
    C#omYT	k֎hn2ԛ"	nn&٬t-nMZnά*6?k2-C3+1	% ݍ0�ĕ7>۔[{+FNN,{d%dZp'�b	
    Xm'4ՙ Re�ߐ7CF\]|h}ꗹkNLk^).qy7ʿU1MF"#"2�}8>� dL-[Jnd+h[
    ż=6`Vho̍p\λ.͔{KG.W3%ܦ@7 �DAD
     m4i<e�'WVL?bNL[Kcn	z_SnnTqKbF
    wq!"kY&n"alWnZ6%Z�x9V²V|V�'jxߘ`dfԼ!1R
    `~”Hn,[Ol1?C6;S]L/nw'Um[oGugnĤܶBsrx7AnnZ݂@VVe#]֬݀\Ƽ|iaẌ́N(L|,m<B![#&YnL+6?I%Gɻhn+Vj\[F7Cibc-覡|yior3ws;y}3/'B'ޞ�_Hk^iʇ&@0!�SۊpBT$)•*-#]|1KupANN;@oF-:7y5٦euavOPd*ڠkL\gWۯd׸OtnLwyPBF@#MQ[Mu
     �N'1J%BO,+-`=e̓q,f {SZ͂^7E_-VưefM3p~DٵRnJ_׹wt)6M}lo
    5a6!wǨV
    6m)׎wYr;GNL3trtߜ/,@-S/gHD>..!xirz)SuQGs{ae9nYbLs皛uhgg:Nin[h]܋Rn
    adL͍%e
    @xՍ'h܊߄ۣn͝P#H_
    ]?+W).G7^�t@f�搩改@?Rdz¼0k}�r;˚ru;Сf:Csϭ9T!i;ܜB]LmMsK[)oah5
    d121НHۚu偟tM,3&k_]|=ƞ(FW5G`r56UkF;|rƦ4SF~2́]ŭ!7>Kڸkf[	֙ھ{
    g6/qoX{$ZEh�?sZnQƼs,Q/%ڼ[Mk3SQXSZm/bUG^>7yZnF<fF�bȕuE~;$�-7(>1D9S[=Ȫu$ܾ3&9o-7+f$-nem:Ԝx~
    (1ǸNϭF4l,Jʱ?\~J^+%ak?ͭmu?3+Vn8_&ǣ¶77 խ<ѭ[{Ϛ0bDAt&t+&gKWkشS[K‘	I	9xo~G/?Alێgy鹡nDM}ـaेISUD& FwmdD\MkZUfh]jo,]kHïЍ|zO!ҎtSe*4J+^6B?PѲЍ7ϯWSmtUŝM
    5\k~^jFae&-<:Nv>w<
    a_,	_1
    Al<6.~Mq"~L]5N{Ɖ=ssid4k`؎-ƚm_1縙؝.n[mދoV:,t(4l]0כM'䶛*x�_>/p비PBÌkE7o5+nc&.w{s؞X`�BTT$.Q^vޙչ
    ΌҀYRCZbG>hnʱf`O1X+e`ȭ%OKRU!gԺ7n%z$( Fmgc͒>LLC*
    `ȹ-Fq52%BJ��
    7kq$7q}6bK]X8
    l=J1'β5ida%L㔋ڣ`iX#xV*|	|EW5M[<䙿Zs>>
    }n=֚99/m9d5q.n
    y<m5k̎ ��"C kL)e>qB�s]k.GS֤	"u.˪)/0�,{n5kXKJkNPCȳǭ7Mx>]hhl4�Aػca(Þ*؃`VoU
    R 85HQAEpܪ 	g3I3/y^n@v$.
    
    Zss;%Jc1pDM܊+tQX(;j.rJJ]hlBLms[=mߒqSbM3ixUm~DP[tBWrq{du8[<�<
    -Z6w#	!/ZB)a@A!сDE`f?#rؿ{iyyed8	hNqlIyWc	5[=*60Zn�[{{[HEaa.BQnx;;g r{'
    ꮖ~ڴ?@]3?34Ư|ɍmmZ'6;tNz؆-WK$pc-r˛Tm_Y
    nAES7+#7zW
    7;=HfJՆ!ҭ!In|mEn%VH[۞܌K?Xj<EnW5܈ƿFnRRGEncSp	n|�DndoW(ڨ͕R
    a&&hV
    WPB.ht�gZvmoYnq
    &/ɮnwaPLK#|%ܶ
    |!T3Ns6׺hr񬥑B(%V
    FqS*En#ওNCnܘ{rܐZEnHrn1g틐Ydzz) ۝[�k[�.5MxjI@nmt*ERu?>eNӓYv|{[9KnEh̞S9j[cMI7wC_fi 
    <�}XEPY$+g!}@jTҪX۪Rb4-ELsx2ǖjKUˣkOy:	saT;P|<o̗FKBcnshvnqJsfX*~
    -w䃯~	ˆ􁌣l)�MX4V3鐛04i1*p'A㌷<n"xk#BU[@NN!/mu)ûนlTinzlڙ
    =kkTqSDBv
    _L/1>Fx
    "px܌pq6hM65H+0!v}ȔCn_bnc P>�R]f=Νl݁H:hzpfᶃd8�7yQ_j|ilVgN�0e- scw轈CnލC)#Yu&BziZ
    i[74WQgde ԃ&7ԡA­7@`<\(MWxCoZe6&0&"gЊ*sGdE	㦗9o4[kִ87_3qh`mQ(6mV
    Z6Ĝ8o6nR<wf+M#[3٧P
    mViˑf(`[9r*m-gnhVl?47y^WbZ	5[Fnصkgc_*�^PVMnoo25978&Kqmu+hsܰ46nvoJ/*uܰsW׾7/'ewK?vaJu@qT'2yO=dYsIvH64$`-
    nB>vC"91!nN
    au7p^BN]];5�wd7YU*1~3%7piQz7nK%7bpCv9օ_sΦ7S
    m9MY6 $pMH8?JBnܤ߼{6By\|x|↰E/q:YrC'7!ESm
    Mǣ1�!p~byl"`ṶYpCVM7!p7~)X
    p}2qZd)s[b--WѴnk}{EnOn
    5
    ^_*\X"}U֛pnQhdv0wG.3u9n&j8 EH%Q7iw!P^ã$Lwqx2Í2[}sor#nOp,zp+on;m/C^^\;i@p;>M2tnmNi�cx*rښrޛfu/2.�pҸ5<.
    ܘ۞s�\531piDycN#nf+1eXF{jKB;�d.?z-#eol&BTԕvzKuE)5oO黐0n:č=u{JD
    .惐5~K?o1D3M*2>%ES3y3kUܛ"%6)K)Ÿ{7zvB*[bgAܛh[8!]6pu6
    yc֬晉]n
    rz{%itsBםHYo)8
    �+2]Λ{qHm7^*&jRp[8Ro\j`6W.VdN5�ۃ7e?p[O7mux`ܶTUmצ5pMZTW!G-X7p^)*-FwnJ R.=
    _`Eujiv~w6�01%
    p;EGD\Ϫ;
    7~
    7pn
    7pnᆛpn	7u㆛pnᆛp
    7܄p
    7܄n&܄nMݸ&܄n&p
    7&p
    7n	7ᆛpnᆛp
    7܄sM	7pMnMn
    7pnnMn
    7pn
    7pnᆛpn.��� ".ƺo@@?ksG(`ofBŌG;!EqSMQM7E7EqSqSMQM7E7S:mDň:&mF	eq"鼻wtۆ	,
    �g3%:1
    !
    !n%㌈qfw1pّ%q+Y,
    <_orC\u+q-\pKkcؙFY^tUl4u"0ùc;nvna_.H6<dWG-p%/:,6^Wx_S,|lj8a,Ƌcfͣv/z^Fy,-m%dI[	,ڏyLw
    'b/n0wwFnC[BP1cnavmߞ-q(bsy--꫱SXzC܈E"q.x.37on̊a	ԋ:UԵbpka0U[v;v妧ߪ^eu2h<omѱ%7[Wk�б+7v/$ұ%7y[)L>б
    7yMat.!2㦕	>!n;$nY$踇))⦈"n"n)(⦈"nֿv���a=u><I4]Y�/����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/win-install-3b-test-suite.png�������������������������������0000644�0000000�0000000�00000036523�11773544727�023426� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������|��PLTE���333�}�<tM~___|s]eedqodspgyyw�����%�(
    1	:���%�(�:	@'M%W?o?q;u9{�BAC	JU�H�YRj1j3fCi@nKtL|U}nvM}����3�33Rfhfv}fkhhf}i~|}f̙f��&5*03D(K0zZ*�;/�6=;CF$J&R.S2CKPM$T(Y7b:_@fGnRsY|bWvZoΕ:Xʹmjr{8?fwKHPsjvWgwրőʒ՗˖ԉ䍶▶蛽ԬƠױȶڪ̩۹˶ަź»̙˗Ȼ̿Ьпӑމߔڤܶ#zfE�U+16�Jr=�4�K�cۍ��:IDATx^90CQVPp2yVߚ9u
    XJ3\U:c>%;R\HGGz<WGG4$o@(0E'󹈈7
    (+\[@.|cR�Pߚ5cJ2+Ѽ'GIIOvj4)P.;Dax=Hㅸw\{JlD6rGv5?$~ۀwI.WE`JabƝ"rߙ'A3pa^;lya:gzp'h7L!n6jW}qmˎ9{,~3h
    ۭV٠7K&7LiJƼ9
    ;)kD9͋bs4\x8=yNB.#sAFBixߺ.d>淔9SK�|Y�Kz;}+͈S-�19^BaR=oS16_϶Op€41On9]WGhsHz8NgBer 6';Mnxyj\zE\1yy
    `4`
    /h�W�GFn
    "J	ֆ%0| 6/ajO1Ks>avx@pUC@gGF_gxȼ.8N/̽ԃGߺ1eQ:G!σ 
    #%ijiU\O\,^]pk/d0IoP
    oZisDh踊4HԡRW3Nb#:(|3<|> .h?Jх`k;lqT|;J\W{
    q=ߧ$I@Wv>==\jMYDE]�!İt6륩|
    z c�|:j\εRT{k,CQ�ӡ\4u|(:`}Ѷp(88!BH[&C,=".M1`H'ˏ7f൉Ol;>a&>8u]I̒52dn bt3npo^N	:BIȼ눙mMKMDb"CupD;M&̍''s
    }}sE֋	?d|+,.ׄUY2:\c4ˊTaۭfU׼|HndBQ"~B,9ēZyȫ{sOzLf.Jj4jN햿ٗyIJW,.sYeG+xZ͜-WYDO]\Kl(DҕG:�1@Ñ0XL1˲<T`MLc:ߢ7w%/v(a >x	^/e &>HK`z�wILP
    MI;;}wb{9:laLu#G4;>חټ>Gk2_,W<6k3'0 rI}6a^	bUlw<,rqKz`ONy{Cn9wms'ms΄ys5ke(<̫KF/9{;[;҂CޏҚ/mz0|^yf¿3gowumRm
    |̟{x^18ί4V6fyOjE<̳2K;GsyH<̯N5q>ڙ;t+</|99ǜ
    ;Xm�P=BzuzQoRCz),z>@4v®\>fvg<
    +vU�ӳsx8@}f$<,yP tH;iΏq&ͩ>/
    <74(iLʜ"8\(321oڶdɱC{-~OyB,<ξQ'Zs՘3c9o7<\Ω*o
    yyEPPLYJG:Bs٦C73'Dsw<q4??oim9ރm̱j7ZSSE|zs1M(A95m^A̫Rhn7`Z*3LsK�9GzrPkжcK&4rW呸Էis^q7wjMmh+�A~4vJo9
    uӈ+3Gmo-@f9Ly;<j7gpJλcQ|0/sYQڱwsUr;JB oȜXeK}yu69Pu9Hr{U=ji^l$.oRkCf=g2/Q[)Pԧrrђ#&SWsJռOs{-^_ļ?KZ.MyuPm߆qۮļ_|+i�oINrk0/h-͍;c䫨<뺺(;X*M\*j{1Kr^#4)IF!GegK,\m^Mq7JO^N:\+4ځznŜVc1zD*>"<xbFV
    Y;`""w0ɗo^�8B(jΌǨ׼Oe]VHT	ռ? T"ihᯨٙ͋ynjwy"/c'yi5OATL
    .NHr{6w]DgsCv7\ּꜨUe|ra0=EAOyxo*9Ȣ@W)@�=@E~?WJN D2(R63etFa82v 
    -ɥ1/x̏yZH\(6b4诣#nSj4́0LqD4l4.WR;Q+\a`70w,>�'4
    <01?18It5+㶯WgQૣ_֑'%fĈs&`1dAcFAzȁؘ2E.#Ae93f tc\mϜgn^Xc.|A&fmr/pbU—bA.`t8#1/8819D^'dpA~钤3[boۓ{;lM\I3/!4ʽT	a
    ɛ?Me+_D>Tx$磼}
    hђB޽q"O
    Em�
    ?R̯&JōWOg<ame%El\c陿EBw/yfes:L#=wy旳r}s{{[yۦ!̲
    i8#rfw~+Mֿ3w_?g0'*O
    sqV|+N.K!>)Ǧy)Ikld~
    A"rf0l9sX#Xea	*ͼ�⫢ډQ"!'r9`-G?nTgy,oIB*q;7U┙Ё8gj,aQ)}5>_%vݰR=kqp|J3ČY U@Ҷ)bBjws'Dݦ*5,q@%z5tJ;dޗZnNpJQ–�9
    Yc)dE!.	liD104TZ
    GC}um|s$G"rHM@yOxf4=9ɘ9W:N5I`xl/@TOJ�p8?+^jZAZ2ap9'f>uZAoqL]0<<ü]I\ ̑([mX`E"G|W8h8/A5tJ
    
    N#?ٻԆa 
    9@ꢇ0]r)C%
    _ʌLc"RJmh/='yXl(^M3azOv<j
    1ǘ&U>ݐOcL޼""@\
    9Fg f:"&G{&i	ݮWIsl5/’c}r_Fe3Y:mرWx-}yeTǖؑHf֗#X:@u6c4*Nb!WxuQGqgکc0hVGZ`*1LuS;9ۮ*5ic-`>Fs\]0G�d~$[#y>9Cs	34ghМy>42mN@~47`^T2Mk?z??O#G)SD,+Mtŕ9A\"I
    N)Z㑯:g17;ǰ^j]ymW?=z\oNv{y}<&).5C|2T@G?tᵙ'=5o6S\ښ̉hyYcv Ջ'y
    9?μ\src/D.sMTَΙC7sޝyYfD]=!~|usB:wᕓ!Mg>c% 1̅5G0gz+wDy֙ψH|LAMT+~3jݕ6gyJNml;K2
    gqgXWW
    W17;:s2Cσ7snűk7Uteٻ7XsbsyOm&_>KhZ^772ygvonq*lXST3WOoygIc~slKGp375'e	׼3qo.uɅAwK.|pq<,r9Eɹ"ܮ&O
    aHޙG!5KuItt2KH(!y<x'j7+9|ˋ;syQ.8X˞ǡ<<=5ɿҥP{%n53AP乹T/bUjMygH܍PJ.҂M=>ba#?C|r#s{\/2/xq\{{	͛\{_1vXr:Rkv)r#v3\[ˀ}
    ̓2\'[sN39|p<G1jmɼ` =BJs.d.=F27ܿ[:sJ&9e,ąey|nT`dR6d>aNkt+lGpw;x%0W;l`M\{=J\h&DArt۫aG9$(ʥ/.2ÿ;xn+V}6Gar@ r^cTc7(9k>O;5L?Jyq	m~#7DGEɑꙅ/2d$ɤyA\5s:.bIfWb
    )ȑ$Srg53Vȑ Ĺe!w\=f3Nř/{{2u͙N_=чC;ЙCmϗb~h3e@<B%z
    r7DіX{CgK0?Ϝ|/ge98ˎ7;?E='tS"cgM]+nMZfO%߸&%9qXg>kj~2gAFm3陋o
    ",#,0ԙ75?Qe9)#e!f0G&qVɷ&Q)Ir#lu3spx̉[?!l\;ep~%n9J\Θ"WR >PQ ]С| sBmhPđР<k<ZZ45Ӽ?swyZn,nl7?͛^]=.nho2B<~~O"ڥ+TeI%&#t"P3CX5gbi]-F~nSAT0CD}~nybM&CPU"EN#,9	b佝+SU~:XbU'T/[A.K9g?ȏDYQ:YȗDVu1w*߉%akn;sm
    W'WPUy9,),$g,	{
    .9QeUhzRa+mREy5oQJz?'<Rwe%A5:r]?ߟN0ٙS:NnJî#O3z!܅~9,v4D<&>sqpq(yA*]jmȘ7y>#	ɠ{`^=Ϩa?1'GG7~]:$19|8_P�dxEr'i=XF[ny1asmRz~9@vE騾| [=<'̰�u-jK>?4sX0MW?Y"IÜ-/^m<Hذ@1oKRJro[{76j
     ty䛷KD=l
    |$厽91^LC:_6F~;,{~O	a\̯C?񣊙;]l$ԃ~v)b}"GDq::.nLG9ٲϱF({kkUe[}x!g?l3M3ћ
    p&U$${@4M&6p1pv0N N	>AbXwD2cбƽ"<fkbU@"ȅFX}G`.~�77Y6k{eؐ0F9|9+A1g͝cN
    =\IR;ch:52>?:0+/A2m?9rP^Ֆ9绵v&npժ{LP1Y9Umy='Ns%F&sǂ<48H֘ۻ=3u̶LE??dD`Zz"?10ء):k+ejHRޒz6(pւs?DRTbS|EݷgԲ	!�
    iɫgFM,c%E;�)KDq֥y/,2zvͮ^Pa9<�p{fZA+XcZ]u%̛ԹmAP.w*YEΙYt(wE,hI0`=q7vq70EQ<wA=ٳ4kƤ}-(BF"|bN34pӣJ&Ͻ%7kҾKĵWdpv,q|]1{?:(19
    YYDD_\?r<Dתq5LNy򣫋|.P6d.kb<| =Y>
    u}ruL
    %6yu.Xuq̣5s%vRH>F
    se>s]Λ5r\rrKExNχ
    �.E#do+[0/K\x(xΐ]ӱf4\oB6*Ŧ4ϫv;߁}Q7$(̐0yL/,X#^KI]BK|85
    @Rz
    W{�`hp
    XʽifhW3Euhr;m0ҡs/࿸.
    Cse͓PmH(!(xϜ"jޓ	2ϣ-uq_,nYey
    y!NƞnKyVK6Iqeo]l`gi!.
    1?-g>y@0Mm>y1槹$#UH#]f[
    >z/>C:ŴoT`͹P|24OmqzjN3yBu~+<EŽVs"+iDyݪV?47L�a<q,a[^}q1G1Z.sf]"ּnҼhEd-?i1$'UU2ޜ~sKdD /Uhc]mGs6V]QM8U
    O]zh` ce ?#M\^E>0*r"exRbi 	خNS:�ϋoop|a(V9 {zg2|,5Ү92ϩ cκ95-g1rfe$MUKjNҮ9:/&q&uwއc%˗pbwumSb0N挵al_a.8($2]UW,?Rn!B.沆CGpr.k8p;;E='zNwi?s p
    䏁2i.̏ş۫m
    6VXy՟;ӊ9	Os_KL$mչ"~	k8ąݳ?[I&j~?\"%zE=Fq!oө^uTo	Z~?3!]rݐ)7SE:e4O:OބTZrPEfMKmfPvO=
    |@7uDZ<x'3}\5S#rHN޿zwa~v0a8pDQ9$Pj	+0(H>DQ4d;}O*�o	q/Nq?tTnS್h֏$<Lyg?_s	RKpqߪ]R7rM{́Y2GCD;pz;W0fZ0(
    C{:}'/#emhHmߨ>s>nϤ7JRes]Nl^sm~upxn/+AnQgj6mDƒ])$[`M2>a+j06@OI,~8JsKx1G79[p2|Dٛ?!9�5%Os+ EuF
    G	}r̜-s_qOq|O}2(d;!`
    xUy~Әz4 n\AY|]crG橕ubCAnq-q؛j~;{^\oZr~p
    S66׼r*C8ULa~u6L6T
    tcZ}|] q{s?X^ֹ1"l!rk8)nUOB~
    'es0F槹.k'8VQ_ݗ3\ǣ�/	gx-ZM"8?wX-�wpsC'sBL\K>GA{sJԛpۑ j6/?X9flra(tў%g�9@oTdmGmuaꉔQ;1HãhȲfȍy*2b8Z-w7/sqN&oۉ#		W9k,a/@.h9D�~EwA,r"C1D9[;ac;QrDbXSgOr;(C^6'mTL?Zg»<ss4b>W\^!332e.|5Efx8.JޏGߡl|:ǁD\tGqnd?
    ڙϡTf@aUiTo:k,؏EZdf928NdɼRM:7F�QaCa-s6z+|5B=ўݼ0o0W76ӡd`x;e*n.Q1xZ+չ\!%n2Fpo>2/%#aX~92?=Hd3s9صM9p90q1t�G(߮aːƌY<Դaph[lGOp%=ET"ݬ>ʟ\`U[dn6\P&D6%	{UFa}x89T  ohvC~{;s.TJ
    v&"o|g>s 'LiI%O2?sXr3w';eh|gCs uANhgG
    [a\l0?-g!9Zg3u,rbKW3Ghw
    @K#>/pSFEVX/xK᢭Xe?bb!%	,?fw*Yd4$#)z|ɍRu]g4/A/p@=n|#{u|*<y1v%
    #(r{EjImռ<^Қh.MrIMufbNo7$HM`\W0ϑϋ91|=jv;rIj|Ũ0 i܈�ODU?E>|@Dn![FiL,UsFj弚s0d!J}3ۙs\jr]ת՜v[@kFosM&(ً4M[ x4-B;WggglO,c!2Go]@z
    å=Yb߬?9(>c5tѫ5͜MF"Tƶ0cӜ`#~sW|~p}?|2ݚG6*`;gPyѡy%[zl%ҚãϿ@ppOT}֙90NisZ͗RٷnH2T9-H~f.4FA<1eWi)hXjݱ`B9yϲc*V_K%y)%41ű7]@PXs<f󙩽yĖuSs`ݜ
    CrKÑk27,rYZsCT	<M:!gzy&z3gVd׍Ln9+
    	]*-K/�_j<E9p=%[cxWx4
    iW	9.n18y=1]pQF<zM{n2nWҘkʖ<7k~XQ<j#�vQ
    GtXsZj%b�Ic]cޣy+h*V�)O5rlh>w4pl1WO_h/MDkS/'pdpx'ni>|^
    2_͙�V葹
    (Cs=KI(,� NwhCOg#w5[O4o))cH\^[se:G2XŇ0N\I穔ըZ
    aj	M+t|wc̵[}p
    miٹ[	7g,26I~s`nuW_Ƃyڭ9cnkgyyuh.qKe�b~f󜾝8w`=
    hbzGs
    Uu幤"U⮜waPj1k%bГٷ?̓9Үs--LFes_<ꖐWux_%yy9ɑjMnvhډk̻`N	n]YʭŵGg>$'jիo[|-N=JnwME;`+ŌG̃9W	{>ϳӻ`Pϟ,ܻ9oy&z҇-g6[9n/kI7'v4XN`<Ӌ'ݖדG5泓xLoX{q�̪u	,x~QرN"[wH4-ioXԹxbB"h"TvU}9&3o?\
    uԳxM;ޜy0?3)-_5
    M&h<R{9UI9oeEgiMrx]|>C/qX^<7&]\	^i&_ۃ6w^(Nt	;u@̓yhZ\kŭə\]	PBU	n'|Z\q,CIpsJ,K	̓i#v86iEUfw9	L*|lw]߮U^<7ky!C;0g@;Ba6[5 .NںIoGm[DCrm$+θ8)0Eq*v\Qs^Z<AH'h~I
    GrPy76-\ّvMbMÕ̃wc#oќ$4^ّOoG9-`
    OO50+s}$QS
    t4›�)(SΏJV8s-Q45taȩ}OW99i_<kq<2yyfso:)* 	�|!Q亿U̓wޠy^,@.	f"P&
    WhI++sFt4y	y繠IN(\c]N~.ڭo3b|KhNk2[CX9NHYpE뵾y0�XGsɼ=5oPPh^<O%);}4)�L-{
    ?Mv2tm]`1N4ґ=lo6J{Fy/_>r4as8on]`>F&}#!iKMx&[3;nZs2IN&yDz<-%9yO°OakBA&)ca lmeIrgo0/g-T]=yw{;+9k{Y^yܹ[}827&Оm%%g>9cl^y0DWR
    ;.5ڷv.t%Q8=}fcYuȣ#9w>9�cٙg\̯1
    ��0Tp` 9Cc��A��#�nVp/qs89Ι PTxMkaxD!XR[%~AP
    |A'`ds{
    0K0
    |A'hds>}2Q$xސk	oN^JA7dF>*#ڨܐm@/`a)z+P%`}bL;f#.:EqK<քأ0O"0ay=&QP3º0gĂA$Ӈ뽑zIy3-9=NdḓՙDdd42?_cQҙ`@'0G7_]6VЂfΜՍ	W9-]]YOwR3P�6+H,eǼ9!/e1Cݖ9ar9@Q#xX
    B?81Qa"g~I~'1Ș,1
    џeQAD!<gØlÏ0qO0I$B3?c
    +I75GK e8DP9s􂢑zc9ѐKR>'w}n-i3RF檞EX''0Fn/lb:sj$	~E/欷."d
    84.vdDmC%ne.`Pμ"KnZpdGSdȵc66i5C 6Ȧ=
    pY$[Hpkz2%cG%bc�V]#F›G}C)j"�UחS#?Ke*/Č77Hc�6#Ov�XpA@�3D}999999ӳ1
    � @$$HmeG4=]k28Qdm|@]����IENDB`�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/ubu-interactive-shell.png�����������������������������������0000644�0000000�0000000�00000016204�11773544727�022764� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������`h[��PLTE��������	�#+'/*�($78��&:� 1###&&('()+++,9-555*4G6J�;T�?@B9DXK��LW��Y��UY--g��o��h�o�hy��w�"�q r--y,(x0,BX�DV'HV*Ne�Uk�^s�cwi|CCCEFHFHKLLLAESLNPSSSTVYVY[[[[AKaHRgQ[oYZbT^pXcZXbu{XZddddeilllcjynptuuugpkrt}{}x~lor|v(s>P~���	*�2� :�$,�(0�-"6,?51$B�D'H*J�G�\�C9bat+s>Y[XZIAZTNEPGRIa\cZPbbtt��fkrxy(mfphyq4?BDWVbdiVnˀ4͆BϊDŎXԕV՚bןi؞dڤnĽƕ­Τҫֲз+-3��EIDATx^A
    ��@[.KfG/BoT³�� U-PV*#]:vU�0{sosGEͷnM֓7i
    ҠA$q'ep%MaƇJ>\yoFgJWt=GoiSH:&>*`!@5QI
    '!޹f;j_֎JmrNO1*
    )oa}m訊M:PTQzS	aHE(t(P(c$/Djh'Ю•ž@!!sܟgsrk*jB&loB�t�BlZ٘W#Qy?k<zwnE]>q/o_G:j>5)uvSdDcR27,I	s3C_+ƯzN1.D!O:J|~wb R'p0;	/1D
    NU07].زl/;rX5y(
    h$t順"!KD9Q::tv
    4]xJT;h##79#GRfcƜY xu*,�H!5A7Qu%to�>_ڐ sOS>gYp.(Tq_<uxqq+e)_!34-r:F:ANV�f
    6tFC3=VrfcYkjˆi*ܗá۷+[	
    ;]Bd:=̴"F;QX�B^["/'hɄ|Fbh	$/ WT1)ܗ]cov:!njU�ݡȆ3xP
    mfZ$a#HR%h1یSE$Cۥ/
    ~}M7\mW2 !5:cw#?^5dynjAbuni@$3Q#N-Q$(^j>VuN>`A\kqrm.Ҡ/7Vl	f*o� ?ALu?ѩ@R+NwI\CGҬNVSVqLʘ_N&;Q~�[U~L8rLޣN{iyb:N)EA9 hh'0�
    M0GL3
    0_f-0K4b5"I=GQ,N_v-;U/B0^eYuXA R9vux
    :9.~A?N뗴]$B3+bojkcn,%Gɼ[j#QH],d9zc*P�iOֽ?	^{zis0tE4EǾRJ)ZUD^ p<=s%$bN"&@ޙKEIf7p
    ,/)w6?r>}b8G@
    )
    !36"SA܉_	�Hģu7n/k7}Dڛj+V>qOv�b 7ug0"+!ҫ6g7/?|٥c��2wN~aU$ׁ(lP *?}GLsC6i�A%9v{2acfSQV=USEQOTQá*)u$_c/](P|SODv_6LCO<	ܻ$�hTq}i{�o㩧3O[sxa$%�i'iHذ;zNVn'4fk
    ΔU:<6+^ڹhD*"z(JRs+h=@E*z*Pל\)S`Ow%T2͝C�PyXk\{)2f-R†"j4HRx+
    '
    KqPOE{j-nF@(!`�sOF8xo
    fbIz:X
    v�
    ;0h<xs)JR#S~iT�e8*?4ns<V>PO^Oe~*itIkISmnt7k'N8HR#e=8�SpU(-oOh^ַnh̤aOd?}|>i)0
    8WOeRz%E8z>U(Sv
    c}3{+!
    r>-Z۝)rw,kz>.lT(!LưTTT!;@O;kOA徔~;:|~*kz3'lYT(' / B=U(-ԇ'^(z]C		J	}iJ(갢r$OEDQOE=UTQOE=UإC�@ H_��=`0x>USSv2>nn^q'\(ӦwTH
    Db'uz4=k^fC)Z:cXPG`SO
    dSip)qQ5:_uRR@&":!ad-yPt\sc|c\iw"
    Xpsg ֻf+U:_un(;�MԒ)n:4<5KtOt�`>w|J?vHyS#Hm+N[y|C&>*A=nrZiwyYMgB:>.k؄r˧Po9Pd}'H.E@T{"H$̧	)Xa>lӰ&^UW:Q7}sSgu/iy
    ji?>9qqW@>%YG_9�纐PS9-G=yYOz:7u\s0ɷ|D.ΞjeP>?UD|zLtf理u8�~eAƏ�ʞ9�>u}j>HqŃ>?O}7>*렫> iFPgۧ�)rO�+@@[}o
    >G"~|<*�Չ$u/Sꐓg}Y4*MO׹>06d&ߣ!@vڭ"ǫu+?}�mGݠ/�)ȳ
    h7:!"uҿgԙyk)|
    OSkk<`>EAO?`:04x%̧ևbO
    |jOO{]8ǵO iMfOG9LQhe?ں9x_;`S9@; fW(tg|z'4̧
    gLl[Sm~pr߅'uLc;>Sҧg_||ZʡK%Iu~ԧܧO1칯�`$dg|>8|
    ==Q"Җ/^wt\U0�J93^qOl§}R1r?:.o>Oof�ir|#ևbS|jS0#h5zOQGY~ɋ:I]濾Oc&dد	E\>gF]WṞЍE>qjsvOC<{|֡OsQWm<8n�rכg>Mzj~<@:H^/49YpݏHuJ&n3wP/}O}ۺEe}y}o�łد|Gw߿s֡P9S9]<'uZN؏H}^bv{ުN%0ۧ>It̤cE}y}6zlꧏ@[>zKF⼥ԹSe=nj~OGE۠f'iΦ.O}k/SSOt"ͧڧ.�_S|;`A(#?)|><@wu7gzO<~N9):n[t>]}=_/+)aη*t~=?s./Xr<@wu_}ꩊ<'uj!NoH:nk$9oϳ=Bg'-]|],{.)CuXkcݫgvfޜD+y}Ϸ_R/`ևbO
    |[0̧U߆a>jX^�Q6)T	#O
    i_�0R�AO^[}sc\0rߊR�e73/˼orCJ1칏P\;mSO+ʼYa(+>!4H(j/~
    ?e9{�_-Ҿ91~|eң9,GmWg-f}s̟ٻC(U5]	 HqX&!@H'#'OcnmEQV#:ENAS):}vϙ3tY2Ag,t;dNi)tNABSt
    :S)4N)tNABSt
    :S))NAt
    :-t
    :ES):N#)NAt
    :-t
    :ES):NN)tNABSt
    :S)4N)tNABSt
    :S))NAt
    :-t
    :ES):N#)NAt
    :-t
    :ES):NN)tNABSt
    :S)4N)tNABSt
    :S))NAt
    :-t
    :ES):N#)NAt
    :-t
    :ES):NN)tNABSt
    :S)4N)tNABSt
    :S))NAt
    :-t
    :ES):N#)NAt
    :-t
    :ES):NN)tNABSt
    :S)4N)tNABSt
    :S))NAt
    :-t
    :ES):N#)NAt
    :-t
    :ES):NN)tNABSt
    :S)
    N)tNABSt
    :S))NAt
    :-t
    :ES):N)N)tNABSt
    :S@t
    :
    t
    :ES):NN)tNAt
    :ES):NN)tNA@St
    :S)4)NAt
    :@St
    :S)4)NAt
    :
    t
    :ES):N#)NAt
    :
    t
    :ES):NN)tNABSt
    :S)4N)tNA@St
    :S)4)NGCSt
    :S):>):}8)NO6}t;|~e:Stnttxtxt[;LwNm~سC3�7h�;
    (f�?kt7-aðvQ`0M"tÿR(rv~z!Y9zepԀSc�t?Ep"8NvBݩ+tړ=N
    3G8jөV9Ep5Jwgs"if@NK"|Tf|sS,niNiɹNݦ|qxHN4ON)S&N)SaDn4VN0^tܮߟ.yU>)S'vH�BA2^GteE>X[Oh@S].��@Ŀ)7FX>ZILv���aowhmR	&p]����IENDB`��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/identica-screenshot.png�������������������������������������0000644�0000000�0000000�00000030423�11773544727�022503� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������^O��PLTE���
    
    ��+  ! +��(&1�71'&3#-+)��U�+U�.n;<@+.n>@?�UU?A@/Jy+Qn2Ly:S{D�U��U�+P/O7)g;d:,B=CU.n^@UC5tFsL*QNMPZn^`__`anWIc^bueSpml�+�.�S�T�t9T+U�tB[UULbKfVkRj\r_xfz}}d{++++UU~luUU��+�%
    )4""33RX)g2U�v9]DQnmMylSSyPslxx~.=.WuCYiQhnԀ+Đ[ǗkԪUԧwU|șŚ͙ؕК⫬ɫج̮ջŶрԪ΅ܷЀۿõ۷ۮϪҖϟȦǨʷƳ֫ܳ׷Ȫȶżԩԭպظ鹌ᾨ̹۾єβŒŗljəԀОȫ̹ӫԹ˥өڷ2u��-IDATx^	
    �07\%� =8NJ[N3c6 o"ՁKB_:qYcDq/pA->BMXTfQc5cŁ5NebmyO7+ofh{*~=LDtl.C1.Qr+> cY,FŐ`r]s
    9!P>,jVp8XƳC5WOwd([]׏54ýtoha鶥u$#qcQq,\حV^>v*VyG*rdne"(aO`ߦ=1�އC!А[j#"*UlZf
    O7e+Ű
    0y[ip0	Y0jҿxdW%맏Uiz}*تN;8;лz0?Ig1ŐDžgq$~˹ny'TaRC>(,}[J~VܝYQ�kr!!@NAU[x6R:CLh,S1וŐ*zu WM~!'EXf	B@^F4Zd+L557 t4䰈0�ymlP7]g@Neu{\s)@X
    R_4Z_:mEoH4w=AmF_3�qtcbش@>r\eAn.`cIroDN'[B+n
    nJ+h}/]_ס1ZJ2bau׌!j/I
    `:܃'/_B.p,-xiӡgxWX~=J@<y}bֶܶM#pCu�ȩ[Z-[_
    ЁBb
    .
    
    q@Gb3CbF8&'X(/W5-A4
    ;.{GXِ}݂,ȓ(^,VGȓʆz0_YyrCr
    9!q/1e|c�A�ֿ.d� �."�˙=6e
    ��/j
    k8h4$8���?z6na?Rhk_6΃�VĀo2E:DvQp@M
    9*^rGYL{d�ﹸ�H�HH�H�H�H�H�H�H^8Ra8W*og7JY�-6�~H.5G�@rTT �.yg+tyg�.K{T6˷:=<)gaank.�InH_ky'qg)˱<ǷxT@򨏿brmH䡣\9J-͡C[(�u!@򨫑Jr
    ;aos%�$/ސA]�k9.^($w> y_vPr@X&&~JHEr<u`+gr`t99 y' y+nߵn!fw?_k<�7$O%t'5!� y98;x=C]OBXZ0uZ/@'~N׭_.Z# L#Dž�$/H)͒M2[+:Ԏ AsXDsz\/K׋v
    %A2@(xdMѪX�ɕVG</m=#ۖ
     pۼ?#%Z''ߊ-$lN
    'VZw30?l	0ZٺK$G\'洛۩Ԓ<ۏW | v"gNy/$OZl,ɫoV?oȬDAi$˽:y=])*{祧+mxV>YjfL>RZ
    .
    a24-F֎-V|Hg~iMm&#m:pSgb9AlOT
    9Grט\m/A>Y,W맽]@r[LgRدW˫'fNfԲZ� ;XD> v$'A! ƁTy$Y}ӿjH.dnؾHխ=2ho{F$\S�O%'�/%K,!�)K,#�)?v0;^`1
    f<#Hb`
    "1XGЮm<ŕ! i_z\YWyY+#]+yp&D^\+B@n66Dr=PÅ\|kxHȭ#?vslKLȫ'tTĉxENm}B8uD>0u93
    (䬬6;{r#=B@yCns_';;kGȋ["_ԲϠB\~ٽU! ]!>
    r0IK.s_}'Gf+6
    b3~9eSbj>r['ASώy3I:M#y<j3# 
    Qo]dȝ<^!W	9Ftˠ
    ȇenN9rh!/ބҼ9-vIrg?@3-+A_+.'i
    %H^&xX!ړ֤,9JQ[CDtd'D]:&��a4F@H>$Ar$ArAr$Ar$Gr$Ar$ɑ$Ar$Ar$Ar$ArAr$ArAr$Ar$Gr$Ar$ɑ$Ar$Ar$Ar$ArAr$3cȍ v8|}3((%`a@EN7(>@@@TT*n\Ǹ|X=oN89z^6ӿi1ݒ?$[9&3v-DH#iv&X'״*!2<"mG _],u_@=G G(vɷ1I|Ҽ�:bs*!ODu2k<-]sL<HMJ,<
    lbRH<F4+չ
    ̍?e>B[_K2Ѿ/ojVJdy>:_fkMm3ҳp)eŤKB唖֔v
    Cޚhד~2$'n xxiխ]ՕV@+LV<W`Si}'nk9rw/3Ƶ"_! ܇9qY9R&+NT3Ϭ%xz̤#"H91%
    Йk{\b䍊T
    f9$9V<q=hڇ9qY(Ne?Vtdl7BA_e	9tHrW#O#j	v*UqlCXU�O/cz)]IBѕU!4݃w!wL,ū	Yt:	f;,wW<
    r4YAo&ܷ!;rkҤ=7*@`Q_$furW/3ƍey$�yy O*΄3) >ρCʫ믃| `Af׃#b=䍊l@.Sr=qbX嵿]YSirY[|o5c9vۇZ:IXD<=h&㲳]%BJ=gB9f~EY
    AM\3]c\O<΄<rړq_-Cn=y8d8wI9Vy8b˵x^WIoCΘ6h2qN<L4ݚ᱇,ux@S0
    @*@xS]yX塈)rS'ֳ7q6 GyА8,,}
    I瞏:w7љK,}aRH٨(@ N/3ueqచSsLMՅ_keAd?r+Cr@NC^v/)C!d4W*QQJی,u'9B|gh߼ȭ71h;Fi 0jiaxgHl=EN.E{iҦ	,[(cCc	`|z]41gtMx,g9�O{99ݎA r9"A r9DA rynE4K@䗯w|^D*M<3_3Q<c@`7gKɢ<CyZg@"\B义}@A䗗'Ѯ7G r9D"9D"A rD"A r9A Rʕk_uJǗ^Kŵ~D r9D"#r9DΞ8RD/bYOv=	'FnO09x^r[]ƹ~~/z5M24 2=d2I~<^wO�g+5
    8Fa:ty>ܑQ'U�"/Zc=F9'ȯrVr6 :ȵcJhvbOC~9cs"�VTE~b\!r@<"EPzT�kNrp(�麒_RA~C@gjȱ@~;_&8#ygU
    `]U9KAW1LcVb|]kqc"?!�ևV#7Qk4+?g!U|syo#/wCVrZZEu�f!`@/SH;;CjyR䵊"olC"bJ!\N<tF䵊\w	9N^36vF>ym 䵊W*E9!z$$mO#0}J]7?~n|�v՛Cz?ᣜ
    r+Z?Cz'/9Y sGE~s#"_\+=]ɑ b1ضmp^޼jJo#䌐@n$
    "69Rj~?SRuWY"'"9sC	gz-SH\̇
    !u~ȗ|?o;c2Z3!G>v;~d|9?|%'W987b09kīag�h-+4;m�"F@#-A*/PtvO@[HQo(b,ZN
    WO`}p7C:ȻKmRxEKGy61Yв9mR7"gu1zJmCtHs|^!_BAqo&9ȼ	|)W86jibSx\PD=
    ywi/J!wi
    [' ~x<D㱊yʂ%�?&rQa")ֈ(-HV!/9t/^1C>+St4nG.@ȷbƿxse99rȔ9zKhˆc oK:w]x3nQS>j ߻g쮘!JW &>`,Wt\#
    Fmռ*˖t|ZzYSXCJ#mp1]F\g8Ct$do%Np.FO֥,WڈV][+;uVs,Mg JWqLJ@+9iTl&dr
    EPG*9[YPDC
    q/D&Y+Ȳ)ϕ |c$Y2TN̒i!-H]Hl+^_h%wWZ-T+ݾyNVr?UOg)BJybNeMs`ǶE
    mi-<yF
    ʊ 9×Ff�\&2,kS|$&r!eEVպ8v% VQa<Ed ϗYXE2Vx`rQTHY3c"G_CTY(A_&ȅ̍J]ii[ȍ"To\2RZ&oѡ\oW9v' `\L?.seKIN·N2z|Smc!Cv5G.-A>ݎܔ-[rLJȍXlI{.*!xE(u cyь쌖~9!BXΧ4q9uPLքdN%.vPGΕ|C+],9r)Mytlȥ2Wya$וrʋZri]*ךk*焼�9"1A+r\*!o'nu{n\)Xa<YKDOI9cOK r
    tUH
    1=ʕwfR=%'] !VO׽{ P)k^�?g?KӝtJ]l!ׯ597Lv**kriM̰yx
    䲫h"L5{m&&vJ~|āJ@JqGL?~|&>\)q9+
    됳7ĪAbE~!! g5,YZ}㹍+=ُ'Jq3+gi%O=Bxey0?eQZ$Eq晓}܎"'y3"GٚDµZ2;}򫈼{|;Q
    T|i<LwvH}~trgφI0+]u@.X-6Cjyi[Yy�t5	#P+YE<7J"/I,ja+FI$iV"9~JMM9%<y}MDhx
    \&_-ΠQ9dau5M#G'y3ѡd9U-Wz`~>tSxBi!{g	3 O<\[kєY#[hZB >@VU"a#[`Dn<|qN p'*cCnxd+rWJMϦII$ʗǧb>6Q\30+ս,`rv]>-ȑRXX&B6vWqhɫ
    =z%G	-.ȣh	vζTDQT2[h?!qRw$W'3I 2NZCPJ:_"ǐ[)4u�`gd
    iVl B:'&b:򐰁W-!),}%a|8.f[<B9yAȟ8�NN!:~!O!wr1ZDbF-rZ"g|3~]^!"d{Aprnǣ"N"RZ*}HFs1iynCgyR�"�\�\(|
    bI�/?yYÄ89'ɲ zP#75 %8�Pf2@�j{IBğ>48y;2C4�-sxz#*즼RO\r;
    DJ7˒DB=F#\Ngtz=AD3|\n7�Q�<wl4;`j�qꔑk=&,5d:luy�
    1U
    SQSJ8AdI,>OrXF~b?zMYU]Y\0rxq
    D/>N?C= ׌|tT5iAeeSVŢS8MWs
    +.	IH# yUR$B>!)]qEA}mZ//Ej;)me?;�
    C[솄
    $by\ʀ7xЇ鴠sY͏_/#Bo{^N#&C	l=B."�	\@ȑ(RÏwUn�#?(^<*v[-CoK@IhVр\d\[�(	)G�=hLm
    �aBDp2A4t7I$'E"zi&rV!O/䀑L@)jMQ#VO'-rX6>h^r(u"Gtlzfye<G�]'8.庈@MBi*8'	yͼ]r},˱߳4Ĉc@vM+xlsP.~G8,ymE1z=?^倘[S
    #:@|+EEIA"WiRY&fCuevM嘯;c689@8"r]UտVP@4C/P
    C+D{>oV(㼸V[a~JQ޸Nux!dub9D|lqGeEy9n{�o7Clw֓k{@2[冐yh{JM[y85pNW1
    Mɸ'x|8{@>>OݦI^m&k෼ߗx]Ǘj~?K=Ji(z㢽<.SKmԾg0hx^e<:u4wwv/�!ׄ[EGQkC@Dz^.'yw{a
    $QC'.9ɻE.y{bPk)T{E1$r$?0=O"[!܊9 UÏ+]}xLh=EBX+׿$6aPh/{wzS EvJAu
    r,=^
    "lC@)]S!Ǧ`djK]t!	͎:?2~yyɼ=(7	߱d<Te<	'0rSy%(gB!>T7==}D~ȥ!g}n9zӎ#J<{w`~"J"WA^]l9>ְ݌GNq�@
    2
    HR%Ees"!)=rۤʫG]gA^OqOЫe^y03!'R1:"Q?_"G8mtz4Id܍SmbbALwrf2VS-w:yhr*At^SGt>^7LLh<% OVە/phN{l]ű|x`-W؅7rJ,q<ä'i
    ~0@<Bow '^̹&r5OKff#RF 2-/M,DD,;LNv($*HĀA`u%'\fv&zS~WNH1l*ͦ,	'ɋlͳ	s9T:NhAٴ.l#r[?ʲʆVMU׈#;?F4ł.H!Ua|
    yF/YuQՅ_nfb)>bEY]nzf M4%c�9+܊xj䓤nMf}Wx]b~z\R%/f#)ANg$Ii2R+MpH;g'7kc}ٹ-BWr.$jī˲<Ѵ}aN7:+NvrQN0t"/uΫP5ubW#>$VOΙ.r\Iܥ\ȼjDpߍ¥j<tWr}+/;ݻ+
    D B}WϤ \č@;i7rn{ԍܶO~3lww=PvyʯVܮbhp#LS{V;7G>=D8ɹB~˲<gf@id\+r>;{\1DR5p~\.__]-TBl-̛JFnܽo?Ikk
    э^=z7E>fyAʋә~o6t\~@n+p#׿0R)Ig"9+軝[GaV!tx8<$~|lp[țʉ~4cM.nƦ6+9"סbYH9o;;>~w>VPcUDAӁ׺[G1ו]bPʹ+|~hl|5[Íz+%0%y}5s}1oinjY0ܿ*ꡭi s3yjn	KB	o߫CP,Y-!
    @~PrB(9!JN%'JN%'B	Pr[_6S
    @(sjOW!ͮOJ(yK]<|wPrp>Xa:~-1vl9UqL|T)䈩(orK0YI߾u1n%؃S	%G5[?@J[yG_VW;S
    2?>dnT<G7]深cX=m9RrJEtQ$v	JA>b!S{y
    )4A%_xeI{t]j!9䡝PɡcɱZɍPJע$ŀS%bJw$'ܕU~XEɥ#=+zJ{,9iqF9ĽAĚޘ|.yzHj*7ᶦJ$מ<\,#BvJN3<B9.Cvŕ
    rܮ\5#^1&k+$<.?_|s*%D|$Jn.PrJ`vY)9!JN%'r0.c����IENDB`���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/ubu-install-5-apply-changes.png�����������������������������0000644�0000000�0000000�00000025523�11773544727�023707� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR��{��l���я��PLTE�����	
    
    
    �	
    #+ /#* 3(;&&'&.6-02667"6I9=B'd-w0"f'.t!7&;{6;CJ8DX?TfJJJAESDKSMNPLSZVWYAKaFQfHSgLVkSZbT]j[]aT^p@yJ\dlV`s]eq\ex^ju^h{fghbjsaj{lnrioxkrzrstqv}tx~{{|6l7u8{Mz^sC|@~R}gpjskyt{t}|~x~39'?0@/A2O?KCYN]Phvzy99BS{u|{{viali|tEQYftwԟ777788yzgkEEUV*2.7?FYGSiqcwXcznjњƒԤ˩ж¼èĵԼƾʶؼÛГŭζ˭ôސ؆ܖ+-3v��(IDATx^1��לr%~HsO*aفc��?&2إC
    a(`;w6^$LPR͓$,+i4iEwΐ	fX§�{_-`_m2kئb~إc�A 
    $FldBbsh7܋:&_m-P3{ϥtLe	˓q{,fdm�0
    c+KUGâ;0&rIop|@(l(Sf�<PʌWUmXsK(@6֩9MǸ )R'mz9|{"*gl\;
    yD,䗔B(/"8[{�Ƀ[D~p$]:Fa(2GC	M! 1Ah']-"I<@YHK:2U|goĥ^ "D	*RgǶJU!罇M]]:Fa0		x:J"N.!`vqSu/tqPAw-~@!}oXF0Eބw<T|'L,
    &WD5ZUuإW�@lD0]	uTQ xN{rN)~
    7̬7H6;pP��@@(Hw	إc*�@R]=tn1o KR>)*.;M��� a!3$:F(|
    \̀=``
    "E@fױ3�hh=h=^ou$nҨh?=Y5\#[z#sutmaYHZI*Cb/h
    _!>~mK*Z_[TO=3hm@\DE:l.lW@+XS'~oKYG#M_fIӄ_4# MoUg/͓R7Q777濉]wM>ԒlyR}?LA cQZgB渆z(!7On	:XfM&:pFF͞՞&j^{B+{BH>{~E{ٰpuǃ8ZC|0ҁoGb6cOm0WmF)8DGc{;ZIN[>pf{[{8L :0	c0R
    .=q`|l8(-	"v{OO/ovaZPv-{yҸŅﴼu#)?7%
    .硯)}q:D⑀U_jD|``/(sべRp>wcm^/0.9ڱu?ERSw]~
    hP"dһ3/\rcn!s lUnM 
    byxwD(]۝3dl3~fKƸxy``-yC׭>7O.8*0{I(bqx}暮ˆ`"XWi8~t^zp`k�؁e
    .6b땟sTrk^ktP@Lmܦ|Xm2S<`Z_jrGz֔EU̳gKUHXcxV(ESzcgItӴҧ͉2mv-P?pA2W{�@-̘\>*1/L0ՅaЁİҭFK쉊ppBwҜxynX~ӏa%-B9>ܫD`o
    b1I*v${w`/|SO'YͿiseUwjY0+<G'*+Y{.68سMܔS<C>Hs1[J7/ͩ[^:#uf/m5BR�-9mUJ\A,s^C$,[
    ^C^vtw6**k4~y\UCvn˗�138T?4ƛLe܄}],Tm dzܴ
    XpzM2!g,_88rڜxy7dbv~ո-rҮjR>Ѧ�aF!uן-+t&6ٲehwrtsWYPC{lHcK5O<3[;4{/u=|a6Cob4;3L;5`Ig4yy10fsxy|箪U6p.pծF/YpPbٮ<@z]K=zCLLltrd]LC1h?ۣfZunqMoo>28ޘloGGP	5yk8>˜SnO8oOcž)L>9kp\gFcNwc{SOBM{1'^*zC%RxjO-b+_q/^m	v1N,ڶ@{͙1CNx=aDu.^{hʙ-8MV{hSwa2gYIx:
    ɚf<w,�un/n^Cȴ΄YVx^^/I^5Ս7Ui�k?%
    ,"g�ּUՊ^JwSi%ܑDAh8he$U)N5#	K9`zWf)%矌sB۬IО[^n˧x̞ʭ܏T=7FI)w;ػ��=@{ػ6 
    4ros@ͧ=>X|AHdS=aWUxj6IaRrzU]<h��vYP&{M`#ur
    =�j=l|쫽]z/8눢%=ߣǸٳ{%si>yްpՂ.JfBDDn;`p'hFpxi\5"5u_Xq,:W.U/6y`�,,3犱a.=ѫh>Nx;\
    K�c)^LhJ5|$pbU4"5U_5y<�U/&ҞԘlXG
    Y18Gz>Wѐ}5E3-PųECw,Ql@	᧛d%y~R(6	h\?I1B泆UNң ~7/:+7dG1*@4I|"!< |hJG)ph> Ȑk*)VT`*^L>sb`}r:Ug*&-g|dܐ}x8mF\l+&Q%NG%EtpGD*O0Dtzaȁ	
    r2<B\m9[ýʆHP<"[hkOXkO,1!vL+Ua(IH֞؋ړcI{2j>3׸^0b'FSO̠48!k</Dt\e1^9/p--!sSߜYclчۜqI0)BSl-#D(jʾɼo?}ט6Ӡz/*n}p\B%BA܇.(rdoi	ݐ}xpQG:A)ϗbxh'q;Zkdވ+w,"櫌;W�q2߱PW!8)Aߟ\x�e^Ix3xьzI{M[ZҞ̣a4\9Wڳʂ[wY8!?^+"GJ㤌ٯq5Dj}@ٯxQ/u;:{%eei/+�?vg7Z>׏= k/koOdeeeGafֳܹ}϶OGzmßd2(ދd(ryz@o@OحgS7i^[MTNBهHf�F�N6Q.VW☨ :Fijz/0uԋYkO	+g<nijU{DCU=v@3퓩3<cM�Sm&G#ZjU{3x:cfjS7+u%ȷ'̕|U.VG7kWKx>$oګ=f3b\x}2KvrLN'»*ծ('
    حgS7aL#'֞LN'i0%\^jkk�3zn<>;U+r
    0k<<ejz/0uI/E^Iș29՞L&r_1JAG)!G^+xRx:GIZnWB!"l=l~ݿ0Ud{$ۓI'ۓlO'ٞlO=ٞlO=ٞd{=d{h"�`8.ޞlo+,ݞl~`/ܞlow`w[cC>٪N.^ll�Ul:Hᜀ٪Muk	d{c<'y
    @2ޞ>b%ۻgrܛ+{qy]*^tkb(*ŪJu14"ٞlO'ٞlO=ٞd{=d{���� u'hAo{{?OHέ]5k:^t"x7#9ln �X1Š7∲T[z1˜f?5ݲGc$mu.s瞗=/{�QWZ<d".O~#(FY M9g[+0 rg`7-Jv#r>F*%[| {2Yʥ5O+T)==Z d0b{
    k	腅/*'gCx{)$O$s]&D#C@Fc)2&{ʆJ:(L ?_=9{oco	BțEa/JQ)FМoP$R�Zڔ<j!V0sˣO~ZoG5$MYpÞȩ+h 4�3@c/cGkl)"kfӶv!{<}-[CPM ~)&tH�
    v}4)7Q{HÐϽkz}>\YK=5e>|Rqǒ\3Q5WB>^{
    t)!!ƞ	>{=cܽLҡF~_!kao5X=	;c={optttpc{?gW.{-a+!,Ֆ(HR& 	�Tɞkd&Yzoy(\{o_|j{jf^;B&rkJb݈mciyy繁Rޫ=^aeƞ`ō�1�	2@
    #5{|oaψϽ:?ZQM!h`L;@w߈?^	TfTL%`I;@>soOgq^w|L}5tglh|ׯϯSn5XϽ*|qqZ={^>V=k秴cy{U3>FO/g
    v,/{٣0wrRiP`n1`2زi?w6X޽#z~4l?7Vs7p|kDb;?=9u`vƞ{;B	9 ?W2.=}d|'TcC*Bf#đj-l�G75KIF2G鲙D32,ֈ38˴v>\Ync
    @h!{m7J{63"' rܠwd/Ki
    3ZS!Ah""9K5aRɣ(ǙRC5(V 6lXfÊ-ze|^̍4Э((H/\'r[9ݕ^l⥆&L;%@SDKarBxg<
    i"\y-zK65r>\ч1tKͪUnXjeF0{l	\'r.?;J`uG	u	N¢ɞB&Junv(i<NŽ>43ߟƒ\v=u
    w	6ցAQP
    k.HaGmkwa.#@$.Rne"u7@ubiٹg(
    waՐD𨍹W
    	.{ĥe|kc2 ߾梲rm1:~^-X{Gۤ0vX5S^:Li7؉Kه:8Z[]㠰^6䞘KeTTT4d¨-*sok
    ksg>w02c'Ƈ};
    w1#_2s*H3SP9	nH@4nR0[5"JQj+T{jv
    Maj1~o6i,0n>4`DcIQ	s�1̄bnhw\ N
    ep�3z*GMF]OD{{&g0TIO;{_^>|<?~_ΝEr#*,/?G3>?@Po P`|`'>`"lKۑ>W='z`ДڮZ]ݺ/{="=':�	{H	{"'PדsHvժme+7D�H sk>=32e]V�8^llc:�Ƥ�],4V$zA{=8Őt7`	{4(;APyߑFQjoTLAA-v5uVݭΔ\EG7z2,7-;vȨ햙WYk5hMM$!k%3p\U6Lc
    tLRW*PqW?w"B/څ*O$c]ģGj=KEgϯ{1+E=g媤ɻV]\"Z>{\?w=
    |]ػ{~Chxm;pᄑ{QiJ@,E3s: I`5#r{ޝO޽jT??<ĞU0$Z]Rb1RRP[kuZSE#Y
    {w^4^,uX"I2S۰#G~O؛{+^fFqn}tw+@uҲ#%8}
    ao~n=+/(~7U?7x6s,U`#�,cg0hќsV�$M�-ao~�o	{O�-a%ٿ^xov*Y>{Rתcl4n'j,Ņ瞝~vyycJDgouMrc(FƤXkU|�9~.�:,ZXb8LH8s(@ۅF6Uun7l I+vB {7TB sm &d0A45xgsnTuܘ2Ä?Iy>;rs.b�a^Ϲ{S>Uc l
    lI{Ic2CI5}vٳܜNpaC67l>]:_Kd5D<ꝿ)#A渟
    5X:cFs2l2#8bNt&Ϲt%Ql52
    {ebc/w(-Bv;i2NQe!k
    at9
    F׹cmTa/%xKv(E^ny99a)u{4֚=2?[i[?$\iTf8-fOM3ilfƗD9K jDžH$쉄=$쉄٥�``o`>y)BoK{{c����;Gd �
    ^tC)�F⾌yw{={={={={={DNR5}^OvBl?$kH;]=A %	S;|xg|"xQH})H,=j/7Nb߻{+Vb{
    a؄=2Hlk6-u$a}fR Bc$^(Hz!dAQBɬm0\f52„r8C&.Yޖ!&Tխ;V߈Й>Htmr^ɒaɮ+pv
    J`ly)Vx>{…,`G1,{{nꦝ&T[?ߺ_4�g^aa(c8c4m,E;ݛ{y7o
    .f+<tR$llL>vk~㓻7)i?I|_ɽ= G_¸t	U	U>XB5ެ/]a6|;1--70c'({%ق16(<"
    8-6TtU^B.vCs9nK}-n(^/Q~^7{l 98Hdj){Zf@EX˻&A6і19ϝR!?Z$BB�^@ <^9^s9pZcCҽ!N@	$jx+m|bմ<wv馇x�E1.#dˍtqEttO$J>ÝM*2Ц{<ǝ>8oʿ"̃P= `ܠJ=J|z`4HwM	p+̓{	tAx1+szMhP3K͝s(z3\QArxG`pA+;T%R1RĚ;yWwtonsƫ ] w
    Qzjve;B0hD.|YxJ|xzqhUt/rcç3S!WGz0,-S/'5/{%#FC7ʴZ%*AWiG6,gCZk'50O_=w
    u:M[Zsyƍ%+WŒzbTN_}wFEu
    q@Yf&j@v»W39=�va+<XQ?3uOP@1+ u,]:F(ceVXS4=B+aaIoa7`1w|	k{=1:{+^q_5<q*^1x�<)ء5ؐ0@=Ak;҉Q-5e.�@�\1@nvx=p=p=n]:6�� *X?Wнtov��GBrлW~RYc(M����IENDB`�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/ubu-install-7-install-progress.png��������������������������0000644�0000000�0000000�00000013331�11773544727�024460� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������i��PLTE�����
    
    
    �	
    ' /$78��##$&&('()**+/01223678789::<*4G>>@?@B9DX1Nl<WrK��LXVUZY--k��my��sg%&s##w()z''z+)x0,x77BCDFFHFHKJKLAESNNPWKKSSUUVXWXYZZ\AKaHRgQ[oYZbT^pJayXbuaTT|BCyNP{XZbbdffhgilijlhltlpvsttuvxvx}zz|gpkrlyo~t}|}x~}v~~���	1
     >�,->>,-$(-"6,99?51$61I�Z
    @?C9JJYY[aljijy{IAMM\\ZT__NEQHXVa\cZceii}~bbwviks
    ze_c\mfphyq}gc~|}zxzہχ7$ҏD֛WĊ|ԃlۧkF½Ƚ҄ߟ΁ЉΠݠ¤ī¬üӴ㟳ƽ͏õ+-3𓖚;L��IDATx^� (\\E|!
     ᭌ!
    l3=wpE&L`b3|fX n};/_ӁKclȌdnUiE	|o5a Bp[BCKіKn6S-QTw.DRs݊fKBw<ӳu,'AcZ̦yt_4x*4Й]BHA+Ƣ,Bͫ>@g#V/gNKaR:oB3\zA
    2/̩qwl;?cñbtm%;4Ic6H4NQX"[٠?ko/Xm(
    ?2AaO^;R^TIRfa
    !/!/ЂLB8HBKu%	h蹶pI[ι/(D$yYQm~>:8~~)2RԫHI�Oz(0"	dQ4hbdoc(fo6LzO_"W\u8$J5ʚo	H$)*r)z_?:f
    UbK2
    =(*A/j.!l!6Xzcz.»Nt]+N~'P5\5	٦MC(b>C\Csysra)gR
    eXz#-pbő4ZWhyiI !*UVͣ&	ⵏ) QA"/{}:vPC%
    6zw">{z R*ȊY	*F#w|uJJFۋDc/F`4,XKn@}úOuf"2E1)T:m_2՗k=栱<n@FJ|HtfXG^˿jT<,
    :Õi><
    2+rGl
    ǨP!;;ӥxU8:<LLbl	HnE0"ZD2q6(V|"H)`UʆMyṁ03j|f3c(2Z+{8XJBmMۄoЧ|6`[W0P7AP<%Mj{ϙ""Y-GnFϢ]_=EF$"@5"PHp S!5�Ć|&8Q@"w�r7(
    1R6Mr6dbR/)`xFY=E$\%{ƈh^ޠq
    Fwh2nQfT[͚dLy}'}}99�IWs<1Zc3f;fu1?U</ Qu+!n=SHq\8ΘYo@Sc;u a#z�cJ];SrBE'-Q͆M-$!.C<Lg|`;9ń{ȵg^	p5dϬ̀Ȝf 7vg⇂j%MB1RFf0Eo<ڄUi4XRs!A+\=jm΁v{|
    f˘-c2fc2f˘-c2f˘-c6f[=^?�s1G�Te_(`!o cn1AN.{
    KIlErrڎHԃ&?Grd^G1
    6P6z_¬yBR]:݇&=�}	&cNn>Hd<I	J.кo[JW:NzeGq.FMW$
    d) Z0`fĸ%yҩ
    4lb!x[Z(d9O�6ѵt*fsaVʘx_,!/G1�QV#2f*1}6GK3v).eḓtIy;uY=:ỹRՕcqk0.lEkg˘QM	
    aVYg!U]!=�2D[Ɯv@� co#vJRo%BS>ytѾYMf3
    e7o#$͖1[lele̖1[le̖1[l̖1[le̖1e3k	G/G31ݘb1f	
    zo3a1f_a̯,#wkowڋb dO^_Dl~G?_QN 7H>dAjQ]qK^"87T|'	R@IK'|~޷g8Ol^:	㱒Ţ0_K+ԿXJ]|࠸l
    92(*@Kz(ÁN1/dJ.\*&q__)ܑSk~*Syt8NrPi;Q^jOדD _tYՁ@nT2r2-ۧ4}JG6Kd$
    ^j5=ujE>78WR0'FO¼=\zM*zh&!ߎZlr6%*8t=IR~0ڳx}c;}}W|cՔKvnY<}:H&xUpKz8p`IEa	 BuG?P^a}jW>|$Rju_ڜ`&>_ԩuZگNZ>aGyAϯ(c\޷/˘^8dOe̖1[e|2f!e\%L@tP$msj䒐FdF!O}P Hˈ:B`xmнr]sHt jCHG>}lWa问(O'lq~J*e]9�1k4^.@9P`
    AG>rfch|]@s?s>AI
    Z>嘍9j^.@9F  B>m/<1"
    0GHAMB	B>m/<1[le̖1[le̖1e̖1[le̖1[l1=:��DA0 Nle	PY+(\lG��@�dD&a(v$U%mmn8Pgc@G6�@P@hkۈ$$JkOf;61'nl{th�ل5n`G#AT^m[66jG7glsk>{tl�Ԉ
    f:CH(~t_{%Vx椡͹9NDg|6O:3XM#Ae 6o	4P$HW}?ٴnJ2Il5afe8Rg 
    c1pu}0ؗP3fB̈́	5S3fB̈́	5#Kj~?K[*Bz޿r.$A[],Va2H$`qDd ;)vW9rU2_dPyXB(\U(Hz\࢑PSpQ[px <@z4'>N/2f-,FlJ8Wq̈;vtHRNᢶI32&x L4ɝk!4[!
    	PcP
    ]+CSU$E#Ia;W0%∐TyhvbՊ_vsuմEtoQ.c4@ɲyf,9(D7v2T\Ol7͸Ռx i3@%x"EƉ=ri4ړ=z餽w'͸Ռx {=#k^L޴_g],9(slUӼ=z4_0[gRn|BͭdKYn5BPiƺJ1[>LP3fB̈́	5jfB̈́	5j&LP3fj޾
    ܿL/¨ųOn/J맧gH<ib7dvrG30WGQ(Un\s8uݜJa$a9tw
    vg/t6+ݢ2͢؛6vS7/6I35Q;nQs%C5j&L	5j&LP3fB̈́P3fB̈́IFY>:/v6a7`C.SD^bz7в6%f#*h)ԓ"8DA^ItDe{7ޔ<|BNq+UBVƌTu2K3Z)/VؘQWƌ
    Č]˧ˉx+ݠaS6/3/>Lx!/#zhp^i#cޞ3of_JI5~cfNo-),a:rf;=)^!OEeƈR1U`i5Sr~3SiU_3W{ܑ;2BstEΌCv<efZIB?3;S:'~+iݎu]lIkll`f^'LW'sK5Ӎ&f]$섧=أ̶X:ׇ~l(w*}Wth冩Cq*~f0?3fV*dƌB(ccF:/
    ,r32dRHoF`F`F`33333333�0�D"VcTtNqB.ofU6ukfHiv���aXI^EWIze5����IENDB`�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/win-install-0-security-warning.png��������������������������0000644�0000000�0000000�00000013422�11773544727�024456� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR����5���[��PLTE���
    7.+103E��i�{ E�<t(L-1S17iM~<DkB=
    O:.O>GQM/iWfE;pb
    BA@LKYSRL^^]LNjhf_kjbffwwvmvvv�����%�(
    1	9���%�(�:Q	@%S�HRj3fMUTfU}qualfjjtM}nw!!��3�33fqjshigi|}f̙f&5*03kD(K0*�;/�6=;CF$J&R.S2CKPM$T(Y7b:_@fGnRsY|b8&
    uKhiœ�Ӭҳ(�îTõgjr{
    -	0Dfb[oNd؃Փǀ͕׉䍹盪虼կƭֱȵץ碯餴鴾̿էý˗ƸՔڰz�VFf7#b�C�YU�Jr+1=�424��IDATx^
    B1Q]3vb\qo]C*w;ʅSQo}ED7jt$wR{\Q5dC_3C"R(i�\:'1DK`dfz_>mQ2u,pnxUw%
    R?Gs J'ܺnV2ZH![qV53y@3eіBYX!+9UbXHHٚ^d|Kq|X*JV
    vhGni3[2R
    8R$Gbc4+K)t/$g@{!lR)3MI΂A挼}|OYL<KԦ
    0$RMHC$д/,4.�,̴HA9OHq*AV}*//	ʏ6q<#hEW6Y\WKKÿw=ǚOy÷�F##%y8ZCQ3R�ܖd[loLAP:BbjPkhw^|)`A2[$R<r`'7<}H$%b!bRn4>ӕ-Mٵ2](h/"[/M\݆DyY"$R'Iă!஼S%
    bF/W$ڞ.8A7S,t1oMKQ-;Sk.DKF[Q")tS0YLwNiL;C"0{<	nDM^
    -X)QY<	=%S+Q�D	fQi! B@F'@R(rgUu�NʡHB\[|dn<}|w31JIȲ<b&%lN,\XUA|u�Aϭc{VDf*eQD!0|C7|lfGKzI$Lf2d0\
    W(-NDJG})qO*70C)dO}x>>e#E|Ƈ[�cHMJ;N)>WDJUR'%1O�4aC-K1ccr
    ׆qh\k{iG&$$k3Q0\m-9:NtzRNZ��?�CpA*'mqΥ
    =OK\m=a%4
    +Zhf/iErYHT)呙կD N2)Q~D#(K-/eQ�a,(M	CP:$
    ڿbJS VQH⅜g=;m�_BbOdcR1
    'H5Qd?B3+zolQ}	Ey2"E(BQ"E(BQ%PEPEP?�lN fQ�l(SUԂ.BGrRh2vm5/! ^%BIz	`&B		{R(>MBQ(7b`ف<-BA)c';Xa]Bn4%(*oP=(B"(B"E(BQ"E(BQE(PE({NI�&lp(sŅr8__~Pp"L+.V#&KPF�aEV`BX$$B(>` [D�Eai�+(J&-B;
    *1sQ\
    (}#(7Rh(),!qGq1Y+?ѳ,wl&J_(e6ěx8BYmgQ$eel|й:*Bi}Jkү5T2iO"~k}*T>eEJ5wNa7j"k;?T@\6HiGMN] Cnx󖴧T[,,A>kFmלGt"
    7liQD	Qڬq{8өmQ-pő)\*Ip(|=CoxDPK=#:Gл|("I윒Z)Y]졆jZ-r<=};}(lb]2(l͍<ýgX%%5He(	
    HeM#cΫg~|)Nc%[q)()p{3yzǩФIDoyGs9>=k(cc&P�~lg(JŮx~M܏EPE"pey@(oc
    +q-PYb,Xle~AIJp)G=D17b׹R*}sc_jd*BqY?( /\8PbW
    A%pe
    H1웞a-rP+Qȡ/nN
    hN$fbNæ'z9_Oj�TE(PEPSٗl̄c1j0
    VB&-sҕ~SEPXiNu2
    #J_B1y'PMֆ"uBQ"E(PE(PEPEP(BP> nC'A B\\2H)b*:%/oڿ8c/J{1*lJT8U&Y	6F:(Qsd!FFV!((#%A_v8ұ:W|�󢸔o\Q&T]zb(%Di7MiQJȢH�/oHX\<3cT(i>7RYܣvSocec0q$T3G|En`�twyR>z#~ `OG1ʯEQd:f(Z@å(a,}}>qq)Z7V1|Es0$]
    ERCM*V (<W,`M;i^5Xb�7Xݱj0{ݳt/h({cJLSJ_EQ<
    
    BBBB(((r-*($P,^~!e'oRb3JLQLi$0P?2ϓ<2KZ&ͷV7-l[1|V|Д6
    ʴ(PeST=JbyVҔ}<ET1kmbJ%((J@xۿlжCe3e}	A멯C{LUS"+'zlK6f:軺fR;5J(
    
    d(((|^%JLę8S@!P@!PPPPovi0uS1")	Q}/2gaq[WD1cuԲ=9	9>iribh;k\wWnw
    @^CHrQL8?:
    -(^%/6?
    $,:[H�izc
    7bv'Ҡmҩ;`>#ꛯ'9S̝I(vќ ;Kd*߫qA1)U]"bMYYB`j(ټ̌@]dK^}&|lMʩyM]]>KK=SFP(hm;8^}~RAinPX71PG51A	_N|bء;	K4_RE]!}k+qV::5hNm01MJzwJŤPn[ed9/	5VYRcDP0Q�ePc9:(ڗ8.)ESed=2(m(qDXPN5(kP�@tq�_"~'bB8yeX_.~0~(5D
    @4&ŌJ)W4."ePPfU&%bN,#T3$h
    Q(@jg*$ҽ8nSG%;k "@1g
    edxp'-;
    Y;E
    #ȗA_!1�=BAg(
    9LrUR:
    D}p(&—PL/(-u.
    .5D0}xhC!J3CᡠCBB(qpIN
    ͡j
    _,|bN_xe*֘ љ>W7扞iWdA`MwЭqYZr%܉c РuT	O+vRL9Kng:ڱJPB ΊuT}'[Jm}Lj@H.ɥ5SBZCnsK~j?|夗]_28-LO;oN(Iۏ"q~10tGQMd!t*V$4qWn$Jl"KmYP4լ(e2&P
    4*iHǁkL*CDXk*e#*'lR�k*{*u:_;`i
    F3h[,ʨ&
    CAJy~w&gTK�6DlaXI'DP+T"Ŗ(M(TQ
    KR"
    Z/SAo&+dK}֧3Da!
    C0D!
    C0DaB(DaB(DnM���f<Ku"'\</&BXj~e\����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/mac-install-3-license.png�����������������������������������0000644�0000000�0000000�00000057611�11773544727�022544� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR��n�����1:��PLTE! &#,++.T4l1=pB{/RvSXZ/B=-@=3](*[=&j
    gtn!c2
    e6s$r:t=e(%r-/r.0~57MH6zByG"MLLP[p[dna[Fd_PxTUrkQfffelvipyumcyufxxx�0&8PL$Z$X/c4kXk5zS[IpJxpzB|:8XvhOW\k`sp|!.8(*:135'(IS2p4NS"_5Z#_8l.k9`:q=HJ]SDFUNWXxY{frqWXuJrm')01?@p1|Hz{dfQQpp/^exgujwPpNzĜdž6γж(9(̎QeԋiݕiݜyƵLDzgĺuױ|GcL[DXT]ov*3<EhEYKTGVHWoQs̎䥸˚ԯ֚̀ǪŷǻݢоĽ½ѸęċȔуҘæȵʧαҪԷڎݥظ.��\GIDATx^
    � :rqg\AA218&�A)WLyŒ2"5+cơ0M
    Bo)YXQ:tHz.^%_ E.ֽCq/%\:\oˏ
    I~|r\YHEB%%L@j{z`dD)| jV]'%׏29`gK%)Q_)lNGۅ_gʪ<ka,
    C,bD{GAۀ97M@/r}˲~L&CkkE
    D)O;l_0R*&J�k$)ܲy4V4|9۶*\/'|9r0ԹV41f);mvNN,M08_o~'N"FX�ha`!
    4L?rFyRJ唾8(#kt~,7{v6wХƞM0!NR&.Qh 
    Z4CKhǂ!~K<:J^F?~>Wxz;_Y.
    +ܰo_ Z"G	 
    �_ɍ&	�+{ɓKۇЦvKb
    Ʀ1ygm6}
    4-&䀀*7Y{9ͥuLQ*0(Ea8(.7+2Vpûz;2֒*7)vܴRjyx
    SFMn˃`31.TӲdpΒ{Whl79g>xI)͚ۭ:|s [­40ڞSYM%#scnʾJ˲h@%W;UY)ph3ޮrtc݌\n7A</>pD;OHj`"e"#]٥cԈa 
    *Rvq"'b].v.|#Ebp>$!T~1ϏQu݆s)C"5}ߜHL)W|#l߈F9U$ʬ)~ZIr
    RD&m%-[]PV'%
    `G1v{hWc
    OwdG���@H_Ǻ0OaB엄8+X؝:WcjRR22ԨCRRR21WS_H[7uaQvfFwM&xs!I
    ϭ`:~l2$fn?e\7nd`6Ls[HZnx0
    涤e`XPm]a$UË٬VXޞAx
    %MƔcUIwSg0V#mQ1I
    CpBӱۛ61>/B0ܳB'oEz0lO~ІilW.=L)R:(MRw`yH)zX"A߹pT.laۯ;!KnK+[m 4L/4=8vNp\ro3jzLePvøfNz�]Nh@{=<_soX0DS;Nb 9V[9i|W[cDa=bN\]8ϗ'wxU-äS
    TANn�
    qNXۛo~IkFv߮XԳy/s^~0CP:24ͪS22--en)sK)s8&����ֿj8Fr`_IF|H++jy_'DDbaǛIq;_X/ֳֹp~,-~mQqcmN]Kycb7I*릈mخmd+֝OuNU$eLŚ3LR?�nWqqu|W4mk>ayLN$EXsMSJpcgnݭ
    +G0QL]E+V2ȱXq[*Lr)
    !)Ɨ)ᨘ;f+(۫fidg&]VAŚrNn
    !:n\	 7,pOġ6qxH$7[5#唸	�au!
    D^	4wF+pThSl8wk0͔ΏT
    fc!>Xn|n|ӨnswqS"jgǭ
    ж&q%`|mpS6*t�Z݁RNOemô"#�@٫<q-\ՌH#nd,๻X3R·[#S=5n]5ߘ滓kI>!iip[-ܖnmPk5]d`Zmi&$6l[ESzaoZ­S{a{Ho`iԮR:Loj=&Ze4t-y%UaI&Np]T&n=ubaY�&1QpL-7RD7L�
    AGrR
    &3gZPTjHYMBJ34P*nFVR@ODd34RNǭj]nX�sT.q�
    OO9#n7\Ĕ-ݍ7nziq[Iw*u>fWFVQ2@(BAÍ�*+`wV@>)n7J{p)r
    Pwf_;M-io_>?=}S|ǼksEے_>}zz~yx9KW5"=nKǠ`5#q=w{,߱9	-Ou/9>IRIdYWP3qˢj_1X't:%.TL&CQy~wոTHs~>jpۆMw0Lfٲ@m;_Lpxw7~P~߾)9ZM#sm'
    9MglC,˂p8]%n7G>nu/gLڔ߬MQ,Fn-|ჾ4n	*4wׇ
    zF]7_Nڲx<IŌ}Nn1ӅSp]bK7V{IܶM&U,'\`g/=bgCm\Q죔b0Rk *YQ(YfkeϤi@#D?֟uGdDF?*ZIBK69Rٷ*/}qX86^X'X:NEVE7A3w>|XL{5䵊[Jǿ[1Zf5Ǐ;{pt7@s+o;ܬʣ<Tb
    jJgĠkk(д	d̀ȡ˵*bGG:c?T?DqnnbBV5t}CžMMB2F6,JYxr|leJWȏ|~݄iq~vM1n΀4yj*E3T}[eϓSed4@S+v?T?Dqnbj1WmD(j&NHƈٙ{jēD(05X7r{_~ZV#wm<@%cY΁jT'
    t^)j�bekުThqXMAn]Ķ3ih!h$7ט(վ�'(Í1Z:j{eHrI}QÉdn%h߾Gv̳Kj\Vgm!?p%NU`M3#(MT8k*ܺ]giJQ`Mp#Tb"1liT9'$clFedaw,hp�VO|W/kP(Fwdj\5M9M1Hl">CʴhvۇCőS}E;h=JqzqX\AWpBpZ�ZLFN]>F1~ȃ[N	pB2Ơ,9zxr|h}$="F׵?}Ys+05ɭm&I8t\ mǐ[HҚMn-yjT0$J0Wn]gCn[@
    \Fw:1P1H+g}A	P#3)#;MF˘u#?gX\eh�e98Ѽe@Z0ntsU
    A#o#<DUFt߀E�LK=ŭY4&u�h3�&c$̢(NHHRS8l#E?#q=yڻ3,k9w5(qC$K~/^
    Km;
    -Oƭ,r*ҦY͵;Љ*9XUgi`]n=9`$n,$~$t8F/>}F~$nFcY3B
    !1U3U{Qb
    At`ŶR oIz*nބ){NitB<|˚k&ؠ̙PP.̓~ۼG_NčG˪boP۩7L˚]nZ`ك-ps
    Q#%i)>۞>/[Ѫ+Vd'X1*?t2؛7*eY3bE|AV(/˙[rw/_MvWו@=Jolwn/kCr�H3&ܟbpR4s[)</mC7?+ϐU]N7N_+*_JA4mZ{:܊ 0ۘL7vp;}Yx+%T'NttGWF\+
    7;nq+ vxjh
    '8Z)G
    7D܊7 /0;jN>qvnDp&p0nƺjf+V{Bv-ڭxoP=^
    =l_-"?ΠEn+~\Ѱ!a.C>BK)S9^J`H̥%5TO+7vvČ#d~!LV +@eR
    >PbDf'@F.?$-OleD0=ewPRᦧM>FdtuKJ/Vy`,+C턈\׈,}[TpIDzYܖ.q+G.Y56_η+iC^7]M'[}q4PT3m�n~lIBF,%JS]
    YIp.n**?K�HJgRYDt.kfzҖĸ3L_xPa16Q•(g:V|F,SyDSgrȸ%IRk|:W`ǻXeRF>^An=cseĸ	QZx�׌JPT]ŧ+a*M7ͫ.?[[W=f5m$Ε 0>t
    ifEA.XU+MrI;}5DNQp!2np#܏D(mxZOs]r;Cq5ifwO
    e~&{95h7Cڔ/36qN?brV/BW ը @Qr,3iMr5ifܱO
    mwndqyjqbZM"lXS7`\GH+
    ˟0KՀ(Jazj?JĭQv[;Cq5؅UN??=~t[sc3u_9sΐ6u7�初;p7\2)$V=%T\wjD\d.( nF0WsOčk"$ Wh?$3;L
    ӳGggtkʧXt_6ү9ө͔Ri[.D"v 8J!2cp[Vb[LL	76mIt]	ĸ~&=cË
    r\sj^Kuq+.ȹ
    Gk:eP
    	r)pՀOs̸�[n~+|AjRh;Ф0qT�3/܎eqf@5~x[o=7 @3Cm#\a
    	t15%WP
    |SJP7vnZLJ;ФmC̖d[.vn@.E\c3HKsn*H"rWSFIK((.qHHЊx!<Ov֊.?}+k>Z4ePSnlm^AB[qK"g	_SY3(|esE/[Na(gxLmTcUT(k&C_,F@*RKpBcY)+%-n>	H`�@ܞ1ԝ]g>�][iZ6j.UUOQ#nKn>!J}-aGc>Oݫ5Ֆy>ԝ[
    ]15jMI1!J}@
    ]C#nV˛&
    @}Tl67Ǐ|ٲ(_;U
    vjwT)yJ5//ks/o^vGlZZ#ng>9'ǭxzh	;`Բq3T%
    R*5>n	;W/o޼EMA7*5W#nWDoήmZbMKκ
    4~qd[ͅbdow	-mj.lR#v{Ι7GL딄'?F3#(9+"иP֦X+jzuڸŜ$	m$Mwo}!ljɟ9M֩C2]Ps[N
    ?5Dg--PSjşVt8Ng?�̐tM�mxTYM^vcWYUf1]Dvf$r)~q!J=M1`uz<kSASZ395ꖶ* mBB\]WkBQEV%iFeADͺqI&.J
    s}X&S^vx4OJiy
    vQ~odp#2wJ*)b3RQ1[-JQU/ޛ8}٭~GLJQg8zǕ4IG/9=6*/Y,/I:p]TA>\t9{.vRPa]Iׅ\ӃMn*RH;`Ԡp˘51E#O<H_lbC'&ȴ&+SJNh^Єŭepv7oo&c>B簜;1E
    q<ql}j(6D6C1W]իmV{K3v9?n#moـ8Iޱ7{zR*V!YGҥ$DCV:՛G%Tԥ,cdNA!JWՂni.74`$n7ap
    
    l@ޞP^Y
    ڃM6ւe3\ZQμ*hoC",+=^|o cwZO0Vy:}_mA *D.%!T'$@z!	7զ#V4%dqpKX[P;89e–	uϘ&n=,֨!n#h<R?iܰ  LF4yMeWzY{ Lk`ڰ)nGb
    irXbN9Amvp{4f(AUUtO⦍Eԕ,n&F@EME1bL8̕ؤNfMG2{
    nrZz۵(L"℡cl	ՄyV Hfp7`nlx3[cҥUVEy74s/gX鑦
    ErD	v$$y33UBX0}3z7m,+O^hP{XGJtPץX7˺,YtHƧDM7WK1F2b]	
    jM)2M!W3DMnCnKܚ�Q`#܈3FAy]w6+?ňڼLaWv7".Φ=y\hne
    7=F`czZqP8)hXLXӑP(h¸)1u(7Wq		
    nj"dzt=3l789
    sI
    FtL5D
    4bHHKо4.9I8bqt.hɖ7S)cMwrOS֊=tqA]"W͚i0ƧLU5F1ϭq#9u1'=5f+3%j hZ_fp:Jtp>qr'T;ۜ/Ē@Z
    HA>FԠLbTaa(27On"DdgtikDeH[ڿQkT/W/6PfEG}s@)ȐO}Oy.A0v/$Is<9wog3=?6*-!m8UI~$'?yaҬa܀٫H{/ќ9[1[5rNDO(Ip洏ǃ)	sYH%ܪGo^'p6y}P*a7SCHqwn
    gv-|ɩ�Uwǩvk\4Ã0j_ř* pzK'
    ;$rIpV>n�nU7mHvM['nf]75Gg6?n/W~xn3"
    Q-;܄/il/|jܹ,26έKmC'?7+B".B3p!Pv"`5sp7;dPʾ„ȸɽTg`K}^@i:[˱"&]a®ع(+om8ۛV.B32t!6:PV8]oa6W~{7*LsVl.:ݴo)=Iam�6mоwL嶑K|ssq5VYY&3!
    ADPEhfklF@nRA)hg]쯇\z#/J7ɪLAGsVlVP:ؼK>:xCC3͠q/Giqt47㶎L4hBd[8TM:P%=oaB)hg]0On~-M*笠ȸ.}Y[~3Zsc4;g2+EM$Uf#A-!Zg@WZދky'nU
    zspo4p�>
    QX@]7ZԪq|VY̊d.eP5nBjGp-b[(5D,aLݲt__7YСGP=_5bNEBvފEٺ2l[A
    %BԖ=8T(!=hi
    BHm#IGKp"`
    ^ku;	n*Cz#⶚BQ5xYm�\h7]@&LFlFs+v()4Y||^PIcWu<%zSkZN1<̑3qxbz#;$nOb:=&III2yՍfU'ڥ~I#RZ8]meS(r.QwdK7*DYMJl"E=4q 7eF_ӛk<e͛K7)vur")*ܤAF-6;#ܜ4%vnV
    [rZk&&^M"~ȃ-k7R
    7R-7f7gq>S8ZJk&`
    n.[nFr&1aEXpA
    ,v֛Y߱7Lu7V@oI2	۪Dܸ7!7ӈF5C}
    3_!7.P5(~1<Bn!7J4s`u渑-[[�7mn\)*i֬q#";8/ކt99[jܬ(kRoRF9r+s�GFEdJ#~U�7[\c+MT6J)6km`H˚EEHmoD94
    22I�i;nw�t3ƭ48@>JaŜѨQi?asPF'hv?TMbwl+\qH)
    Sm�a
    pj]gZh[z^aFq­Rb^pڽe^ri͒q	nXHQ[nUYSZ-njjG-MsAS1_:a旧-[:MR|%
    �ڇ>rSl
    9m1s@֌MU^p[XlOGhn;Frl
    +m?6gԝHDž9l;9s#7VLnXG	7
    SIM&_qMomlѓBS7dOߟOW/K5oB?u[
    WGi✶%U0<D* 807!$M&UQ&IŨ2nU8TlqMvF2:qCͬf]oMnOr՗W_O^]W6$R|YD;fQ,<q
    {L	KFbN39^m4_qġ_!e�9ߣar+#�_"<ۙ`n3h"{wpncfst?([ȭv8-("
    :^PweHzF/\2q|[
    U|il=LuDcKGC";}QHU`N:$H/`rN%ya~PQ"ϼ"-:
    ;,Am|M{-htHli:%Ls'06z
    O'PnZleq兕Zm,z0 pL)[ˮz8"72V5f@rOdnԈ>.@nL0wbDmBw}BW*:=(ۍχ5+6r+ZnIbu|f3JQ\vIIF(GF�aDHx[i>.(`.|hVn^axEϋ{Wrs(yR~!l-ge2lCo1B:H3I6ۣfCmC{@ncF7JHd'#ʆwiG (䆽;pk^S
    x?z1qRGw-nm~`Žt{~6MVm)$BP^Le'zJbhC+Y-i.i](;gQr0֌4_<}ru$9Ho8Uq[0S947DtpENh6ޑqVƯ䰸YV*_Džlbتmg{'R^>·)d]6}#j7X1D/=ԞĴYD`zo?ԯV37͌(dF
    |mqa+]Jn0偆ipn̛ޞYoe%{1n5c
    z5QwN}|Ac�>f8L\{_{-yA&/kfd35RFg`mzÏ֨
    օ-o[d9B75S=^֌)&OO֬["2؀u[fYA7nN4Tv%jȈ-X,LmٛMkRg%(nA
    BųWJ[2xίM@uWO4ьHrSmRZt#|WXP
    &o-k+F˚pqWj_f͌mY3n,+7Ǎa`F-YX:
    [&4/%&Gf![[nRyvY3p=vy
    pKon`S6fTP.#I0Si|pCN],o;%BHjapcAPx݊j:C%78q󳠊5&PHѱ;T&ack$1{]тX&^:ݎ[ȕ,q6/Fqafb
    XqSљE"ܠ+NCmqZ
    2P]�$![bר8*f08:C-7rq+ea+֘7@qK56,tjֵؔIR}cãIu.ؒ[~�[]h=چ�gTGarVH%#4{5n&|ž-NKAF1B;]c_PhA-ZXaB3n,Xz(NсPjQ
    QHWNR@bB#\xv|6[2wqQp30NA`]q=b, *#`VSg Bq+n,\_oqsVJKI$AСBchTbuG=JmhәA#<r-_#?r۱u"(oRQBpn<`VB:C
    ­BHWXHmRC*I
    jAp,nxƘt.xvp;ogs$a|l[~KHt#-fJnnem)čt!TBf00:C#+Jncip#U>n+(VсsIwr	&uɊg0*IUE2Y^t%.kmW!&ibi|
    n<30y$kGH1%4Hz-VKF1͊0*K_f03Hh+	7c&96rT1n{]8
    M†(87Q@$޻
    OVC-{_ɍi5dqQf#PyHU,xEHɷc׵AFh3`PYԞU4_yZd\l	7}^+odm9Mn*b|V98ܬ9}Hnhs*~)_}؄=l(  N!'6rHшtuM]:6	.<;jZxo\%p&Kv�w{"-v˃l\_N6NJ.'W
    nvnǛjvwڲGH$}TЕ'K}bm;jkK
    W!zv?C[K\4^AZb}$ntׅ5G_KMrMl{hW߯0`]m&d_un
    &8V֓:<'I6v 6rm?Wu,6KWD}|G nfq_mo?[='cYqK懕`{8ṯk
    1hc,MP�f0$3!8`7LDIꁸY\>HO6dlL)}E[ːu{,9͠{h=3;Եj
    ۥKi/fxVDJ&HHPbNeDȶL8qӳV}|Hy~Ë6_Xw˾	v4u8g\yy0ECAl0k&$r"A
    _:aDvbPMZAz
    s"5lQ!nk'y=갿5D8ۍ"2@`/؉`BqBoPCa(+TΈl˄C=75kU%[s7z%.mY7<-nOw{H_Qgp(pKv-D,7i
    D; Kap&gi`=dok^%|I}xT{'V �g%pVڏ:~؋)!9"۰~I+m	փ4CqBop#N9#--hqT)&tHǚ-p@z<&a8	zwT]zYt\,n5K؉H\d:AB6Z&	XѳV}mM'4MAW
    }<Χ
    <7{25nr?Σ$R_(/:i@[8t:BȶX ȷ'
    Ϧ1q;<r[8nd0lŸݼԸwUߏ	7@7@rNxA^l_meV4qkv1n]6g=7B
    [؇BCƭWx̧MKkm0Ƶwm3Q�F/<@ࢍ%ثWBY%},~'RcjtUK $[-ڪ-L8uwl#N 4Ok�cnb-TsQa{Rr[Ƨ5禗ܪVMn:mce.i9 PFG_�su-Sn;	
    ;lY>
    Ry \^{?�Ob5ׄE^Ko[6no?nFЗ#pX'= %Íw3ܒ-Zf
    =TE41P�l1[B
    0ܘ[|V3ުۼegUý2ʈfЉ-"En->ѫ7zV't
    VJQ$#-DQ/pp"r\ܘ[|j.2'k6^M/m[
    C"Mb^.*MoyH4XХۅJ5]!+k6*.;81\!Nz"\JxS�ӡTG%-FFіnRFJSGi׺u4G
    Qo<mf(熓SaiK6gnu)]i1Rjl3q\HLʰH�YPp-]gqgJ{nd\,�tTfˍfxAFsu)p3L;V|-˵e?vIZq5ڶ,ndXEeL{Tu@&涳e%7MӍ17ns5ͩax_&NhK�lbn[|3STJ2�fog7nQ7]
    oQͶNlD=EcC^`(hgY/<C`14!n-Wa&xmf~U�<XZ,1I2*[7"0ma{!،Y3΋z8GO	nBㆰi{تlQXW
    [˾?
    7@-pp9nll9ࣽJEU_A.چcPpP'XF2{A3G)Zn2F*uUmrF:X0OiJq*oK
    @ۗ02.ց*5=lEtUU0H]gŃ\lrC9.8n%C܆F:=dTr\5 ghz8	74X.
    _G`
    m𴇽Y$
    �j-zJ#-PXb##HTӡiuHPmCԴFá>*gLxmҽY�[cIEYhM![8:	nEUO9@H+KHTr3-g[jZPf*$vEȶ6i+$\(dGnl%^.0V*7)hi4C
    CF۩
    t({H%ghAE&f%5SqͤUzON86Ʃxi{pC�lߋfO`VkyrXnr\t`QxɐjqHTrQmNin\3iޓAHu)N0c@�6–)h&&^.ĪP,E`e;e䌡
    E&fh?+abZ3LZDN4
    zট^˽KYkKV5,iTKQv({h%gdBv̴fe	Wۖ*ǻa	-|Dk,wR45ӻywݿ6gʱ7mKI<NqHoۇrm{L�xqk4%O	ӦDʁO8ĂsZ.wƪq_|Hnh	/*>4vea&	XÒcms~�>n8?Ų\|�V
    p
    n96cˑ�w;ܱɣ~q`A0&ƲNB*P?xѼ	\=z:gl_9ETwuʞ,>Η\qok2"E!>FC&X/!TjI$P܆:"W)[ϨKnN!w]]~&6S$x{RJTм	~r:t0_y(nt߁^1VV	ɻ�,p}o1o
    /Y3}3EEBXu=P%D.w1j^QOZ.BYU`(k^䡸ia\1VV	ҝ/?[o1]wnǀۿW-B	Xu=1nze:a7y,S;+ʪ5gntY}h(A{yXp{A_z�Dp>_(F# ?丕p"CD
    G_˲c p~N@+s5M`&}E\ͮFB7ҳD._(F# 丕)E( cy@7MwUkB!/7
    8
    axHo\xJ#,#|̋uC+95fa4j3TZi,}_Ѷ(|@-?B#IzwU 97䑫˪d5_nt6ÅK=jn:ƜUq<3u2խFU:m9	q-0e1,$y!ne>M:Ats%6o[MCߨLӟ]4M>VD4:ͻ247+t|z~S�w2}
    | [)
    6UQ`.Lmkfm}ӠRGR
    1 2\
    {\hҍgm�rEҞ*sօD`pa2nn}j|W^=!<! 2\؃oDǢpL߂f1
    vHL&-ܥ!dڙt'ێ	”v
    }#	.,I A߱<eqXC`ᇩ!=oop&RAt58yBHRMt;vuYV(Q`צDӌn}^q7MA7b��Χowm;I}s?6#XN|gs;hͧr^|	To[mq.úCXȗsXYxwH7f^+c6^QwJaXvޜ		kd3dl-UտXMsNhpےT5?}W~%B4HjZ!aMrQ̟NC^Ռ.7=).PF}5-͗࣬c/+7"C݁	I폝ia2Ɵ-9vk/I2lz%P'vgyp4+
    II?a2mqޟ!,TH¬VhVFL	b[l2|9+=g]&_^n_?It;
    _j;rS
    k!a?CXTnWTn)7#ݚۅ?]SVXco#7J~ϟL09%7ldE燰܆{a$"7Tvӭ;]`}c>L7؂XceØe\8q;6LEcv-.P0 7^,]frS
    cq[*Ws?0,|ûMcXK,Nl(xMlf9xB&]nF,Ko9a
    K-(Qv.PLM;Ֆ&]nm
    zٍI[esayyc.G7v_HJ܀HDڡo2nzzLH!oY.C:GS{3\嶇H4CrwDHz~ܢHR<
    n9C 4Q{8 @!"
    xMH,a!s=~sTo(c
    ^s>xM'ye`_Xt"i�{Aw͐FOv	F'�Em$hLEYKbox
    i>%f]ef_((6v@ ;
    h	 BAJPe}=c^!SF_(h,HH~Gyad`tBG?}uRFO 5K_Xr;EH-
    @)r"!/44
    rS6m	SQat)!5twK^.)~i~KEd`tD	 bח4L0"Jbgx
    +r<Nbr;MD	bgmP
    r܀H`ȋ"
    xM0:"@|x%:G07n	^W^C|J霏^hy$dADmU� HC7崍hCkBY/,ĂAwyΦ=4I_Ht]?1&M*$5u"Gy"F{"[<6qap\ET45ȍ>hWEⷢ-5>	"zX#r67ʥ]ϓ[A�'`4kGqUS^8pDh
    IaZSϢ6MSVtP7.B^a v
    !ya*>�86&TO
    e-V<vGqQ	"4Unc@Z5ap$ :0-)g[r]N	p2XDv71
     -2{=U<\F,u4A
    P9*m8*7qh EI./Edw�p
    	zü ҴQ-~wKPA$$W"iL@.R}oM"Y8DIefLK_r7tTnƱ3!"iHPj>U#k?B-,7IefLK[={\nĄpo+Ҍ#ۇ=\nbx�F#AbsLK[=|r~]q,2y`]C&#9m$zH]n-"zXq5$q$'6-iSZR'B.˪f]n//li'qwѻ?.r;[,^kFj#mWf$()qSx#\#s".[R۞u7]ArC6n\nv 9|Bhc'Qhq%K[V+:ǎ)&pE\AfTMr~@ns|)?QJN8?bo`A!4c'Q[,1n!r~Rr`#v\L~኎j[#rȭJSH.n/|](t8	[}T'duķ؈1SL~AE-W|@m~Y&7!'ur)?\nĺs#f/
    hS5/
    ?"=V.H
    Uac@
    w~T'dq-P	6bG_C 3-&r+A!'HPr-c'a[(Y"emWS#Gz`#vL1+:
    uH~Hnax$(YT
    BQȍM>8	Y}'D[(YbBCn|+9Xn3+m	A!B,vQ_5آB4q(&AmR<JTzq[N+(U+F/뼻](w[_8|Y(.EGwƱ,]G1(ɓlv0C&#]n.f'x"`<Ɇ'7ˍ),7]A! ? 7N^h!8@>N<kM
    Ubn^)<4}<].k[Iy[nL9�f`Yb]C~bÍXdrx$wT9#KJe֤)mh UCpO$^J.'MY<<>xgAv#?RyYJ]Fh ]nL9�f`ro~^.2_~?9I6�)sFzp?L۰4EtpX_@GenϚdxΒ*YB~M4y۷aiLtf`Yy
    ^DnY
    |]Bj'N;-UbCnʼ<'
    orr3Ѕ ?JBd-
    g#VNd
    vZĞ%ܔyKKo3 Bs15tI6HNyT2DFvkKyƉvkJy4G
    8?GX-1ro >|rk
    &!Znp�3豤8ǼƷ\0@d"zLn?إ�a \Һ=3	D04>ۻ'7r!7rCn 7rCn
    -iĆsc^K#7lhnrXuSGةѯ`bKC
    do`ucfp�*R5gh cV['K cKP cɝh
    bcNyR|<{l&4qn5[޵?& fTykALy)�t;BjY뉠k#sgNN-gfxc報CՠPnG
    s0qw.[!0H)ҕT
    1s7bt!ٔ@%_b\j??ts\
    ԭ٠"@GT'MTH0-j[5҄<V!j3nՎLR*Mb`%ŠEbQ5)ɴ84a<!gA ͐iZ)FV!EdXF7=%
    /fX3o*I8oxɐ3V@l+鶻$)K%5ȭn
    PQ6*	bЊiؐdTP1A^l>&9u{[džncW O趵1G$	ǘ͐i
    p-lErVৃ*n[fm.!1R-탣"hcs9AϞc^ _0μ?Y2j)dtMh#f\*_ϒ0V-n!s&1һE=0O�	q5( 
    #m)Z�Pfb84uE}u�:[UƆn/1	ƕ
    #%e_kc='[Ⓦ.->X?R1xa`A
    /dp�ӏp=%DY nbұ?tn	&
    CtL���b0K:hnnnnn8&���A hF1bU)	K����IENDB`�����������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/openclipart.org_media_files_johnny_automatic_5154.png�������0000644�0000000�0000000�00000015031�11773544727�030306� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR��������<^���PLTE���###^^^nnn222CCC!!!cccqqqrrr@@@AAABBB   PPP111bbb333pppQQQ???```"""RRRsssaaaSSS000ooo///OOO___444$$$...~~~>>>��IDATx^rH\WU˛wo�[TKћFFІzC1Gz媿3o}�ql,�eׇ{q1k,-],%$�;!Bre~qO�CŘ	I1=p.I1Q2DfmG##0x	"}9z9ϺbL5\�g0,s:سy"HڜcFĚ
    %3n֍~~#joY57T_7d �n[sjV2ύk '=�R̡z6e!s+$ice/(\
    I	CPfS}QHQZC+kȦ+<d=T֣1PF0-%Czx@3Aز*V'e#E.鮐T�T#֑*vn,j<:âM\M\{ك{Ѳ)eJ`y|4a/v�G$餴K|vp
    7|
    lmBԪ#T{T>BaЪg—){.<Sl:h۔4>KTwǚAXUyzmSRy|l&S3rt$aM9<kwjg`fܺ6I˶Pqt6<L<+D2-I&k)I^9&7kam;mē{
    �^�%[#Ř$%%i<G|'O|�
    67u|f"|O${Uh1ƉM9:ϹRl>.3<g<&:é6X'$"><+!i9!Gjqr2{^XӧzQEe%`m4vۢ>Ý10z�CkQ|VnIWq)*�GnpKrY}I3H)�`J"VB<a]NwbQM90`#$5krs'|EH��Pbr$tFثI!ݢ2VT6WQ=mʑs$	O?]޿etÑղi~9k'{Z�!rf:V—<ԠU9"p; 'nًCp.bۓ{w%O%~.s-cI,\':aMB)Y8E94^e!5ܛ_ʼnL(DIb|!_rHi'%9CR؞$Sp#S%d\M3E-dr&IR:£g66"X`3ALғ
    bNx$]Ip/cOh%|D.Zϗ
    oAJACR6I#)W<ot4[/FߎK$,%c6?	!̐3) O3xnvYq7̷}6"irۏb*:h1brpon!d8|AjeE$9@Վq›AK
    ^s2U}o|p_Fm0&KXۧRe.${YV_*75Tm\jX\iRnܳ{N}3SU)e&nsIy;Ԑ^G,ˀ~/^L$!>4HH:TC(ov;C
    I@U,+<Ċ*|eؤZGRni԰k*kv2⫖U]
    ̤8<:WL!t!Ϳ:+kԐ&Q4Iow%n!naSäMqtT()"!k<ˑeo"_#Mt0,R^}_֚Ԉ)B)3[!άQ##ϲHc\V]lPGX1noQy󢆽<MdIzd:vWg^8>fnm^kfL ɶU�/[#	!zyB2
    Fip4N׫4"qAf�
    }R�~[|j_1LjTy,;-xITZ=pr0fܔ'"O hwr�H�8f3)'2EjW̻{
    w5xΘ<xmLOhBAu�#ܿ3wi�%Zc6Cg)GIayePPC;>܏!BK<daArx'\[rDۚ820@U\s㸟z
    B|Qavٽ~tPg.zqR߀sf-I1j敵
     p>^_:qڢۃ`v! NbH O#nK⟣;C?dϓP'Nm;Asͮ"F{	vkzq8̲P_4f48Z[01#0:Nw;c5+DZ>NY-Za2tH씉2)%΃i-LlمqB?-,Z>pˠ*Na;¸H%lAWP|δ\_AX(LSFBlKq ^䇅9.3u2LAH-rs󎭋$mu1" ORwʹaLIMĥJU6W|O>2=nGtZU4ןٙ*[0{c_=Ұ-{|a�7@FΡ!=o6_3si8du#[Ly\C*y*.?gE%Ժ	+M}F>M_
    ;jjY)UFB߾#�a~
    ryEL"cj.Y!dQm
    @
    |UEn$mtqGX-JLS Fn0O旁Ț_=b"ᐙ;\�
    ̕nz> Ah+񺨾A78Ef?];<Ew#R@rg9.01wnz,ԻT(EQs-G5SLXAEJ̶Nh8'Oy0�#|	={q(px>`Z:ECָ7W^^*yBϭ?
    "Z/}֏.?~E3EM.1'nգ֘)Kx\9+[S0зz|*C㙠ӠQ+k;h?yW.%o_&ʈh2eitQZ0C</�pݢmV5iTEI~uA}M/lRMUПn_[uYLOQl*?"F|{THKl5ca+eEBAlDi۹鏟u�njpkCL:P')'|8h9Ͳd^q^/}p!	}N	0o;X+:!馑262@q~+>>_SCOb"m'V\~6?DVa;R\ -a"�vRym""xA.{.ݰ>^QpM	!6R>E\@qomw
    *<|t݁gNCaA
    *]gpecAQ6;�a݃:+	<?"2F83;F5Jpjf+[AI47&	G"U::%]
    /Q*2a"[#_qIFU}k]*aܬ̡MsOu{8J]STGX<8RbسRk%܌JeyMA|HmJYwB{Y(8XJ
    <UbcAOM>c˯sÌ4>S/æjw_۽(4rybsb)'cir53<I8tne成NU[:<2)/Z'cv5Kj$"ҎrgԬ_֩~M;5"m5+ho*~, Q$W.(E+cdY_!Aci3G)3Ssj
    M~z]WN~+1kӸ>VhH\̔!)R_I3TK
    A^R7lş#,|(c / Zrk2UV:LSHsͩP(3&D*!teJ)/w`kE3q>sa7Qb mu+un(�a)[~p> 3Km=hqfmÆ(/cA*I3EᐓV}c0[ as3e90Rgz
    89(Kz!i6^dADp`o+_OO?3!8ý'~/>"W%&5zVd(v<^�!�҉8x}$
    )8dY"Wby^̶mXD$FیC@+tSE0_-GK=2..afW]qtmɋrjWe 40$c⩪/em.!i0&ojK<J2;ؓ!vp3)ɠZNrP(`H{
    :Da^"=r(H|xxwz&85ž/2f'7\ΨB=[BQ
    w <Rhm^,13m&bIz8XLrOдm<)!lYz/!9VX
    6�;DlTo*Y@\!%fTLPNC5h7)2XGAuX=vun	")A,f"cSAA}SA>j?ރ�unҝ?ZW#ԢE4snV60CefkFoSpv4lk<zr1p7hw QUR|FenF8Du
    
    KTi&O>`g#l?E6)%P/rgW&sԗ]PnBvBJSnV~BuG"PyO^MmD?G=Mzc5a|ap8w[VVQ pɉh	?eR5f)DTگН98U2<)g"D5Em1"+uK8cӐF$jB\dd՘5lSNZF鬅-@h-g|"@%
    ðv	L>#66¶kpJp_mƍ>oOnf0zfuDʸ葂h=۬{Ld3V}ۊֆ?!''-˗,գByi֍` O0+t;=:3B6a ]Qa~HwqS8U .7;=׶ɟIzmgMxYS8WRQ5pT#V>[X*&#vFסq18bbqJKwi`@
    GRVC/0[0@T`<T7L#l1le*aW{0֬8.v]@Z1QEVsQ'Q7]\cP	X׬kuj$pQk׉q?qFundwfݛSԼJ$ή!v)Pn?k%ua>j#Vag4,r2ʹX`*LN_ΐ{OePH@8#
    1Ųz
    DU
    -�MS<^̆!ZY)߅!7xe
    j~/hO!l#8,;̈WV8qSC}q߯sd-lo)����IENDB`�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/ubu-install-6-download-progress.png�������������������������0000644�0000000�0000000�00000013236�11773544727�024624� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR����������PLTE���
    
    
    �	
    '/$7##$&'(++,/02234668789:;<*4G>>@?@A9DX1Nl<WrK��[��Uk��y��y,(BBDFFHFHKJKLNNPOPRWKKUWZAKaHRgQ[oT^pJay^adXbuaTTabedeifhkhltmpvtuyux}zz}gpjslyo~wzt}|}}z���	1
     >�,-$(-"6,99?51$61C�I�S]@?C9JJYY[aljegJE\\__NEQHXVbZceiibbwvhfrt|e_c\mf}gc~|}zxzބ̀)Ά6م&։1%7ЎBӓI֚VĊ|ԃlޠYڤf߲~C]FazȽ҄ߟ΁ЉΠݠ¤ī¬üӴ㟳万佒Ö͏˪õѳΧѬغ+.3ᒕ{XZ\]aY--x~L x0,phZTAESyq��qrt8��ijlA��\IDATx^E0Ѿ%0Dy9oY"RӧM ]	?GzhЙN=޺n!ZG`	9‚lOU)
    4Dq�Xl	
    
    fB61(DZIKt+DՃ;B(H2եC!HBJ;c9V;pГܭم{T`PJs۸RGIiz�=q~s췷8=ϫ*zfh7eF&|@p~6n
    èZӪU>sBH,	Nw׎�*FdI}EPҍ:Dɚ֤U&ָ_2E>]hU)IׄmJI60&ѡqMcw)t3ɂή61ms^Kg&bW|A
    RlXν9c?wν[M	VRۭo~yks.(;p^P-:φе$Mv" 9
    9N> \9ьDڕw>]0J:t\.Zp|-L:@sk$!joz;=?#Kj(@0h1KEXO1Sl9umdG,Įq0,P>f1_j_"϶yJxuIm^nZZ^*�t9z("#ir}BpM!j_tAXwostBE/%q
    θ)BV/ľB#Y?#?Jm\ܸ~g<o."�4!T"`Ԥ4?S�INFAiPo[(v;)LǒJBZԊG9ġKg?E.(<y6Ǡ鴛>=&1
    aOьj79RauڕΑkj2a`AĕB6 \e@هf՞svv?ojcg4a4�ўMDp4|"Nd>G$;9}|g4tP>*|>~>WD>1>2<\)ݜzk/g;Dc�6s�1W04QhW nDNH@'E&8.#..uAB$\ })勥R)
    PT*|6egǍ/|Hn,9:. +Mr¥t4C7=-*G+*G%²*,)d<e6U>}r*I’ˏn+SWanR\/86OM~9IUWf''-R“0_^E ٰm}Z1[2cm�2uy2BJS8kcV!GUHP׻+|_6+X[w@qdQ9}ˠmӍ+Hm]eai]y+)@Y͢.]!1bt:Eǵӹu?D>OĊ|"'|"'|�{qǕ�?r|\e�u|hߔ3yaNe/]k"(Q	mmui	 U$ɖ~~x+
    ^n&dœxikGrS >t Z2k"DsHߙm{F\/VpQ�BWg75I9'L|$GV$#C{<A۶g)<"x84!ҙ|ۺc2|@ur.F1㸂!Bg(غG8l36�E-uiKt&OR2'H鬦1|
    ipkߦ5;%l~Wx]9k
    ,Jf16Ŭ7JCR(|d$X6w>  r0'l2y',hEȧgLPߦ>+�Wb"]bO`UڸX
    lh	<߆|/W_Q^RW`yj&#_{;x2
    L ~:}|0*A>~ɣ)_jO`QvzNMWr|
    \?M-ի+|"'|"'c 
    ӀUـWz\h]☘`&xv?&*$5>ć<fQI~A,GO]Eޤ}~F٬Dax]	ompNI7^ݔvխ+p~&Yhh5-Us$8P@s#|sK9Yn7]\hޏ	~NZAVۣ&w-Bv?`:"\T5AKy-"
    :arŢ%	9O-|8$œW!\ymX8	Sk?X&P"<	`Y7qv$3+N\w(Ϭd9De4IDaA4�3cIlq!
    R�I-$;06w܂G{?&LʧIF'/;wAH\?i"4%�I!>
    #@]<<*e˗'ml'zZԎ6'2eee0�BRL$R(FL?mr5aBSsL]7CwH#Xv;n2UU\]uZ7n@Rp}vffZ.?D"GEq$>0~]qA.Ts\	 {z<*
    3ڴ|:4(.aN#: "\pp F<P8~Fx҂|pO&<S)ѡ>8]$DžHͳ>ɿh؇H>Da!нE![K]*;{ۮWtQo9Qy4j}㝳p2;uf~f?TQ>G(|#OCK8*<}ɂ_8Ř-@D�^@l
    9 s&=pytnu.zyw|�,`8N0Gk|F-HdĽMґvREYDD:s.�2
    Dr.�ڷx>sgn`k8jL9~kp1|\/"L2`N
    'EԃtҾțbM($
    z|b|akYl+#Of>7rS:i_Yq1|\u0>�f
    .;2`~�
    GPV'~{0"mcl,<DO5vS~S=+.f8|HQrJ
    ؃I!.o_7)0(!sg[־^o}`kSgp	1Ίy>r?vOxbCt'
    x#lܤ㕕OYq
    lYY9|LuU1C-糮�K?Pp�"3t=E@0Ǎ|=�yI>Rͪϟ>܃|*&PЈ; )#w}%N{6AKoK1GY56_'/c:*l_5X"ChQ>G(|Q>G(||/$SL;)>xSxw$! =#gwH߾iݛ~?n{`_$r�y>a9>B†�^`%6YK 0i<1rJ'>^*ZG_ML@I*&xto^+ҷ�O|zXNbL}ۋSm;p79~}RC
    =,$Ťo{y
    {|)MC:zUa9s&&HgbԮM]1'5>rd>G|Q>G(|P>G(|P>G$s,nP�CRGkt&KةSc4
    ą\3ˠM?7xAgEŸ|yZ&*OTn[F|L-Q+ݣSu.!]'0d.2yjÇֳzӭTD}<ύLR4M|nWb{p8gTa;ǕB2tu�ͯ;w5*6v~kVu
    ez#&ցqW*IpeѾWfھGz#&u�8�j=~ٟl<=def<-3Ce%}DvS_	CR$RTfGgf;iYBHh}J		ʁ8.v:`]ޙhHu_jiE[fmrl}Lu*bOp̳QܱO.PDuJܵf.|ʧi46<}~y}>xK
    � DA*wo$L3O,~~p1����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/mac-install-5-standard-install.png��������������������������0000644�0000000�0000000�00000036136�11773544727�024367� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR��n�����1:��PLTE
    
    '%4!#"//01P8e$9N1=rDt/DY0NnSXZ/@=1](*[=&j
    gtn!c2
    e6s$r:t=e(%r-/r.0~57GA1zByG"HHHHZqLcyxTUicOfffdlunpwwkb~zcwwwP$Z!^/c4kr<}HpJxo{@?8XrgOY\k`sp!.8(*:135'(IS2p4NS"_5Z#_8l.k9`:q=HJ]SDFUNWXhMrcrqWXuJrm')01?@p1|Hz{dfQQpp/\{ivgyPfNdĜdž6γж(9(̎QeԋiݕiݜyƵLDzgĺuױ|GcL[DXT]ov*,1/2.3(7<EhEYKTGVHWoQs̎㥸˝ԯ֚̀ǪƼʽݢ̺ýѸċŖljɕуЕƬõ˨ҫӹۍݥø`��9"IDATx^ű� 1B"M8k2AU_v���a%s0 f)^4[2A1Ã%)5(-RUB
    +C`xwUxx]yv'gg6Bե!>{|S%&DXJK
    &1^nEya)srXRuP*<t?~opBa%R˗Sb gi3\DAm}m6_>aȹ	oΏ~ĹuPJ7ʃAS3sYtwlٹd2{zQ?mGu>
    b
    `4$vd@b-Mu(mnC_4b۟{v
     7[/MuϺ|Rn*~|zzUnqnKFXZjŮzͮ2<oNu-Zsj($=@yF"q!�UCc1OٱjPwsK=%*(z'N
    )8qtTKQfH{*tmǂ@H!!/#=ʲ^F?~tPfLוWwٟ4pwWsÚC">G<V{@!G&䀹n{}+{gfwM(R4>r%n7+랇ͷOd2Dr,&,@(ĩgܔ"1FӺE;3bem%-a?(Ea .煷
    d#l|3dʍDTZ<^䀧ۖAB)Zn{`<6ڌdpN;W]73}b%,_d-
    
    Zns$·e9HҹInq&Ff_N*
    OWܠ5hrhoקU9nU	.c^&ϋ
    Rw4t#7�+EBڊ4+m٥ca(.:8(!z\�NN
    }JZ\^-abv}߽J|S!u12a	7L6fU284&nbӚ&TY;p+  
    /mNeQB#h�9PBd.2?-˜ف���$-|q=cV\a(�<6
    ^${#2&mppQ8v$/>B-_-2InLr$Lrk	 1n$Lr$L&VtbyUY+9m&vwc,mJKn �}x:{-I4$.=*LvhrVЮjV,U
    %F@{BRU*-ݲX۵ os?nhAO�AIn1PżlfNNfܖRtuf` CEhS�k*,[=r&inuvYcC}'ke4t,z*	v1xZSs4զܢ8ut4k{+}r.WLrs7iC
    1*MspcBa:n3ʮhI0Fw�(4jvMD*Vvx7LnMds[E~Mu%64�W%[*;'߸`onKon,%ɹ0]5Q}έ7knṼZpknvm7LnCKv@Z1/nKy-.mE5+nP۱vvme&G	Z	snEx;y
    WL?6&+f�E&!]NnC #FMU7A5\涺}ivr
    %sI6w}?wk~!O6OnLr$Lrd[&e2-2In$oq;Vq0*pf_C8W!,PRz'qHD$!0;32GvuP7n
    !p7p7n
    
    !pCn7p7pCNvd:p{11tY}|Jܞn52QEYকdL"x%\N*74,#Gp6].yw&iNo	M*mJ^Q*>7hztW"7!Gh!)d?^dF|NokFRw1-[x(UGYǫ&OSFE-v1-4Bs#!;nS
    n7[)VϸMz^Qtdn9c7?pO9L1<Q>s0	(m!p#_PLh^]%pK{J2QEv7~(7p[a˥
    8ziGg!E"FڶiMZuougyt7p4:N}[orUm۝
    
    ކF]˲˾n/ԎZp5햙
    øX߳:#DwpCv&Wi
    gmiYY3nh:ԯԶzmց0zvvTe!p#	6~>m}
    �i`l|}IvWt?�Q[m篻tk)hkoqn__`Ǎlyaz[6|+@G]I8%*3LH)6<Iq$a~蝾m7]8kzڪ?j=Hp{{|@9R QrZ}o�)jtSkԌmDnNھ
    ur̄|ƍ­/&ѻn 1lBDMbDY;+h{u}8	
    7v_Xa]L	7ar5n)m�oo7y(nZukX$Y(nRw J=a1\MAB܍z*R9r"tcfΕ�}L6	6[9&Hm˰m_<n?Ϸ~?	nqCW
    '
    :Ɯ{[7a'SrZ3B.(fPĐ&ō\<
    xIHEJFh6I T*u"PUrJP2MPfJRBaMפ/Cyc�5|J7änjjۑ3u20"ZyV8u
    ?7}68eqf(ԫ(t9`&J
    ]gELS)nD8u	0(nܖtHZ)yn
    &9Nm<fĖf-̒{c-M{4�mlR}v[a2b	3
    6㖈Hsh<Aԕ"٤XRk󻛿[NIq`abjxDd+ZV-XR֠pk@]-c"N{'JaD.C4ӫ'Ekn^*zwuqu56XVM9b"yzC�gt�1	 fp#M5nCq+q`e*{D"
    (u[o3k=G5ںu'^)p'6GlQ1
    9A)l9LEK	@dA_J3n[ȩsŰLK.KDhDJV3e
    Ж$rq6of@ܱHí\ǚ0!UhQ?߼Bcf)yl(o8RZ}*aIrC@0V\R@θI
    \9[CT21	}~--B;B(s|#PM-1": �$p+@^6v=޾ˏ|
    |ַ\>?KG)sz*$Wz=ULrRcRd_ph+jvc^n^b~?n
    wQ@�@%^\Z32`9(#푋e'AʞAj{3:	fF9Ɏ+
    bn;̬ͰIbgn`eo^�EWu-Wmh֠?Ȯvtc֤d~ec|}/Gn9q{z"mc
    ӏkV[|{Xs},�:kʹXP�k8fgrnn~\|Û2o+}W�[֡p3)7\:*pYsӔV,\WMjD[ȹigcS?n)�G'i [Zm9�BsӔo�:!|ȹi'۞&LQQh&4v \b0%46Z2#9 +7L51a�b,pPɹ'@	`۱t;rvC!7m>U;: UMVnb(ڈpd9"Z
    n~苹`d$fva/o$)e2}@MplG8`Q}a`ޫ07׾#<	1$:}|m$KdeA.U"[s%}f3
    /mN	HXn
    [gEpkIL[Zw[faхaK_ZIm/87teKiKOG]8]7gT^dqS^pk{d-�vm-[۫΅qG\OkdΜ@YWg
    cy.;Tf6n2G[ns-ZɠU,}i͂E-B#õ�fqmQXu#>*lcܬ*n-5wKqӠ.
    6iF6m
    
    :\j(:hfgbc74SԛwWFv3-<(1n<)ZNq|ϴO,[Nep(on3vzp,(wlƸu¯#-4ۤ3Z&ڻ*=j(:hfgWXQܛ2ޢsc8wyS*mv5CM@f~!(^CVo7Np#[
    lܔ=*[savi`;Љqv(%qVk{05ycTt.̚8pN8x\OkFYčlôT�:'Sr�4n
    a6Md&nm.M*쌆}	df0(E^s[[svy	7Y]pδpm7.u8ѭ<TWZH74y0]5nNe7n-IRܨGnhYAхLMT3e OBNxV岻p).@Eiyiͱ|rvׁ€Llv
    7[s7
    ة&74lpQ53]΄m\*]jnpDM7uS6ΑU!k74]�Pe5n-5wKq+@Zۤ32ӭ7:hA`|x4yunp웳Id5
    m-s7_{ڤɬs&9b^un8q[hۺ=nkؤmq
    ^eǯ'ǫ&-ۇvr|8
    ;iq;tm?Ge3ZZ:/t_ڐrbYmNGÝk}ܨWgܔBlY"|vi\jMBRmQnƷ.GA`S6N=ޞLOs0ъp+C!muG;Lp4
    :%6Ez9Q[v?	w{k݌y٦֫PӐS@ᚶZTerRWhjHH
    ^f"൧k욄ҕ>
    D<Vi*^_:yacpr5ޤM)2=n)]tϓo~K13yJJZ鹦
    l\&pܐ&Zy)3>ꯊ8Q=qV-N<*v;IAӨq;ew?÷_pk*U^|JȩTUJTrJr$֗23]O	eD$Ճ֚*^3]M�×	lϏol7	m?|mӖ	g2y}!pa堽z1nrTI'*fKqN"Pe]JV7	KmrV-x_k҆4ў^zK{-m!�<j6/i/xM	BQjrfGBNdI5[[%aV29-\
    o%@ԙhZsYY
    [q5fpx˃h0|1Mp[m[#n?E~yPԤ+T&!I}MpI$@RqKR@ٸ]/^lu|�W{�ӽqz}HFGŔ'=ӳhH%
    Abao⸽wg0USE%4@kjP\&Pi$RO:
    [z/Cס_mW6T.Az֝دÆ[`LRNA}	A6)C9N{ߟےn3.B,+^1V�3X F'�1A8nF!&pYF�9!vVvĦ;bT}~
    OdžCzl{GǽC;6}g,Ҕ�0ۖ?RO%eŰr;.V`EAܖ`5pb,OtgFE䈙P]f6"[tᤷۛ[Ϛuqd~&؅6*FCDܖ=7koZcCF;jYO�ٙ-om7PNkN02<\ *3 nV
    [-A	Fyn\IyuSJIUm59<Bx*UBՌ;nVcfIs,pqe#p)6	H8IIEvZwn-,o𝤡ּy'S̪|0<7{2D0V <7pC|be2vg`~ k
    =ĭ]ߗc~}*|e3'aE;$eNc
    k^JաիIN
    -fn~ɨfgڹ΍TܮZkB}?[wӁ[opǪ9cҏZm})mӞPk%J7G6][Nn/ҳsifiu^Cm:su7gs'̚
    Icz۶8ӪLv-}3+%Q R5Kݷ
    %Imɛ=!%Ӣ)˖]؂"xJ#UAsbq3{)$Kh
    [nD-ߪn긝
    d5!Sq:n|T
     Gl5*}ZqAvc!�6͎hMF-Yyq3n&,mnxpӼ-<͛q;oVɶNIW۬UE7uoTy3�nMm&7oݬu[tul8eMDRes=<KkW!ŵ*3$TruGš|mrka-@#l[A,晇bxg5
    aM=2oSYp~88: )n~ov>Y;b<{18Px$@C`e,
    	c҄W>zpȮm6/�ܴ`29L+n=`#]F0D[?a?
    8a^<@>_�ix @>'pYoKyś-�_ѸG@	/)"_k14["J=J_*Br^<^ pdgnZq{99aIX&1rXrYUnbF%7^,�fb,ܸp\{1rW)nzqk͞k7|QPqIpXrèq7!,q-BpLl7M/nαqƚbv04,]Թyx
    cc"ay{2nr#
    u,%$!
    tn|ϹHBMGfuv	t#GrpPrc1@n# pyLܴV
    ;yZ5RxARتW%p$2}[t/se(݈|ZVn]}
    kLkU\QiQLO$/P7,|p+-Jm7yffaa\rRؘ4mmM
    ֯Lbiڠv[q;KMmXX]bΙ*mrZqSR[s+5C[TRL%}q
    HiC01g聛(mJۧެ)mk66Sڠ1_J9nx”]mkFΧjͮn9n/,
    W3Ț~wƛFnXjLm*x_>-*n_7\isJś;/K, jgZݕd"w5Ӧgf~|L۟5JnE-q`+%AE3ݯ7SM7LWتZp暩re(lhό󇩤DWq[
    SWZcs#DnRɻ(lw͍5!̘(xJ
    P7.>z_?tӓw(lF~Mnɭx,K\_`m`BImN6
    1v@NChB*k*a]:]@4'
    DqrN4,PZݒh?۲渁6
    x`Eڞ'OCyg1
    	{[Ciނ 0L&q܎)neZHL|2uDڌx؛9@-M3nrsܒ2nmQj1U*
    4/Vr3/I".fvnۚFp`Db0@s[?8OyjpbGٸ}ť.7TFlvcJn4؟6ln*s[T}UиF`7>Jyf0˸Q2۲skFZέ5y8ljQz8Sg
    c/sn8(p[w7>[ZDn3ֹ6U
    jq㉨c[*2YGpFjq|o}FmX.im1fV~Qs[pg2(bTqGInAhfԆá06m$7m)yFNNnTbm
    kC-\9nWpS?䦴E쮱�Gƭ)qHTFsJF�TV6z4nSb�cb2|QQ
    :(p`=ҥ۪yq;%6+N^�98D])7ۓG䶲/t:6cmSlFK5썱^9n_Ԇ4;ҹyB5nywG_ʼ$cJimg_fi8τ&Rsd3[Y[qBBAN +pGX.|tX%{"(OcqY9r-qo6NM]˦p{
    .%f
    [F&nO6�&q}̭ӌu7qXjb->S(ּ\me#[+_
    |imf*h{iѶгS<c\ښx@N&O&9GwW4fc^_Bp"Xk@[anBjko舊#c=MemC~s=is~b1ߚxk]p6EnT(-R*(m?Jils]q0й4qٔbí([7
    ֕
    q5##n_:&nJ5J5y<nLnֳJp$q='Bn0nKamͿVt)�uBneoPBnkF7BgKn$y-m-p+ZC/!ghjzaؖ8;漛`
    fm6Ȯ[s0IB~(؝D*~w/+a癆TV!KKL(Bj#m3YL|QQA\Y)'.OȦnTz^_kV&b>A5GqiN&.`
    ۺ՜jc;
    c)sC&j@CQR(7vY
    MVl>bvڧaQ*7榮K-Mz-ܾ1X17՗͝	p
    i-A?ܘ͈+L%hmf
    <	
    |
    (mMH,qF-ݜrF&<k7bPmov\nMXNඝYn)hcn&fa@-(E17sX	ך7
    6vR17uUlrb-ĭռV6\ho0jp›lm㶛FVcejg9-�_[[dP4YKMژrlo[eix۬,$o27J_ξ<OݜmLJe;{w&a/QTī4YflU@5d,^EJqڶϺ}OqCndynD|z}t'0ݼ6?ݒܤ7Ŕ¾&-6374ZJeF[7/җ½~M>nRݎG|ޑ&7ivrn=|&5Zq$bJ}Ng=7*rBnOO;Zs3n+^[~d7i|pcncDT7:$7nr.s[IͱGpnBPw
    *n@07?bU֍L7NRJq9n;B[Ls?
    7ompCBvíh*\	~x9o;n_ts޼"7)QZ{.RlNs*U-�)QJ%!pBnB|uϴFyn܊=HCc>yoilas]۸KxSM)1
    [WhF3SU3@[i͋-cqgu-�'V=>r=qbn
    &KknABmػ(㾸Bhf1tN[(/;L_(>.&Ix[?3_n+8pݦąuq7qLmPp{U6|<o?8ܢ#7C.z⠮Ub��n-QV%ty��1L[V˧
    7Rp'ԗv�b݆~=77o2TPw*o)~kJ+o*eHw'MڛVz{9mp>yޜ#؛6bFN)ލ뭕iUO)
    ܸ׭$8\81o{RV+
    Mޢ0Q[,xK鐧
    j]F\2Em;EfNn^=8v7F|mZ qU6cpm��UB汥INq)vQMlyֲ(C
    nW<8vۨXc:`k-.4�ۍk7vOg"2tެ즚v6
    ܖm\$gr[7p[\cSmG7ܖȄlWR/ՙbx9n7;v
    Da�&&Lwr8[[,CNC~	[rǏ??FnFn#7r#7rcȍ1r#7r#7FnFnȍ1r#7r#7Fnȍ1rcFn#7r#7rcȍȍ#7Fn5FnfToاNr3[vۖ|u~Y
    0d5r.Ta9~n{}VAne=UtsR#soCO!meJ=֐ćr6i?7Yx":m!mRQ^tYvN: j)]D{R,CEױEVzqۭՃ*z>rkbdU+YC/nCt	tH֌s#b$1GlEQ20P]Ky{nIn#/l@U
    hFALb$/n%0|1vP}=`(R0#\܏᪗[jj9
    ĝUuqS�&z>N#2@9U۔�Ro#WS3^zqL`ȝw1qN^ec)yr{[؎;]Mkw^պwp|2<q!$L҇"D$5Vtǂ{pomФ6CE-c-[Z$Nn7)e܉*JuVCE4Nn5	w~Ĝ B?c-5ѝ[nŴ}6YǍprۭ	aZ8m[0Kۆ![bOHێ!z۩npr4 2.eNn;}+r1r?r#7FnGnȍػc� Vcr	&V|fX^r7!7rCn 7rCn 7@nQFDnnGN=UԣS7r{;cUa
    KԸTد$K$N"x[|a /sL1?zhhzc.ܞqGY
    QOtL=zhhzc"܌ןf}CUJEn7G]O_<;
    *	u
    ^64LY5-tD\@c
    ,QEE#z
    Ek]F#B%weөgHxO:	QgdcdWB[J%W
    
    S
    fu, 
    gm0JÕ5Y	n1n^7,:RIN(bMH:PsiLV_54LYBܨnr6o@TlTt:.7Wk{Rܢcܚ/NN
    1ebUe甆UNaʲU
    I[	q9T;'fET]n''Ӹ#WvMkXTO/R݉W
    Ģ騼#pׂ(Jq~n_N(eA
    *'eC*]+*P. ɨ#M?
    %pK2nᎊ}~vB9؆dVu; RQ՛m(@PUÚe_`IF*&c!1n&:	IV%vvB"u/
    lYV/Փ؋)WXfu( z2*P=t\:\YÛNj쿊4yqYlTV$7gAb
    QOt̃z[	SƨG:&Mɯ|1ꑎpSQ0|G;8(h?^]݃7 J;:
    }FͿ\n#VG
    !7r!7rCn 7w;pL���@>.tc0>R`g:W*Pz����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/mac-install-4-license-dialog.png����������������������������0000644�0000000�0000000�00000054342�11773544727�024000� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR��n�����1:��PLTE#&5 &#...z0G;e#6K1=pDq2F[0NkSXZ/C>-](*[=&j
    gtn!c2
    e6s$r:t=e(%r-/r.0~57MG5zByG"NNNU\i[agc\Fd_PxTUngPfffimqmqusmdyufwww.(-OQ%\.\3d8mr7zTU^_JoKwpzhr>8XwgSTeu}!.8(*:135'(IS2p4NS"_5Z#_8l.k9`:q=HJ]SDFUNWXyYzdsrWXuJrm')01?@p1|Hz{dfQQpp&2^dygvjyPqMuĜdž6γ϶'9(̎QeԋiݕiݜyǷMDzfĹsױ|GcL[DXT]ov*3<EhEYKTGVHWoQsȋ׉맻Ҕ˥֚̀Ǫŷǻݢо½ýѸŽĖċȔуЙĦúʨιҫӷډܦƸz��UIDATx^
    � A/yD|F* ^T%ej��`J2zHDž)eDjʳWa�f[BVAG1l3DJAٜJ+IHư[&_pHyMH:5r&E}y)vg \p)rUIrcx *7!WQ(LD`py+>
    +,~~VH&j\L@2oxCmHl|Ӏ
    zޜ_࿷6"iL&
    RLBwtSƅ,Mwa8_;TS�gܡ;�^--		)_VriYn2\ŗDf[ݶmrlbܶC۾-VuۖYexq*8qiS
    eU½(�ФҼM'BH˃\.^Cc1/ԱjP=ХƚM(!NR&.qhc#MZ4CKhǂ!~K<:W^F?~>e`ߖWş45nm
    ϧx]<LV`BuF+ P½d5 |nJٟ|]>N",-Ypclz?|6ئ7!ʊBP8zM^Aiiݢ̌AYq
    0Q-RrYz߬q%[
    &ޑֹLdDrJ|.rW -m0ʤlr]vpS&N]\s-6~Β{Wh\7(XdVM m+­80ڞѣ+IЕ`6`l~^^;pLUY5ɤU
    J1+n7ܟό6mv~_ÛfX`w[^|lᦉ(&- D.
    )yYB.0Q�ҽcaJ#8H*<p{7ps.AB%"??[E~BLnڶy?SITbOǣH`RI@
    Ђ\21*T4#] 8ZqV7y"Kʐ8㘮$d.qOw2{vn��0
    xu n8xb#d=v`?)b4p+U΋݀h=e-8jܭ8/tL��@z2 u7tC۱cǺ
    0@Oeɟ{ќ;jhGču7$MJ qn3Nsa֘[78昛9昛9ȉx3Rx7g
    -Op	QM0SD-g=xbndٹ}\z)BF� W\3*A0ﱬG6ni,fn
    57զ3MT↟ %7aPqᙷgfnf3Ir#ȏ颸U&?r3vۖĐwXe	Z0[lǺ$QP.eyfԟhaq\x2t.ڋ{Db>Y	omE#OÒdzwnYTC
    {G_2_u'lfWB`s_Nvo�7Q"98\K x NE~n)[{]Nl<r
    K7wh
    Cɽ4q3Oqhx
    =L
    `1.Cd{hs;6gZP�zsuAT_�  ZxE˝r	8yޕwh0ĺ^0Ct촻<=Nqchqʁˉځ9g}o~
    kT=,*EK#DvJN9`$He`ED7<^h[$n6+PbE+nf,O\~縆!Yu	G#N|\ݬ_K'X*g59`SROIvJJw̹+VUpۡ&u;Nܦfi?7m;8/=pspa]]›
    ؿqsm8p'nMka5h";c$q̹j4qmz6}[ܺ@r;na͏
    ۯp	<r7mXFW9;rg&�y+m"q7#ˮo'R?_�YpDx-C9[+`@[}qc-1fȴ*O<r܍[K4;yiL+zq@#�DjG8BdX)R[
    7"zõ^q;L˴�Bs
    g܂iU>("K1qSF%@[r+@#DvJ{&迺L�;A(
    Mرٰ潆sȾr;Q"wҋNp\U?�=kUt:Tu흀Ն_zweNu̳6Q\q8kؽNikyi/5޽h8+fۯXR}5s6BL_#TAkKD�;qn]ڟf10#p+T�{VR%J`}
    ~p7n)^W�K_vtA.k|v'`p^6!(Jvk:?ǭފ?j'f#G>uӼi'>,>ަt�ad^fmRcvt?£=
    7�
    ܈d=4\/lT肄U(z@MidN=ڝ.&Vw7.lR͊cV\~d6j}­:ǝtfrP<BBR2(j2r'6?=Z:OBwq;6iEq;7c)&idNpkavݍt]2hߦiƍzNmDMMF5/Ӧɸmjof0F	7۱Ho7.?7БR\C51&eҚ1}gH܎F:~sq٨_'Qm^C5'rd\6'ܨ-ވv.$ٸ~OENiQgͮz73/1c|b[Z`Yf17f1,"gj1#f1
    R06,f"45np;c齗7"~*ִIs)%ǠM'ZP <Iyg1#!1r-e*v~n[{En
    ŭnf5YR)pk7
    "Oġ m[8"sXU?5íI)\n);6p+%qK[_93ܤk-9&iO!";!n=R{)SF�3B,p+Gp
    @k9_`AvsgH`Ms#8LaXJBA>zٮ<yIm1|5[5ܒ-fMݺj'nE)6j	fxU(<bMm+6cV7fdܶ6p!718c׻9&	Yt-w_cA&"+˳#K٣v/YD;߻;7r9𶏡Υ@=œ}3(6J"lEp'`P
    mPBOT+ͅM>!w3gdOu+@!F0n,&}w3%q~.^?[Gb|HfpSnxk	n|CG;MQ8
    "]nW:	xQܘ҄E#.%G�Z+;n֠{I�(F)Hڬ%9r
    iJXIYV%1^ V }Yst%&fvebM*zMa	ësd[l1&HGE_Re-:f]pd_m+R_kh:qmx5F˘Y+n=9mWAiM_qi8y>,Ȇ 	K(<A5Hiչm%74طWy(nZx(nl܅;V`Le
    pe*7{5Q bkQ;_m}gJ½Niǭ0l!\#yB=v<O⺌mBRR=c$ŭvF9
    (u}46CT.=W=' ǹgKY7
    7HOSqCEQ_D}o<Be|;"om/jqs;D~zZH0|WmI-pIWWΙ;c 7
    :/nD_퉚vjVyiw)0ܞt#&p)]vܶIqK{܆O?!L:i})ʋ:iHDXxr'pW8nvܼC
    Yu1CÏmyZk)5s'9.N{*
    =?5KL1g\cRuHCaB	s*͊4m|Sߧ
    1xؽtXt&ZM-܁[t{pU{ĵf�O,R>nf^0=ҙ;ͷY5a"
    F$eL[;m`6麈BrmҪF.n	Ҏ̨[+C'-+'*f^P7zyUnoZ<"] 6eӎw2|0n"5Bu0s!|7�!nWuP%e3K1*QIv$ZߙV�i-#'Lp@5@9.L�`r�$	$.J)d)IV؋{qs'ncG,qvn,#9nѡ]&]kpOq 7^cQiOuڲI{#
    v7EO"onȮ\`Czx#<>
     qS1ךDxʞ�{mGY9}NXgkW0[?ǭmS_hm$
    م!龅PJ
    ^SKU	T|SMl`h,U,[_DGb A|x=qϭm͆T*D\v/bӉL*[ۚrD㔹1ҜoqVzܑxn\M2e7/ETy.rfnnbn.nۂLsVi5G)%e>:n&s976E
    7-sd~l#=s0慘ψD:XЈ~o?cyk[ebŶ1BwxnwegAP.}ДSR3+J1"`[&%bҜMtd,vWᆛ)Mc'SY,Cb7k"dJ^h_YWhۂA35N]9)5
    ݉ȺE&iTM0/)fKp	θqZs[NVv([J?9\sdAiMs{dTrs00ȸ%2q]4WLDT]LےrI)1ŀz-Ebf̞=)[ּ5n vbDwFrc['67nfʼל\Wϔ-nsxd%uLS;ft&#ai@/D�xn*R{pV<bIv]*p�uIi
    ֟
    ~orCŕ6MY
    ?Xq7(ւzn@%n@Y^7즌�綖X*cp-6"wʷ&8GI=GA,TK5jn97q;\]]>LS^S
    ti7jn,7|ʦ`p9n8>L&OPf>B)7{ͫjckU^<<<\>&(
    msC=7A:mɷAū۠[|[I)o5Q)-&
    05
    <3amk67YEoݴ ۠m&iͲm5sVK"eB�ϭIŶ75l
    xϭ"ƌF$'H�OV;Z<|<7ٌs<'`
    S,Œ6O&gdq[.7i5͸jetVܴ6W>YKsaszx_+%gs^|�gMSͯznr]hn'9N<7m9^d/qR7yrau<7&HlG7ؾDzui/sCޢXa69ݏYp#?0qnb`Q!$ӽ(X*aHvb<ʮ-jH]R.>1[DDnY~x[4&ƤmZM#TYlRݨ].t#5cnIeMPL
    Ff9K+t˦"k
    ՔqNȜMR穨lҸ;HݖIңAC`U=[DPBE8~6xt7ΦЍ9h2hJ>G8iUdMwgǝM7-!t%/rxM!(zF])kfS+y-{"TKö@E%�̷!
    젰۷bk<@CC
    w^8˃	!RR:z:Zjfu0nmY7}˄{`aPJT01w7o|ĝMkF_`tEE5iUtڕmttfgF㏑|i_b39J4RնyFY*>kq>dCS
    R6RrPgK쀪OzͿh
    ݮ߲sԬnщ!nΫHY
    ) 9 .u<@rFTzȏG-S뙝xXAT_K_^R1#SXeDRxi)/:.n{_zN7ݢc݅60#ZsRKDR5.ՠnҩBԏnz@\%:=
    IXKP^7SYȪ(V*VF-!]V3@}|̚uk5o�z{Zfqŵ%tٹyZ
    _u�<rH7"	RhuJ?ŰUج͖޽#U!+KT˗^_"t2HV'Nj.Du% Nn|>B7.ºk)$zc汮t;ʥvæs7|"ԅ;u8ʥ<[̫t{k͜nAs!31M.^i>#;1:f&06.`VgTvyb<F0c{kF:"40HC"F#ЍN! iԾn	i'z	nSi>[s--2d/xzO"gۚ(l]S ."Oϊcp6Oq
    kF6
    9)�J@@$p@{I7~6n@nB{}\7uAH-0+E-W|
    "USlB	[&Qen{)`u3hmx]P/rzJKw><v%z 7bE'syLjoeQͷ-\%eH*Rdݚcw`q9*{#3[VPԒ|M۵J']l%^{E/0+"sfZW`\td7Fms3^>tlYu_(ac~V$
    @
    p'`J;26ay*fߝlMܨIJ3ݦJEzPN^oÊZ40vXw'pof6N
    nxbSt2zPd MK׿#%6M[qӭ`2K&-!sFO̒?l30%Eו/TS44txL'{w qأ-|�˺b-EŘ,X.6iz0e08n?6hStZtq_xwXy1u묞ǚ
    r,WhjGE]\ƚnFVW26l]dynѢܤk6ꛛik&pM
    kкqS'M>nT[m	3,4	7Pc(p6lބk:܈@[�LLB"fLݚB	cZ5-!qpn>.Ki7p:BnknmM]mH*ox	7,ȍNMF͍gMym@n}.6]؂_B]�
    ."rW4cqr}n7
    AC<`ධ 驷}קz{ЙdSufEICئMNʲi,¦j.
    *
    VZۀeR20它=#\C`M~q{=ǭu%m^ŵi9}Е^>Á:z ./U1@/F"r$PH8o!QEZNv ;&bb8$fsq>$nJ{|>mx+lj !"@jxg7U'jAi)=zDNX%L4q)/|]U_WyҌ
    J^iVD_$)JIQ#$)M!iijcacMkM !}AөBuΰb!/F 3f#H0anh2"F\pd6C6m{uS|?o}{>wdr^-TiiѼcv%b'ɰcC2KjMi}AFh煮"Ȟڱ�bH:184JBzX]קbrݹʹm
     
    ٫7ɓٵ|O|oV+Yv.h\ͲLv.aJkQ4ZXV#y(Q>cok^Ey'=
    P d`c-S;'9f#�I/Sih4+I�zsQNmCu_f O?o/3p~~>")%3ISf,{Re*)	NMlU9Z<MJp(v0Z".#�Yl$OFMZt;0t]oصv)۰<\y٦׫</nCw79nwvsί<YyQpA(>:>ju<Z
    RQɻ:v,t./ R"eXleYCPQ3Ca8|
    Ecf6h0|7P_7XPË&pL&A>}<'o7_
    oަt80˜٘s(,1BV1&@	wEP!hrlt,:JG�T`LF#'p j|2ML\_]de.
    -}΍=W;dBnu/$3"D1䪯m0Fq= Qj^6!/%Uҩ)Bi'5B4p;@W|4__,f3l=OII͛o_›R3F^�dktt`ϴ�q `%�Fmqh=
    2Jq�%oN6`ǧ`
    !qb4"7�Dh	d8}1l;5nSElqf|t:|ʾ<\ɾ,E^yit"[q:oSTfYDIe]ܕa-4fwX&?'Q6wLE>76}<a}f?&z̟WgggU񘋋<C]QT?Py;5&c7KbRpR7?[;{t3j! nfVO.fM!IDdp#7n|rtNOO>X*ov{ӀTj,FwneLs}ҕ'B/͐6vV|9Q+r+nHicɔpuƵW7;+nMFT}[^9(hI6g5)i*|g| |eNK_rFkcv&TUܦSLi۾=OM~DŽYۜfƶ
    ^FAQ.ߏ۳qD0a*5U2rpZqkh4
    Le+
    Ũso']=ᶯgR=7d*|Vx	7W[{'WW`[SvyyI;
    nx]>$f.Fd챱0G?…
    iGX
    IUL\Zqn2 CQo5LFv$V-f1F>(
    HzzHI@bfTL#6\I+
    �F.KҵAi6vXXSݤZgeW!Vǂ,%,%rh:fyqñO,fL!6(ndx2<
    2ց
    ʨZ9p*n8	EQhE{d0n
    IT	ՆY㗐eAL)s7l%k	vJ:=.../X- '܊/rLhAAXQ#H
    -ѡ;n8@u]Bk*G:kh68ګ<ƁΣj=ܚD.EtWz:*pJ)$I+d
    *8*N?C2D▌M5[9s2}x1sd
    ͊kc`*T5,n75:[
    2$Oc3R&z]ݢ(
    W%.<f&M($iAWZu-םᶽJ2ٯ/͘4a-ƭbrc%,ˇ7=[K(#*C%ϬsE=ynݱGI7G[~H7MY[V镥1\*$M6	N\!iZtyF:]wSy2>NJ|~vvMsD\|�X)˽۲<)n;n'X<cXPx1i3Z<l-nِVz52Ha&H	n)GU7O%ZsS'YE@Z!F5s+ؕ
    %'Y.Pp{n“XӋۋFr[Y;5[\aY-Cq'PD
    DYMPo1nҟ9�*nd1vV=ȯ6PMB<{	44܊vӮE69$c5wn֋[W緅Lv/=˖ZWō^څo!9IC"w2:e}E1/: ']Bn0e~I	M3hm܈z?HP8;?I>C@\h~!l݃S|+eO)RhCD
    7Oz<#Ԩ?5ǘ9XO«g&J<ބȴ$p{Uc
    ya袷[b�+ŭ:o(mQ=iRnv5m뇵-/^]&8ѭp{״m&u8$ տؚT|ukjQ[2,mw+pod-7>nm<8b{Xv[3Tl;}M%47{VHo$`z,6bIܴ.-8_.;rmJ`OZGm\L&_ބ6[戝RbIu~aCp[d {rDZ
    #l gmcDk+"#ߐB:&
    .q5DY&<I0Ti,[)pw6z:EފWݞ9Vi1eCXyFȲ%$6DnFr:@š	?NhQ+U3ŕN-LR�[
    c1oxؤ6߆᠅*aMQVnup9ץ_9_8ǗAlp7,LYMq"ĵb.Ud(1TY'Y`3sF
    aDvxBM+Pn[3+F#Is>SŒZq#Cӥ]c]z6D搑.\D'B\.RE6BMehN@0jL11V[�H+pfEy.%X,o[d70z`pNGpMq-REѯ@tMh*: geuTy, Ҋ)-nL5/A {~oςV_۬MO4O3Mu&#�c.WGո
    dI$"xTp[qc'ׂ
    th*D; \n[Y&�*Tj&(C5F<#F^xѯ$:<grt;rh}0xH"Mȼ	77a7�_&NKh
    (։v@u7խ,�SDJ=69SzEܞ</IЂvEQNmsҋТlo)$	iNDTa&ec~gDwqvBuvCaCpՔ~Ap2r7,n3&ѨS#}oqs3pr>.ȴFK$sֶ0B.]stXQRc7I&!u4�5n|A%z-p;h::+e2Cp!0FݰEj9nEkހ Yn^`7{wDp|Kn/i'1!5,ԾߠR!$x2g)%:LFg$:dӔtgۯ`fmzu\Qv݂ j2At<B%7+}2nrLn97,?k=7Vty\%p#!'2^}eu� 7^2'ma3%sk:!..�?%kR>R	+"7=472nב!	d|d߇�€È#[ܮzs܂ܹ%P׍@7$`.�#\#Z!]#"HHr{o[M{˓֖Ls
    �|r2�PrShk�MP#"EnmzV7o[j6nvdpq_+E#In0�#"sCn˪oڛjYڴ/38u"o=$)nP.'cO_J]bfش6Vۭ6S\|9RJ%0"c)�s }Myy]�өTD/GK馃qЅ,mzuɭsԁHڐVMҖ7]LY27XU=W$+ZܒRb.lCn˺ UUͨŰe\RclR�M/\ua,L_�r;	ڬ)p)9<^цt{l6ܔ7՞-ʗ۪\YMW_ԩ7ѾҶOY~w3ڤ�(r̂`_:]d
    f
    ܐN7e
    tssc;Udr=Tl	o/ReMm]P#g6/ 7~wFmKr@zmԺQz_$z0wI3C
    =x
    mvw0;K|P9K磍4E<_V/!-o
    74=""$Xg̨bA"W O7|`3=ZhWW{>H\b?7@2<-æ%تQE;Vj|hYfpv7Ә(Fo"WiUe/1CdMic3xǰ`pU>P	Ͱ.Rr|!RWU`ZhBn՘֌:({L	ǛOǑo2	ǘJOk~BꊸCCu]<EV0*ێ͐j6ԼllhC&H2D:RLzzXӚ1w	մG{r+M?Y7sq#>LN*P^Tx^, X!@=^.b4\9c-hTӦiMllhCF+%h9CNn1tqpMs''vuoHTջwCpkbJYBbKC7<vG`7r| o9@G	jA36:|DC>'(nִ7pMs''zEȖbVඏqlKg2Ⴉčͱ
    n=-
    ܂fXGrx	TJgLq35sqMs''_bQ_{q*h2&~/jR8-9Vv@(%ܯ.l^.E&ۮ&-hF1bPƆFN=dRƒpg(n;453qMs''EV-ȜUFN0P%A�0Xb]78}{ي;(n܂fXG>*ֆFN=dR
    NL1k=3%
    4uݲL}</c;ԅ2)КfKL!l˦{haִ̯	i{Rm\:78
    m]#]V]vss;OҼl|;nK+qSض�=qZܶG]}[_V]\S\U~M}<~;66jDLiԧ/%^jVP9yqG9Erk?rnWlɃUpogX ft1^;@Yspk"y-n~W;~l9pyon6)nb$DIȲP%;9?](nV},<7=tjxz_]"Y
    8wV>-v;s齭u؈jRIв0*
    #wj4L'(_z:ƀLY⦇]3+re/iYΝ!wmxv&6qH	YEXNZ<OQ b\j%AW:lyPjx
    O:aw@uxv稡zΘ/p@,u<0+wI9&ϓX-!T"j*$&+rQkr0˻uরv�J({jJ@GDԬe_#^6ܸ8㶶urMu(}9|2nR1ngqӤ?$z|~0H}_Ԫwhb(dIXuD*Fa0r<9mu"J`
    Պ
    gD8iW3jeƸf|eqA
    YnvG0BRBNb/FV�s,n3򏲾X/Getn?/W&, ;w2Nq{w6EK[~dرŦjIХC�KM@Σez.p@ɵ59BU@	n-'N/^w?3TXE^]zGbuy*3_qInSo$"7S*cn͑aి'aܖ1U$KEaʸxʾt[Kp7x#nLT"ֳ2EH306
    ǩ6f݌"n	8-vyjek?~M"7ݍy+ޔ6Fu :(.HFmm͞mνiR^R݄D 	7<�gm,9JSQŝm[*HNpsZIzGQ~zzPAu"P\[Y
    X�Gښ33Fܞ^D 7l}
    iz
    |#m :(.HFͭFı7nϭ4 :(.HF
    c=c
    qk7QAaN+?HͭLA[䭂7/[m78zɕlm(ŃɞypHYp;|psMn?
    ޔ:7
    n7[ު:I\rȿ?п|Գ|7P:~GnT=VZ\%,uvpL\On~VB~rK8"W4ƍyk;u{7Λ~.zf$ȿ,M+tBlIqPwn77E?G!,<۷p	,ľ1+&wg?3isEYɌM܀o"(L7>YdfrQhqvkM96±.P<8\?Ðt%36rI+&;.Y\-s"r	jUlec.+avq,x28`u%76rCNU[f>rS,Ceo-0&ܲ5EͻNLR0y$o4B]u%766r?~tl3e#3(Mv4?E6Ƒ`8ݚ̟yA[ؤܾT@np2XnRfKƎ
    a"r[sۼkta5}rHŒ1PM\62]nZb~nxY)|T:p'<Ylf9:c)t]6Yc){[h;E7^ۇ-!]dojV[76rl`X)ڜ~clvu9ǸZ龱I[M?O+r"q9㱽^:#y 
    ,z=^	"Q&M>mׇK#nnLC/sazdq]n@$B8EhBgP,Bi?9:z=߿QYԇ<ȗo:I>\BT$
    `/r"qH'Ax"^v~Lsd*F12dQ^C*|-]˰E~}~قԿƙaQn@$�_̌4|Mp0:!XC7ORbT7NɩYԇ]a4LrEp 
    k; mD8EÓO	F'�{n{)SQx#mW.neUA/-E"N*0(7 H|Mp0:!\
    r6mSQx+< ͏Qxݢ_`&^�JA	yQO>&tB dr[%i5a›\,kҾZ[pb(m-(r[�JA	yQO>&tB @nn<ӎE07ꇽ"dQ^C(|J9T^x]+6V 
    x94�pAlG9m-@5^#XA}t'~˭Ę45?@*M.ѣ>dJ[6	{",҂R 7Ʈs?]n>A8\ExAn6#\\zܺ܀8lA8Np?=	","O1
    <pBTmt‘#s4Y
    1-೵r{Ex7q'Ф`}idPj>,Uaz$82GC*'ִ(Wr 7GlSn8p!*8\&msLHPj>,Uaz$822u`Z!gk2aNpePp\'mSLHNsUܜH8: %0E.78L*7q8A!Jp|ݧk\vثX; fMK`r]nxo 7&WG\߷Ed#Qj>,UƠ,Rpd&St?MAnJ2eTG\7Ex1@Z5RajE?[Xn͘p|HocrÒ?\j8"xE4Ex	p
    aTj94-&wDK.8g4Eq5$ɍn+ErI0ˮ!ijƑܐ[Xi-!MJz?$/lgɺi
    [L!v
    `K]=wbuZ1u
    Rn0M)Wy垻/-.Rgr}.7~]n,?wr3P;_,>X-ɋG'GqK4-DKm|9Xn3vWtdFR
    &DPrbpK[
    V'&uV	.n$ss#f+ȡ*_@nEbII!4ģK[�lqGq-,1n!|rqm|9Xn3v*:s7P5e(~In-)`r"Y!"l/i`5y.�Y"ea)7"7F;t¯-,M삤[r:N�Y?;E*
    2jz[)DnC	,pnqGq-,)‘#	6bG/R%WG~In~|@!'H
    r;faE! 768I6Jdn!r)7,7F̈;]pARr.D.ʋ[Qs'<X@XG:[fL
    <eTr~sF\/ε--w[ڎhiώ�5\ABG._9~]nvţRE?qs
    FQdgV/t
    .7,b'QUt>$zv3ܠ.7�3rWO@~@nlt+],x$;-UbnϽR&Y?M Oxaʰ|o1�C(-3r@'K'^5fu*1gx^)¼PXJ;fF�f`e-[�7b–\)/d:x|NKv#?Ry °\78"]nO�@[ʀE+эs&�(wGDR%Y+;,AotX[�zeЅMm :4E.q+x$w%ܔy xX]n�d)@~X+¢)RNܝdwĜ%ܔy x'YKcMa[](Or+
    xх|Ű*G,;rS4TIvFrSe.ACXw.xq1P Nܝd$)l..r:vti]+U홗λG6W܄<ԸKyGoN_bՀ嶼
    .!0G\0@d.7|kDFmL豦HbrF#
    w%]: H19q$0Єexit~,wܠ~n
    ܐ
    ܐ
    !7[X
    GǼG䜱8ᛰS7gZŽpMB
    bfZ?X_t~RusT c}хKwoybcwE9kN4ݺXu5.T?i@~ɾkbs(�OvQBj2uq0`SHqΠ$vxUz�}:L~#ڱ9eVFDː$
    JU`OQA9
    1lJV/Ʒ9Ce�e֭賢"@[T'MPH1[S(&Uhy9mvpD`Ri/c~=I	e™Ќ	ij(rx$
    ~bdR4LefyT&(Ip4A>~Uf]c(pұCW#Eۛ!_@+pAR=JopbUIkE+H ޱD%
    sh@y^Ta7n?b}ԭMcSqX ]79c(EI1hi
    HM"8#hE?n]*V`s ulދ|Gck
    0,0:Frat}d0~/*jAkXRz)=EО
    hc3VU:n1V[xwn)sŎ&9r[*z_?'ߋ��P�)q�Pc<+x@돺uE�tcqX?u%p^b._0Ht(861V0[G	 c}uƴfIՍiֈ薟d/Tݘ^<Ҷ&M�A f4n=HDǯ6vsQ17iWJP1&oD��0L1a1\$Jֹ)r!7rCn 7@n
    ܰ�� B�9S*v!Tc[h����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/mac-install-0-dmg-contents.png������������������������������0000644�0000000�0000000�00000046044�11773544727�023517� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������.B��PLTE 4 !6	!;> 
    .//Wj!R6l<>@(O.C'5V'By>@B'JyX	[�XR,](*Z<&j
    gx�tq;f)&g:"r-/r.0v<$68WE6In1|CvJ)rd	HIIZ]aJn@[hXYfhaOAcSGd\V~^E{WXqkSmnn�1�7(<1KV-T"\8c.iOOe.V)W9v8gJ^RqKvernk@]B{IuW4b>g;T~sKxssF}K9<UZwmoON\swo} 0001
    ()HR.vl2LX&s<HJ\CDFWKWXnO{dxxxgxuTVwBst')01A3T?@<aW�e	p1|GqrPRpp3]oRdJnNtWkjuěɂ;׭ܵ,9/ЊWՔdͮVբwLcPv ,4c}Fh[gΑЍ糺ġ۫ю̶ˣӑԯǷﯩȓЮÑѱP��HIDATx^� A_!6A9:#P,eYۈ8DC;ddA!xj!jf`/Etޱf(YCw\'C,Bt?/D 0ܧP,hGڕ+A
    qڳ9q=j4X/Yz['<�1x!n)Vgx}=ke8~wq$k"2�DWURٵ}Ooa.gO٘BfK*x%c+Z?ErpWiAS='OO|v5v???Y}ׇAX"
    M~P9𝃏HI�7�R_Fy~wVoq6<{,j&ANi:']"K+-%dR?g1Ù$D0EX+Y\=HKGRc{vFp|n{*~DG$&<
    =M۔4(\ b]f&\R}d!(0wrr~[ojpXj,^iЉ"QmS(-$%B(E7򼍓r!FlwpFLlgyݫW>`Re대Fb/PHOŏR�B'gR�h>=/NM~΃ߡԿFCK-#3>D Rؑmv(E1{
    3
    ]:cÃ-~A/ܯldR^w$*f<ڼ?nPsB7t\�xH]Z."%C$샐!xMC*d1;ig)3x2R|=*/[Ի5nKhTLG)7zʽއيD$w(TYpEqvx>_,,[7M+,nx%L�FZG-@mnif%낇ixn2z,-Sug
    XM%f`7\<M�>E\e
    h+_	`0cgg|
    4x8x~K6�PDY?]BH Ao\#3o0=F<ح{A �YqY^=
    I6RҐgYB }"~mLS>\|zg:Z<xGgT.?||~gW9UQJM)xOqx�	Z"P)<'E})Zć7��oCʭw|
    9Bze,x5`eJ0ްli 4xI1HeN\!xkDбF2Kf&3x|^G"+("}ogjkkIrb,бq}vڨoiĢss೸;F}
    ow(xG^>11lQ�Ńi]MwO/ۂ">PZ<x;W;/!sخ]	l
    _|A-J\U+S5h9ÞHp[%|/be?u3x3J)~+Mw"blmY93<[pf=yy<SǾyY,I<~Q?FK66WS;},IBc$k7 %f#
    0
    ~}7Y{|e26Lo
    ^�aP"'xwn!=s!x=5\w};_/GWǏ4 wp]R
    <.;@86/4/=
    @!ww_l9..'iQi%'S &><DeDЅ3;:^c3s\xs;p@����h
    !26ٻcݶa �,|a37X@
    Icpek/\zd, 1ĐoX0%
    7|a	1ӳa$ic=z
    �/	x㭀<ɻGLKa%op	eQ2Y=eRT�ZYU@Q@5P)烏EQh>𒀇)Hp[^eJכQ
    \
    |_sJVu��AUHK)7UUxZw$>*U-Q;<H,ypn[E
    +sm{�+\!xI;S|t.T8liF._rRW^k#xU%ZWӻ<]Lq�
    nOU#𩼽iQ!TcӍ=lfn\`VS<Ѝ kc/O)b.gf3KǿA?~竎|f<SZ0|C	xpxq=3KO!h=3X>z"`8Ub`:X	g,iMJS0!1gxցAϼgmY/2izb	zfakmW9T~~ԓ=g*[̚!._-x&,=}wX$/'xb47CWBCL|>m<içI"wL÷7%ěuY@K`lu?
    <A%nZH07З6L$F:6h3M4lin$ٝ>̊
    3hX
    fS]KV%y4MWWwLa~.5%]z{{VH=!5<A!oC0
    9E}O}+x <%x&Ϲ3@;xM3=N;߱}qH89YلȞ:#iycz=!n/	<fIn=sNEA?gg85]OC!To:6^}l=jWHF	!	A)ó҅pN(S>y?Ž׳OZϮx%$w;<axX0F
    ޾^Twܹ
    "|%	LP&%㊉K()\QI`pA!z	xBZwhJ_	vX13*"uk1Mه%*xw]<Q bJʩ
    (0J(\	J�G)N:ɭ}Ξsоѳ>=L4k~H+C2[~hԣޱlǾ*D4 1tX@r"Џ 5($xm4v|cL _XPȡ^jRU
    בALLy1ɭ}6s>uoH&5Ў{ddrN<ῸR/
    !c<yf=
    =yc,i6@I~S w86po;*mm 0b	xd'9!Նaw&Cd?�AE$tGJ
    t]!FEmJ'[7'<&k5�	c^ ,@A5`LO&%T.S>&x ]Iy<*rM񽳷
    �|87xJDH`S�(}AA9aDJ	p.E=9k7gt*1y,hxS|-SU#C&)΅`J*@I'*tOk׉'+eu9fpv(1%e*xY>?zZ)T4c6
    |>{fw0C!<BUabGH;kaUO8}%b|)%!t$8(G1D=C{ 
    Z3uE8_QW$p;3E9',*5pd�FR΄T30\x
    qmwcC;|:|t1x$NNߞWb']QAk\K.dpjCB0O1!h2fyN4w|f!x|mEn,FصnX3tcR}B<JT,@K`!ȊJA	#k'\s0+7X%13|0'+?K	H),Tky)>-d;^ߜnFe.g=mޏc^)oZ.WiF{l;8P@hOI�O웮޲ڳ-O,>CoZ|8'L1HJL)vxLb#^_ݞ^NZI)7A)W{?kÅ3"֡#K
    8T?	>	^ʀjz҉e$lC;;;&x|no=EM�|ρLJJcA%o\@Ϳ"xׂ&>�
    g/b(
    u !>&x
    q-&LdP	mcP{:ky4^Dzd	OuJyNi\Ḯ+4x!<i83<i8+KJ9c"Jť)>OBx}>۠<"gkY
    %yW_zxo'3}]jܗ;֛~l{xX\oĒ&%UNdS>?7+(<oү}�}EkwG6߭7h">!x<۶M}IJpp9h9`TbSv>GfS>OD=2֞	^kOM,�_f~AJ仗<~:ùףd4/7xpyϓh_ߜM_2;?.HN~qIO6<E3ן<zO
    &&4y
    4qArǘъ'y2~r*zV_^fGxL-kIj?x2)rj_nW[jbh׌᭘|m>�P,O<E>|7W`A4&�9<'g3z--~G(s/~4Z�ES>i
    2;ɧ"zCܫ79>Ko b =Ei>r5K?x
    5AXK('ܝkWUr9D`Ku;ȱ
    EH{"BA=bMJ%40A_RCڅ@`.m}̥om$WBa~Ho8$MQ /K=Or>T6^|/|hA2ČF+@FmXtmQ_ZCLdQ#aeyyf\d"A>k)vϪVNv^퇟ϕbӆg-Z1�MdL"֠sL`EyjyfIޗ/lKݐMR.?jhlZ$%GQ~xAi QC"u*|HHDFքV!y�JjgAih$
    3+(~xۇj[N7>y$?Ӛ7'`?|DŽ?,+S3?y!5yG5>/H3a/Z[mO9>لqo0_g"*3?*4>5#K	OeqOݬ=s'M.`&&45$lQƫ42a!r
    EO-OOo
    Ɍӿֻ]xHl[
    v{nwDL(NUAf|8H.X?b:+qbA0i!@63,YyJS3O{]%RʇRؾ[;;I?~y	y.`ՍtEBpOku
    �hQ@(Y ;J22 !
    mHiE2aeyyO/3~+c|1,T&U)?&7;yJp鎺r*	�fRHZ"2DtkUI0l/by=5>gB{otSn޸?j]Ī9KNU2+Ul~d5%Z2YGJ.`gy0jd&F3h~+S3Uh|O.o}Ηw$qyBﵟt-ʒ]*߾֦߸ᣫVR5gc
    fW
    /Zh4̿]fqfJ}Yuo/`=$iJ3~#aMy{?o
    K {:၉3!)_i?|@vNLr%h<5>kn=Xn2E}uϪoV1*
    &`-XM+Қ"eH![F`j$Cɲ)5:̟
    n&]@~SGՕ%9bd`&BGi ?ADGY4�2u
    )mXGzeOxa/>\F@ޗm!X~`Dz #P$PZ[VHE>d5ȢtFl_ПZWKȊ\d|g~D>GٻƍD<vjRؤWq*ʠưU 06$mXsj80q!6̼ӌbY6Bbg<+~i7`M&.|=]ҁ=tIvʬ}BGAxGQ3d#vN~}_2~oO}Vb>a8W
    p%J�՘›jAci LA
    m ,;1:m"ʐ<'ٍC5ꡅwEk
    Huj>p*Q<4ͩ=L}9ܧ-5M;լ!on3a]	�Rk
    0vN+҈4UY>S+֘RAuBȅfJ	5=osW23ٷeW9.()xFſ#J<JH
    5P4X 5RVBaB	ұ<
    4mzɵi:>SB*kǀvvOhqN$azcy3v٘&=76{&u.s8Q+[5glxIdZDQqJ5twǹ!#Z81[6+Y_nnfl:;_t*$e
    ?HD^$~QΟJȓ()*)|ׄqWq)o؊Ui
    .Vxc|_fL>ex$wZ	4Xߕ8eECMN2JWv;-@>^X5\*D
    M	Q5L:=CHf}k;ys-7WC
    DɢExv2t,x(Rn*BivOvwBU:ژBnTdn{w( %G|w?pÏ2Pk]B_m;2Mλ[Vg`RJP_)?Z|LӔ.4T)2y}8WIԪay?%c>D'HQC_4R3cy6>2Zwgq>/<C0.}~_pl(z/t
    q,P	8z%bQ$B
    s#.2!Ol/?uz;q-,J�t/</keuS(-)JK
    ~B!^/BgiSCO!Nz=s֏LpJ/#ƘQjCx8ɱZx9|h
    O+Xn}xֺ<3(p�&ѫ.Q[Y}Y6ݷX> ~߷8nYM0uYgb
    rlȲz.rwϪ@%>2&U/AEǿS.`aBĂ:ɇ3[Ƞ'9yg#<h&WW"w:s(|PI_'q|"adyAԿt[LQ"aΆ@$`9yg%)Ox*
    YX"-
    ?ijx}x#Oy$0q!B18#mYxo	݉w·DY|icBƣ3{F^(m&4dYww/1v5�x|Ɲqp8<}]L x!>u>a+\ `Xhi2yy/hoWA1λ41M9ݪvϵL.3|f~ktXߟY{O
    |>?e3^G!)8Y/4q{bYi$}KC8Ǐ'~.i9F*j-a:Y/'
    ~ٜ
    cz^:j|>?Y3xΏUcwywB܇ !d콏/0)52xQK($\@VE2@HgW8i=,#g;ڣOOO{91!3<A ^_�18d !pp8H<zY|gGwG殍~WZA tcAO	:@dV<`sQ]31oΎG0..
    _,*h-5ٝ>?ߤ]z?1?AOu9(/]g%f=w'~y;Sxʏ	?qq=O7=BC|͢wB'\/bAԕ.<Ss[Oڟ4^jJZn++tiRشzө=�CR"x cv҈Ď8F#LjCsye2b3|݇&vKc]]Z'lj.
    1D`)%l)uF,}h(Ȋ΅�<t}`Ce^Z&q/
    ~o4Q[v:uN<8#i"@>KP>@F) 31Xfُ}W(KVrY,׍]*ڦu}SL<<\(h-?Kכ'OՃZ8;kz׶iU]v
    ~y?|<BZ˘\L|WݾFwKv-~>'z'L>xGWLa}4w[%RKM+44f-}$8BG̈g1x,&H<s>Pm>YYk.ͪ*
    ^Xےyb8fROumn"_~3xj:eʃo<QW/QגDS(JW�92;D�	P|1߬Ns,
    avH XACJĴ~~-Z.}xif$Rx)dzz8Ik2@}x�s%!#x6Q~d)
    I^o,C}x4qY<gzywFeᢉ,C}fၳ)2eOzA6YYd`x=cy9rY?B[tc x=#cMeH)K+M)
    `Xh$d3_�dt{^W˶m)?<hn%g43o(
    `{U<_ԯ1gҖg0{gjSTU>tiʍ%[ gϼpAV޽RjЇ/iF�vv3/g@�^֌	-;ѯD*,XM[l|26;#WC^?8а&{r	1$Hؓ?KAwxtNԺ5=YfQF;U_>)ij4>3>[[—ѧU"HsϺ)S(J){נ=H4ߏW0_`e^$V{}Ν;o"qm�k1g+p5=t�PR2/]+j'k;pfm)/@q8CTËD2?'ևƌ4K#]/LEËD:lOȞk3<Ht;+ks"NH$o-42Z 7DG
    ҈Ǘם`\g:YޘjwV[];1ǟ||_oc_ ߶L
    td:�T|GjoT}zQ)]s;�רGo!CB>a/Ze<u+-)&	r=64#DqQzB!!qiiDO5a
    MUi'�>^4(G{q{>eӠbꠥUդxEg<*y?#(wx&U�#:4e訖+'jio0
    CӧlZuGr
    \u%[o@o"Rd~mThl4x*r\W::}�<yPm^fi4[7}x*F@nZٔfxryUgS%
    =xZtAms'l8>^'N讑㩀;~#]K=)*y?ᑁ�3�MU |'~Jd:>F4&#$S (㉀GK$@hw;hWPB.Nhԕ._e/ZU^rSEW쥹J)/$d+[V~M	Y5纩sX5j{o|тUg!NVfT?9C{[*)o6ËdZ
    Wx[&=UR&nl,ϓ#	�&_ZdI.1je%룝	&뾇MÛWImϝݘy2?yxѾM*6(_$lk#v8p>yxh[9ߑ]um~PM,ËD�1K	Ii9sӕ-Ëᡋ!l6ƴ7)h<H$"ËD2/<H$""ш/nS�ܠË?ݐËW?bF$7?^=]<*f꭪VG6/_͏X3�_wf*K	|xjœ]
    38#g
    fut|M�MgK@Z5>yx�zzrzB~P,jdbKSA'8_ReTj5Z{x�.~^9T]^ɲ)DvLË7	٣I("HWE)!Yq{f;Ëu"޷fHFCG/WCn0�zo,|§'ؿ{FFhl"VU@5k+*qu<";K#+o}3v3^:jru,U<H]GG	͐}vanz84�!uoE@'a|ϋO{؃Xw餟3F4`݀w0x²ezeDd\Y=CG/g*3rn99Q?q+9bYd6C޹s[$OQs26,Ƒɟ-b^KRH
    s2=\]A|NoZж1]
    5Z|N_?ש5x&9|U<(Qd=#iw_^b.$̥;Y|z豋3<$8Ƿ~MQ5]㲘զkxK߉#^|_<Iɓ'6⋪rq~xr'E]^ki:W߁O|O{4)7~ti
    +Ȇ,>o³O?МëQ_UsxD03ߎϞ{xu
    j_k,>?%ëkM]^o5
    P?^0> 9jZ{PH<Q�oG?~z5*!)2(( !^|_Ef� �"�I�>bDB1^ɢ>zA'@dQ�
    (hŘsZ
    ;ìți>d{mU7/~^F)pCꬑD[⎰ވY|]wvi$SD
    AA�a-gߦ|C!Ã�Q`�dhAC: $T7H!R×w~71c6XDz1"f453t4g2u=b-\4|�͆%>g?8S*=|?jDŃ%>O&,ƻwcŲn:~3mn1@k{xX3xzpE9|4khjT\4uUVX	E"M*i(HD8�T d&PvЫxL!a
    mUtѬ@\P5p	9)B]?-wCq:/|Ϡȥ#&U)3άh-8j5INU:xi/j]�h>@E܎%B@�e*qmPVR~/ρeR\ba6;,Cqzxm
    O]雄_
    ׏ӰUq
    oQc=ūj3xMsTŬhVg^)y
    ,>Y-fS6[|֭҇03WN9`Q]T/D?@|@S�ā1�
    &/[>G~h3xIL �`o*>m3 YnV=12#ȕț�|pH^kd=|7g[.gÿ,>?z(Pgӱgz};O;?g;\lz6|ٽO]>;5gMmFD4.l&̲XHgp3.pށ:@H(HB!*
    @eT1dXɇ dD()60_jSb޴ij(B8+m-_ZO!qjUQ	j�$&i@}	f�e3mN4ŭ%Z㬡<:yyZM4q`DS1	
    KjO.C}+6lfEEWaa?{M<pg"|y4w^8a=|bk[{{.O.Jhۣh۬t/?5oEXrYE\e('{XG1jFUwrh&$GلtԼf?`v}Ⱥa&b@"!
    b0NHiH?eUo7T01&;U0XPL>!^:PRF𣇣*I$ޚ
    FUK_vٔDĄ
    6,B}~woT-Y6.y#zd
    Ʊ2ös1c>!$C&6Pe(
    Q
    hjH{A3Q4oT#1�0T1"G%@A0H*@ߔ]4D%BPo,Z:"ۃ!|N~/[.`b~
    <f2-gW]\|Nzx±UE0jYi9
    Gn^|Nz@FQ-d@1`0+PO�.d\	`fQxk5K/p35N#&SVF2+1yD*3$9yussi}痊o|NodA4zLոcb&Ql~Pǔ!"]r]<j"	
    :CB$L#`l/`}ώ`2xYM3Ѣx~~hNywMf<S%�HHGMOL�
    tP${>o&]\Rקq뼞&,k5NV2ͽ3zmp�|h/R7޺{O':AoV#="Gi$3/-o]do~Ղ_5"LN|d+eg;]h~<-}a]pөLЇܿI/m[bڍÜgҽ/̺5ɉ<Iǣj|>??L[}x}/O?输z
    HlF"IbےLPػJ2lj66%GR~5f.-iDVY6M.iѬɇO>xd|
    b	=Y$_:ѶQRapY˱^.u=Evo'uִųhIX+>\<t5E<!iAWft\ht椓:U<]~mKtf;6Dɻ41?/~
    4VK}?6Mvsi=Ox7,6+a�J^ǠgP3Ȫlk$vvYlW氙~ڂ?) V)*{e={8xqFU#U5Q_
    R+cRSe{NZ"b5B¦�cZbb\~!/F-FO0FX+'&B=0ҒSbեDZb*A+"5)v))1ՂD)tX@V޸TJS[GDݓPq=аu 74asmi /TeԾSIJ~tϢz5ֵwlB8/s9OdX(i;#*S$Ք*q2K)U%Q5dhuFNe|s n98_i5pQ1ZGOU*U52n+;8Ga?Sw
    d	WoUW+cvRjUcjjRUnKZ+uw!D߁MxU!_B|ZOqi9f>cyK5?	�?7s1l24:zz~; !&GU(5cV6bJ0saQ*lZ)G-l(^,kۦ|1ґd*)jdQJ1p$Q"x|~T% |%S%V62E2DT,1qє
    ZV&7_�oUOJqןwo|Y{_wZ?|7)7
    9x}vC<{kg/kjYwV|>)aky3x-ED{Ȫ߽qƧ>f�
    #
    =]y
    '�F;iosޡLx|O9 !m+"~_Nk?�ap3k`ʘf_$xuU߆i$"<-4=
    x
    އW?37y3r%=iB_1{7`9�qW>G@<|9ψ9�#B}70z5"Lꕁx5:kH=vZߞ
    [kYxwZe@_	x@D
    {C\
    xЧ�;<�;$U}x8_<� F`UNkkK!~WxV#AUKNex5n>ec`;~D*Ux<n�h}P}z1ĔsDfGdXutP;zZ5D/=1UR[wZ fMpzțmX˵1j0h3|[8BU;4rgǚ\4m2Eq:1lmL}!<ҐF@DRQ
    @<k;N+ڲQ|z
    Wy.pg:^-Pxp~y,s~�gzfG/@
    6vV%)�r<.Q}4}zps}ko\2 &�!�_H|,=j jz>ߩzk(w=iߥxs~[߇xxZ|8xx>R.|,h6q2Mk|Wf|s^uJ?;Q���0;?o7C"t10-y-BK!q7
    Tcx/pwYe,B'QCh8�w<B?*W{E4asyx&w܆yI
    4/?b%.3+cH*YNL'5]0,jA*=I\oЛ31
    uI{3kd4΀>;$)T^x{vuP"y9$k,L2Sl2o<XsOǺvc޴鰐@ݽ)碏}f ?к)|%h<Y/Rd
    y'+/cXfsENbMSnT	+I
    4#wLw])?;)Wqf]C˷
    {Cc|d-ydc&k1Sގ1Ivs#
    ߡ>F7*>«kUuY!ȗ] ;v�!
    �:·Wx�ـPVjN)<PK80two~?<J`d�	"ŁMP*i8˛geFm2S/D\ʔaۙ!9E>bWè;xǣMA݅oclÚj5[0aKv��)†*r6WFQ'/UVa����IENDB`��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/win-interactive-shell.png�����������������������������������0000644�0000000�0000000�00000013506�11773544727�022770� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������*��PLTE����}w��qod��������$�"
    ,�"�*�,
    1;��� �,�(�7?�<�61�=1�:
    DEHKA�BDC	J@
    GL
    I�R�ZTOT�HP
    Y�S�Z�[R^]^\Y�aehlilssw(V(^0\#\(_(b$d#j(d,i'v4g2l9n5t4z;s<}nvBuDzJ|P~KSY]facfflegfhjhryi~|||}&5*03D(K0*�;/�6=��;AECF$F"I#L*L(R.S4T1CKPL#N)T(U2Z5\;b<a4_@cCfHhCiLnRqUrYqVuZx^|bjr{րΒՅ␯Զڪ#�T�LKz#�T�J�Y1+1�XMr�=c�E�D�Kjj�Eb�1=M��IDATx^	1DQ_
    3X{X
    gsc>T/\	LD4?׳	u"f
    cNUW)PR8׳PUY#"_v@ (A"AVr{"+�6Aq�H [\:a6Uq^TW>.=''}IJu Cax,rL+HH:HVAu#Psy0+"!sIJ"L!ى9 NIuG>.=ym8>Am(/Gm$ҕ!.^vADԃ60lOҋ"C<sy5-
    C?<͡Ԧyݗ5*Ҟm$WuUrBN]XOtyhfwLv:#;) @D׮LjUQ9s:Lo^Oi-μys6,t=4 aW*]TUN(r=isw+-ΔzsCq_N(3V: "L,1"'Bn
    :=oX粉RWj@H~.CI$VZWXte{ntO+5U
    >�!7?CdMj]ǐc<C\>gv4JQi|PaD,Twxa
    �!<znDPѴZU$KhtLySۚ^J沉u)k?oǭ'~`g̟aL(Uk}_J%Ibz3HJ)1(+dEA]t(@^URSt*Aj6:8E@Z	X.!A|�|\K�4)(K3KշG,)%LMJ`KZaIHt{1JʖvtLk5fK랷N4-]ZXXda۔؎rK3ni֨+wmth=@xt>xR;iVDm06Wk$u'=aIz]YJ鴦,%IuNLC٭�B(DA<T%81d{ύa2zAq$+(n1a4Jb}b
    K _CCMk@WS▻`R9w&	p\&sanRʍ4i*ώEauzRJiT)Aş7&ḫR�_m=`;IJ7\iR\eYWy~zz݅N/Vc΅ZiWVbb�cc<n%
    4�Ai`k/p/c,i*%M^-(һ�ғCԵ47D`CVQE59TkKN*	Z9AEѶiA1lJIQrWRȞ!zYƬEG%{ۏ},CJ<rqMq.%:<My>yu$tp<J[T(HmƠPާHl<y3A:r@ں@�Yo^|\]iblWx�HmYP窯ZJmxYTnrAtX`Lx<-jEGYȯCpX
    EZ;4MǓc)##]1H[pnyTl{vTg`nJ]Ҡ5�lItFH$wMǀ�9n)6FZH'cJ]La!Eiݳdhhp0m:+9oLrdUʨRNݢѤ1vzᾞm:@st5rd?R7,hA#]n?t
    iZ/Fcq2~,BUg,i:MOv`(N0
    Ҏ	`#Iϯ
    NI/3X/%yBO10D_vVܿ<(정0; ?'wO)Bi(UA>ck1ꎦ��+앛t#z,']`2QT)`+SJPH,eT|dw)]X,@95pT%7~KJF\dX<	v
    >Y;1�bYpg�O)2P*)V4%TqJ})F)UliNJC))%-y^J],|9=U( ؘY[
    ZZŎ;<hќ6_z`(X(,>(FQ(B]:�(*N#6jѐfxgyܥ0'3ح`1vl_@oQk4$9::;Lv;N:h<p,JىP^�R難t4FCh(ഠIP=j�[hshޕX.H*B
    SQ`ЋңҵA_fxDZ&c~d
    m"{88aGZ$:ʾWo!#sP
    c4ڞGº_K^OWz=KKf`Eic4lqOUj^(8!Sz|UE6<k#iJ)4V	Rkr,VPEq\<hO!84<*(9AGǁ�4~Vu<LGirR�(>KW`契](_=qS9^y|SJ9TqRהSJR/BE)eŸ(DTq|O)T.@O)uRPS{S
    $;a&ʼn4lxl4:*Jc?km;hh(O	)5/)_d۵U`ϟ=nQ]C)| J
    JD|BQ:J?^َP뛤t4^:Kx)Uy'[j4x}!4/okxh4?{KG㥣xh4^F㥣R�KCzhhu3}F,.pձO^{=<EyJBJy`abs*lq\'}(o	@^_t]�(y>Q2}>K}z-
    ^Ƶ"Y*X!u(Ւq)
    r4_[+E)sW/ͤ"u	k)@>-S*/<QRחD9	~ғҏzJ7(!HR׷S|7^z	RxD*uRp%RA䥐@o#V}~f6$@<<D}tT?Vըpޜ^\QK
    J'ܺpJ^ZR_1PQSOnAp	Vsbs	pN.~2
    Xi}KҲ?R+EKh4V}+EKi۴Rt#E+EK7sjh)o|RJRRZ
    Z
    Zh)h)h)Zh)h)h)Z
    Z
    ZMg3h)h)Z
    Z
    ZRR---EKAKRRR'ブh)h)h)Z
    Z	--EKAKAKqAKRR---Mh)h)Z
    Z
    Zh)h)h)Z
    Z
    ZRR---EKAKRRR43h)h)Z
    Z
    Zh)h)hiBKAKRRR---EKAKAKZ
    Zh)h)Z
    Z
    Z{|pZRR---EKAKRRR4h)h)h)h)Z
    Z	--EKAKAKRRR---EKAKAKZ
    Zh)h)Z
    Z
    Z&---EKAKAKRR---Mh)h)Z
    Z
    Zh)h)h)Z
    Z
    ZRR---EKAKRRR4h)h)h)Z
    Z
    Zh)h)hiBKAKRRR--EKAKAKRR҄h)h)h)Z
    Z	--EKAKAKRRR---EKAKAKZ
    Zh)h)Z
    Z
    Zh}hi---EKAKRRR4h)h)h)Z
    Z
    Zh)h)hiBKAKRRR--EKAKAKRR҄h)h)h)Z
    Z	--EKAKAKRRR--큖h)h)h)Z
    ZhAKAKRRR--EKAKAKRRR-=-͕h)h)Z
    Z
    Z&---EKAK=>AKRRR4h)h)h)Z
    Z
    Z	--EKAKAKRRR---EKAKAKZ
    Z{|ph)hi---EKAKAKRR-2h)h)Z
    Z
    Z[)V:ҘW>JJJRRth^)Ztx=-#^)^O^O›]:��h=5`B߹
    %	(_#_"Zė{v0DAp$u>>k%#Kyl;rd	u5c*Q6cRJAʩgޕTJAW2;_)TCssU+c/UWL=WTjUG+柞@\r*6t|5}=TP)bQ��a(ƁQfWd11Zc%u�$�N;pL��@R+
    Zi@x�E����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/win-install-4-copying.png�����������������������������������0000644�0000000�0000000�00000011315�11773544727�022617� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������|��PLTE���333�}�<tM~A.)F+6[$*P<-dD<vV4___hhh{zz���������$�"
    ,�"�*�-
    1	:��� �,�(�7�=	?�61�=1�:	@'M%W�BAC	J�@L�R�ZT�H�T�Y�[R�aj3fnvM}.1ADMPxz��3�33fh{ffifflfhi~|}f̙f&16:*03D(K0*�;/�6=;AECF$F"I#L*L(R.S4T1CKPL#N)T(U2Z5\;b<a4_@cCfHhCiLnRqUrYqVuZx^|bjr{fրΒՉ䍳▶蛽Զڪ琫̦̙Ǻ�T�T�LKz##K1�Y�E+1�=rM�XDd�c�K�E�1jj=Q��IDATx^0DQ_%2H*'Nj
    yRXNGY5@8u͏qќy]mȟ?95Y9W՘YZUσ|٭cb
    opNP9"<r4	WDnsoȖE˚;ɔ"ӯ:7S(cPz.pGњ"%HDsM7<{FS
    hp-ww{Aݛi0\A*Z{ &šHAIZғo\\TT(u½4]ÁsLWge@DJO˶=b?27fp
    T4ƪU%a{Ӵ7jGs<=<4gWg:SUE5iߜ-ǜ[7k9VE(בI:oeYd;')(EE7¯T|˸@D5`/I;x,@(NAt
    C.�(12ΒeD"u#ډ-
    ^|'b ޜ
    it{&Gxf 撦1$
    T*57HnܺU4_<�`Lfް?Isd5)4g}c,	EQ("!TcCcT_&yXoRȆ"9Txp\4E9z?pY~py%�Q<afEع:ך
    uH@e@sl]'tGh�S*\;*3u<9d،G֓?&/TseSJb\cD�1SoHDu|1ˉ2#Y"sQrnD|9:tN⼶Rj1;D=RQH9> c#|[~xܗ;f|rzf4b\))cք(
    tYY,Yt{vmA6ٓ!d1]=w󂛃޹]1md $,Ll
    G`UQh+۴ozD{nʝ.>G6rA1a%V9HVm&zQ^YUfԚ]{x.<k	@f<D^fn;y&(4v͠ 
    C e!ue=xEa1iӂbҲI*@
    ^ElSz =҆y2TYh~0}sogv`GBDpݧcL3 Z-!ӛ-q#܊s)'#FF5+K5	+7{V.99m?ٞ{PyV)"u.?5|+ұց9fbPYFO9#'ocɫ7ȹʱKk熱~9w@i^Kzȩ~ip,2jK1:_֙Z*|KIƕ2&&hϡ*A$[zQZHy98;\*'iqsJW
    buuyyi%.tC׹-'>0#UB@Ryzǹ8_ٺ}.	BRs~ӡ]X?T6붯,fX@_ B2qPC2GM|<Ln&*I(~t6nQ~7"adu` ZtB#4[MSD ɏ?x|~yin榹in榹in|/s}ss47MsMs4OL$)6̃kI\M|ly/kyayR4/7 Nv͑KLofsGPAýk5<Yj>m+	XMoX4i~Iin榹?N榹in榹in榹in暛榹in榹in榹in~w47MsMs47Ms47榹in榹iiny@˹urz+{Y^l6.l3$ųx<cmR\iqsewؼ۱;6i߼_!qFV̖Mw/ga@謷Y�*]e6hX>aQg81BmXc5гaf-/k|ҜMX[d}l_6|,*`=6iߜky.37q6ycs^y
    cO.=w8CslYyd2c>ýCvWĀ7yͭ3{<X:]m*sϝۏs#sV9dǑ!术:*Fɮ0Fg,,=wڼG;Oos;Xv=۱ints͹Xĵ+.+m R("R)n5Q|x4<ܖ]G|榹inQ4Ms47Ms447Msܼf榹in{i=gO3bׯO5뛑4g;[yf]u[9GY+#]/mNm<3Rbknku5y7G_~[ͳoH,9OO.c󔿺{>x=d^5ѻE7pkn榹in榹4'Ms/
    hL!6J`2ƦJϧ"$x�H:n=
    `a`(銌
     9M.\wyt(>isE^GDI[k-QʽwDI[gvGhA� @pP1/CXK3ٷ/{vH�AB�p7o#\_MŜ9sb.b.b.b.b.b.b.b\\\\\\\\̙9s1s1s1s1s1s1s1s1g.
    3s1s1s1s1s1s1s1g>͙9s1s1s1s1s1s1s1s1g.b.b.b.b.b.b.b.n.b.b.b.b.b.b.b|3g.b.b.b.b.b.Ek.b.b.b.b.b._M\̙?��JPMKt(k<#]ۡ�!�E�
    =`gln&s4Gs4Gs4M9?n\Lg|Ů6q�DCDn�ԇkT0vPVGK
    Apd" F)A2ʑ0y~Yu,W)p$l~?	ؼN+)H|$km\$%	;IɜuL2gsyu8DZ9C�c4<(s6[Yfǝtj7UwmA7od ][3�>sh5Z\h6gszV
    Z<T?rW\`md2gs
    v:[\W3̹$y{Lʷy=iy Yq+qܣJSݟ˴ۥDLon͋9*7797]yAU#alrbL|÷w٘Q9ѻQJo6�@FAK8KUt6H"">^5%1s1s1s1s1s1sO;pL�Gf0�;H`E#ֿW
    S9!<
    s����IENDB`�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/mac-install-10-application-folder.png�����������������������0000644�0000000�0000000�00000044504�11773544727�024751� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������X��PLTE%4 #%!;,,-Wj!R&k9:B(O.C'5V'K|>@CX	[�XA>>](*nq#f)&r-/r.068@?AHF;In1iXoN*rd	KKLZ\aJn@\eZJgD|z]adRetRqma^^{WX`^`nkSeffjmqopnnquqnjpoturlwwx�1	,1Uag$X+J2j5sCO.V)W8gUQ\VRwF{a]aYeqrm@]Iu~vW4b>g;T~sKytsF}K=2VVwktT\^maws 0001
    ()L+ni9LX&e4MKrNzvTVuWrt')01A3T?@<aW�e	p1~@qrPRpp{{Ŏ	>[uRdPlWsWkjuɂ;իײ-90śK̞yеR͵qGQq094Qm}JnTt̑ψ颛֮˺ѫՕ״˲ӑȸûﺁǑȴڋ۲IS]��FIDATx^
    �0@~"dU[8HW厤>
    Dq?ᨡA]!L4 u<(j2[E(Mf*Yz=᪒jtM \6idkSBRxM�DLRx@w9߭-UΫVUca4$r6a͍V+x`mAqJbEls	pi`4;Vmm(w^ҹst\ i054iEQ
    m1i!RdDՊXH8C:~w,NJѫdvv??6eA=o=@qlٻr\1hq lt];''Ǿ
    ogw5tu
    Vdo&{Z 
    &6cM&Q&i0ǯ:~c.ma�pu)t;CV:TI@T &4
    "u\$SCiSQ!Y/}/R9zW%yx、ƦbcyZɕ⇏G.(9g2lf2Dv_/tZ{̰LFlL\:x=
    
    uPY]?O:)[EVЩl]M=Lhv83Ղ%1fH\*CI6G\(1~-xx7AbB(u臞
    *='FІόA5zMue|C74{@XrRVUJdIOOt:G&NueK:^hr6b=z=Wέ+Y+QgRM9ON>Тqqq޲n~o_Pj.88Z�z<=AUy
    ;Xz|v&/AOcF#CT>1^>Q&+m3Ҷ̄4fx7 6ލq,Em쌥@Gl뻍k]
    Qṳ+_|ƃ:M	׼FWivwIO8!6'Q`pYݱe&d;~hM϶%Dxl
     FBCԔY¤CjNAL;0	sW#1#!	NB;�Hp	Ij aO |yfF&u-?+q	Qd/BCKB%9zM >-]aXw~	Y
    I2B!fB7`ĪqA C9бnOkk\rp~&4>Ђ;4"h4.M-�ghcd	4,9/=9j[2Gm#蘫5L[ߜk=g.'@sМŜMqM|:A [:\[ev:;]MAc^[Uo4:;巍>hff��W@[[&y_f^-ϵoahA>[=ikvО3E9F)t*CACZh=BC;~
    %af9ΡX]u�]Ϡ)1Gͅ ?;	C-5fՉa=st]Σyf	HKq.>c6&it8Apk)0�EgyCI`DFpjlc%bن$]+}
    B=ԥnM�`[v~u&V
    rhKX u_ڵ"VVIZHC#h/`kxqb2a	ljȺQӡu
    x	th(._f/Bs_wU^Ru
    4ᙴ,f	!~ТdФK/t
    �K'Pdפ:GE4͓̀$s;G
    !h*''HNxݤ�1YwP
    BߦRb)-D2KX&fpo[h7|@0??۠迉):E
    8Wf{n-z]qܻ]31nCv	O>$HZ}Y$̱
    x>etGBt*AtN	:A'hkNм7Ê@2T�e
    P0LNSY
    F@ɼ{PesJaq	:AK-֌!tXGV�=C=:Aj$+z�kQp{�Θ*
    �]x`C{	嵽G'hkϠ-Q
    0oZSZ쪠4@V`=BsG/CO=gA6Bh3
    B^t7+�+\%:ACTN_n:o[m3ơ1{2oA'cs25֠!wQ;d||"k#B+gs�CΌE2ub8t;ގ'm::kA
    1C|$Ã$9pIeKC'{z4.t+QWy3C	
    0wG֎t5M�d4ZP&k(!9�]~,
    Cݣ	-iɀS@<Ā0sƧ,	bʘAMOYYiND56絛nQ~`Fz4BаZep&=tv/-ܼak,h#ʪ]634'wC3
    CВEA%iX3nO{w$hk:
    xZe0C%.ݞ8,y涏E
    3L»RY]Z7@[9`E+ʪP|}zH>Cxh;ѡ8B)%Wa/� tܓ5.Q,e~{?5|<tH[݉@>yp=
    mqwNqpw>=#wTa_ъ6G)(>v>eA@Hp@
    bD1*)]'!rS䦅Xz8=\e'VG㧞i*Ulv
    9a}5M2-RhNm/7DahIVHOݿ9?47dA[':t@[K!fClqM~HXrhB060&7Vv)d@ei	vpuDPܿ2&Yט6nietYS$Dz�(`cU8ƥ(RjGcc|(=^>"vH0H1M%]hQ*@t9/"1*I5ƮFރߐɱ_0�Ǝ(ߓc)fQjeѮa�{A<oKl#톏ZuƔf3-sUR$Dz_ûӁs@?GS:h	31JgTyS4*Ba\e,}W>6e
    shĕC~X(}}0zRw>	qut5+tᐊρ+ha`	N��\7Yz&=*#<8::2EcFDc
    h ryiiIVx>Ў5k=E%`)J�N�Z%-z@?v(qzcABqQ؍$rsї,פJHespy;u۴A�zp�]E\7TE"}.�ˌ*y=,*kJEdY@U.ZqSt2c|Ei1~ſhhD,
    A!"F
    ƦD6bm8#c(17
    掊wtDUw̠I߂LrB!BC]KMr!v.e�MV74gGpdib@@JZ-
    Hc%Osnمusszr7Uqm[VRr.D]Lc肢&PmCj2WH+dz
    ;ry
    nI.듟??(Uy6GFvYZ@"�gx4Ƚn_^^fy|jt<tz$5*)@؟v%5T5ﳮo&n░\9K&R[v>paJ7WFh@IHEEcC ynl.^f޻G&ɒ W_ă54׌d<6ږ.l;,,#
    UbOclMʊ929MLJ_+j|ƉC@he]U@MK~Vk3PJih]|7GJ@BQ5Rycj0trsi
    X+Vk0[C7ITBsWydH1acdZ%GcԐv` (>yZ檽gOH;X_LsxqZ`lt]?W
    x:Iᙢ1*0M)e0Eއ0S^Ic4'>rT+҃&'�:1>^Sd%1">)2(0f31t@ɼ}$9f_D+ܩA}fffQ/{>;(Qbhvxo2P^n!U9Bz~omS,M#TSLX(гYr)DIzVm:>zL89,"1S?,l50Tn709fO!Nٌ }@HL$5hjd'#Ѥh)BKj0̪yf�&׭b;tI@h:5hfoq[z^E҂Z2xjl쓻M7ҬW*}Cʝ 	s{k=ɱ+{0k@:F@S	#H@;TT%P*DMzr`s#9&XsZu0h̒ҿgn^Q@tָt;t_Q??,Xa�ZDs4X@LN\ b},
    @iAœ0|uc0hss7>iUܢg	zpI�8w.C1G}"
    Au
    &F
    aq/I;P
    wk4+9/ky޻ՍK}>qc'modhUZnnhѬ4/ f	?SAoHL_sn[-|st�!Wkk[2hD]`
    L{&\mkXhTAOb4?CfE:}J46€kMl&qйFcXzc66Ϲ!sfv,9f.MODHă=pzv`1r:g4עqm'v2(х5fƫ8C%@CrzDy;Pb]78-	N`#z;hm�\te?r[JY|^b!iO",
    RPhp	Z")]m1
    D䙌Qv"A>fG,b㗻>hX>
    $=Tٔ
    X^G1MUA&NIxjs4fV
    E@˫1JpʐAmr*c[+6p0Y3
    BAٞ a2ХvrүI͞ɑUf"hQ\@+A/Q)@\
    RhWUR^GاW9i;ysgq1�?=~ܢP5v<j,/A]˩r-*/3Bc@nΛG,U~t-F]?tv"e96O�Y",恟kTyK3~nJ˂o[ 3C(g<3DSMG*@<)pGXQj\Pv+5eY@6mm
    @sCA͜eT}ncg~%
    @W�:\[q3g-	z	�'e[UW[Dŷ8~$i,аU
    Г"Xnס#}((ihϯtJZA4%e/-1CW:Z_랔 k
    wXQc"fi#q6CJ@_):Z$'Oqn>2!+Afb@
    &ԎvAzwΖif$VԜ*ЍuA7�z	Gmݶ;	3MsGjXQ`GTC|ɭՒ*7]Yа[~d%i"V^�}|ƾaȽ+,j4!U~.:!ݹaA
    P5zWwA#^
    SF+Q3
    'ET`™-BWcrIzz߀}g<&<Io^]Pn9r_c	fAmh:5KưdSQUx٬:�F:er\zBgG˛k^%t-D#?06[F{@7}ц\F]
    't8n#{:2tP͝4PZ-	H:&ڃ;m@!@O"TBGBֿ;2"@ھ_jf/65E@H9#EPO@#wljv
    .?~"r]p-'Ab5vOd*_o+h8`~ɘB34ҙѮc�'-{
    ɐ)ˆqpߒq;!ܚNqH(z0<
    2AuĜܓisPW[^sm
    2Y>egl(͟3/$n,d=!
    	V)l&|LKý9z9鏫ܝj8Sl{g\B&,,HaGch`9	^ziNa$.-
    &Uxc˲_,O2Xb)?&ghL
    덧M7zm,@3Cwп5Ι|vc\>^]/Dh4MډB&	 F:A+)Fc_1>fR堑:#-[](}(\SJϳ
    <H"Q;1/GFcy-!u6ouq^)K	w5ٚivzRUbе�
    .yyׅ,t.6נ!*^/6]X,-l .ŞGdȭ'yY@L&r+xz64*Mp^oGA4Ty^4
    syk hI@>$9ͮ3NLlkbzX)stxmA{z
    ;ϱn
    CGcc$!C+ȣANA(Pq+�
     tXۃ`|
    q{MÃ}TRk�mg%0ҲNCet${:I2(ӓz_!""tqX f>Kh90i]ZVn֥y!Mh΢m6M8GirQܡrrnKCV^N>;휉Ń6益Fkru$W=><ϒ1e!gRYPV/AG|<F.@GS.SztAg=]6Tگ?
    eQb1c]hh$}wɚ=hqry򳗾]FbyW$# 0XZA[&0A
    1<MF='1]Ϊ.dN֐AW46fT@h<QK;@@![dst^RAhL3V5{݄a#8'h^tvAHw4w6F#_JK
    mgC;`d?iј	Y*z!)9A*[[[&hZ r @
    ŹtY|,r
    MoL%w[##bu!TpڙsD͛YE2?)9\vQ	/ȃ
    h4T&ȓ@1֑5jnrڪШ3٥T
    "5Ӣi,ےqdq�]|r-| <	-ǐC>	arJf0`FFҗx 9D4)4uW쫩:2{a^Oݣ.w[4re8ƣ׻յ@)ŞBZ6T}Jx<[N&".eۗ4)gؿ_7tg&݆ikI&JdsM7G{F&s\[=?`Ɗi"ɛiqfrǽ\#;c|n63C=ۺB#u{
    -M}}to+m矺g2v3CWDrFvQh2&ps7=,$gМtj3e9:5}3CsyfRjhJ['?vqel٬VbhUЖ ֝IZ3f0)14g:8
    d 2}mʕkABCsoZ O4isے͙1{:R9hD~>P}ߘ=xABG ./4gmE{IZT%פ/]9U3c$	LD*Ѵ&mYCOUhgSm9]ԇE;h0π"Nl	//<kjA؂9q/4iS@.�J#4Ccr
    SY<{yZvB{a2AB@J"'hh}bɡ.g{t^~m€]W7Cq-}4M’CwjCRsrCkB@gel3@Q(tN'&9dzB΋jFšYYQIa}q@3g^/*;�Щ<K&*
    ְ֟;D,`9qnxJn֞`dJ>t|q|~৿XQDV�~uSmNmK
    ޑt[h~qwm@yP->QnAm&(߇f	z}}}NyX?\W&j}(+W):Vfh}?[vRwc-ax#rzj'REPBh>x"YvBGh<@tKĘJf	4"6G=d("eY{J4Z	zdoYh7�[B°ʼnI{'}9ahC34C3fh,84CPK|2Mn^ӇC349C.24Cx=\:^*[]Da\]h0wF4
    nq >HlUh}&RŽ[&o֎&hM@ai44C{G'Kѱ.]SUfh.w0$V;qÊTxq_j,24�)2X^&C%>u98rDa-3P}RĪaz	
    M
    ؍IjPP"c@`3
    vWRwfwP[UXHu헋a_49/:“>Iڣ3#=ǁ6Qz
    &穷OG~ݙҡI"h*�thc0ݽߘ¡Qz^aIp7hhR]tД]o~Ѝ4e9y!TX"tD7: KGO	BPT(4>NM	wv-Sv_6V̭p6l%@f|,~Pj8hq
    8c?>v.H7
    إ7VLVBՋ!MJ{G(M8,MMtph=͙Ȝzc;Z)-#Wzj8h@{%CcFM@;g<UWemג=MJЄq҅BSDžn{hYF)B8z(BTC;K$tThv{<=Z,ѓEWq@Wj hkb#t>tn-fw.:FK,а҇ƘRojA7Є.t>0t75&ʆ,Y йr'ڔ+}>x߁ ]лghVp34	=*:Y%�`
    w$5߁6ޕ=f%C0&C#1Z)2eГEhR2Ґ'VT0*$i1Dzzv-Ճ9
    Z&uhQv˟n?3%NנCJo3A<RObW\u:$t"$c{B4,b	_l}jcvi=+V߫|cFaZPeAI'n?t򢮽t7kͭeH#*dq1%bQ-Zw^o?;R+9se!t}s-ι3>H
    9sY	Ҡc:
    FO�X?ɷ!^|zSkG/CO@	�.;et\/B+5JWhׁVqa4v~?=9aל3a_W 1A tA-qۺ~Wr|ޖf2tC'N~Mv0h*AlQ7{lkmc9�3ᔔs3W>HuecS"h"	 a7Ŝj
    
    baYEZ쮔c[JάgBD+7[!.&[ Az/wz=<ߣS?'Ѕ@ς۶I;_Ђ8|cU<W /wh?P)5@/ߣ)SwGI_jA
    퓊<_xlve9bBGklÎ.-*g=9ƾ !	tTAWYǽRr֕cH1r~
    B$^T2X,wZ߄./6Fih̢BqƶQ.[[UPg$4!тJ ,(t3@w@4>GbBf@FQWz1k)x6chEBchJ'c. tH)(j0$kovkw0/̇s_s>H.t}rttzgg;O{q:zde~?KG{hmn7g:-R%t(kPƛ`0D.(
    slh1[4g²,}NJR0\7JvnOͻB7u:XMPFjԛ#c4O"f~z	F3j;^/6٬?�0o97�Z9#3)P@ED&By>;UOݣŒvYBt&t
    /RI[[!6u;pֲށaCۇ/Z4n6qӊ�Z^AE1ص~8Hc_h@Wo 
    �5hAFGB@iZ'9ִ+ch}3 ,^A:_ ׾vhofKxx$eZ'k3]!%}V>3Bu)S^O+u5�(khN))hiOO&}ʼBB#nUkᡍ=i+zǛ4tEx3.*iag3:Кv^Ҿ�cl:Р&F
    O0`&Ov_\Ϳ<C\ˌWwݹFkv6N 9Gw Adhێk،ݎhPflVT4bIɫ`i9IAwt@zBa!hO^y=_xϬƲyEs}_6y>G<7@CfCx]3XvZ<XZΔj3hJ7UCt7�c6x*ZĐhѡ#f\+h0
    :[^pFI4[h)eD1#\p耠4
    }
    :`hY{{{@ 'Кv!h)ƟZ|nRZP!PjeMnޫW?ppf0aJ2Z@yxr2ry^B
    A7q6-8>q+3k%t4IN'M\C/i#nR?4a_Δs
    gд>#um!(
    f�YCH'&�KQWp.9VOtm/LX(bgB(KhH@Fsgs7|`(ؕBTW
    :XBlju\):#"t*-^})IAIx%A}|6
    ?~^(LV.y
    %RW|I)g@)%@Ke|C@{蠐@15dRrB|?[oA3M#N)~t̝q6uc1=սA0CˀfpNllpͰG/[&qs߇&+ni%4;D[W 
    ]%nA:Hmգ4ss_v`ō@�{*0CyǘWA0
    uԂuuˣv8!vڌv4b`Rf/^%1rly6D_}>!ں?-^	Zg&FɡqyNF/^iWVЍ]7QbT+GG
    Csh^Yi=^K</hs>+C:th~6~_ܬ-i)4�І΍͊iQE:ԅ].H�o;$V>8tBB1"t/mB_]:K4N4Mv(>s#M̉	̹~;c
    4h{Et
    Ae[tVKCtLl_	u^1MC_Ն&4\&ip9Bc:FYLNupK9ܣ1mAfߠTjuƾB[yaFi0p|7X#hhO1V&-F4@G)BMk,mVy}nWFB0t@(Qr,1jC{zDM6CD7ޘ3fT+Xvp7@.ؖƨ
    iU[)FR#hc]1tGwZxL[7=�u
    PzhxW\fhp!h%&.gٝпAGB3V_~(oLeKVln^9ny3chR
    >`(vDɠ;c�Znv-*RX\A6ҕQe
    T>\-SiD=:L}kG?B[	\y]}Q@#1t$1/ߩ3v9Au#WcHkczj: d]4@;ckf@khUJe
    ;'c4@w3(s@2yMgh)tGcht5PۺЏm^:v
    hC"oA`
    s=t1qZ; j'I�0>L*tC[OzK}XHd͟F<be[!BRv�`}p	:c-P({Yj@&¸1l;\&HtX59JXfqSwu5"$|Θ@k`0`͠@;P;>Y
    4JЁŋ]	oS[4'|VD3Vk}*H1w+YKdg8d'=M`^~//,ԾT%X\b4.*s(r1ZH69Ė6Gh^zqY3ZhD
    "jDOw>ggLm|zP'KnA|Ж)1@u*Q&C?YsL~6h˹{:3Ж{懶Y.Lim1hA[bl~{h%	{G/A/BlOB*uVB?=KaH)]rhH|
    �<fGE'0'r"tUzwNq+cnS	U4U#Stе{zz_%A�A%	u�	t	1F^:@L&$i<j.2A,}+BL[G<^^?==M%V#"cXݕv,@
    #'He1,SB6MЕheT4uE_9sA(Z7b2m<
    a1Vy&ɳ]-hc݀Kvͮ=0	bTRH[@,N(w/284z"a.IW+ YG<t]+tvlAsغoBڬ}y΃&[D&AVj2CW@w
    JD:Z:DS@kZU	臇4S%+)0>SE}p-?�:@qh*pGM)L߅Ͽjپ$V8͟]Nn͚xxٴH_#
    Ъ멈:GZ70tF!v9bCQFtI?y@yIV2xO@W+"βadB"ҫlD2B{\[w %@@FDH	eLF<OeV7I&/j Dǔp 藾N&|=O84*@iǏ!&_._
    kw]"怶X=b<mi'a\үo*/ڠ9a=rAGȕ}�I:f6jZBD]G4(Ʀ"@
    UBPp^[Lk5ΊCBz-VA;zqSxVxzB$ by!=cM]HCi]f
    (FV<AG(?#J79]qOjhNo
    N-Zz:>AO3_]%:"8Đ'9|>9crYs7tʾ/Q
    : to#	(RtdL	P䜮gDapй?U.n[0z~W3V*,s5ʹЖzƪ]ozqF5ZWjO
    mgj@N;j߉<-:N2SXVڱ,ha[aRh=c~4o0eb3f1Ybz,SϘz,h})ЖzƖΕ[Ҩ'L3\@܎@C:ZvU\\d@[&SEZUshxuzЖzգs{l�
    nnPDMP3Įߚo
    .l_1.]C[7
    ]74nF?@SkgsnO	T(BD>cB[ؾ9>qGd:7hXϘz,V1hA[b3mm1hA[ڠ���E{	Ȁ+{e@A*?d?ߎޟ)>H]8Oq\1l|?!
    ]僨Оa@|AU20I}&_ttҩysqܛ`vaZh4ӤiXYy47q?Pވ~CM:@�ժRЮ/u`E$NA* aU~OYS%~2).uTXB[R:٣$J3`Lܐ0J!Dޭ${238,alW8=Y#N]Vt2LE(,n贱�:Ӕ֘ܲN&SOHX&@H@a%
    %{	�О>�K9mpBK	I+i{>!
    Ӂe,R:`+)ɖ69c59XuŵxGl
    \!@)øzR%
    MKBpvY>Vu\L.ݩ3- nF̢'Mzӂ4fu�JZ0A8 a
    °$΋)a
    :5~ƼQtڨqdyUT0FTP1+~Ib@4Hk0Ftip̢U:?3/9Вf(z[gߨ$–
    l$hq[2{[J,݆C����IENDB`��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/mac-interactive-shell.png�����������������������������������0000644�0000000�0000000�00000013205�11773544727�022727� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR��
    �����vɕ��PLTE���.	12: > 8$K(P0T-C&/D(1U"5X#4Y)<V.SQVZ^]](*j
    djw��pyn!s$e(%r-/r.0~57Af(@n%Ch)Gk=Kk1Li<K~.Uv4Jn@WeRZfTuSU{SRzVXs|pR7Y8S,Z7\3b?b=e;i;dAnDrUvKwljBn@rCuFyN~T}K!/.8&)*,:1234668!$12"$,-I*_5e/u7NS"_5Z#_8l.`:HJ]SDFUNWXqrsqWXgh{btu25"$&'&($&+,&'9:*+01449:?@e*v3q/}?~@wx{|cdfhYZIJBBIIWWeeffyyxkRnc`LIMNQQTXU\\spw`kgmquǁ;Ѓ;7:śKܟ}ͮVAEIWLXT]\^orc}^lc`ehlqt֚۫̀ݢľﺁ䤤þֻؽ;;;@@@MMMsss+++|||333SSSYYY"""eeekkk4}'��CIDATx^E?MZo|B?&%EPp2К/_ 7&W(̈́	c`n8?,'F}r!__L`oqv9J/1zU?9cuܟa5@*U_Th[_vUP}G`p.G*lMʁq٣=K(ILVFF'_B=PXxT!:�*o\FT�V?Ra1Pe\A.XRÃ5~y%Brg]wN嬵*<�b8s~E{	8׫Ts2~M$=V!䮂3ŵ7}
    jל<p¶+mxnR
    �u]7lכL
    @j뚵T!bְij>BE"6n%%1^RTu<62MR|
    _ܨTJdx^}bWbp%~6drYƗJO
    @4⮵*(@$k&`UY2:w�dmgeʼ7`{m>NZk՜pyUpWZ҃6UJ2k
    ]&lU
    ʘ0w,۸~,2UsnH]ZYme$cTVJ+ZvUWdHhUTQ5
    d/UH3J*
    ۸]D2ǔutBxѫD>FX٦EcXOT<I@0EU{
    DR]~zfœ
    ۸&2$
    <YcTTF+
    I{�-M$z@J8i62:V
    $@)$hGIy*hYYmLفD4*8^亗{y66ܘzmTe\%Ƌ^oT9HU13;2_*'o;{-lB#�-M}B	Yq)<)NTc{F&>GN\	upNx#{2RJ{ۇZFR3%E\Y琵M3&—|;p@��0@I8��@F<'ѓ;pl���#\Aف���ojnI$ƮP*,/"g3$
    .i ݗ_@x(pPH^ ~iE$BBC:إ��jxdn&.eW. J0ձ	�0Q4`)KΉrXQP>$$gZ:�6n྆ᦰM@
    7J`ϭLM0Ž^ 1{ޣR$VǨR|suk?8 ƶp(0F4?%Ep=2%xxyGb@bUw}Uvwwpzӱ8N<3[
    AG�"Xήp6L�2n.&W5yD7TQxIϲi3>J[wI :98	 9eWA,ɭjA?-{[Ig4|g�MJz\Н<=Tn[`x#`谲MQ̅�F@!5&KwbVeRN?xqupݨWY
    }`(sqVa
    r
    FqHcVy�IۈVȔec*�1A~UĘ|T.
    y&07[Nj3i
    H$==F#[^Jcu%h<iCDƳ^ V4JT2`*P"U0|ւwT
    +ۤ^u(ҩ
    ^B/$7[b'z	b{?Rҍ$ɲ,ݖ)!󕾪oگ䅌ēMEif3b`t2ޢ ł,o0ʦ`KӴҙ	"x;8[(9sjS}(Bz6u}!/SiDS05suo>�d)!Q*t}h|6LQȫ6ow-d4CxvbNaKq71'~]xy̯d.='_n 5a(.ՕDЂ;l\"m	IӤZ#I
    B0,CJ>xz~mnaP鱗ךM1V/`覆jI3b	2w=+/
    6.r&i)I#X7v;CUօOA=pK)b_
    p@T
    �EB:{$+u
    Y	?nyYQ&ͩ6\T3tmX]
    KCq"L5w(EgVCʋJᗝ:Fa0[9<x-�^C#AV!KMJ1wՏyTn:
    .ʲH<NJq]�XkM|?@`PʰqeilyBxȸ/0S@XD&p)Iw7;wl0PTORź2)Oa>•ѣ@d&HݓУ@aXy>m<))8kq0ʜ
    ٦>J":0C1!0d
    ?(
    B(P(+$͓N1u`bFP	٬NWAD_8
    xz<+h#
    mQ0fs1>I\rJ,2
    D6~<\(hvjC	
    ,*)Y45!J
    7}<^o~Q
    8d(L	}
    E
    vs	dj	Gv re~۫k.lONXtGQl;PI!Ban:z)ڮuDAzg$P(
    BAJv}p
    ݃MiX30̙壺&
    o~sRF7Q
    AC!+йSo'lѠL-(qNvڎfd.4[@DvR1D;)H
    ԁP`=ݧ(t$%(`K(8Z@
    WaWF"
    @eQ;
    2Iĝϴ/eO&\$1KGAl|
    'pϟ(?XE^
    2P(+f`ޤf
    TJj~)M:=
    m'
    n;Qia(h)&52KQQI
    k %C	vB%yG�62CIa$*^'c20Y~&	n%җ@anAՆL䟠0%<38
    d@P};
    uHGQNxs({z}C7g?Yhenbm!R*EXBMt@l+>e\yڗW_aa+`a׎M(0:0#DE#
    ɿp|nF
    H)*
    SBmk
    R-WLHkH) R@
    H) R@
    H)  R@
    H) R@
    H) R@
    H) R@
    H) R@
    H) R@
    H) R@
    H8R@
    H) R@
    H) R@
    H) R@
    H) 餀R@
    H) R@
    H) R@
    H) R@
    H) I) R@
    H) R@
    H) R@
    H) R@
    R@
    H) R@
    H) R@
    H) R@
    H) H'R@
    H) R@
    H) R@
    H) R@
    H)N
    H) R@
    H) R@
    H) R@
    H) R R@
    H) R@
    H) R@
    H) R@
    H) @>) R@
    H) R@
    H) R@
    H) R@
    H|R@
    H) R@
    H) R@
    H) R@
    H) R@
    H) R@
    H) R@
    H) R@
    Hҡ
    �0?%RݮVXP
    =[0<kĸQF]$Bи)Y@B
    ?O6 ,'
    ]$dBA&dBaB$^DA( )P:RC?TP(ӅN8<5<==8@0rN]u4SHA($Co9{y'
    aR)(
    jPkJ8O!C
    XRBTPs`@Ʉ0d
    	 \Q
    npsmVqn(P@m+Tmw%Nqn)3
    BBoC
    jN
    өʼn;XA83D߇
    YzW0. ^h=W{v0ax
     ` 
    dgM//ݚ"y>k
    -?BJF�Ni;v,K����IENDB`�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/mac-pythonlauncher.png��������������������������������������0000644�0000000�0000000�00000030210�11773544727�022343� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������;7I��PLTE
    
    #.	16#+)8 :#+6*1;s1J,5A3<I !$K(P0T.C'5V&7AN:FU)Ge6K`>Vn<[zSW](*jtr-/r.0~57Aj&Jj7K~.Uv4AM]KYlJn@XeSWg{wTV%1,07-.1:HTZ-Y)[4T9j'd:sv,k$}0m2tABEIVpEmGwGvZhY}ash{hq{}JyW7S,[5b?b=g;dAnDrUvKwljBn@uG~T}K6>=VoccltzwFDK[YHL]PO^Ybfgt{reuwhfsxw~!(*35!$12%'HJDFWXqrWXghtu25#%'(9:*+45?@z{dfYZHHWWeeffyyxRnc`SY\s`kgmqu}ƅԄޑ͔ѐׇ慼梺׹ˡ۫݊ۥ֚̀ƾ䤤¾EEE&&&XXXfffuuu666��-OIDATx^ێ";E붝&n#Z3H,)6on|#>߇08a]2IiAJwý4`mpK:)s=9(I !ǪaolbrKX'<%du#)1\ݞ/t@啀	/&?7C
    :8R\X]aJ;oLY*H`&Y!5N2haF&+0ĬIdV:;\#
    꾄UCaU:
    (T.YQOk4+LdAz,,b:amR᮰0 u(ijڀH$cU6ª([4S�ɲr(t_:4lZ+Imp7g"BQV 
    {+RZ9Afu:ń2a:Ui-	x:(a%zzz42CV䑷¾޶Y,qppE|0֥áb10+$
    ҁ4}䜥0^.3G0FF`V7a$W.B0¼աuS̬@}8<
    5/3ma$?yr�;,e	Ol
    n&}"FwaI"
    1mevDvdo)FX
    '
    aC!a4ֶVXd9JB=F$N0ї	+-+Aڡ0^-=Q
    '\BLh6:+'h=f0j,eQI"E'V
    ;t:�Hᱰla謿L}H)II~,=C)lº(tl%5Jlx-2
    1gUȁ~G3pdf_'JR1RԹV8Y$,
    :/FRN'r
    8d>ɇ 䫄-cn~$O{>o���ÿ%\\XZDɳ6�� YX9H5RaZva6Iq؀
    lȧX%J$?1C]U4_._-ltSd3]tt0![;cߎu8w&qPl.b$oC 0Ecn+n
    I{W*_^�]!%39<XcTiقپ,InTb HZjz1�ϋ}WQo,w-(sW&w~@LL|X͈qY|gqoEPCWa`Q%52,rqq:esg^Wa;C7nSQV!fBt\w8
    ]iVmU-˶m۲[R<FF{N# U%qe+]!X(Da�>P|#"zQ!l(ivAE	$g̙cggld??"I;g3_Ύc,;К9dQ@XS[+߰38t[i[KeWyp~tz}0c6OZ<kEWY�Be4'x_y6ϢdUj�3#: "kb(]+]܌'O9jˣ^e	|h`A*qZ�KY	"xHcZJuO|ZZ.!v1|l[>ն{|jU.>
    5p`)C%p2
    G@m;)~~
    /]wnvQbqw'
    &5X#8,
    P"5d=2HahX(Xz\
     xiE͟fj?	~/}84S%'Jj*�relo܆GVUi5
    M`D8D(`PxHyP>ѱ
     Ibt|a90a&azl„0aC0!L&,{ɣc#� �vҩ(ntZ#PrTl+<m%ǰEuC(cDB.<ʧU";wǠBA4G~O<aM5^1LWuř~ow6ˮU5=
    ɉ3-w_may(DSgk̵eP!ⷄWƯ%/޼Ogs$D@(|
    |40G7&rc9-?o9Yi<w,٬|x07plgpBNfh_7/K6	QD٣K9zp
    507̔;=8`IP
    UMX
    ke :L[@aCKW&%\E4>0o
    V2qL:#aj>'S[af	
    I ;
    >z$!i:NBx9`z8#hvW	kZ&&(.P8"ݻ"c؆c=C:~�)@#ƀq4V+$CF|	Ԗ}"]4>q0&CaPUma+,zKXGv8U̻ЃHA5, "緵3(DM"x}
    c,5=*ޙwD/츰4`G,cH|0="*;LX',,Rg<M*LdP0NXAѵG	bkm4yD I@P9moѲ߼%H/)h6
    laצ"bp_Z3"	㌀6aI>B݁p 	k.uA,^3Y3zxo]8M�zWEH6̀x	v)IrgLW]!z~
    :c¬-l=xגggWbE7[6DŽzgC<Cfڂ/;6Wf
    F\ń-u^8⤰Br@(°9C B
    y[Ikcȷ•_r%h:gF┨-.`oh
    r9
    exzصc"��awӏH-dkJ	0&`L	00-{tl@@VFpM)Ѵ000201a6aW٣C#�@`-箆*HVH+Va~0	CXأc��ǂ܀Dz܁yo
    'liivZi#T+�0!ȹѼctk6naupi|ZZ(-{_ԥmHOR'٠(bذ_q6ɥʤL*E?ky^_~ȖOFoW__u~L3
    צ~|>6l:�;aB^KM'_3h8]%ʚY[ir`-EQ
    EO*�6(2I*%
    Q[Voyb-
    >�iQ5Gm,"G=~a#|j0Ân6V"b+:tz5{5FlO{gMo*�VdOY4d/VM+4w̔LNcb
    ғ;r*b䐢'@Ψ!DpKԶfDNxZKpyn`zVo)Ԑ!LM+c( -0.bҦE3
    K$?	\{҃~1"Bl:62v+=RQ
    kЇ\f+¢;;hEM+c;bB-|:LOVjX1pkhfHC"aEv!vWRELUQ8fl"!veZhXhE`-&[AuP?;f'')0΁q4L cE):~̵R	رU2SnTU
    +3]TЁq1nZVs`Z]`XYB[8]p
    `'D3ۑNчq4TӼ?e)h`1S5M*eűvy5Kt'x2Yazójsӣ'#HRjB,4+sb�ŶKlCF=G^nu];60B5\@mf�C	6ԁ_~~鰎բ鐢c/1.Y};9,Dcw	Bmѓ`J`D~/f@z9'"6sΔHWu +9q.~]9~aca3݈	x	h0pbM=>ߏh8X蔄	 Յɸ!&RVœ/rnh*J\X$ˆ
    aV؄}20J$VR*tCkNu"CpkrYDL{/1[fE!T&aQ'I0+uf镶ؠm%bqZ(6jfa]ȀJN¬D1	K@0EL\fGa%fP$W�vF8kO@$ou4%qkhaVE-]r "!$DoE"1u\Q�bUI?aXLQ	8m4N%+Hq9zk@H'	hKXĴLXET_fIuFOzp$i@kmR+3u
    +c+pQBMX%U+̐MMAka
    kaEfLu}4waQt!
    J2b
    S*V1n%U.Qx鯅CM2hc!xaf+ׅZ@!VGՈX%I*B:!tc/1҄}6	3^ka^k9	Ga=8ֻo:&_Tl<E E.©|PF�b#`Pư0ư0.Y
    9,?~1[qCXn}@"[a#l\6	sX;{ϛ0PsB9qd{UXggO/.A	l
    ^b&LJ:l}:;<1/j/a[hI:YN@:u=:ovgwGbEF&y6˷B(Թ=å
    P,lճnwA$l󴋺'nFa[Y
    h�	5piߠ :zWS:+L0Ti!l0zϣr.4¯,Ηo2C/2#b
    7yTå]ؠ\u=y_⧗(.(%X!LG'a=^6y\K'aQ_YOZسg71{6
    k!0+L6
    \K'aE	_YOZwoy+|B�eYoΌ.0ΑCHYH9"0ư001,1,aa,aa1,aa,aacamo(aaवҕC%TkGBģHXU0䘤G
    D̀ MHLZ%`aF~r2�\@g$>e%IR+XW	Pճi/T!T.bQXXQ|u(,:sBNkaaa9pWX0K
    #U$@]VT"(, < ,I2  e2ESJFaRQ!!P8	
    /,=:8��A�BW&WP0;FruDG9S+SgӍp%K –6ⵉë	`�	`�",.rg2J'Z8$ul14^L3H*/Vz0$T(I3�%;H-	@y͉6Iԗ#Jj/
    	PMop;MlAiiPqx�9&1
    -E/2}ڱ2l(5`	,�8p|9f�'"	`m_6`]`@)ԁ5
    9fE1;,2.:sLAv:	\'0o|l}'6E+J:`�KgF2Ph0-߀'43e;>A_[lhBPBSDĽ80BKPԀ	I0I(op;7^X*�49x}?	TF/	<A(zL7{<A�H�H��	k*j8{CHXSC̼xBzBQZ�=gz'*!%�\!],@HU܊Q~”[*&Km+3‰
    kj"pΒ]~MbA%^xdxBK =\sE(53(߈QHRXQ_:C 2A!I#v1j)@MW`aM!SSZ~^nĨK`+^,)(�u`S1DI5u~|֔g�:tXd8ߋQNTXSNƜҏ(+^D5|؋Է�@�H�`�	`ߖ"aMe<П_$U\eO]]Sg>T7�y{
    +<Q:L?`krK䬜2{jL
    `6x)g(gTmYwTe!IRse))ɲ55$%KRW̞Z)fYjYcM*0BsRS;{_StlMtM)-2ecijo{V�nAgϊL+oR;Ϲ!�^
    >cMtMM3؀V&u
    -PaӀcC{YN<w`>7,up
    dHXSʩL	CMgX�1<ap}wwR|LiHXS;0p5kdU
    TQ'|{Ve*2gz.zXGk>L32e;F]SAj1DR$Ȳqӳz*JTS^)i�ΎLjJϝ;Y&-z=K	*2?u<z>̎P",�	`�"aMEkAš.վj_NXS:fդ.4>LˁSEpz,G=V]M:䨋.),'m/
    =>s
    $~O߱|DTSETTuN77JR=>lkjrI_wItob#2 {|DTⵉ&~]MdN77AJ&=LUe٧֔$W\M%Fn:؇5O|GDC	×Te_T5,N77!>=eLU{8ic:gOtM.Jd]OnA
    bdrj	Q=[D<>5դ{J}	meɋ>EMzԷI "",X$EX�k*_*J)M/[fw;ʟ.aM14�9`eA.{jT`yq{x|D
    bWlXJaWxɔGM죉u*mgߩ׉)S1&TaS[FriE)/:>2<>2[`.$,鋮)�,XԨߪRlZ\z+'GNjAR2?:5fS|Jٿ -WΒ;05`^'%E.֔jszԩQ	Jv`>ܨr`QNtMMXSSF5UK`Nyɔlb;}Ip+`WL
    ¨k`bꔗLAG
    V'5,y2vRLk
    ULrQG/ީ&,5Ʒ4Z�H�{2,X�`XtM5UtV,�/3~5URkd_g�2%ٝ,,*|^rOXCO'+2ajj.I&uNd+՘%BlUjpc+
    /Ēv`?,`J)=N`J-S2˦Zo;΁YK
    WU
    }`V`.k)IQ02M^(;ΙJ<_ͤʪHgBX
    ^C)#T0eIwHwk1O؝lHPMˡvW`5D*kʁ=XH?A	s`Vt:Y~p+mގ6*#aʁj25]v<Z=NOh�B='
    +�xU+b,Z7JR5EӁ=_<KD^17Bv'\&$UDbUr`^Qj;09W?˚z$L=n_Z[<n`Q	kyMeUeJXS/ȋ*JCC",�	`�"	`�	`,z?:a?Xؽr+!a^xPsd묝u>3{?q^R",JI�쀥Af`xm�M2#%`ZOS T,)	k8
    a:}j+QENVu#&6:䦙I,`ޢn-$^=,w>"w];Co0d`շ:n;c}I/!TB3-4,ŕ9P9J,a”oϮ�PV	DH7PA2G	G	V%U! D| S [R<j{,>۟0&`L	00`&`lJT`9͎6EzIꗤ)D;Y
    ”p`/VK
    չ;T`wԉ`=3>CL牁}N$&zMaTWIXLj!6۪
    Q80uCnx!N?%̋7\$Ģe�
    ۥ<L:c;cUH7+%gi)$dɣm]ʈMV$,13P<YB2,*g7+`L	* !}\XD\'vG:yXQs>ֱs(	XH3[BXuN@b
    7)N?$,t4YԭKՍ4:o/v9|Kܿh4ԫi:	`(Wu&nx�@QTTAH_a[_=ChDJn+d"$sX$_JrCi4W 
    GF[ƁNN?,Yͬ$p3-jh7[�/w4I,ֻ,~a'(9?=--ߢhO4NQB0.숚k0])IQ+EO	[ìKaGkRX|Sq>�",DBw
    ]Cl7a#սoFEIl!̗~RuHxbRUt)E髰f+\yi<gB~졃ԴZ..naU0KЇ0HTI1[zz5Z*0		FXoTɌSe0JE0{\pN?%lVCr!,1{_釰*̦$D¦;-3`}0H*`a,
    nYI�B}%VPNwa^QaHGP
    @/N?jߠz>]lz5\
    @	W|zV~f)e|P{=_S6pLIXx7ޝD7aصb_l$"pG̾
    *Q}Lp	00`&``&`L	~;,9|vr,XzԚC&VWb(֣^.eEL{膡!x$*AaʋWw}?j_0I}G0n(֡
    /B	an6?~ց	uJe8Iz<ſew,sbKRIn&Kg.n&g_X4uYjK$ϤeٕA2H6A֥ecd$y0F@v"^A~;a?!ktqK5b
    ,G0]ñ{׺r;kNG#TVeb~A	/%"deYA*Hz%ƉCM82q~t!ͫJTBܓKf?G[0^X=,yQ?4{>yI*{)lbZl?UOss+On,=<E#6
    adYeҦK3!9
    E/ZŴIUB
    YiiD5hҤ*sUط^ǡ%8
    %hǣi*9BEN.)ei-%$E$kɔRMDf*ZDz.UE6NaNɹ"q@qC֔F.	#js "k<ɵ/g on̤?7KE�f~;aA=5s8F֨UPm3M0>lNeÁ^xjuîPE1-.I
    _`q&s0\nn&`L	yv7i|	00`&`l}LS?XzxM.0^iյa
    7Wj0^φL7��0Hdfh`5w<X#>:]0����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/win-install-5-finish.png������������������������������������0000644�0000000�0000000�00000032725�11773544727�022440� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������|��PLTE���333�}�<tL}A.)F+6[$*P<-dD<vV4___|s]eedspgyyw�����%�(
    1	:���%�(�:	@'M"T?o?q;u9{�BAC	JU�H�YRj3fCi@nMwW|L|nvM}��3�33_Rbfifvwfkhhf}i~|}f̙f&5*03D(K0zZ*�;/�6=;CF$J&R.S2CKPM$T(Y7b:_@fGnRsY|bWvZoXʹmjr{8?fwKHPsjvWgwրőʒ՗˖ԉ䍶▶蛽ԬƠױȶڪ̩۸̶ަź½̙˗ǹЬѼӑމߔڤܶ#zEf�U7�J+1r�c�K=�4ĥ=��2IDATx^90CQWPp2yVߺ9dnX-R7\Dc9:\jGGy<WGG4$o@(;0E:[)
    (+\[@.|cR�Pߚ5cJ2+Ѽ%GIIOvtk)P.;Dax6rD
    
    6rGv5?$~ ]q+UإDX+Ylwfr\d$˯szQ+vÄxfFqW?Gі؜8=SѰj5
    ^{d|D6߬+an̛Ѱ#ћ¼@[ؼX,Vi>Gcȅ71s|r507N	LR@D~OO.0e
    /q4#Nj�za>JM6O@.|I>>S	\px?͊2ttI^ua= y8mΟ!
    ؎u;ˁl<�ڜv6J2[$V{ks!Pe3CP5|Ѩ)hLWF?u4*%g;[Vn6d~y{ڼw>,i�F#L
    iV
    6A_jg"4(s;0R}Ɣ%ΓG<|B(9o)!WIspIsxuRI=0?	Vz8G&�Q8㢃ѯ@k4qI޴oB/3mr|42
    FRpĵS=zqt 0qy`(c�!p߬/ٹvIe;l\n!P:Ti
    \ʷoY:(qsQ9iJyZov힥y(
    x:w+Ʒ};	(`}Ѷx
    .NuqȦЭ.ɐ'PM1f?$ÁGBA3
    a
    Tlb#^ذIsLzs=ovRksr27|7_8/J|S
    bl29bf[jh}s9m"v&FM|ń`%^pkXf,gLxy.T1neŇ^\q0Vk{D�$Nd2(C?s!IzqxʼnE}
    'pUᯙˬzRS{Osi^:,\VzʢmV~*}1'yKŕ[36
    ft!0DQ�+Gi:@c d.yx݋lFb�xr|^ZbV0�
    !zKo.=^d`ɓ "xeat2o$`6vFw3,?8;<.ie4RhX~~s|W?תCkܢK2s <̓V`9gQ0OdIJ&m[W\ja6+7ID9/z雇Yb~b)f:3GYMa./ҹD~/9όnZ0{k
    |g8@+9FhN!?l&:gyaC'_",[(2CenGup%Bs'Uyk{Otם0[vC97NޮۛX̝6s$;yK19O<]%OfnoW?|6XG+~/{0)8v\F%ē0	UH;qAzoGfȤ:S͎FzCˬM@]_󀖂\C䓘@Qfw2J1x|xG%B51q9F53l3/~*ۅ|G= $Y\`GFm74\ew6ü^),0qBU@ȧ0'0m<
    
    F9gn-1%bY#Ï*˜)}T0gdBjYBh3[]e{`.WhR$˨e}ky9ķ=DKq)v3$yś9sdE9<3\_fRkKz3DܯQo&bnd]S9[M	wquҤ_~Cm9+8`}<M�[p'
    8G	6һx1^s{t	RJ	+*^,	o98.]x+[ :9ry}s#AVsw@p2WP|\h$i/+|\3XXw9fSت8mK}Pͼ95ޝB.ԯ>s5j`.93qR8U2ObѕhU՘	Nޯyy9	GW`9uy9VW}o.1/X\{c㉘?(1h/~j`Lv1O
    ј"Ͷ T$4oe�!FKfd]bhڈ}m6eoed)iovqHE'0Ks	=ȵe[A5)w< ;.ahIRZۧz-X4QRlQ&`߈7ҙ˘[va-.ᣆ'<nd'o$ ;XC+*zu7{i18ă|cHuu'{q
    W@g/[jA޳F
    B5뛧~|A7^ޙ,|~vTӇ|1#1jDp#4oXn;7pC!;>ǪB(g#l#G뚧/Y\W%'Ly_%ohg\u&CI+Gr&x
    s2io_ Vӈ2_\psuؽov?jϭp:+*+
    9ߐi˥CC~<a1t@>/qjKl\bCXqwlj\|آbۊoHU4_9s#"~8Z'a/�ŏ%,R<g8ćk{gꚧ|l=<V+FqVPp'gH6q9O_v~>gк'(UX@7oꯟ˸q^.c4dq3lZroe"4?.7$!Ā.6OsW>P|YWm\�~_Ofe]p'LHJW!les\n3t4:,<m
    R_[\#Nu9nZ-RgyGx6b#y9b
    V)ς[69(vNg
    \ݳ"FiѴ56d�9]
    ik;pD}
    
    Fus;o8jю6ΠP:*r3W69g ~!�7+ȫ86D>]N$$2m�B]nn0y@Hr`A&l\q债&(F^CQIӝ
    YlF0=P"Sιv~ȥOF;)?N.j}"/N<Y"ko@5jTTsT=�}xAPgxI_1fSЄx{,6$%mሕqEK<PxA6e\?G.J 2ܱͧcsO?6wl|TͲm^k+/z^o^<R%YVY|iO"m.n#re;PsW˜?Ŕ09+weO�se9L>w)ݴE;7lns$ׇN9+[71C}-_GW]!o)%SSJ7jnsy|zgBnz6?,<fM/.Z$&fn}mU߽#k)a32|F_@ZIH09s/={ɻ͉۬†vhbiۼS|]w\U"Ty3-s</"|{EaE$ϫ7�$P||43̰VCMna>_dG�[$'`$rS?#pWǩ1͏tN0?.rE#`ػݸm-zOЏMŽ\w7J�*tdv7h�N(YՑipe
    $?֡dJL&:ihê	qrgҪXxUiC+Qr2ga|s[n^m2w%WM,kT鴎'sz9'd褉ӳ%_ҠV̽dH|91n~8܈d^qǑ|>%\3_:6s>lri>aR,{"xS2+ȅx?9A>QB+b .
    J|Eys 7R\q1 fno,29tLr8BX+fB<lS-\E^铢`rOsN>/
    'ӨOIąd}P|rAjiy)[g1.a:'$BJ)Taɯ|l֞R!qlQ`FKa,[D5/rr|0\Me9Ishs]%z;ܞ*{b{.Axh
    g\㨻=/~G|Ǹ~n)Ϸc1A,#3}iS䛿#ǭ,㗛F{*prg5bDF'wsXXK%ɛN`2~=k'h<XFYkk'GzH~i-OQ`+^[u]>SkY<ٚxv8J*
    i9:c4k2/C\=㟳ɸ&߰91:|奔YYUV,=E	F`74FBfG>zN 
    x.r[=ϕua%̘qt0a=(n^yك+{
    ]W+ݍ$?iIĩIeks8Ie>s)ssf}M1&7)Mv(;Nޢ<mAbq#^gfzV٠받jGmμ̓<>sg|otEx sxƽV7iu{̵m.V\77�sԐ{5?qem:u{Nvro�/̑.+)^y
    ͉\ɀ#??%l,ܥ#Hse@5Gۻ&m}C4a[ܥT]<7$)F^[4Ƣ .(xU)qqɜY(v=6#sEҞY6bEUr͕_U9DɢLy5s渖os%ub*׶:ߔ#L#Q|x!)kDcGl=.TT5~lgB8mUWN"2vzhU9=c*'j1k~S+;aN8�ٌoZL֩y
    #O<	谛5}7Gqs@f|sPC\(
    rjA."n<p&8C=<<ۦ+XsrE9bsnm5Prǘg|DsXC\
    O䍹)W@k5n3myPV$O!A\̍)ɏ*ncP9v1Et\ʵq6
    oW
    ݣ1s[m O3|r[`.y֚|p!G:{0^r]@
    rgn\rv7ӸhikܘL׶2Nh΁O^Fb&v~M˜h9|
    H9F5/T&<Rȯ}W6\a
    ͱ_|Ca>=l\iܢLIk!-3U	^E1$]hZ°CۭlAk'	Aި
    P~SS<ܐ4oț%\HS̻acbp
    Xz+yJHlƄwar>$bu;WPGeÏ*"\*nѼѐƎ v<t;6ٳ¤(_>WD$i0Q-r:34ETog{NrTUL#9!8?`R͑sO\3QVe]9̕SZ⁼I9XvR̋0&lUUGT*9+ѵiF.XK5ciSa͑=o(|Q~%-o%`/kw︍A}çpـLP'&PlyheN:wTz^l
    4l2D".:>^>.%0r@푟k^K/U}F4IooY%tOi_75/�@Dt׆uXgZ9*
    U姦Hvg3<;j"_RmgvnOSƺ@7_Pyc5Aq~o)zzZӜѡ`>{Y?)LS@`yspGU3v^?LI_`iI[yۈyz~e0ul!<͍IEε�S4x0-*W$֜|as>Os.WC?NIЕ.`i	H9;4][zȽLȵ	\4G:w=JogPm>'y~;2'J+|^?}zm
    @É./)#^/Ob.oͣHGlϖ~bMxG5 kZH-X6t WĘ9L]c{m>2{u)i";@x|:+iO8DPwFobyZzB2ъ$
    ޾ydXA#~~Ī+14T^=<uer8ՂX<̚BJ@\\ڥ 4Ps9oƊR6vyQ"JyKB
    !Vev\zRq5<|;fݾt(9l8V
    !6_9Łߎw�+Wy/Ëp.6:r
    ~]~.7ޛ֢!\""]y+QGf
    2OsP%HЍ*C`#D,7L4`yf8�BB|^d"r߂	x\qt_rMKkPu`rPeقӜK`'��!<f\-<R7ң+^~J8jZ&~s'8>)NƩy	ȺTY`x\_F8Ouio};;'8M]j̄vĉGuK5sfģӜa/jm"/1�4đ\_aё|r͍w7vVW`ÙHnڲr%{5*A/LNT.Q|5'g%gCY|3Os}[>Op3h^̳zEV>"!WN%!֎iQTӆWI)&N<[phq3bwm0
    Þb<`aJ%.:"NDVF':rb79{<PBӭ�¼g9ڹ[{|$][D,9/5Wdg:0#
    jc0JoY0*aFB,'9_F�a
    u9Ckm�,8(mW ̙ļw~a9yyx�aΪ餧J4LFqWn7R7�CGVTȋxbn~F݃yWCn%y|j+xpXk\2q%pƺ@x9'qD|p<xr7{ץyp3qǯ͵>@2sI>ܒN-9{{9 g5c/"P;56@tCn/9G<̏3v!΋rU6@[C<6&*=%OT^^J>@vTGxC[]ܹ{0sx2BxREy^#pM
    .\
    :^r�<ΥJ2qI;"/,Dy'ZB>/�Ī-y@*)_{-'7sQq.Mr-2^{3LHx~(e9sg<[	vʋLg.cn}'v`
    \2:!@אM@+])GuY-r~^p1UgZgBy/0!̳bWxsٵ;4sR/D	OI%JǝvvwkO41'#16Z[
    ˙=*`.;ys4Q"9Y'V:Wbމy
    BΪ^gYb.6;yM</+)lGW']+1Nbޭy1% <r^Bmq7r>7bU0/#H)Ε�wcɈ:U&ۣ8=Af4?ɱ3=xsǭdσYp;9=Y0Yg"S,r=ԩ2[vyO%Eﻌ1[<
    Ԓ#_̮=
    1Ik/#ώ|svj"暣_GBN!Otjve+cy,?&qg1םۆW5_sũ�(C+T0s8*X٩}ػq(�=F1h);Ud$!z.b0Dy]ivXލs/dC\Y~$K
    �1Nĝ̨Ylc<0ݜNnoۧ^2ד<hy\ȑ6
    @!
    %|f ŀ:ݾnb>OѼ"%څ1)B޶tʹ"Ȳ _~}qɗw�bɣ7<o\='F7"IA
    Nek/W<|Vv@6g}Pb._G;||LFGs	yFrA�,_Is�bǕkץͦs)[27�6oYܲ<"{r]^G1ܝy\$K2kM%pD$GΣyXLFEonܖsN{1bipyn)�kL3w�#1wͣqB&{2�s\<C"G;J^$�Ե&as0e+'<TK�T)�6w
    c_?[k54<tsJFh:I*K;4<qfա19+|mESN^>
    mu'|YNuȚXNe֚ǵȈ|N@o.:"u<9QSm�|hsGk0>
    dq<OPns]Qs%=5@4([t#Xtl/5ws_y
    !"�qncbΝ;A/}(xuawE{y4B[s:0޸{]GΣ9\CS0_*.Zj	yMpќ-᠏{wA(1-
    xidv^!\tj'V|5ǽ72OryssBqt~КW/[ũyඁ K{Lkv�}*GKCZ5;m<$确wCThvr5
    智q_Foͱ~|Xw	:ٓ;w805-Spy1ƚƉߢXyr@˜3
    #ExBpKvU'ڬngͭw&myzϾ<3{v>O <2H{r?0wzŚ3<&xS27	hz<Akwޘy7c!-M	u)r5((i3M!_+INYi_ZSiCZD~/w%*+.`M/fޘ"9-2A~\0@r\i,/Y
    ̠QŐϼLZղ܀y>:q+]<s
    rs昮19y{ec4sւ[Ù'B@}	9֧1sw=w4ₜryN#^sj<}cDs!yB]muzד#b7~pt^y.յis;4fW<f߉Vq??+\+MeYsN:r}pOm7.kU%K=e2oҽ9
    ;jǂ,#Vr"1<?{2ږ&r"2#!]W]6$9bS4/H͜~Ot%6+Ża]W5JsPnr#bn4zvnO'Z1'_4}?5*0[ຶb-St\7wgo	@=sV=OuAM[ypt5LD7_OnaQHD�eÚOE&sw4ϲqҜϼedg#Zц5	>mXdhܪk_;rTc/溹g)gb\u5oԼ9۞6+Io)CrOd/5_a؀n
    swI{೵劈VמN29qg:59#^s[:9|:v(.!bcN:;|Nyvwjzi!&*pO^#b>>52o
    =`F~tH[j%H/o6dz]r2{8kՃYi/`.|*
    $Obv҅q-zOABn\z&E
    eɴ/au ʚt[Wڏ|3&Y�|aǏWnɷ>0=In393g�L@dGjW獇zNB'q}ЛlMk\mi9_z(C-d.6@m__i3
    k^kq!̀2�_NVs`AU=ܽW hĘQK@<edACə�E@&=F\|D9<jlǸy0+0W0!��A*0@Е ogl hsѹ
     DA`Q"~A8"@̾t)sb.b.b.b.;u|yf0a4V�ڡK[)|�@l
    z@.닅FJ"G'}
    L'Vf,?6DyYʛ*jBy׊u(X,�;W$[TEI윝WQQ;AN:ow<'rW:g8;Ϸي~9[g9;דPhؽ<us)8<XSv!pW6k70t;.<9;0ğsE^80[㜳s�ܛTDhd2Oqi[{vss=>8<MG}g8~x9Av>#:/ۥtp.M,%)s;{_}{e&f)E@:Ș`ȉ
    V$s3L^Iw|g׎HF}"صC"�@ �T`Hπ )[eQ7Cx 9999999G5�0�Б sXe_14C1⣧X`}����IENDB`�������������������������������������������diveintopython3-20110517-77958af.orig/i/ubu-install-0-add-remove-programs.png�����������������������0000644�0000000�0000000�00000054164�11773544727�025025� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR�������ԍdo��PLTE������
    '")	$7.
    	*/&&&,9-.35:8%7774V8l,9I!?z7M�Cx8CO8Sl;`{WT5N5+np*
    v-+DWNL+Tj�tIoW2dxPQRAKaELwCTjE\wY]cS\rXcZVcsvY[jdRmnp;OGji-T,X6g/nI;pLZUqPumsb}Oy+&TT+YE*vv,p1YO[nNN}T~uRllt#:6]WtjNKVow{no,43	&3,U
    K(ef)PD7e
    s/Y[GGXZvOkhNJLneYji
    '*(22\�D5lw({QNOeZojWWcUkigQg{�7*.MyTdWrOo04Q|ڋ̊/δͮ2+5ЏMҙhйMҩp@Pm
    */:RpOsQsÂ֒ⴺãđ܈ʲ͗Мвʵⵍ䲲ʾđͳ̒հ+.2'��U;IDATx^1��0;.{f	s$I%<;ph���0lno frd$<tl!`N9!ll$8G4
    n[@\BWt6x?Е);0Ƃ%] { 8&vv
    mt&OXvZVLV3A4BȽIV_>+,Q?:Bt HAoO:2n60
    !^dB40Nftt%A_*[Ps:N
    c\7_:;`?l�H\:*d [@$ðu~sfol̉txs0%r_ӱA3ĢHb40n9NytˉxfƱʚ+4+XC,!c~YLsT:Do[i|F\t~&b%:͊is2E\"r''O=w7xH�PD=/$xAd9<#jUcmBy1T&(J~"f:ij5O)	p1Sw1jG"E'BLOp,qc$3tH+٬x1/>f*pHi!.Te'=n7
    ֿ$1nU}691ߕOJU<奷WÂb1[@ wd6D܀\ijm<@5HTTXzz'CF,hF#u1$bVNf3C%SY32bk\b1!!%%") "IٴS}*d~"GKD5^#fI3I%i07'9';f1>pVCp0y%O·MBpbq&;X]LkQ
    /&lZb]Q&BDrA~؎KQP1Tž+RRCP|~GɅ_CCLЏ}g9�&
    }5ؖ~ZX5m7DH27Zż'ス%iX8X|~11W=bn!KG11c 
    Ow&mlAZUU.|01өInHH(JH_1iu0^`"4jY\-G(?*,P&X'�z@l
    +?LnY~-[p~ox}nOk scߟLK 1i	fD|扞[_)'RɃ2<Ϗ;z{)Q &"^9ΪL"v,�nv[!p,LjI▄#PzxX+T6`fM(ʢPT
    W? 7i7[V3[6'tl0aFi⒖!wp	:!]q#0	GHxD2Ӈ@=0W{]Xr51
    &<L1ފ@v8Y=MBnۍGʼ{&&c}:4� H}aq)"%ġP;	|& Lf	��@�W!Ka81}:$���ho"{a%& &			bb & &اc�@�Bpob'ZInsc?Lxbn*sOǨ
    AsB*`Amƅ1.@E".AVk"z1+IgYbLœV︧GœT[Y\-	@</¬[qA0%Lq1u7Ygҍ[\Lo	2�fL@uM\L}<G\)Ys̚a&aL�.fU8"dYScn>໸4KHɖQ9PnGiŒ()]E%*}a:<NR_
    t9108e׃A9遵řS3j@[SV=`?{.Ŋv/Ygs+Mm,\*Uf	S0k
    aJ0{f	|Gf%0C$0JURj>.^k1[&
    o,Z,i5@smM̞?-`ސ 0]D	`Sz�Bx&ϗ?AkG`\H	J 0`z|)&VC/PTtj>7,B))so.PtFo5G#^޼y;xv^o0]'�5;@	 " 5`O'OL	U`"LHtAqcmoTBlBw!b R)!iSvyxhMc@tͥ`*R$p'.=A,"Jn~v++޿e"�Zw;r0[&*0% $DfB\6Oa|0KE@XI㲹i5VC#wh-v@`Smr_m
    ?iNG`~aoݛ=);[U-K"!KLei4J <4k%/Aݸ";?qL:X6|#"oPF!�o~J@mрF'`*tQ%9qL�xdfُpx}Rv}}ZT1Yk9V2pZ@0tQ"yiΡS<$qfmվ'_>=??	Ĥx$mc䨟wh'L*L&Wgópp.j΃vY=|R(Or9d�RSRS5Ip 1qgqc.[M3ak0W
    }YǢ|VIx+曝2`nTlnɴ$|l0$!ZbcE�&
    ~!0}0]5E6$ 0#�QLT$L0ݳ9/>·f/EF鯾8G4�ٜOqmu}O:KY\ʆl9`q`r~\s_XӥJfد}EjBoX~EfkLj12f;4=P$c42ڧa0?FZ}2lxTE
    Ç3ک<qZ_,' 0:ط\XLZ6&J!pwvL%J!I$PN
    9m.aRWs\ʛ
    ^ʲ|5?OWX]N\a0/z;?r,iX0OT,C`P2' լNV[�q}0s8a0?'V@$|)6/kQy'4QͮlLj~\v;ߧ+Y|dT a0cNݽwK_bK5~F7`ހy
    k6�0E[0t֦x҄`(I
    n?Gt�KDoCd:6Y0)tB&8mb#)DiB<8l"؈߇;<x0xk6<
    3B%&$&sa:U_Y;LlhNN+LHIglhZ*-H\R0u! r熽 L)ݱк8h0oZcπ+{gG)xdMuDiaA"RZIGJD(ؠ-Q4!r$("aXyI̼Y={=s޼N޿3ռw4{{b~l~YӁM01Ǐb>nw޳ݒ�b}$f
    <#TLEk!
    X~ƣp"c;օq:߃ʣ<*-]y+yz	#;$O:1=@8ie1=]js@A"1'!
    ̍Pa~r&mḺ(ԂSsuϬ3o�쭸d7
    8fH6'&
    EY5r!>eżsE⪳jNHjIGe>CqŤ1(1߼/yW
    o?~=x/,fqҤTTL>ep+Aǟ
    Yˊ)<ß606]C	'X,Lx1sPK&'f'oMʯK2 KY4y1qcOLٳrX11.bb39&"bs縚WpstŬLERnQuQ1pU
    A7DH+i;c')ZYLc&#	kiYb~
    *7UV`zB|rOe)z!TSP13*&1#DŜK,KgaP[1\w?>,c#
    {Ŕ,TBB0눩b:SSmXTFL/V1ҰMb1Ib@,fṃ5HXgeQH-&@yeGVd)Brsͭ黇K5ƒD3x%8> Y!yO#D0%Rb(r0JH%bHT3/d+9sXˋ=_T1mb*bJ! +Zx1X?%b[sVvb*e1g+m=TĬv̧/&ϖ?)8n.*`%*R2Ybb&
    659uIe:wp%ZL%Q, *6-&@L5ӓ8cMˁ$`lt=`RbVRJ5"dT0̱Mڏ�JLA,/U
    󐱡	_4P1EQ1='4\EQ1< 9}-IZ�"e|l@
    fb**fQi>onŤ
    Z	1Xbs<(ӂsƍ&wDLaBj tb\B_b**&/8+z8ݻwJb6&a(%
    Z11ͅ0V?è±QB؂QP\?UBIL8c"Iw-0R;LaBL*Ik$}y:PGL.CKHC!&&6hWAa,%p z?$H%ݯZkyҫjG~f|K/y=`1x\u(Jyc)wn9R1e)۝iR0Ή)ylA|~|)sOM,/,TFۊ+Bk'bc)[~;w޽&_b,2]AbLYQt)^;wܼ?He.e`W*Rb*|nܸ1!ac
    E1/ULEM_Dr]t3`G"8%@Eddk)&�.9h)/DLEdYLS &Ɉ
    1e*fA.\9sb**0P30.9Q3sPTLAn>gI켘r1 O4bOPAB83@=%.@;*`CQ1U̓93l\&f]iD[:(*&!O&93-,Hh!)<>Sqff<)&Q,wT1
    [LvrzV1O˖L>%Yl�au\ʪE4mćU<K=/Gf$9HѲw3L:*+A)]71ˏ{$ej|,5�]bFpb~
    Tb~6|y!Kx9es1)Y/^'Z.&@j>e1766Ĕ⪋)^{h\gTLBW"VO5nΉ*K)^F{	+*fPńq5y}{q˓53uN8,^OC*97$>jx4j9Luq`bI5c^\Sy901Py,�
    C!%fG1#Rd;?0|
    877ǏOqX,;7apZEtPNGKSVi4P-"1sۤu:tsr]ɪba3fgZVbnTbKYIjD@^69W!U-4VMtzsVY?oeO*3}lel}XNs244L�D@?�X1	Wa0�k(&e.
    s<`=wj/w,.ˈ얲/ n+/d:x	r
    D5PNش/fpH/�\13ieNk,=T@97h^ ":H&mbjx	bFv{ϱv`VeIR̈mCX;H4Peܠ\Lvl?P1?㌘>�f):c_jzZNZi\,l4mYcP#c.>=CԦDPG$bbyvvV)e'qF
    Ĕ<A*EKGD$\mr&Zdp	[%#'F&@]ycI
    exRBPP<'@&H_Ќbg''%^#f0JHP+S݄SSB/*O>g1ڄ[Ŕ3c1IO2_?4RL8jI36&ɉ}=\)"\wQɌ)	>P>u/|켘rdcBe?	W%5"T1i1I[^;1-f*X+aS(X"CB(V21!o1-*->hXv;._*f>-1EWPaeޙS09_Zvm(!5;&_(*-1%>=LL")#%l&ȓV_`X-yNevA	g=c
    f3&Yݬ?	W?c._*l BnrV>klcWyEc#{pqNEbJҘt cBGlPp[eb:_*)5y!$`}Q
    k=	4uAPLiYdLR(H].sɝKʽxs9**b*bVȈOTKFQ1h2|Qy(*&VZ;w>L<ퟐy(*&N&ׇuxrۯt8~퟿}pkcwUKٳDa8cu*$r* }ẐwSmgaPā�+dw{A/,BB6i22DH6[={8*fY-Jìp]rh= ϭL#MCP,dXd,<::OSr;J/T|:S$	ћF$r$B떑dXtLOD{räq
    /T|Jw}I4N
    $ʂpХ>h$ꏫOb1s^$:h/w$IB*0ȅV%tmw)C,&bRڧ]fD]b …d+
    *Y)j>Zv lP̑*@.,FðhE΅IbQ`^Y+(lPX{Ħ4-&b⚨GTcgJ?TȮ~lҴְ)C3-+D?P;gb2,fJH/7Oz*dW.bڔR	Ā'eݣɰJ74y81p!(kt^PiŌrs2`b=+`6XPc;m&KLrkZ٦ "C.\'{cRJ,N?*	s13Ħ)[94;-&1pl(DߡCn^	/&B/ebZ
    u]}23#[*{͏$&b>aT?D@DBs~~``SJ"ٍ$;qui(fNncfZRGLH-í %fy[]̛=381/(g(܄*JEDRIBbV8ޛEv
    ]u\b˻ä/<(έW%KBW
    P@I93"!݊;s4ɶ@3|ZFw?GJBdZpP6sS<RQD+)0??>Qo0	<eGM2W"
    BuR0`f`:|B0O׀OSI<$TZ/dS/r0.NAƫL<ksi`6(x<.|XoD-$.)i?`
    Ft
    bUj&r9dzH&LqqJCPɕm0Po0NF㵍g	i|r
    țBl<0eE8/1NQ(bY.$x6lYx`d`>өuD
    8h|91/Y9.eUuC-^+{7&gͥ[6W1UsC0drz
    lrsؒRF)=WRIE޵spF2h�v|,
    J>]<IM㋪(kҖWׇ~x`!'׸f`> (&KpVzth
    _AƫVGy#(T\vii+v&`I`tytNJdҔj>3�*&$*s~<�4e뇇=F'~&/HHXZL<OEHKXwRHC&|IPISդ3&A)l<?�Kz72ϻ8a O!8F~+F)4h:QhQ!W,etϹ|VWZkY
    3$p`LcP!^^v$f/o/'CPOz=W<jX[0QA.sV2%tǔBJe2-
    0gӤT=<dInTX#<0qɽK90_w=U	L<-1G8o.a\%h
    Q!,eG�,3L`(Uf2|8Ɂ	zw/SqZqvY
    fJ
    F!Q|iFt-RRQhÜPə1q=#zjPZflGr`*2xF.OO
    0ӂ@`)�´Bs=̜1
    01,Ch3m慶J�h"c	o3棃z]eU0&p\oCT.MJ8P!/dg dWbo?Dm?mKs?zz/{S.T2sC9@GF|Ds"m9<KLi!l]^/C#nJYd̂Cs?Y10]-/!1
    9Xf	hhdR&"@f$ILE$D40L<G-&@+K{UY)JPw}`Q#oO`귦O_򐚖9FW=ݱOD^6hJ=%C$&cu6.{̟8DLPZdd`Xdz`J՝nO6X�*+L&YrHj8Z_Ğ&ɷ桹Fd`2ShSƌN6x`^_&:$,K.q*d20r*i20afY_?ozg d`EE-̥i20w?q$W�}y9
    u{629ZFƉ/Z6?H	$7,8ȷhs1kWE0'ﰇ=5z_P.A;1SY}>MbT#)LYV#)L`j
    Sa~N`j
    Sa> z:05!͞=;<s0_ĕ)L\a]lӁ2�>2Hx	!Zc,k
    
    cٳ'O9/�$92Ya1.?y_]?w0Le`:pY4eVu_/i Y
    &e`PMo0Y&&g=ש
    ΀q1``zps1!:T،)v,.Yh0wNY eMa&q*Aœ}ۯ"e@N<`!gs,9-|+̺�k\|ظu\s4i@OtJjsPc)Kbxfobn90<3er�6^]j
    �)zԸĽrI`I#gb{22L�B�tӖr&-(g|qrAwN	ȚLc߽�BՍ*T3yYyR`ZQl&CN�Rqyh}	3LFXfW]
    ^24z7>vR`o9*Z@b4pWVaHaLカR2 Cyqg&,"t0J0R`2BRV@rPfR67
    
    cO߱ޠx~|=x)b7n|S\^D7;
    T�,0)o0P3}Owq=.e0KNIaޜ-(~];Pq.Kݒ0s4V˝{+27LNʬg}'`b�Cpʂ򜲠)Z4R\5FrguUHI.^J|'@6eynSLjLqy8h7-Ba^|Yk
    3+̃Wj6&-yïKr~rya*,^cIp}` o=˗gMk¬t9:fIr`7͍̆FSaքK}Od_Tymsj;XX_xa*Lz0/Q�=̇Y0+#y¥�b+
    sc}_L*LιC#IMG2љ9+[,aBq^F z*09{E}0]\JXq[0&9}F<M
    SZ
    F2$c9K)@1T2
    <kgl\nYu|>@a~w⿘Ÿ;	d<
    3G3Ue@9MaLaLRx
    .91#fӔ2Df-P%Rl#05"CyQcGL>MaxM`0c]ʶMڲT[v[
    sxG�[d+ֲ%`j
    LI:}?fE̮r,{ge*rAs_Dַy6Bd)+|-r:3)/`ua[H,k٬SfK׀).i#sKd3	4Ru`;<Gaidu`˭g)y
    q9nO&[ۓm9x,e딼M(Ml[tzOb/a"B]MVK)|?6t1.-ՌIc6<t
    SSyt\~ÔL�ۄ`i) 07.{w CSIfE*SToH|	.\L!z[1</FSs0BR	�	l~eX&JS�E(cb.c6!$RXa㰋O78>BW)%[m 5"
    Yo	dAR<kx0߄ÌUntUf*#y&?QuSƻu0q%b7kf14LfQ|'
    ?0c
    
    zLeJ]47{vh��AAhV$ʣvKwɥ?o6p
    77҉ߠ͟@8P8t7t7t(k]i)e$RQ${ط9(/0hk�}a@?فR$@ H̿H̝Ib$&�yh$&H	$aA՟j6'x<{b+5觋9^zǯOr4ٯG]ZUM~eb|zf4]2WʒUrZD/ӳ$HqR^UUϪvڗIkZ1U#3cYfxs꫘J<48ǗʢJ鮘	Ō07/'&AbzʖUR=iEG)f9*K:t)E7js>6A's'$fļQ+ְZ7bG5<x*̝X;�AEQjsͻ
    ^Raf,n1fw)+HGAL,nY\^]ex[*G;y:v7銸ub[.8`1I3ȝwW2>8H/xet\]U԰(TDis[F&5pWM
    ?EWpb(fF>GM	 
    =̝M54nao E1	he0ɶU/^ư�<�K]8XL҉9?N;.sZ9s]-o[2 1I,ǻy#_"zaf"(`8fb2SV3+Z_	hUFQuNhb$f/;s3^.h2
    4Ӊ)!.Vb6(FLL]WOumXOL3U-1eu-&T6h-bNϕʦ:ƽbj(%3KmAyq̮/2N1u+~b9ΕJKlg
    Et3Nm>:Z5=$HLWK$3TubvL`m,8]f*R^?bV^+tb$fgUf(Bb	
    1Iv/%RY`WƙT 1-0*3z]ƺ},8q|ĕ\uKd1`{DC͒?�ftv.EAR;K|3Y`*u*
    .!HV?{%9wyv׽�ߞ;փ$&/#Fٛf'I‰%yb|t<- 1?ZPLھRQZz/M=A,@Ѽ^~2HP*Kbbv~g̜W3	JeILfdt1A^.<IP*K{֒TDJt@P*y!1l�0709"<'1
    Abr	
    ϡ
    nfO$~)Ywcۻ)X7[#
    EĔW;6A{3[nQHm$[BQFR
    !@.&:%&Abƍ+k|683/EN/yN
    0
    / @LCm25]SZi1kY?=?-uuZۚߚ>\o3`"=~	d	>jROޥ[GD{KD^.2EqFTyTg&Eo!oV&+tqwwƄTpL|_e@2S͢LH"i_/&
    K]rKE`T0`x
    E2!iVN`8YQټejjܘ^-[�?2R1ʑCb`jZE0yݕDt`n@Z5&>t7XxmH
    Ʉ'1'Q&Z
    QJS�L=&2D~۪R4g灻`%Xwg`>r0g%�SL=OdC#DePVw:cgX!^'NQg:J&WLh|B돫E~u{7>DveP('<Q}\Ī&"?uN)w/^3EwV,7f1I"0ekFfKILF
    R{ȬV}rB^@50ї"${PQӲs<ٷe;V$;~HcIeT�>`&R3.XL$"x6!գObtn͠";LS5R=�!ye);YUL=V�-C0qڍi~
    2�[xÊB:J+M}?~D# ?m~n+E>_[=D2cb8"c)	%hl@6!9'U:АN9U:?]4`Oy'	W@jSq,QL,?
    beB"/<YaeELC1S=f.4F؟8uilxQP3m'�0գi_>p,u{1Z uA'P%dyJՔ\|FPq]vʄWVVmh&v*S<(IhlOSVx._.ƆR((Np`�oG9c?gdw8s"F6J's: kyTtj.j)5{;J`EA"|fͅ+XVvDȨ5-꧶Z8s<z
    L?=&ʃP	oU<u++7J?N_EA}eGp=w|+Cɛ?f3?}AP<aȏyG%VQ\EOл[xQPo7x\9.\fBђǟB`+d{bEE8*5%	 :8xPWz\Rv/
    h{{`AMU)�z${!4G[{x4XM%~̳ǟV?0~M0N_fEnEAQ�mܪ7o�s5scfZ\0Ӆ>tZ)0+*x0+*6YVYVL^mX
    &Lm
    
    f
    fP܆U`.'*p/=-W\y'CV|
    \ᗃbHRS&tӷvt&'Z>0˂YŃɇO39۫}}nR!.Eܖ)?o_]Fw)rPy0+C֋"C$ZR[rImT$܉BqLM/.iroˆޣ2m۷ݑܥ+,e	G.^3ۇe5WD0-#W(QTƄ,Ʌ(y@+.0xˢM"*.U2}ﯮB^5H=Vy^ZQȧAʇ)a%$x%DIHh(2	9[YY-JydѮ"NPvyK]&d|ϠA0We2I4$XWڼf(g4Z)B`r	I3YfZ/Ұt8L/ɐ3@~$(DgBnUիvE]L|Qg[3~|{Cv<<O*jXN &r4Ek`JjJir^!ɥ/qEs�dѮ VG.
    Q$RM.3xkO	/T2m}2[ϓ
    ђU3ih!%֊\@d(<L
    biv9вY
    &"4\Wd0ѽ``Т4L++``0=-,P^27W&OŤ%d`"%	ˆdjK0g++0(\/qEV1@&3)oe9-QNoepM1ɝ|0K3-Lv>cTM^Hga&?Xoyt%pK 3veI6w%	M"K'LXh41Pj"㳿\1s`vwt�SQXleɦ,sH^L&!qIKf	iK\))y y$*|D!J(I,4*1r41㳿X1s`m{w=9{T(,`Tt^E.i0D(.KHrJb\/R&󟔾A
    2hWVs'	Q2GMBdq/S?.?~x<Y5ⲲX
    aϭ`Y 2k_[By4Lėn9`V6zw]<0W
    f5׬`}rQU0
    G͟eUEUlx4YZՕ`V`V0U`V0U0+RـP斷Ll)kn[Y`/y`[shMK`͟_<tha)R9$*wDIMX\/
    ޼Y(Kbbpg$uA>`Mnʔ%/.ƽ|xXaw`BБNl#N
    C&	J.(ILPIziլ,�DTݞ)K^"b:&{wlaw`B�!*KDHHJjЪ"$eu,W.$'*Vhw{V,yI6*>%07*.ߥKhT*'b#IzA&䡒gЄ`=YBzF=x
    4Ż=W+SġhJs'2o�&(R`Nkiʉ&ɵIJuOj㚒n(yxH‘<	Z%윍{	M9خ
    &-5~S`BB%`BAa>
    Lv#y2eKL>$0M2	Lі**[~VKH\b@&kf+h1.-dJҸW877]f=0^>Ve	I%0c+EIj %IEQ\д4-j)LY򒋁^Gs`H'Id$0ź|<BG1_		K8P8q	>ɳ$$Q"$&=YYɨ&!wV,yiYS¸W4]w`xXC$]yp##?
    <0qt.|R9(
    `B 1BEkNhx0Βd(j
    DLY"0$07
    fbq!)>'ɐ'>j9K֡ZRBD\jΣҪ߲U	L~
    LO@AV
    A4C)Qd(  F$iZ(+Y>~{LeG7e/A G2愸\B6ʅ̀`ժˀ#q\yd`wL2zawO@(lLo|Z|0_Sks2ߢ`RPVGDȍ\Yy+[BaAj	ã}<y:&4BEFwMvbD *0U0?ъI̔y8{S.Ffp"L!rYy/_/_‡&`ƜL+=kN?`9P.3fmpnFx?8J(ښU4N"?%!%Ъ\Z`АL$%iw_k)?RfK(W9 ѭ3T$=M'Ҋ6;@LFSb#}odxv&#RqsFļ}Ì4(>Mu>5[Cbӗi<imO	@L;(JW^OYm6Ƃ�騯tݍȫ(Yy9N&Tg>c\A�tW:RVQVk/ę9gn2XvǢ.ݍ˟x:e2)|nJ2�Y
    .αKWwc"L$y+jCͬ~%UC̟kp׵tWKKfSLhMO@Lٮ(䫧8;g	 &(n1X4L41ϻ�bۯIY_}3{,7�)ڱX'AwwcEd$p!K�T+cNՓvnBc0w
    QVz'pIJQKL鬞`??sՓ�bBLTO7U��1!&/1/AL�� vkCjp;&QbFqc&>�Q4ƐdNA$  u.ZzȨa0a0aaaa			e
    =8ػCb{=xE{K&ӐeH;7+C"$nU2(xf,JǴ2$$H9gp*210ҔEi
    yYjv`7qdFVob6-YrhJp-y6QK'pweN84x3vQLSN7OvaNՄO%6`lGǻr0ԤlN\;IfY`
    +=V1Jqf\0Un6||\8T`Mva'LIr
    	dW�(y[IDJWa$eYf(�`@'
    0LBDjSa^iT?YYQy_W|*pY)3MaJDRDa^jT^ǏϏ1˒8?}a^L)AyT�ڎ	&"!
    sPLfp8`�sj�$�5t9݂df^R@ڤǁe1o.-wL[EZG6tKҺ,R_OIe%`0ǫ,aFv
    l:,�̙N >6Ӊ|d6Xv7]
    F(/EձtM7aIv.KDZw˅}ݞ0=֋V2eߏd3OCŲA	#Yz3J[a"00*1t5LD1&RԷj2%GzWL|hF&dG?zQ]<GQj0 5x0:M0]s|	bfe˵iI$pZWGaRHuSs>{e櫒H1~4{Np+e:L]~ítC`NKVb}$~z8д|˳,}t9BBf
    j@P00	v,_6?6üERf
    H"V0oiqS
    `[Y
    r5G6bv�S:VUL{tͫUb+4i$Qy1%xKbqw˟w4t9Y A&FUaRT\KvO`Ikj@
    ?Rkm	a|%S~~:LTs`6<ߺd%Q
    �S{tF[\b)]ldu2<__O0`[}-mā@+[
    LEXlzhSytII&E)IO`]`/`.l6}C{LMLח0&SlӁ
    ҶU30˶TxLI̴=`H|8ݞ`,WLD|H|s�^.|*7Lmuuٱ:.ІhTtmK@o*4T`i9hx28sZ1l<F!)6o0YjNOY0ԙR-6&o\*_ІB {:m 
    d
    aNo0cW&&<(]}.{R_Mΰ& L& L& L& L@ L@tH���Ah4Gŭ^L�nL�}:&���a_H$;A�\Lu�m	��`
    Л"9T7`Sk&����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/ubu-install-8-success.png�����������������������������������0000644�0000000�0000000�00000024171�11773544727�022625� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR��O��(���v�#��PLTE����	
    '!$78��'''/00777s'z,{2|*4G??@ 5}9DXK��L[��UY--k��y��y,(x0,GGGIKQOPQUW[AKaHRgX\fT^p^agXbu{XZgghglunqwvwx/6:"?DC)K"H2E6V%L*U.[5[1^6l8c7u8{FVA`MzUcFgCkC|KrPmWwTwir`ry}q{c|`|Vz99BS~~iiliyw|tEYYgfqv}wԉ�	 *+##;;
     $(+!6,97$%1$66C9NOyzgkFCXUKFQHbZ}++mfphys*2.7?FYGSiqcwXczςъljӌіđ͒ԫ̦۶¼èܽȼٳ΂ÛҔŭζۿ˭ôސ؆ܖ+.2*w��%7IDATx^�0@?\p=R됆CZgq�8[`#0
    p+:I`L/~b\'U>$oj
    Σ{G`C܆.0a'Xl,,rI]B4``:AN!˔j؀l6g�Qxjb3i%7[aWךl+|''R�eӚDUUK:#=MJ)Uu�l2!z=2t'~إc
    .7^61v}mC$@5*E "KkS3DA"IHׅRJZҴ.V/z:L8any<_;|sZ_lzإca 
    V%mdatz-d.뱐	KNgk3;c!
    
    @o1c?�mִDA_N|Y_b<81{K(0oClJn]]bwB8WPLz|Ǜ?fN>QrJ>qD>궟oUQrw5CqC
    ,(T5ǹf1r_.v A p
    j*ҋ>aKEDLg�
    ݴt'&}0s{
    !Dj?j&>o?_;"ӈ9�:uinmԿm2,r4��4ga=* \4ChN[k?z7DD.Uӊ'DWve:N*9KD� �W@
    A
    Ą^W
    ocإC�@/L'
    
    0sĻWtDЎO?>O8$���`ֿÓ^fI8;u0Q8YTqTy,O6Z@I%dSZP"}J~~c3Dx"<Dx"<D
    O'Sc'>=cVTwaNUZ*RwV4TlW"<8jל@u`*GxE5î-Ǿ,vފ:9by�|xsT3nH
    pcO6FPsVxt0:N)LD9O<UBxfO6Qf@)`0K96 sW
    ^6Ctua&!/
    2贇l*ԫ[~z<:m{^^KI'TI �iUryU>H\REVy<İ'v=Vpahp(F){I\t.�UhFiBй!0"f-]#SSDzN~7Xb;Di&jM@l9zaO}~q<zԁXY+_+b�*	Qsg 6v{+UuUAees3L</!VŁQ3UɚqUɝn-	U^|rʧ㶞ܚrI:2ԉp]lSY@Pʰ/s1h`"-ԓ|{+ۛAdoc8[r|kT9}`jo)e짟[I>qB=M1[}lػCVSع0"CAUeo,[.vOzo-PG%$NB"xB&WsJ!ktH&ov�Ag9|s1h`BEГ!K"BOvv@Zw[ۥsXxʪ Zi,W
    ;"d0>$,!OO;ṷ0v|Q[AaAAO}22U�zb8|g=3ģ'rLyG
    'կ'@ZP0�Uȯ6L$L=_,]|uTd0E걆abw޵eLz*[ׄ}aO[@m N]s͏֞x́'rkXU^Nw}ܛQy
    '8�6�ahK<T>^^].e*;dyy/XkR!c7,
    J{A9mʽ|sY؎iguflU`vع0{G[FjNJ�z*>z|;eKOOEXlerȀO펧orl\=z*0Q tΆm�>=�U{4WOhGӭ'+.5yudfj\1iNkQZA{a-#JMW\slNr|X~gvΆm ~=iC=H{5~=fu0Z:p$Ԯe)R $Ra*ʃ;'R&0DXoq=[WINbm{ko
    :仹GO=s9=A1==z%z
    COWPcOB]{t=iv	ГMOR[�zJ-&�S=M�zMΔGByXn =#ʑ|GJpm�=u&cJ~OXf&SmK]Pp'źLNEO	Smu\Os=Tc<AfIG|,1 |.y\Nj}G`n]aA=1d"Ą̵x{vHϧ[tFN0ke1Nt*?䔎6]goEhMIپ]ɩENwF$V/jk6eu7f_@R5G'�	�z靽W	}�-Kz~K9tm܆.YCs.F_ڡ#TZ
    ,g@cӔy?aQ_O'p=idm'=gma\OKOHW#¸qp2lt`9S>8Uoes+.d3L$Pk	9G=iճa]@5LCcY`g#eax�Vz
    UA5#	ĞsH̒MFsnQR<,rB+<.!T)DM�jSiRm躺aR7~l1&9:W`S~Vn.˔&5H(a#
    "C"Fܜ/OO)DCx�lizC26LCƏzbQ-F�ÔXf=G1=Qk-^2bWW1һ:~C"=E_:EH>t!o/md!xI7LCƏzbQ-F�X&?fO=2bU.J`cY=с^3:g98TNQ$ {HYI=ifX=ilhplL1ƸXfw=ׇ/�.b"6zaln{piq'PӾ'cf]FLyDg`t
    ~Y#sS]w6HV6~_L'6|{R*D~繿[4d8tSxvJO딘rz:0*T>Пq_T$Z!q=	ȓ!S^2Y=گ—)7
    v6X|ѩ�XsyN+=SbtzFN@HdTE/VOT`g#e~V&۽~Cqj:O]PzZ`>'v[7�U=lS37sszC&=ȻCt0'V4dD`䈂*le׎M� 9C2olR9mU<Ӿi=%)z|'=z='@O	=zف���@jQ47q+Eo(0L@.{13&vKE不>xaT*X߷l%Fy~z$K|<$%%%yyDD�i%
    mᐔ{r3(eI.m 䄛[yHOVT_='CJTN7T; 䮵J	p!$!Fo_ɁoKm[Sdd�
    I$; d[I@“!Bo˓l2~R	SGw&'rњ�*%@9!5!,ӾKOjX\A	@__=9{T'S88UHkt8@hcF8VsW![*+O7GzoM;|3“rzA@VZ%OTZ4 MWQz\(v?6")dD
    ،�D>o-OGx2DyETniCmWXJ\5*yjIv<pz݆*|j;|&(
    cwI`COsI`Ɂ	yh=N<i2A@L([6		ͬ)}-N\?)<i@Q<u_0)GGG?v|y=~]j&-uI�8:SO\#E=nGxu=v5?Ihɐ~dp��P@髣'/8;9޲@vJ(!O$5<) yMh'b^6R9#O8=ŷg7|B~[Tf<<ӟdd+2a&J@r gqzÛ'xlSvw[i"O_իW7Ӽ"9u<Z߷绦:5s<E񆧧tLf-KSKϞQQ~SSg$('飇t'1OIxZj}�E+6_dZpgiW^i߿=.v g	53;@=Gfɶi{?n&<ՠ6Kԭį^>>"]̀`bN(F=PdiSVr@xO
    oFj8h69 ^Òڑ)J= pihy:ow{}zG֊.K"uIe)Y'!9-t%aE穤h#
    *Xf}ZX♻A>Ox#aLc~rX.
    n{IK)5^j?GS|N}>?q'2%*rvt!1EMIGA\4?8UEc8H8A/hY35
    =FK'	hY?
    N^Ońt 5t&ڤ1<-
    9[2"T+:飋1&qlR
    }7׭,&BѭKݨ@\Љ(͈a`CE6D{x	=DZ[N{aJNwOXWV:*GRRO5w	#)Aiq-$`󝍍\0['O݂[?i(]gFKRGO$i<a$48h6!Nh橤)51ߟ!O OTiJx))$,Dp~g~&hM	FOh9FB$0MzyJlK)/XP,UN>a@ȓ˯l;J	y,<Mx	41`كPqlR
    }7a$֎z)9Z'|i!?_~h,؏ OBi#iy,9~2A_afqb<E	J)J)J)ysip6|@D�_e|?(jᮠ6rQDE܉^_X(jf0g殜NLWj]/{uG:Iqn'I$<]S"I$<'$<'kf/Ӗ1u.mVJx7a[3RhkEGQ
    5yZlz c`�<Jx"x=<wlZ[صa-x.[D 4Dj,O:N}hCR%<ygw478pԠ)
    CUEVpLBpb=TX	O_w<@!t|zrh"z"pV@b%<տ+E9O=)i.QxdQ*�iwg3	BSȐn8qvUa&Dl
    v	!A̯ǹJxw<uu'uZЙV`-,u$<yBK'zZIn'z<]�J@Dsa3|悟J>:.ؑ2pR@瘥6!&-�-?	O3x8WjSg&{#}9QAh7	Osh*0nrҶZi]슡]e5mE<GWJ$<տ$	O_Կ]$|wǴD£}Y4WADE@7%UfO:$d?w'''HNՔ;Tn;*`G+UTE{/ߝoB0A_0q4�QUMeG׿y/ݏdF0YU[rolGp|lp\|T3U	FoE׿Ԛ`Tv5=vw'/5<
    ;Tb?
    :682
    5_m.ڇ}pJ|p	hI^j{@iZ7Y?b,ixɘ!቎IwMyr@x=H`0cq-D@$yA
    P4&47ѓǎAMIxRi߾xB1db<K9>`Ur'CAn<i;fb<D[bz/8Df�N8绫yvjv|YHBE
    
    3;_ <u`×ʗ?<q;fR
    
    4qjC~g
    Oen.mCoPxr[p{I$D-Hx	O"_v�X?&H"?'tѰKD�� _yE
    e'		'|§W		|'|		|Zv�(/˜H�wroTWi?PWo8]O]:�(ZPqfqЩn!$|xAjXSE$*jO#1V+O'.�0d#T1\~\T+諕?
    {u0EQ4AU0Rqm7S"䨷nH`A~a\Ȋ#}a@|>4tZ^Oκ˯|=%$:'׈�p~~�^
    #
    .Z/ґW!J)'	Q/�ޤ:Y/	S9lZcnLF))~IH+<+]vr29<u\%_HÑꖞhW@G)�ue[O]Up8Fs.엷3ո 1tthG9z!('K0Wb̂>C^@^tА}2L.T4-CS_]Pk4"}\YAtO"@&
    b/ R=$PX
    H<5@]ӥsl.z^M{_+cV0Ÿ!lj=ӻv].dvAef3[X(:2��G0^:lLZY|5cu"깪2i0PF9	{Eɱ՞RFפ8.xR7٫Yz`i{eo5@9\-XxJGQtY��Q9uӗL:d.DJk!picӀX,ac+8RiVC#"O̸CDF77/ˌ"%ILVjb'Kb5H-PYAF4Ҥoţ1%xgʡQ
    S{jJW2OZ	pxg,ؿJtb0v{։SXV9O#8L;pd;U'ɣQS1
    �Eʵܮ'uYh@ȓ?c5I~:ϻ̛58֏C1�?y
    (&yOaOI"Z'Nk8ϻY6t|<�e5Eqyzɻ!w82FnJ?O|tJ%HS$Z[�R'UcP:?gSШӸJ$P|:Ͷ,;oOϠ2Wrv<y3q[�To<
    yJ!)a1$JHIpʱQC+-HZPQ>l)snpeN8G3ϰ2Ws4Sr?7*!]_[$uLdm<a_ޔ.1w8:<p488(ۧWV5Os*ӹo9�X<65-+1͓Q"MҞ^*F׺OҖru"�:<�4O͛;{(Of3SbW?%p˗Mm+ȟӴabs/t�P4ڨ)g"6T'cj꫁];4�a(YPݙmPMjPov,j~{XMXʦVܡ
    @nRyɭ|K$7AUSC.|
    OםhcqZNUqt0DCVٻC��a,jf7
    =�zBO	=z='􄞎8$���`?%GK&�� [@@t3}?9m��@&aW?OS_*�p5vL����IENDB`�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/mac-install-2-information.png�������������������������������0000644�0000000�0000000�00000055405�11773544727�023445� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR��n�����1:��PLTE
    
    
    ! #!'$+++.T4l1=pB{=EM/RvSXZ/B>-A>4](*[=&j
    gtn!c2
    e6s$r:t=e(%r-/r.0~57NI7zByG"LLLO[oZdnb\Da^QxTUskPeeeelvhp{wkb{wfxxx��8&8PL$Z$X/c4kXk5zS[IpJxpzB|:;XvhOQ\p`up}!.8(*:135'(IS2p4NS"_5Z#_8l.k9`:q=HJ]SDFUNWXwX{brqWXuJrm')01?@p1|Hz{dfQQpp/]fyfthtPqN{Ĝdž6γж(9(̎QeԋiݕiݜyƵLDzgĺuױ|GcL[DXT]ov*3<EhEYKTGVHWoQs̍奸ːԯ֚̀ǪŶŻݢƼýѸØŋɕуљĥ·̦ϷѪӷڍݥظ윛]��WIDATx^
    � :rqg\AA218&�A)WLyŒ2"5+cơ8�%o(B[B+(:W	r8[h/G2]
    J9xQ*"n/5\ːe hLY ,Ddߓ$nm@ؔ6՜*KJEr'w+)@
    k-[=ֲkg^ٹov+ϒ{MIBoܫ/<7D?V+I{4!h:=FW2es+P8	xOGel~8TqLLjHWD)T�z<ޔ[[i;Ηfe?ƍ1m[֙yr+BM˸Hnm{ǮoGRhΰ}-S-e�Q§(��/	C+7@a!12qDLZ~N
    Ea�>]3tDS>L'K8HC騖6͐.ڱ |!~C:YF/`>g($}W_̂:ve6<Rt:Z�"G	9 
    yP)XE(>
    dvipU$E&Y̓Wps<?o~|lfoXAdBfP8Z&gж~Q!FiP}:n(qEñ+RrYzKެp%[
    7ޑMWL"i:HW_4"Mn˃b.}y*۩/kn&/wv^M&<$/Lvd
    \)nl]|9J$KG#wcnl^cn&"P57(ŬZup~mYou9]JnGu	׍`Pr[i"
    'EIr0vBz"+]٥ca0
    Yvvl�9x.w'/	 8Gyقjx<b*guN%IP!q<_ܫH`RI@
    Ђ\21͚ٙ)iRi(F"Ρe_KF),K_RY%'s1ˈ[9ف���v&-|q=cώq O^y"
    Ad`U?=(8x9ss朹9ssV朹9ssܜ9ss;-usl-ւVn9sޟ_nw`?nuw?%s*(%9Đ4rIWJAiE̤-m~@\Z	I4i JgBWtI12".4]NHo[`kAg `jF`	)%thR_<R~R'cA0$gBEjԆ 4A0skR0#MIl)I7]n~o~NBj[`⣸۔F.7d>qfnA>y|[#"䖇
    Kp3
    Fu㖴-q/ȂXgH)ȑ>%0$u nv*r%pAݖSZ	n4:ͥyh=|rs1gnܜ37gnΙ37͙37M؁c���`ۈÈn$릞pkX,m%y5'".)#GQuCCŇaeҩRj_U53=q{N*,ff",'nϩS|76>q;1ᯯ7AӦsd>-;<
    Im[<$@B:Br-\ݠA!$Mv-A)s3܇BR긖�uj23\H3(Ca}#B3� !8ByNa&ff\9TɒSԭ3J_qc!;F+]9s̹nhw>l!eNk'I	sM0dC)
    nZQd*21%P*"c(o܈Wܤ%bdnMR1mt)`ie츳+ #:SGQΆIÍYDHZ**ĜXU #eEAz%n.BAzA;ݽj*q�'G3Ndv!prІ�	C�>;9ء3,|tinUG,9FyWnokfT
    1gWD>HDp
    &"Kǭ_[3q"foS!x][ac H:nh6%4q<.no▉2-[gf%Jsb> DDpLq崽&60mSŧױA6:+]\Ϭ2q+h
    bno&�`Jh
    v10?F'n("BeA�5ј2}*n3=n^B0�#@Љw�Nڂ書1Sl%�\_rwꟚ?("jm,EگkN1Wjse܋J7*ſo]TV2?,!ߦNXuP	6U*%RUDat^NaS'n=Zaeb'EZP؛fdlh`PK~@xդm
    uM&/['n3ZQš%h8!(GciʸutjrF"ɑ4y:?MPH6v،qgd$GFt|.֠H0HK}(c:6jrFII%'B
    q#bM]Aőqp5v،5))qÁt\r6BBtX[dd0x5+nݸ3)#E2qIi^r=nnώ	b#u-.2=xAꝡnܙG"qtUH!ZsH7ŠWtOE@$7@�H!˓#u#1q	)ۥw	u4Τu_R$'M'sN&n�b%AZHY$攍hjT2<}"Dl0'a@yb4U5&AQ*Dv[WR0B>K6Di ~g:&7<\U74qOV@wyͤ&f-&s{>v^ݒהۙ1GICL*;Z�rE"4!FVp+5q'n9Rf5C+essk=q18v`
    px7wnD,K-r% >ZWOQ1VUgqF-NԳ&O~^JÀ]b#W"[ЄFt7޾{y{L"ye˗/_yU.bf wɏBޖ(ۊs#pJ*]#coJ۷޿͟߻^zO|O?FnHy(`ҘwɏbWܽ-1긭27ȕ`Ș9Sԙayڮmwnm@Mʕw]AڃUJ}UPr+J/@n)Q`Zx̄uheO/]|?DV)@}uVPj]KpypSA&ǔW#nH.=GlH`<	*ygZ
    5QYGo`:t-
    ̙a0Z$PPqFCȵG-O"i�n[)ːHxyB$ԽVĵqzƙ!̽"S3gqmptZMZ!*Exvƍup3?Up#PGNnWbF7rɵGȘ-)pt|d;DlzI
    n&QZg~qu:+Ms]n&k5\{uM7ܾ7)�kq:꾛"ˢe\KTܰGyԲIL讇4]i>&naねD;Yfz˖d74KcXn	&Chb@c7M40jD	Q�_ԚB LۭC[$
    jEF@$p{KϭR}�818+S-Ϗ۶ZmB'6ycۙC۩4M$Mjx�8!kokўDԋS$DAﺉ
    "-}AU � E\m74$59F
    #p6nqyx"Q}U(M7WHW
    Iu=%l$og 53DKD譫j
    mU,{l1]dn!M�|܌qm3 ]ز1̲^
    Zk@ pIoJ:ae*X,3qpK&V!
    Q՞Lmh:l'q"#>8N|�͋SZWpXLgnТ25Wjq07CL[K뉛M"Ǔ
    j26;L}-ƌF7@
    EF|s5V(V*
    _QYa7݅nŎ
    cŗp̸*Ƹ-+n�x	Hez154č[}AVwzkku)NY^>f)N5G:-UJϵqr�5IP#yۤ?nw/nqZn}pmǭ~�naSW쥦vΟ3}3}n[?ܬnk0OZvχ[-ᆴǍ!rngps=ornRa׺䇩C:Gŀ*N
    Ӹ2.i/5/O?-[}vԛ2ֽw>6?]~|.ncK"oO#.b@�AθrGrHBAIa֡2v7pagtA>=(R;1'<]^`[m3a=𒯡"Ku6h߯wD[#�a&)zBPVzCr`?Ěs+|H0R
    ~Dp}5cCV17`y12Ђ	'Sn40hrsIMPBZKӔ={Lr~*qk@.kOUDԫH%?rW[IQz,"\FqSZ�1'4 h�^X9դGw4f(\UEEr�.+5\9$oFAhGčЂ	$mYhn40Bp&5<1{FI粸!9n>[U3nu5GuU<n{ҫJ<<76pCV1	n8dHޮb$1'wB8 hMjxBZc%mL
    J6$_RU-bTA	!eJ~pIq p!2 -FB8y/�qR96Nc16eџLivյ2mGI7xpr_ppN=gs{MΏTUiTmSջpEֶu=VX*hR/mkUWjv5%ͤq3nKܱ3
    8}XY5NA9ޗ/wuEfni-ENq-RPO訃ff(,W4~7r47ٸEڔWN�vJ3yq#~s2ԣ$Ɉ}wͧ$|h/)R'nhqQ"me1k*s}TU?	BS~-l|N݌FtsmaO`7;IGp0EB
    "Wpd%SXؗ7
    bm͹+.RqE>YSch]Kd>͵7͹.ڎ>ɨlX6~JRS[v%^[ENQА=]Z;){K8}}pǰR#IW (%ObVTeٗp�ws:ʥgp` A0oՎܞ}1ph.R7$(ɇ)w7p1~�IIWSwOb^wj[71Amsܦy&fo	nO^[_S
    eJ;AӡyYDEb (~𫰓bC{|y1 4.P#d
    vy;vO'pt!"`
    ,Rxm仠K8�3nhE>6yP^nAfiܨQ{7Gt{:*}vqA=]
    �0
    Е>$,Ծ.a۴+Cx`GLoxT-"Ҁ`o/bj,,2ݞ6čL
    !Ct݄�䴀)[|tȏMR%BBɃRhXˍ 79E<-s,Tw7u
    #M,_䖌i[Ǵ+,c49qEuTVSp{m`])Nh#
    w;tݛ�l'vY:nk۵%njj@Zq[Vۊw|ܞw[qdL߾)tn&]wMTt<n'uss{{'Q3t޿G7wG7:`vs4VUͤqwzW_ήm#
    C+]/݋J06IJhA[t*;{l$B-U֦眙X7KGclrp.oHs  mU4Dv4,MSqg꙾"ld F
    6^e9pk6}[iS[
    pPA4*phqo5--Y8x;;v jXw:`
    !S2h r/AּH2]e3-5{јHVOJ
    :~*U0Ѵ]7m	6/_>ݪ˚C΍N$z+sӈޤu["p<ĸ6޲KdZ]<m8p]x9#n0]iaED s3'3
    m?`>>xw]-}oS-i.'nydDM7h4Nx|QxEt}>&N'ڣx5�6wǵt폪UvWN_!Klv!Iu
    =x[r2g`JWї0qB:
    p!D.0pp=6e<p9Q&XBMSv&T$Y]̲
    a̱Į]Npfn˧B6#GS 0Jd<3].5<n!Ԙ9dVk>`4`t/sKc6t4QpźqHI{#/rB-DJA2_!nh=2nM0i3o<,1 иnVyWtDs]mnX3ӨƭO)=^غ=7R9O?րXp�ltԦ&Jzb8Z-)9r2g:	U),v7Yϴ\tH 8C5@�O#pY\ڕ%pn#S'\q4hy
    	=`鋄%ɣtzG,91k䔝>d2-k<8~W4Do-pnRR*,<n	9b֒c),Ube]nC G<{`	7xܧ{w$GQA)=1	o#j@\$5ke+FUƳxpKTA%vɄ=;ր^9tԦ&*z]\RYVУq]Nd2̅V!h@G%Ø{rY<E'rI<M07Smո~1}{Cߓ{DvZ&ƿ
    7C<n=E+J(m9yJ5bʥ5n	Fg
    TV17dZ.kD9Zh+U䑴i밶I\$,~f$Hk?K)3p!t[(iDZ֣7n5]ҌMw9;)"V,M�WFϔ[5njҾ>
    lP>ca[Bä�UVMk욦%.]I:FjHGI2op+toUMw9}P\P}(^о*0wv#gd^Ġ%d 	`nBK4ɝ6i819Щ33QQNqG֐U]jIVlkVoӥ|ࡪyUW`)MхtcL0!s,	ߕıdg07ZM#65|4_T,)1E{Op<V16`ZԀ7.R#r;(n4aJyl~7C0sqjUlσv7,q74]6t$nkt"4Z)`Z6/ָa^F{*r?&d̿`gSֆ�7pK{`,I�6_=kjp#X4ni/'`HmVζK;dzgj}exk䗨nneLCHP+lSP<hL
    6O9iiʚa@?TtSو~›qF9a%;k88q\d|Ca"[=,BX-0~l*yP FzLX&;gz1~]$6
    Y>H+oFvʩ7厃5;.=Ng][$EZ&&hI7GMDx;4{hd{-0`~C-mŀ4cB+h7٩<SU�{cL")
    xGW9jY#N	vBLlBÀۄ=`x(u?a.}TF@(Cdk$܁xmz塖cX5@�LU¦n$mCd
    42{9F;2츄ELsu	N(n(u\:yvh0f!qì&	q7pP FzLPdwVaf[ϸfΧ8d2?f-9'Kvrc
    MH1
    +t f7Y<r}i7ٹ.ڞBܳ:lAP
    [Mj1~o"f螌1<GsLN,B&L;w%蟋<."p!j0f!;a7帑S1@�M1Aa坘AZ*m}aPڳRuOQJz7l@g[hJ-	Ea	An}va.[]DCDk$Cw Fm增ty@D!;
    (@#<&a{]𻁛pPx-*QڨBQF'fg#Kۄc9};g(qP1=Z-,W4{G4{c#+L 9AozKءh޻=ԠW5-D&i+1&t st0&
    f2ר<w8GaǷ؄LY?Ƨi1aPEx?nҦFx30USF�lK2xLgj-1_*n^qB9tp&ZGo[:7פ0hVCn
    n^(J&Qpxng0cMOՌ67BZm�߭M<&x7/TS1qnĊnMh펴m[<o
    ҚcE75qc>g-bGEfs]
    �m:nVr0,p㿈ՀFw(mpYh`:8n0rݐV]l
    Қ4nȐ.	Gnp;ܾ9[N'7niܕ$V8\G	%\IŒ+I55_~n'^m+QmP
    7U~CϤm:@CiSL;LYa;n%V;>X"; WVݢ
    n/%Ƹ
    [(XG
    h-xq2\H
    V)Ak/І[?w�>L?&n&oŪ`b�`76?F9j6̄-Npc638f*E-j**pMwu
    T_Kūi#ܲo`j,8gnlSi-nl?G)hq./+~j<%'D[[w
    n'l0E)m|PV\P7Ut7Qf–[Kn/şm$qvIl4sc8ߑBFn"f.}32VL9d(`m^6\Yjg@Q9\'+//w9k6}{qoG3B)&Y9J`*
    )a`y7jy+f.}"cF۱rgR˵=D0~ZiVOp\(x%ͯ[ku{疤XJ$nS
    <%(-pE
    ,!pX^�ryheſ) {F)k{@0:!v6t< Oō][2,r>޼;ֶ8]b_`p.:h7.F}~uɲ02HFҋ`]]5cYv)2;^LX.~HVHye\!;6j@K?@�n|ͻ҈Zx<Cᆨ}2P)j!{lg{&esat+ڃݷ~7yp$bnZ"(;Z=ٴp	im8ŋ	ܖ8rnMᦢWxZ kuf|@sYcl3g
    MV|\}+w7a[JZț6�nX5]ƄuzvhNEQnހF3ëSmTk˱7�n?{*zw7IYENC]OkffϠ&4P)7fj=Vﶫ'Hb"#p޴~㬝$e}{	j]fT(K5QLWSmJ+^9njQZ"7aAOӟW63lg{&\A=;}+g(L
    ܚ\}a29fWWoNX唋"pNh
    r<#'&BnL4hyCRV*gL[ Fq[@\V5n$GƏl+7)C
    q;1b<ܪªw8n<bԸGůlj<0T;Ѩ2b·_/,1.,mXzJ8IYL4ZU^ywmGMF*7i)ok朡"R[rҍUhd63e~_,Ӹmx{l![R^Blt9}~bH%!woZ^Z"hF
    uWUi͋lewz/^G2q;RyCȸ0nKK$i~=CSLVpZ@W< 5<!˜#яdiQk])r!fNvjLLv<jd{;+H*PzG2f`QGW3j*VfWNOqlng=	k-eDdn.V5.nٗ+w|ܕc_)!FNʽ1"ގq;43ԍB#3×G=ŭpn7aަI8Gz 	ij|>؞pE7NJ1iSC7xvVY;4!鎨c&33=\0!n$m!UVk۶pv
     GWbY?H?8fC̜85{c*E72DTX+::
    33M[MIϦL@vihd3%ln-V_kgvN[1iS&ij�7ZAd/̠ԱWHYj^yݓ3Lq+!3K.nh`yBn~
    '-bV<p3$I5;X
    :
    3#U3\(tB	iӡy�VHٞA'W
    �lcӢڽae�7ۡ7Y;b�7#EuD{̑jݠ{M[1p\z,h
    o]ַ;%T =Xb\0	?{Qے&xT1߭ZXsbL/ڴwWN\EӲSNw>M<a},
    "xzY=/A}%&œ +dU<l&҃ˣЃn/j]qy21T/Rz03~y\b<-G#nNiѴi+f*f-+F=b\il$)m L775m|
    h`(r4fiÛM-W/Bl[Su{6mguL̷nwNjlpBmq,yzdǶwDq}5tDfQ8n¼dK2qsS+Hrj#p"ܸNE6$#!A�7=vD}~kޕ67T|7ݭWkL4nU[ʒH#}A=e),c"XUpw
    (#<
     gC0IX3uPlZ8S1n!�~] C{b!p4pK-XUpwMpċpA
    [Gxov!j*Rn	vA{(@2o4Ll,aT>MQ
    {ZFQ7°
    yVwDjn6807BK%M6a GqV/le{{Ю n2a11Bqg7MrA@F0qC$cuz
    X!Bfl�&a)%qVfph07t|7}WƸƭlYm7<DvBF?A_sy^Mr߬6*
    AM"	nQ!p9f'c'ǹJ	n1ݨ[szfU
    `C$p-7m4ٻ{ 49	7@Y7DGy@!W�"T!qD	L
    ~	XNcS4ԏvU87iyΨ߹qs7-FQ-.y[*n:p
    bnMέskUan_$zߍ-o[[�4WL	PXnzܚsbdJnqP!׆9n)-nz2#~XGSSi]/;swymMZ#m[m6JVS|\0s;,hܰ6ɲ7qnRz)tڨ
    MnK
    R7V}B5M6FnS8tX*nXqk5s%�,lmg7(2sL[5nz봽'S܂"?Nе/�m1p`D_>KNpɰ7jSgyr_eӋLqAFnu~j+춒8l
    7{WIE?&:2a>dnf,݈SDݓ3f1+|_oTwT1ЇPu{P>ggPL2q%_&/%2]cRd[w<o?NWS(}1Vim6Dv_n߭;邮rSr6)UXĔДcOj1Y-F5[Z-c!=!cMRF)(Ǝ~_K2zr
    xMn&w9UނB4eTBc_-b!/EQIRKQB"m+x|Hk~?ݺaGϺ`-8)-DS@QOi$Y\w*F-3R㺝2DIGi!7JAnĽwO*ˢ9@<%!|4ˊC$7f*TdŐ*EɎj#KȍRj q=n)UF9tA-$7OTDSVKi$Z\Ȑ%j
    9k1#!
    *j q݆aeO^	gx2[ 70A+BcCY-OlarK-.lcŅZn3aqBnrj q}݆/
    H#_ ~[(~ۃ)-DSV=ИpLl!R"CwRQnr5~n×۳
    6*x)
    Zhb1ؒZ\Hexj7W@^{
    YnɺHSs/7KҋF݈t݆/7z
    ,t+wl5JR~w8&q˗sa_9-Tkl&k弎M'[P喑R[ǭ9f"oE"_yݮEnY,"BVrK6LYr2{;>耍~?^(#<%
    8B`Phu|`۱
    r4E(lmqF(`wkc/o5[Rj|QaDו
    8B`
    av֎,pb;mr4"l|sNmEuqiD<NrÈ,{G!.v`[ "n4?#ZQbw�Nz([4_=d>Ȳz�Hnp\a("@hA[(҈Ulm~(nF<.(%a
    8B`
    av֎,pb;Anafx+ʰO-8:ښOCK,ḟY^W3{*fjiь0HkI; 7Ј%#TjB/7 [ix}1u}Fr	<>u+("mX'v)a6̐rXX{`[n<#-7.̉
    8p@I}`Y]R/@ѐP,:>h1
    4hÌQ1䶻v0YnWrNU'-X]its|`E
    ;:8ݳ~ރqգܞ'^	9\͇ѽ+J(޻Ǐ?OnACpϷI#Q(2Tآ?{oV%75&?܀
    M٣R}wmwo)MXmVnr{岭ôi0bѝԣ|mh7%O͏{nr[kdh&+vqʾw`hsȊTx-:Mܴi7EԻyrܪ߹}o+_n_2mDat7~C7A.,&UM 	
    5eT6)t!gdZi@.b;`p@F"䄷YBQ~v[W}m`4z*u{U~f=pF薠CgbIbU?%?W\BńcgpW*FA
    L"kaa/ql	op{v|@cOĵKMĦpEN@fΈlW`Qz&veZG~J~0b1䶁30=+TT0k/K#u=ilw'n\/
    o<e{> tMDΔ1v27I%X7g,T`Oq)&Cn8b_\qlčy!n"~UJRV�>o"f`7BiN+KLܺtKBdے8R_Y|%pm:q=+t0k?ĭv;"􁸽Q"Euo"j`7E.3}gn	:|Pp
    =׮U*;p2b1䶁3,]y&Wf8nW7>nÈ�qo?|Ӕ@'qc.%zQtBY3B>(~8nTXBńcmg]?cA
    qy|nwD�o
    KVI@LN-A njMggn	:|Pz&C)UbQa	!_;
    z&Wfxk"n
    /SMާ6eV~f.a^c2
    "GUWL0<CfI%536[|o-/pxԇȄɸsf|OD7!yQ,}߭|I+lj7}bz#X>?_f%iCq=ފ3B.7e95M*="q[~.o!oygYY6~**<"U@$l$v+j"UPɷp|OW9qsŴjbo(z6f.2[P$mjx(Ck nEBL+k(ɷvO7!7	!hMUИAtMRPD&r7'ŘTJjj ]o­jx7s$gM0s?i	
     	+v`h܁ n"neeCORPIi%3S	znUûy3GT|$ټ:wp{/4tDw߿eā nrF:MALjF4V!nMRkj 7V5[QJA7s,ղIBhb
    ws :xNRPGY
    HMU
    CR<n]v1qJKBOh9,
    p&(p
    O7`nn}�jͅ7DҽH}_CO:v[ąF;҆Vkb"I^'ĭU2kDqt=o8pwhwD|pa[FjrJ$Wi\IrrN
    d
    ֈ!"XIqfV78lV2.40cā(G$I
    `aNbXmV9Kc?p!o͘R(9ty[V`r	ߩ7Sp{3N/Pk{vbQs�uGpnЈ0>t42"=GB`|Vp#rWC
    pcaZ9Z)#2Z܃pdL;&4Rw;6[A>	w䥋.
    Bk>H{ZXs2/yv
    y`�/3?Zn_'mLڞܜ~wCc�0}`$d._ۈHs|aTR
    pd b5Gʼn4ܼ*ϕ9lbܲI3btPfeb;>`'b0XmMAϔK~G@nџsdHcͫȭqtA:b(lr[IrǯmD_\V
    Д)ؠ㏀DZndu{FC3 7Cn_fMn㎍t[XLñ>
    9cBc GD9O7׫˭TCsFrp>~m#"lPnjJdL7x�WFFMs"7.\16egLCl_7&7ڑ`l-,KѭDϔ~GrCrZn|rc9UA:b(l~XHNܖMn#Xqn)7roY,yxj
    1M=C;b^,]aGj?.xy,y5�V"}pM[;e>?wGt=Wu"˭W[[[[.^]n]n]n]nܺܺܺzuuuur֫˭˭˭˭W@SU齷:n$zǩ;}ƈ!V)Ȣ"kW#r^۵3/]p<ad2o.7b0%9⌍~^hbkq[qAJTn.4Nai9)rK9$beJ6	&Ii/lRmq1Tv%Lt<UN9v!;!7Beq[b"L0RL3  8.fc0؅ЮD9u6NHYP[n[|�V±V&#ա)ց0[mq1$d"c"]mQǜ>PqrK9C�]$
    V&#ա)*i[mq1Tv%Ltrc1䆏Yp9ܘRT
    =Rؖ-
    fK3&oL+amNvuCosX(7X]8WT@n0πuȲfr6CbЄEn]	]mnr["7_ҩrN!BHBkŒCw`Ћʮdx&*_b'BmCoTi\yHK{>Pn1i':rwr{d~L{L|Rr% ŚV5u@e򂷿g:B|}|ܛϔV9v|;b‹M+L!UzbB+A>$3[;ŖA/v]KpIKMR+Q4<|ġmiSHGZ1X#Ůp	.ɽzbx)nB˩#e
    ;8o&-r#X20kIk*d[B`u.ܸWOL/Mz9^D|
    0L�)ۇAnd%($wci8ȇhl[AŮp	ƽzbx)	/EOz_}<Vs}F(&LL&6bCd7-!0^ܫ'&<"&k8"o#7@(wXL.dFЋ]\{dR[d|aC\;-X�4�+]`[b
    bp	.ɽjbx)A/Bn2Fˍ0Qn!aw#i8HځKXj"_Jo)`|
    ګˍ0ŷc/^7rk)q<Gt&]n^]nOR1Ir*暈!?L]ةq4KX9列VKjCO7WL/7LS\:A|]n&h"puEW8k
    "Ze0&\YB?B$@D{c^j:j36	p<\YjS!#8j|$  \
    P�?bT{ydڎgeK`"LQ60HprsےL<cJ0TSj`ݔ6$d/vW{yra*Gؖk KmB0HHT
    8
    ˨({ErT&[!TĖ$hr
    dMQȂ	)3u,(
     QZgH~:~bAw˃rk:JM+6-@,aVՉhPy#A
    bJa
    v!Wp
    Q/mGͽ[A�+|
    @ndAڭλk\hXk@k a#R/SgH#$V
    V*ƣ^ێ
    @n 
    m`[,4E!BFp$nuWWV &$!m^GVtٖGeHx+])u`XKzyu0.GW.<`r.wFs.t8^i UR1
    Wr3Q<Qn<vD5甛x.�P.xX0d	#qk۷Qt
    ܐr!7r!7rpǹe̵#ua :
    :*4plv.*�|
    l8C]LZ:Y]J7]HTOtvG{ k1D?x=(?w=&VùZutGmyX3`tG-rpZ1ӍI"
    @A+Ԫ�1k=tݲzd1ɩf<fP;d„m&	w\et+#/B5Ej2X~2s<fPtB.$)ƋA
    T@nT!@}6J tm�DVd*m5~-
    iB
    PeF5ljGKG&)&10xb"y1(爚dZJ>KςA!oRB#c,D`@J^42Ͱ8f!_ݪ$E#1^r3#n	n|)׭#ʻ'CάMb91[Ra#IJRI?o|3T
    JBDcb6$hw"(T̥r/6fmjfaU!1?ư8f(A1@/m3jZC|9R"9+h*6n[ì\$b.η�?#{aq̠gOX1z/3'"1SMTnʐҋpH	MƥlЄ|Vt3} ֪JY:1]ld<ft@P.gQZP',F�ɛn}�(3c<4ֿtlU!Uta{unO1^7t.JP~mV0-ݳy=?X?:1u,>X?B1ZⓌ.ËǛJ,cK.��@}"fH<
    rEǜvHz٥c��`W=YJhnnnnn8&���A hD1bU)=9ȊZX����IENDB`�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/i/openclipart.org_media_files_Selanit_8331.png����������������0000644�0000000�0000000�00000063431�11773544727�026341� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG
    
    ���
    IHDR��.�����ɾ"���PLTE���###$$$%%%TTT___￿aaa!!!???@@@CCC222PPPQQQ   ```///cccooorrrsss"""111SSSρpppAAA000bbbBBBRRRqqq333*��fIDATx^iw8/ջTUW(SI[U3u|"Gba="9
    =cVqTs7sR3䊸$Iycz& =5EIkD¤rKqœ`n9ĥ|LcHW;r>KXsZ‘6*lhOO^>Khz-]#NW{&10	p%۵b�xR#h5ٷ<XR{7;9PqJK諚d\ex+J3p`?=ކa|LX.m\mO]KA<%
    ^#9�Г<Ui)34XK`D0笰?ž-re#R}LTSXVp^V)vq7?sY�#d<Ys�]qy?5$k3ys#
    ʜ b+p$yE)ӄukTM?wHm�qx9ῆ5X2,˄ƸLrk$&$x㕥AF,g<K	[%�,>SSr?9FXJj?S'!$Fϳ[fU}’"�>{ґd5豃[D&d\/	I֚rOR$;'Ϗ%IQ%L$xY2Cv^v!ϣ_%xtP�XE3ðF&1nwr
    u/YϬQh(<˩돤&9&Zz̎=1lHn�5l[%`C	`ϐ0^쥒dž&fʳ'|<�R1<EJx_k
    ;fY`5bwdt5Vl(b1;�|-.w0|Se2J#3z+.o=Kޱ⺃F$_\8Fu1>g6V@큂MB4.	dDa\ٗңS!5y[=GxTM%癍BɏI\
    rlU:0IOYl55}vP<*NZ9l*#]XEĥ
    	x=wExJ, "5ˉr̾{0ySapΛz=fM-'X(rQ\v(oy;p]KI'TRxZ=  p"7R M1NZ~J֎XM=U݃d
     ,�S|sn0񹂙G/P.C|SkD`Ve$]XK%2|䬍_K>V%D=)Vehb.IGsv)ѡˀ;.b\p�ȳK	Iz�xrQPI�~5qꍁ]7'r)BkRʽuVOp+a'g�ٱM`\}XNxpGl>K܂έ$7Y8al
    }d]a:[ ,<}kJ@
    f@䳕GQi.OxyqAA"
    e1q- H&ԋ"ZS"|6
    oPYKbʮKKD,ѕ$t1V<Է2hȽRlQ N\0d(x _Q	G8%c=*g'z]E04<)y"*-8I˿'|oS?{XXl�tfر+Rxe6"yV\
    .p+�
    A
    f1p'A<P?g]dlŻiZҤRea$N*9W]QtȰbzh6ٷ p4YJUTrQwc<Rr9x?zEd$z퓽tNNJ
    ҳ{43xnL[Q]umtߍ-myVԪW�j:ʑ)"%<Iuϫdu,PQ@mݾw(cb%i;l
    V#
    [5q1pK	hnq;
    "Q]NT;e^o3LxIޖ4+QR!t#|~{uo
    f7E
    ]
    2IqB)P|{	>n?NXVet8BV|#V^PX9wḃ�	$#le/w4;e
    @KQbo,:0˂}�M)nyc	FN]M}DLX8LH7Px`9..®U^"tSٻA5jp}^fd?VOw:A/ǥ<iP0MMpำZ2l "-	FR
    r
    rvH=&=
    ;联`kΣMTE|PDY<fTXPYaVrh[y@id]quW&x�Β\Av6}Y"tydsy,݊uUb>`Խ"ʲzE(,󮰲"ƒpA
    3ЏHlsրyƋyM>$+ݟTIM&V5�T6l&
    ۄGLG/eZ6�ܟ9
    ~[�$K2f>IjvԆ=N @}3.'9T^9O@{\
    ,яG̗}NF&jfǃpr	RبrDUSяX#n  ,`wd9
    A8a1@0qٰ|+]a-t尷Ϫ޸ĢXiv܈#�{T'_A$?	烾;Ʈժw2$ji^srgVN)W۾<>I<')뎕:9&W/n c%a~݊DPM$I=pJO$)y
    26e]F7,4?<(5% {d>!dV/H�`+EDiˎb2'ifyop:ޓ,Ml*n9!NҬ�g;}/Is4YS5	U'zzCm̰&9\q-Bx:K_%H7^'aCÜdjŠ9	1FYk^uE qSR[l%z0]GQ#bU78cw+RőE>צX|uV<�zp>KOPp+2Y{!󥍀<,ՙsCgϻuc>V..	?5`emN5ڞ$HtI@HUK$j
    Id͸ذ"("{ZS|F(w9�vόt%ٷ#G	T3TPﺱ)J4>ݷph֝nc2<G!$ٷ{J.쾭uVN	gIIgkr\б _΅Ð=N)|w)~-gbscvpg
    2RXãAo?mރhסv0͕Sg-=szLi>y�3CaIOM)No5m3*\.w惫ti˔+0Sy{B>u~98~Ċq\mpMft!B.	\NI!b=onS-mp!Sst\4(!?ze{>07Pԭ/(b7_KPL!!"؇f.Uֵ6^{ǀty*㇀Eczڡ	.kz){uӫ)t&lΦ
    pTV)V9,qֺlȣ1Y�iOAi_o8 <PB_
    SKdw۝˸D?J�*LSӶ>5c^@])xSA(l QV9HTvs7l0jixk<$
    0gx	%	NzH)'ۈM\_wMy0a\\Ghҝ'{7M3 _Chh%SN.Avl%JڬSdyitz{ZܓAHg)L?ÞHƶK#[zj^:d&
    mo8`R
    >;kѢ.JT\1FqBE˰knKad:a{(2%ƛ8	#BܱIt=.]lsbCrnqgũsxϞ!A%[jU,
    \<Ώ}QyB[}9L$\߶[FǡQ`:l Avg|b(II~`gP$nV/OZGhJ(zWVMFQ
    |8Sg@EȢNB>螼V&�%Ѳ7lFѬ%+I>$y"Ȇ^4t:3x2+]F)Th.:$I"]8ב灱#oG51  %UT*b}K(腜G,dgpDxZ)x_s}򉱁a'#<=PIp@OtG-KgjFw76{Ip>V^Hy1v ń|ؒB$JŸ|<hs`B8}C_�,]UEhZj*6�"fxKYi- ^KͽGvj
    H.y
    βQP$1(xzȧo⺌CƋ<VTqG~ωc~sc�ӛj27L*1'
    N!V~.;TtHZV�
    nm]Ah=^�媂R�(<
    G,Y5($)Rj�酚I&\$n!aB8EROa5@dҗӑQo[�l\#ީY
    \@�I# e:SWK9S~8$#O?=3m?%1\5a~&fEg[M\LY�TLS6WWwZK͈
    Suڀ{uISqq<zf2"fMcOLѤsqX7ڀt&-P+\^v�%o	JGf\k]s0G+2gW],{yn)+tIGd+S$^	::5T}̣L'e2(3K2vT{6aWUhOE:2v%7s{mRsGnԖ;dg@?aa8#%wLޠL$\(";9/y5aRv>E4\;,ߓGcSmYDľzJy_<g^|,Tؠ6Q$ت&phm%d2H6g@0$JKGR^r
    AX
    *C4rwP
    3;B3˒!B8.W4!
    ;LZט�+E.?]ۺPVF^U%7a,=f5Ad$
    'Q.9eͩ5M+^Qދp%Yؿ.lmVWРFɖ㢥7JX3C
    Lt4T2vWP9&xM~^vA\_Ic\NO ΡLbGț/EٰldXAgN<[yj`-Bq YwJfh4̱˜ݞ޴RxT!tv_~siBi1dSmpپIvt=>4.Sh['YH)`MWT8G.X|%P10@O
    D^fgρn)P+WMCۋcL{#mp	L_iǻ쌄L
    Z4FKc)3,5-r-f	s9v^r@J=žEqq=◒`U:
    /@U0h"8}‡-p"A)E<)w2b\|HS28ScqJ
    ޲fOCR3upKzt~�4P<GA)|+EOyę"x62/u{3f=t<!VKyz/rj#xO{l9/$DCj?km29e*bkS�%&.$4 `(o$2JKZzf!Fvebq ܤR+Kگ풿d�3Oe4nF=1vUUq4|[ʎsx%Πe=)3C]BVY>B})jxk6Kvz
    44lUn
    ~xd*NRq{bQjy.Șu\ڜQ$Aa]?e.LǏQƝ6:%ɫ,SO~Gq%uOJ^seS[I=dVglW;5WSXlEЩ$,8'@rI7fmr?.,9)U
    U3pF[&T/&C5l9ۉZ6{|Hm~yW#tRxBm
    Q;?*|b,A!:2q-1aXWv+LI^2ƒVqԤ5T,d|n/xr9v9ÞZVED/%T@%
    � 
    YٝT!;
    1>@C;LoIEVZqNq潳ƲZx8ŶW>n;nNb@A[}+\b%mxhx!\2$z\B]].Viݍ̌n qSFh[~p#gj0W	WtsJbnp?!uh=r(yb<uc+\4-)Һ8rvի+bzX#zhYUr:O؊
    BQNY6ܙ4ތZ|&8z=yGY\k|^J+-Eu^w=ϖޟq_xsy/!UrE)*0g	)Ȣnhق}*\DM
    <r~e)G%V~Dߖ=iqkQlNnL(u򝹫.cE.ƍpQ>=lК-V)-qh�\(gmRtͷ̥ȯ%&zRZ϶AmǏ[\s@g̚-6NΥv�c|nٰW7X5q_I	8ҺE8J9d^`""-xu]2f*#Q&<wq1-G�Y.ey6/W*lqVhG$l̉ҏ#f{XAc0<7öv:5Pr`_؋̼đm0
    b]F-NCo,cfqa7bd
    M%\.9mFjVzL0ǧLGs?,W|S3NBotJYCemBmpcU0X!9'5T2DMD<ط%9oJ^>nQЪD~BB}K%JV5pJGm^	L^&U$	,(X \٧-MJ}s^K.َkPSgǂx˞
    Cu*/rKR$h*PWD@ogBpp~s,\HإUEYh9idzEغQ{gsh$ShpjN{YFn.]В`mg;/c?kmeBϾ]~.cGo�`4	#E'\	BctU4x/
    }l*5Z7o10g*(y
    ڀx^&SSmMI%c1/,I7I6
    `}5.SDC썠o5A+$H`aֱ{KyL:2j~ڋiObd:sd<
    bIg;<žWz-)m-@QM_,?oQyO./wX"odؼ;J+|UPy;uхuۖ	,I4;Bx(YT9㺠X]wybfhe!˜?$LexCmcY6˓}HПy	Ёe$sF=(*u{*,[߳;nF. %>o-73izFoG#dl:œh0_WFJ6	ˎYկԛ?Yj6NJbi;@g
    ٞ2ش0cʣѤEk$ d$ǫS7
    eK0cs>;xN=9֠ELEMikg./,-"Bedҗ橳T!%(QcWKag?_T>yE9sQ5q	1\FRn|F0:k촿9	|)^pxBd[iөNZ69ˀ4QgrL&GcH>kZǬ_u崪RK!ʪm5oȋ	.ݦKɦ鬠)Pîktfqk~Z׏!hC.(B)FT
    UtIm*| ESBdfRߺģL9kSp!l)p%5ZpuqOCb>2/;Ӡ}uVPΜ]DQN]&y;ubƂb&
    lHG&Z6ߢ''E{o[#e;d+\0KIF?d@)\Ww8J.=tvߡ/v
    ,4g0't‘T3@ ??d鐣30Ju6_ռ쬱{ҩlSiL?xmpA6R\AgDO{7-?>+6rs}O\ݖpGl[CN"v01w9JT2ew
    rD5E	\jCRjDt 6L̀#Joy`OlHp^r-;r.]R㚿17
    eQ6]_o:Y<o�|ҍpb	.?-`dX?bwk*^d|6Sf8rcĬVuԄ=-?ʅW.]74XUyKjp᪲$DZPk.7:cɻpzLnxǨr Aׅ\5ޤ8%cpd|o\L/
    ʝFJ1yd&#c3E-m؅P؁+S:y"+XM*PE
    l6RMå	uS|[ˈwe\f/ʃ>Lg{Xw$Y;#�[	@YW|~ț/А%
    yg\Z(�Ee?KȂJoFD?;\fE#;th=n}L:cfÑPGI/-aÿ	{]\X3a=Gܣ5%Ej\nl&3I*7a`w,s؎L)a©@*P\𢐭CQQPQ!eոItyoDwjIȘX<k\P]H=T!{F"fSxz�KFSK+韱BzQ?ջn># [`MZfcP4` �2@u֞bu<|޺tQH)#8e4<Y/r/NE(bcH.%dw=po2QM@˘efl1/eMۓdF~G�2(.٩۾O3
    3
    �2\W5	XwZ@aU]0mFQބyd2(f+?4nlಮXeGŰX5J.>7yx
    ["Q5 /|!^a6'lQ|+"I?8}6Z\%+N7
    .KG+E<YAB΅Zm,Ά
    P͞*A9eoH֑@H[Mj8fW(a;筴˽d.잍xnFkIh\IqzqC ѱ�•r(}
    "@.ubbJvEeh K9.+ΆŽ(-AfBe5MIݗ$Ir?*i2]5En8nOJ`ل2Y1hGZel1}k%
    C')f:P%Ϯ;>옴*%}A?0!ܔ<"j?$pH%’6O"g,)ĺZ$p!;7*k
    Qp!oSypPQMf/v		iV=
    [rRu(ɓ2)mIf첥:CRjtc&awmefEW�]lH	/S^T}hŶ#BG`TIb:nN@Dʵ[L!Z›N&s9Ztb٬8^rKs/D9]Fe╝
    1$|6XOh={xaSlE"̩XMC*H%: 9 |J>`~Xr{_eZwθKYԸlhHI[VbbʢѠN-׎і�el=20A$AdVTϮ|NgHix<G#Χ3�π*H(iRdIP(!*S p`y>|<=h44[M::\߲
    6
    lgI[ZΰncVXgMky@3&05{̮(ۥ0to�("slS[]R
    VHr[:�]JZ;�
    0ݸhѭ=JX|F\n]ڿr\zO%j傋;̹r.$lΙOoMpA[4o|&/1G+h5vv/e㤻ɶGvSyH(2[-{k}I=Ojk0.cK� bpcLW))9P;Gh-1db 5sI^^,NՒEZ�"(dXi7jG"e
    j
    =wpwXK);5waGcoV\'#.Jڗ&
    i.tI0JWXS=#	Ώ&K9ޜJ.8B>cMZrqޝbObrK=yeշuQܬmj{DZ~fs2e'LdG2p?zr7Jo/yp54LZdx}׈G|Yź3Lof̟)Ȼ-	Fc;*su^p�G-Z(|Iw	VCPUb&_iq:} ڑ
    [2f-6˄.Hr(
    Z
    _􁷚jϦ:=цa.}>@c»D\QWTkkUj.lKR`d\䗌.Z(@tq<nOH9R38Fg[SVQE^T3Z<XŬ*\֎ޑ9,=3eobp7VW).lc#W]tȹFN<#^| x>ˏoh٨$pƿ$P"b6SU�V3b^
    ôBI>0ІTPzCD3♆ڦš50UV{~s@(0%Iknӫ&gS @Ä)ԕn
    w
    I;K0΃i{)%==UwUI`lI:!ﱔ<b 'nƲ+柽W36 3r!>MOtKߓ2Lqy$ZPf5uNC|-hOֵCIھLڧOĩ'1ԀW1sx3~Fi	mp!7	}9Zv)N3
    Bo:(NT	y	)C<qWv$SJ>MKN3ۥ5$W4IbGs5بt52C
    ~
    EIn.ݦ	6RPPa^v@u=N< eSycZF
    KQ J2o/]Eಷh׊FD}RW}-	D=
    P, ƅq?	ٹu@OOJ6Mp̈_L1ζ
    Gj<�i.xyCI`!Ȇ`,Θ=>>BjiZb,/a5e/dҢ6'3F7$M8'XZ6ьڋJ ię6nL=0슿2+6}׃˔0ȅ7UZĥ2e{.#5/pU4:1u	`if䐯ߖ>6
    )宂XTTB;e::q-j́;ْ[vM7~*(	4I�ewA>`kĺa1;q[Kg]i*K#l_\takSm+95{_YJjuIUZⲹqO?}KFo>dM!&Pl8bvt\q+$gMN)0|CR{h.1YP﹁K鈊غ.#N/u7{.)="/,쳕Ɗl-k>f%%`;&-K\l15t^ɁIϩ"8F\Oᆏm	ѣٝLїQNCV.]쁿mGN3n2lg Fr6L]kaddb_Ģ{Y6ƊT
    �'l_NbдGhH{wK
    '\2ߝ{u|m2'&c4/!cUI<}B?,>B/{a]ueǭ=3UG.ϓQ;)~fCo=dΓ
    ȟ>ʞr.&:KsKfQdpԽd6,v	^AS upQwNd.D?װ~ݗ=RW";rkr3UX�dKFU~KWer:f}&ivfX
    1U|(n	?;FFD4�#U$o`c}񹼃H^`EJQ"gJvwoCR/28M/tLOv@@t11k-"-%e5%TVH!jgE9Ngԏ0ͮħJ-iC'h'eoU\{"(?r
    T̙:Z$"1}}i(bUzmr==ھPdJB3![?DXBfDTdx&v(A9I[i,&ŝu2"_VKV˴\T?i	lZbzV!/W:rIc~
    (d�7bˢGB>S<
    s82WDj Q sF4g]*	VO#F‘g;&| Y.dN>ei%J*9dX-@^̲>#u4셼˰ ndaJ>r	T&"£P9
    B겅ۘ{,kShSLu#	MƘG^.H bpn:ZKs]Uq(&sb3iYa~YqA+[M1*)դaw	<@TmNbQ	bւ:y݃׭t+-n(x_7ROeO=xtg`wD]6ffKe8UR{.]E0YgS=U44BO Sme@Uaҡ_̜^^쓮F(RnxֲsN?)24{\Ze^07?*9"ȍ�&g%UlZ2P%AW;wmE 1&=+؈ln7T<K
    :]pt[7+b70Q6Bx֚Wo.wD?}ږ3?|0r屵^0Eܱp"L	$m_s.fI{3(J࿖{NaysYZ=�ѳI5>6Y]qeBJ()ӫ[exZ}U\GTuoZ4v/
    }*M!@Sα
    $%e=qŦckrc/0˾D;,m3&ͱ
    l-LܫQ|5_<eQ/#!c8ZejG趋[:%yMZAKBw	Cm:Z0,,4dnlNmpr7b=}fO:ft`ucFS͡OU7$ZT)*aM34&%\^/-�e#ݰ_G|]y\*$֐\P]'1Gj3&e3ZU[T5%"
    8a#QG{$1lxhR
    
    N3%+J�Nr̩0f-^쁽0]fuҕdFrCĉ]<,6 o읈  ܘh*pBnGMPp;h<"Y*=}ݨ؎<\oj'Q 	EضKHQI	
    h曮QF,=[ӹ;F$uLicz`xRݨA}Ka{;F2b,nly>OAOaVQu/?)L(:+O
    ŶzMJޭ%xu1Y6Ag	]mؤOGj2wc�v-:4̿oK?0#sMbEȼ)3vBeqD!oZΚ3G0E㖉(9\a,^g'hR:ɼP{>q!,|l3ߚ
    |@O5y[Tl8{XNLGK
    �F<Bj;>&	 i	c!G2iw5i<'d-pɚZWx^w%twCj=mX76�N3Agc*T,}7}+qM^ӕ#3@r%v}Vg85[RxU6hkiHY5>2`	b#`ͳ/U7e-;܃m5
    ޅ*@]&wAF@uQ/DxQIcf?,zg>1<7o
    6m8}s^
    ~$wIy!O9ٌDJzYdM0:2Դ,W8W7T�\~p*3#NŢA)ct;[^S;E<V}e$@)Zk(2a:ޥF#L:X�PRў
    .We,{�eJ&i%qٟmI+͜&xݝS$.KjLL'm�
    |*YPEhd$y|HtlgaTD2ӋyUOŞ:溂wΩXH|s=D>Hz`&eyN.>\*F҇ 髦gH"a/a,]/]2=d|(+0q'zyYRl&{4A.ڲ_ڪBnU=$%Y3>; N<r#t{L.vTApWt&^L\^4EvAb?nȦȹGf-Ϥ!\
    RKL/E)-ORma18-wʫ)FcX>z�k)nOCVh- h|r^%Аk3=
    _**lK y	RB8.DXȥz?Q	`Hn*}Sgq}X˺c}=iZ^B
    QjSPʻm`Xq].s{k8XJnܮMMA
    V׭\Ϯ:uOIn~J7c:h5BZ(o⌉tn:n"W'Dg3d_[�*FRj3?tG8#�^ѹ|ݹ“E/ގ,FB}2	Fcˎs!9xM,[WUy؃&DF7qƂ@^ܘ%M\gwc|2rO
    pp;xЊꨢ\ k"pfaZYoXp$Yb^kƣ+e R4<:퐶uCdȾlK2DKq1eBGB"Iğx8vo˚mc12.?QMm3:t=a+.dZ |_A|eJZ
    54v"3敢ʙť8uѤ]Vp*"tEA
    .	7[7S<yu<>"
    +J]sAE?i8qƮI;(gs3H#
    [rpᨎx_LP	o\6Ԫyƭgߣ� rĂr11*j6rTJ{IBoV]{gOE%WK&PoPfxY0]RNKg#e&IVؘ
    )KmpQBG{paroNEZNjt0]8c�?5ebp|}
    N-.crC݆\_%+7N_\#۫pDUڄrQ!8Ԑŧ,{.{{.�?*3Eɹ8Y.cН%j}Z<J1;5Z:1HGt0�
    8WM
    9W55K+0N.cmp(r/^bԨIgyx1F!^|WմWimA¢INsarSݻ8T/<\Ye000a18
    @(uj"^:jo5wihDРOr!\zjnuՎ=0EƮQoV[)H_߃kKVKuqե7ꤠN5<:&FlF0fZ >e-w"\v?MR{)n"ź.Yu(u,uӾ](|p6C2cW ^.Dּ)ϚyZ^PMR:늣Q労ggOd6:YkjDl䂁Sfj0 kM!�QȄ iP.@-atsk�KlsQr�\Ĺ\@.v�^˥RKXŐrr\r\Ν\\@.N.qx. t0@.ǼW"oC.sgޛSչw DZiԶ3|QXIV`mVǬ3guO~]Y"u4H:4_m/ƞ&�Z"._ڛWjK-hy
    n?(|	ftmE*ُatuy$]a[�*ks\hK>2ePyANwORJ'{.Pg3x<Y]GOS_n"yg/}X] }?[^^qaPPa_|o,떹X\Rz,&HǦ#Cx1m⽁htPT6.'}P-K'-C蕭\I
    :ƚE\L0U̟h%%`:OY#W9Z%jq1LK]R(A$q(h^V/(}v7䒡g+WZ'lx.t"wOx@i<rue=.9\0�K)V4&cB}yfgk*.�]Å"Ԇe#
    JJmԅq.C9p.1bO}ݍZ१Eta~tr/YJO(ԫx#/Ȑ߆Ԟe*f1�a'2\ 1'Z\fBBжDE+K^^$Ⴆ8bnu.t
    gyȤOs8VU<9j52\z52΅~5o"y"kse/PI..*A9гr@Ką0nOKݦEcsAV@Ņ6%0;@(.9qF\ШU>"P^'Tçc;f5�8a	1PGklb|H)jČvkh!Z
    4+qRH0
    _ɿCPpY".ԕҋRXqŸ.[No#.XJ/X.G9k':\@boڸ0̅{rGr	;$pɸӱV.$^:N/pApaGs\].eQ霶dQiQGS5&p9%9FK…"{Y*6:3eJ۪|UcJj.ҋb). Kzz\p9&'FڂvJK?v2fF&W"\
    E*]&8a^	t.{6.Y;I\gd.9g@I@
    R^R0KU떚\5#Ne$\?
    sU#Z\fr~R=%R2#:cᏒ)ɥls:%Uob.vR"Rz:@K`L0\|#qa™г<"Rp\<S|ޞPm[iy%.5+̅\,[CW[TFd;k#ϷUOÅզI0C:mPM$TeF1kA׃|w0iqCG'$�~2=s,)rWCM/}vZw2~zUʙ^ʳqY^+KeN	6=hHQ8R
    w`rAG}0O	D]t.8SrA>GRbHYᄉ9	M{bÇ[�^l;h7oþmݏ_WzavW+@^.+å-Vs[7p9K$<z\dᲂ1٫o]Bf9..L˅ݨĽ-.P:\bh8E֭r"Q7ĥT]O-r1\|eъ�}.[أJ
    r9KׯQjlD.&%J.b.&K~Ho�"p1\ńbp1a.BayɽI8Ts@EQIǓ׸
    N݁xb[ֆ8g	~B~B™`"O{0MnLD==vCV0\B/b‪yy^,qѓ\X;t	ݒCwh..p)G7)~AHވh1�htߌ.l	G!w&q7˝Bͭ'4Q:py=̄Q:sJb6֕3"yt	?:bLL%N^+&3*}b%b_}'4ÁDl"z/1\V<=qpDYbAm8YzҵTdD4?heT&?g\-Xb<G6tJd	7\JhQ`@N.x):k}:8qYvw00\2)\Ƥe?<	p|֣|υ:DbVZ4Mk^[i|
    AiyC}Yu"j=[B^oJD_
    ȅh No~	6A{Q
    \fw^:-\vu\ke8#p:Dm-Hٵpļv.ЅVd2a^Kipm0Gp=~\ 1_"#moͅu8e<%V%1>rb+WÅiq.T`uqK-.8r9D@&N44^V. \wH.L%Tr	\o#W\qY^;_$?]|WVC9wyWm"o.s
    \6_>4>z\0CťKbj[z\Js:0-pkda~e\pɡ?$P86]K\RˆK/~.pa]\6.ڰn�\.$(%D[ź.SO3:[xS_rhQXXJPVKbFHXP\AYp2煎E.+^TI2.LpzL(A.iV+fK_X>.֣VΚ'̈{']Gr(\!-xgRt.f̻$%.rtD$tFe|KDȋ}5[R3"▐o~[s[j.!.OvoQ"ܼ[}a%J#
    ف䓋&($f%Wʕk^--,G1W#ہ."
    _K,A_!p1!d2r/~.6.r	
    dc"h	@LW_R.qEZfշL<爠[_[v$.*ʈ:l&s:^=zb!@_Яk[=�0\%z=o)	57:#Ks*^bv}Y.?MQ/vSj.Z!-
    W\݆'*|T_uP%\%iѽc˟;ӞN]l=wY7J.X~w(y*쀠I_6Mٴأg{Ȯ�_K\܍/%ńzF1":(@yWxfȓ+Z0 eH#\~6\rA.esA.U:)0�  \g[qSxuyW\Z7v$.7}a̳uC$Zv>~oX/;}Cٺx;oa9J.XvKt}+w9>n墽?~e_EGy#hrX|Rً\Fݑ\V\ʭ/reGrrwttW]\6rnsYQ^Vu"z,Xnݔ[g1hrY^e}alx^
    }eeztMbf@\2k|?4\*u!l͚q5#v\;H&rE.c"V�\N ĭ"Ґ*\:UٚM$Y2ݯyM#\gKwB9"r9G]x.Vkeu\u_g˲5PeUZeZ(tW/X.Z-ʝ˃r}WY\v^߻m,Ir%˲?k'ʝɻeM\FMnF uĠOzX%ry'[rA.*ҐK \\K<\rA.]!:!\8rA.\"
    HA.\KD.)�r@}\4NrA. i>2 4\r \r^. \*r8rh.5	sA.&r)rA.ݱU==\&\hA.]~#r\V\qc%rA.HC.}4!i>2~ \,@/r/ \*rj.\rA.X.  \r|.ȥ !\rA.7\J|\rA.\rA.Gr;PR	t\KKrA. 2 \\"
    u!/rA.O\rYDrUB.8F.L#lg�ȥ>\rA.]!xx \8r9hC.c \ \rsA.zsA. R'C.l"
    #
    \GrK9"ϑ\#
    ,#,�ȥ{~+rY)ȥ/i Y9G
    ryl.%\:$r-r)OrA.PJnR.\K \ri.E3/(\R%|.P_R. rA. sE\rA.rA.:r)#"rA. rA. |.0x.,,j)o'Sɥzȥ':\8ٜgʅB.YKK*nu_AWVrɠ^.yr)r`VnlUdy\
    %K)QC!^7ȅm.!7ͰsC~s Z.yr%O.ɥ%u}r6ҽ\{ӝ*FqxOvUZX1稉9^AeГpoY>ӯȅd<{[/5?9Vb�’0w1?1E<#{ؓG$>R"=X2F@"1^0Eĸ[WaMc�8ۺ\wꯞ4>�cZи)d2/kJ>6Ns9X°V.Y1n_B. Ns9eM6,�ՃC®cr
    yCk.q[rh#cWT$,QrxԀerX}gℽؾ\{K�[&SǀxѦ\e匽fH:C?ew욕yxM.�CLp\ˎ5%GΫ%\wNr`S$X(d\J%KR$J<b?˹10<lOu.B^g8X0nq."r
    惕O.kEw�`x2&bB(`,ŹfCю|߃�EDjX#I~mg.́EGnQx
    +[R!nf^?!c�#p/#tQbE8\iKZ8 z{.xKFmO7aQyZ
    ^Q"̜.,P"x|20ԏn\[s1C(XA>uWI:Mc"v@@F9EƟ>EU="1O7.as'1ۍ>-X63WxK:mm.ˑhX,uhK@86.J|t^-|&K;�0Er3|Ӄ;L@ֿЈ"bwt?xO
    M) bN{s6\F"@̻,s9ҮĬa`Ԑ\
    	b.
    \:Ñ;ˍeݻdr{/u߳P0^kkX.ҋ;."�^_
    t0<o5nZ.lnŋ@2C\MX5.f>SM9ÌLSwO16.jI?bIiZes^3ݐFLp^H/P~O8p=lZ.7y#l^.b:?L{
    tFzL̴\ PW\x#>&l:aXAZsc|DO�,Z�3=�|f	7$2[.@bYCBa&AJ-3%&:;ch'P
    ~#'|,sO\>aˣ�F6iV~dC
    ~>poY
    tD"6@8^C:*WcIND(,:?Jh}A.+8ﺍcAD`0UIaɡ{0%kxT_LE�ŏN;C�ovZZw/2P
    ppek>�z&5;hTT=Z~ײ۾JOgrJk"j1P\.i`yXv*(n,ݼ.&|"%R:St\.-
    h����IENDB`���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/unit-testing.html���������������������������������������������0000644�0000000�0000000�00000164755�11773544727�021152� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE html>
    <meta charset=utf-8>
    <title>Unit testing - Dive Into Python 3</title>
    <!--[if IE]><script src=j/html5.js></script><![endif]-->
    <link rel=stylesheet href=dip3.css>
    <style>
    body{counter-reset:h1 9}
    </style>
    <link rel=stylesheet media='only screen and (max-device-width: 480px)' href=mobile.css>
    <link rel=stylesheet media=print href=print.css>
    <meta name=viewport content='initial-scale=1.0'>
    <form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:l5eihuescdw><input type=hidden name=ie value=UTF-8>&nbsp;<input type=search name=q size=25 placeholder="powered by Google&trade;">&nbsp;<input type=submit name=root value=Search></div></form>
    <p>You are here: <a href=index.html>Home</a> <span class=u>&#8227;</span> <a href=table-of-contents.html#unit-testing>Dive Into Python 3</a> <span class=u>&#8227;</span>
    <p id=level>Difficulty level: <span class=u title=beginner>&#x2666;&#x2666;&#x2662;&#x2662;&#x2662;</span>
    <h1>Unit Testing</h1>
    <blockquote class=q>
    <p><span class=u>&#x275D;</span> Certitude is not the test of certainty. We have been cocksure of many things that were not so. <span class=u>&#x275E;</span><br>&mdash; <a href=http://en.wikiquote.org/wiki/Oliver_Wendell_Holmes,_Jr.>Oliver Wendell Holmes, Jr.</a>
    </blockquote>
    <p id=toc>&nbsp;
    <h2 id=divingin>(Not) Diving In</h2>
    <p class=f>Kids today. So spoiled by these fast computers and fancy &#8220;dynamic&#8221; languages. Write first, ship second, debug third (if ever). In my day, we had discipline. Discipline, I say! We had to write programs by <em>hand</em>, on <em>paper</em>, and feed them to the computer on <em>punchcards</em>. And we <em>liked it!</em>
    
    <p>In this chapter, you&#8217;re going to write and debug a set of utility functions to convert to and from Roman numerals. You saw the mechanics of constructing and validating Roman numerals in <a href=regular-expressions.html#romannumerals>&#8220;Case study: roman numerals&#8221;</a>. Now step back and consider what it would take to expand that into a two-way utility.
    <p><a href=regular-expressions.html#romannumerals>The rules for Roman numerals</a> lead to a number of interesting observations:
    <ol>
    <li>There is only one correct way to represent a particular number as a Roman numeral.
    <li>The converse is also true: if a string of characters is a valid Roman numeral, it represents only one number (that is, it can only be interpreted one way).
    <li>There is a limited range of numbers that can be expressed as Roman numerals, specifically <code>1</code> through <code>3999</code>. The Romans did have several ways of expressing larger numbers, for instance by having a bar over a numeral to represent that its normal value should be multiplied by <code>1000</code>. For the purposes of this chapter, let&#8217;s stipulate that Roman numerals go from <code>1</code> to <code>3999</code>.
    <li>There is no way to represent 0 in Roman numerals.
    <li>There is no way to represent negative numbers in Roman numerals.
    <li>There is no way to represent fractions or non-integer numbers in Roman numerals.
    </ol>
    <p>Let&#8217;s start mapping out what a <code>roman.py</code> module should do.  It will have two main functions, <code>to_roman()</code> and <code>from_roman()</code>. The <code>to_roman()</code> function should take an integer from <code>1</code> to <code>3999</code> and return the Roman numeral representation as a string&hellip;
    <p>Stop right there. Now let&#8217;s do something a little unexpected: write a test case that checks whether the <code>to_roman()</code> function does what you want it to. You read that right: you&#8217;re going to write code that tests code that you haven&#8217;t written yet.
    <p>This is called <i>test-driven development</i>, or <abbr>TDD</abbr>. The set of two conversion functions&nbsp;&mdash;&nbsp;<code>to_roman()</code>, and later <code>from_roman()</code>&nbsp;&mdash;&nbsp;can be written and tested as a unit, separate from any larger program that imports them. Python has a framework for unit testing, the appropriately-named <code>unittest</code> module.
    <p>Unit testing is an important part of an overall testing-centric development strategy. If you write unit tests, it is important to write them early and to keep them updated as code and requirements change. Many people advocate writing tests before they write the code they&#8217;re testing, and that&#8217;s the style I&#8217;m going to demonstrate in this chapter. But unit tests are beneficial no matter when you write them.
    <ul>
    <li>Before writing code, writing unit tests forces you to detail your requirements in a useful fashion.
    <li>While writing code, unit tests keep you from over-coding. When all the test cases pass, the function is complete.
    <li>When refactoring code, they can help prove that the new version behaves the same way as the old version.
    <li>When maintaining code, having tests will help you cover your ass when someone comes screaming that your latest change broke their old code. (&#8220;But <em>sir</em>, all the unit tests passed when I checked it in...&#8221;)
    <li>When writing code in a team, having a comprehensive test suite dramatically decreases the chances that your code will break someone else&#8217;s code, because you can run their unit tests first. (I&#8217;ve seen this sort of thing in code sprints. A team breaks up the assignment, everybody takes the specs for their task, writes unit tests for it, then shares their unit tests with the rest of the team. That way, nobody goes off too far into developing code that doesn&#8217;t play well with others.)
    </ul>
    <p class=a>&#x2042;
    
    <h2 id=romantest1>A Single Question</h2>
    <aside>Every test is an island.</aside>
    <p>A test case answers a single question about the code it is testing. A test case should be able to...
    <ul>
    <li>...run completely by itself, without any human input. Unit testing is about automation.
    <li>...determine by itself whether the function it is testing has passed or failed, without a human interpreting the results.
    <li>...run in isolation, separate from any other test cases (even if they test the same functions). Each test case is an island.
    </ul>
    <p>Given that, let&#8217;s build a test case for the first requirement:
    <ol>
    <li>The <code>to_roman()</code> function should return the Roman numeral representation for all integers <code>1</code> to <code>3999</code>.
    </ol>
    <p>It is not immediately obvious how this code does&hellip; well, <em>anything</em>. It defines a class which has no <code>__init__()</code> method. The class <em>does</em> have another method, but it is never called. The entire script has a <code>__main__</code> block, but it doesn&#8217;t reference the class or its method. But it does do something, I promise.
    <p class=d>[<a href=examples/romantest1.py>download <code>romantest1.py</code></a>]
    <pre class=pp><code>import roman1
    import unittest
    
    <a>class KnownValues(unittest.TestCase):               <span class=u>&#x2460;</span></a>
        known_values = ( (1, 'I'),
                         (2, 'II'),
                         (3, 'III'),
                         (4, 'IV'),
                         (5, 'V'),
                         (6, 'VI'),
                         (7, 'VII'),
                         (8, 'VIII'),
                         (9, 'IX'),
                         (10, 'X'),
                         (50, 'L'),
                         (100, 'C'),
                         (500, 'D'),
                         (1000, 'M'),
                         (31, 'XXXI'),
                         (148, 'CXLVIII'),
                         (294, 'CCXCIV'),
                         (312, 'CCCXII'),
                         (421, 'CDXXI'),
                         (528, 'DXXVIII'),
                         (621, 'DCXXI'),
                         (782, 'DCCLXXXII'),
                         (870, 'DCCCLXX'),
                         (941, 'CMXLI'),
                         (1043, 'MXLIII'),
                         (1110, 'MCX'),
                         (1226, 'MCCXXVI'),
                         (1301, 'MCCCI'),
                         (1485, 'MCDLXXXV'),
                         (1509, 'MDIX'),
                         (1607, 'MDCVII'),
                         (1754, 'MDCCLIV'),
                         (1832, 'MDCCCXXXII'),
                         (1993, 'MCMXCIII'),
                         (2074, 'MMLXXIV'),
                         (2152, 'MMCLII'),
                         (2212, 'MMCCXII'),
                         (2343, 'MMCCCXLIII'),
                         (2499, 'MMCDXCIX'),
                         (2574, 'MMDLXXIV'),
                         (2646, 'MMDCXLVI'),
                         (2723, 'MMDCCXXIII'),
                         (2892, 'MMDCCCXCII'),
                         (2975, 'MMCMLXXV'),
                         (3051, 'MMMLI'),
                         (3185, 'MMMCLXXXV'),
                         (3250, 'MMMCCL'),
                         (3313, 'MMMCCCXIII'),
                         (3408, 'MMMCDVIII'),
                         (3501, 'MMMDI'),
                         (3610, 'MMMDCX'),
                         (3743, 'MMMDCCXLIII'),
                         (3844, 'MMMDCCCXLIV'),
                         (3888, 'MMMDCCCLXXXVIII'),
                         (3940, 'MMMCMXL'),
    <a>                     (3999, 'MMMCMXCIX'))           <span class=u>&#x2461;</span></a>
    
    <a>    def test_to_roman_known_values(self):           <span class=u>&#x2462;</span></a>
            '''to_roman should give known result with known input'''
            for integer, numeral in self.known_values:
    <a>            result = roman1.to_roman(integer)       <span class=u>&#x2463;</span></a>
    <a>            self.assertEqual(numeral, result)       <span class=u>&#x2464;</span></a>
    
    if __name__ == '__main__':
        unittest.main()</code></pre>
    <ol>
    <li>To write a test case, first subclass the <code>TestCase</code> class of the <code>unittest</code> module. This class provides many useful methods which you can use in your test case to test specific conditions.
    <li>This is a tuple of integer/numeral pairs that I verified manually. It includes the lowest ten numbers, the highest number, every number that translates to a single-character Roman numeral, and a random sampling of other valid numbers. You don&#8217;t need to test every possible input, but you should try to test all the obvious edge cases.
    <li>Every individual test is its own method. A test method takes no parameters, returns no value, and must have a name beginning with the four letters <code>test</code>. If a test method exits normally without raising an exception, the test is considered passed; if the method raises an exception, the test is considered failed.
    <li>Here you call the actual <code>to_roman()</code> function. (Well, the function hasn&#8217;t been written yet, but once it is, this is the line that will call it.)  Notice that you have now defined the <abbr>API</abbr> for the <code>to_roman()</code> function: it must take an integer (the number to convert) and return a string (the Roman numeral representation). If the <abbr>API</abbr> is different than that, this test is considered failed. Also notice that you are not trapping any exceptions when you call <code>to_roman()</code>. This is intentional. <code>to_roman()</code> shouldn&#8217;t raise an exception when you call it with valid input, and these input values are all valid. If <code>to_roman()</code> raises an exception, this test is considered failed.
    <li>Assuming the <code>to_roman()</code> function was defined correctly, called correctly, completed successfully, and returned a value, the last step is to check whether it returned the <em>right</em> value. This is a common question, and the <code>TestCase</code> class provides a method, <code>assertEqual</code>, to check whether two values are equal. If the result returned from <code>to_roman()</code> (<var>result</var>) does not match the known value you were expecting (<var>numeral</var>), <code>assertEqual</code> will raise an exception and the test will fail. If the two values are equal, <code>assertEqual</code> will do nothing. If every value returned from <code>to_roman()</code> matches the known value you expect, <code>assertEqual</code> never raises an exception, so <code>test_to_roman_known_values</code> eventually exits normally, which means <code>to_roman()</code> has passed this test.
    </ol>
    <aside>Write a test that fails, then code until it passes.</aside>
    <p>Once you have a test case, you can start coding the <code>to_roman()</code> function. First, you should stub it out as an empty function and make sure the tests fail. If the tests succeed before you&#8217;ve written any code, your tests aren&#8217;t testing your code at all! Unit testing is a dance: tests lead, code follows. Write a test that fails, then code until it passes.
    <pre class=pp><code># roman1.py
    
    def to_roman(n):
        '''convert integer to Roman numeral'''
    <a>    pass                                   <span class=u>&#x2460;</span></a></code></pre>
    <ol>
    <li>At this stage, you want to define the <abbr>API</abbr> of the <code>to_roman()</code> function, but you don&#8217;t want to code it yet. (Your test needs to fail first.) To stub it out, use the Python reserved word <code>pass</code>, which does precisely nothing.
    </ol>
    <p>Execute <code>romantest1.py</code> on the command line to run the test. If you call it with the <code>-v</code> command-line option, it will give more verbose output so you can see exactly what&#8217;s going on as each test case runs. With any luck, your output should look like this:
    <pre class='screen cmdline'>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 romantest1.py -v</kbd>
    <a><samp>test_to_roman_known_values (__main__.KnownValues)</samp>                      <span class=u>&#x2460;</span></a>
    <a><samp>to_roman should give known result with known input ... FAIL</samp>            <span class=u>&#x2461;</span></a>
    <samp>
    ======================================================================
    FAIL: to_roman should give known result with known input
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "romantest1.py", line 73, in test_to_roman_known_values
        self.assertEqual(numeral, result)
    <a>AssertionError: 'I' != None                                            <span class=u>&#x2462;</span></a>
    
    ----------------------------------------------------------------------
    <a>Ran 1 test in 0.016s                                                   <span class=u>&#x2463;</span></a>
    
    <a>FAILED (failures=1)                                                    <span class=u>&#x2464;</span></a></samp></pre>
    <ol>
    <li>Running the script runs <code>unittest.main()</code>, which runs each test case. Each test case is a method within a class in <code>romantest.py</code>. There is no required organization of these test classes; they can each contain a single test method, or you can have one class that contains multiple test methods. The only requirement is that each test class must inherit from <code>unittest.TestCase</code>.
    <li>For each test case, the <code>unittest</code> module will print out the <code>docstring</code> of the method and whether that test passed or failed. As expected, this test case fails.
    <li>For each failed test case, <code>unittest</code> displays the trace information showing exactly what happened. In this case, the call to <code>assertEqual()</code> raised an <code>AssertionError</code> because it was expecting <code>to_roman(1)</code> to return <code>'I'</code>, but it didn&#8217;t. (Since there was no explicit return statement, the function returned <code>None</code>, the Python null value.)
    <li>After the detail of each test, <code>unittest</code> displays a summary of how many tests were performed and how long it took.
    <li>Overall, the test run failed because at least one test case did not pass. When a test case doesn&#8217;t pass, <code>unittest</code> distinguishes between failures and errors. A failure is a call to an <code>assertXYZ</code> method, like <code>assertEqual</code> or <code>assertRaises</code>, that fails because the asserted condition is not true or the expected exception was not raised. An error is any other sort of exception raised in the code you&#8217;re testing or the unit test case itself.
    </ol>
    <p><em>Now</em>, finally, you can write the <code>to_roman()</code> function.
    <p class=d>[<a href=examples/roman1.py>download <code>roman1.py</code></a>]
    <pre class=pp><code>roman_numeral_map = (('M',  1000),
                         ('CM', 900),
                         ('D',  500),
                         ('CD', 400),
                         ('C',  100),
                         ('XC', 90),
                         ('L',  50),
                         ('XL', 40),
                         ('X',  10),
                         ('IX', 9),
                         ('V',  5),
                         ('IV', 4),
    <a>                     ('I',  1))                 <span class=u>&#x2460;</span></a>
    
    def to_roman(n):
        '''convert integer to Roman numeral'''
        result = ''
        for numeral, integer in roman_numeral_map:
    <a>        while n >= integer:                     <span class=u>&#x2461;</span></a>
                result += numeral
                n -= integer
        return result</code></pre>
    <ol>
    <li><var>roman_numeral_map</var> is a tuple of tuples which defines three things: the character representations of the most basic Roman numerals; the order of the Roman numerals (in descending value order, from <code>M</code> all the way down to <code>I</code>); the value of each Roman numeral. Each inner tuple is a pair of <code>(<var>numeral</var>, <var>value</var>)</code>. It&#8217;s not just single-character Roman numerals; it also defines two-character pairs like <code>CM</code> (&#8220;one hundred less than one thousand&#8221;). This makes the <code>to_roman()</code> function code simpler.
    <li>Here&#8217;s where the rich data structure of <var>roman_numeral_map</var> pays off, because you don&#8217;t need any special logic to handle the subtraction rule. To convert to Roman numerals, simply iterate through <var>roman_numeral_map</var> looking for the largest integer value less than or equal to the input. Once found, add the Roman numeral representation to the end of the output, subtract the corresponding integer value from the input, lather, rinse, repeat.
    </ol>
    <p>If you&#8217;re still not clear how the <code>to_roman()</code> function works, add a <code>print()</code> call to the end of the <code>while</code> loop:
    <pre class='nd pp'><code>
    while n >= integer:
        result += numeral
        n -= integer
        print('subtracting {0} from input, adding {1} to output'.format(integer, numeral))</code></pre>
    <p>With the debug <code>print()</code> statements, the output looks like this:
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>import roman1</kbd>
    <samp class=p>>>> </samp><kbd class=pp>roman1.to_roman(1424)</kbd>
    <samp>subtracting 1000 from input, adding M to output
    subtracting 400 from input, adding CD to output
    subtracting 10 from input, adding X to output
    subtracting 10 from input, adding X to output
    subtracting 4 from input, adding IV to output
    'MCDXXIV'</samp></pre>
    <p>So the <code>to_roman()</code> function appears to work, at least in this manual spot check. But will it pass the test case you wrote?
    <pre class='nd screen cmdline'>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 romantest1.py -v</kbd>
    <samp>test_to_roman_known_values (__main__.KnownValues)
    <a>to_roman should give known result with known input ... ok               <span class=u>&#x2460;</span></a>
    
    ----------------------------------------------------------------------
    Ran 1 test in 0.016s
    
    OK</samp></pre>
    <ol>
    <li>Hooray! The <code>to_roman()</code> function passes the &#8220;known values&#8221; test case. It&#8217;s not comprehensive, but it does put the function through its paces with a variety of inputs, including inputs that produce every single-character Roman numeral, the largest possible input (<code>3999</code>), and the input that produces the longest possible Roman numeral (<code>3888</code>). At this point, you can be reasonably confident that the function works for any good input value you could throw at it.
    </ol>
    <p>&#8220;Good&#8221; input? Hmm. What about bad input?
    <p class=a>&#x2042;
    
    <h2 id=romantest2>&#8220;Halt And Catch Fire&#8221;</h2>
    <aside>The Pythonic way to halt and catch fire is to raise an exception.</aside>
    <p>It is not enough to test that functions succeed when given good input; you must also test that they fail when given bad input. And not just any sort of failure; they must fail in the way you expect.
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>import roman1</kbd>
    <samp class=p>>>> </samp><kbd class=pp>roman1.to_roman(4000)</kbd>
    <samp class=pp>'MMMM'</samp>
    <samp class=p>>>> </samp><kbd class=pp>roman1.to_roman(5000)</kbd>
    <samp class=pp>'MMMMM'</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>roman1.to_roman(9000)</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=pp>'MMMMMMMMM'</samp></pre>
    <ol>
    <li>That&#8217;s definitely not what you wanted&nbsp;&mdash;&nbsp;that&#8217;s not even a valid Roman numeral! In fact, each of these numbers is outside the range of acceptable input, but the function returns a bogus value anyway. Silently returning bad values is <em>baaaaaaad</em>; if a program is going to fail, it is far better if it fails quickly and noisily. &#8220;Halt and catch fire,&#8221; as the saying goes. The Pythonic way to halt and catch fire is to raise an exception.
    </ol>
    <p>The question to ask yourself is, &#8220;How can I express this as a testable requirement?&#8221; How&#8217;s this for starters:
    <blockquote>
    <p>The <code>to_roman()</code> function should raise an <code>OutOfRangeError</code> when given an integer greater than <code>3999</code>.
    </blockquote>
    <p>What would that test look like?
    <p class=d>[<a href=examples/romantest2.py>download <code>romantest2.py</code></a>]
    <pre class=pp><code>import unittest, roman2
    <a>class ToRomanBadInput(unittest.TestCase):                                 <span class=u>&#x2460;</span></a>
    <a>    def test_too_large(self):                                             <span class=u>&#x2461;</span></a>
            '''to_roman should fail with large input'''
    <a>        self.assertRaises(roman2.OutOfRangeError, roman2.to_roman, 4000)  <span class=u>&#x2462;</span></a></code></pre>
    <ol>
    <li>Like the previous test case, you create a class that inherits from <code>unittest.TestCase</code>. You can have more than one test per class (as you&#8217;ll see later in this chapter), but I chose to create a new class here because this test is something different than the last one. We&#8217;ll keep all the good input tests together in one class, and all the bad input tests together in another.
    <li>Like the previous test case, the test itself is a method of the class, with a name starting with <code>test</code>.
    <li>The <code>unittest.TestCase</code> class provides the <code>assertRaises</code> method, which takes the following arguments: the exception you&#8217;re expecting, the function you&#8217;re testing, and the arguments you&#8217;re passing to that function. (If the function you&#8217;re testing takes more than one argument, pass them all to <code>assertRaises</code>, in order, and it will pass them right along to the function you&#8217;re testing.)
    </ol>
    <p>Pay close attention to this last line of code. Instead of calling <code>to_roman()</code> directly and manually checking that it raises a particular exception (by wrapping it in <a href=your-first-python-program.html#exceptions>a <code>try...except</code> block</a>), the <code>assertRaises</code> method has encapsulated all of that for us. All you do is tell it what exception you&#8217;re expecting (<code>roman2.OutOfRangeError</code>), the function (<code>to_roman()</code>), and the function&#8217;s arguments (<code>4000</code>). The <code>assertRaises</code> method takes care of calling <code>to_roman()</code> and checking that it raises <code>roman2.OutOfRangeError</code>.
    <p>Also note that you&#8217;re passing the <code>to_roman()</code> function itself as an argument; you&#8217;re not calling it, and you&#8217;re not passing the name of it as a string. Have I mentioned recently how handy it is that <a href=your-first-python-program.html#everythingisanobject>everything in Python is an object</a>?
    <p>So what happens when you run the test suite with this new test?
    <pre class='screen cmdline'>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 romantest2.py -v</kbd>
    <samp>test_to_roman_known_values (__main__.KnownValues)
    to_roman should give known result with known input ... ok
    test_too_large (__main__.ToRomanBadInput)
    <a>to_roman should fail with large input ... ERROR                         <span class=u>&#x2460;</span></a>
    
    ======================================================================
    ERROR: to_roman should fail with large input                          
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "romantest2.py", line 78, in test_too_large
        self.assertRaises(roman2.OutOfRangeError, roman2.to_roman, 4000)
    <a>AttributeError: 'module' object has no attribute 'OutOfRangeError'      <span class=u>&#x2461;</span></a>
    
    ----------------------------------------------------------------------
    Ran 2 tests in 0.000s
    
    FAILED (errors=1)</samp></pre>
    <ol>
    <li>You should have expected this to fail (since you haven&#8217;t written any code to pass it yet), but... it didn&#8217;t actually &#8220;fail,&#8221; it had an &#8220;error&#8221; instead. This is a subtle but important distinction. A unit test actually has <em>three</em> return values: pass, fail, and error. Pass, of course, means that the test passed&nbsp;&mdash;&nbsp;the code did what you expected. &#8220;Fail&#8221; is what the previous test case did (until you wrote code to make it pass)&nbsp;&mdash;&nbsp;it executed the code but the result was not what you expected. &#8220;Error&#8221; means that the code didn&#8217;t even execute properly.
    <li>Why didn&#8217;t the code execute properly? The traceback tells all. The module you&#8217;re testing doesn&#8217;t have an exception called <code>OutOfRangeError</code>. Remember, you passed this exception to the <code>assertRaises()</code> method, because it&#8217;s the exception you want the function to raise given an out-of-range input. But the exception doesn&#8217;t exist, so the call to the <code>assertRaises()</code> method failed. It never got a chance to test the <code>to_roman()</code> function; it didn&#8217;t get that far.
    </ol>
    <p>To solve this problem, you need to define the <code>OutOfRangeError</code> exception in <code>roman2.py</code>.
    <pre class=pp><code><a>class OutOfRangeError(ValueError):  <span class=u>&#x2460;</span></a>
    <a>    pass                            <span class=u>&#x2461;</span></a></code></pre>
    <ol>
    <li>Exceptions are classes. An &#8220;out of range&#8221; error is a kind of value error&nbsp;&mdash;&nbsp;the argument value is out of its acceptable range. So this exception inherits from the built-in <code>ValueError</code> exception. This is not strictly necessary (it could just inherit from the base <code>Exception</code> class), but it feels right.
    <li>Exceptions don&#8217;t actually do anything, but you need at least one line of code to make a class. Calling <code>pass</code> does precisely nothing, but it&#8217;s a line of Python code, so that makes it a class.
    </ol>
    <p>Now run the test suite again.
    <pre class='screen cmdline'>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 romantest2.py -v</kbd>
    <samp>test_to_roman_known_values (__main__.KnownValues)
    to_roman should give known result with known input ... ok
    test_too_large (__main__.ToRomanBadInput)
    <a>to_roman should fail with large input ... FAIL                          <span class=u>&#x2460;</span></a>
    
    ======================================================================
    FAIL: to_roman should fail with large input
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "romantest2.py", line 78, in test_too_large
        self.assertRaises(roman2.OutOfRangeError, roman2.to_roman, 4000)
    <a>AssertionError: OutOfRangeError not raised by to_roman                 <span class=u>&#x2461;</span></a>
    
    ----------------------------------------------------------------------
    Ran 2 tests in 0.016s
    
    FAILED (failures=1)</samp></pre>
    <ol>
    <li>The new test is still not passing, but it&#8217;s not returning an error either. Instead, the test is failing. That&#8217;s progress! It means the call to the <code>assertRaises()</code> method succeeded this time, and the unit test framework actually tested the <code>to_roman()</code> function.
    <li>Of course, the <code>to_roman()</code> function isn&#8217;t raising the <code>OutOfRangeError</code> exception you just defined, because you haven&#8217;t told it to do that yet. That&#8217;s excellent news! It means this is a valid test case&nbsp;&mdash;&nbsp;it fails before you write the code to make it pass.
    </ol>
    <p>Now you can write the code to make this test pass.
    <p class=d>[<a href=examples/roman2.py>download <code>roman2.py</code></a>]
    <pre class=pp><code>def to_roman(n):
        '''convert integer to Roman numeral'''
        if n > 3999:
    <a>        raise OutOfRangeError('number out of range (must be less than 4000)')  <span class=u>&#x2460;</span></a>
    
        result = ''
        for numeral, integer in roman_numeral_map:
            while n >= integer:
                result += numeral
                n -= integer
        return result</code></pre>
    <ol>
    <li>This is straightforward: if the given input (<var>n</var>) is greater than <code>3999</code>, raise an <code>OutOfRangeError</code> exception. The unit test does not check the human-readable string that accompanies the exception, although you could write another test that did check it (but watch out for internationalization issues for strings that vary by the user&#8217;s language or environment).
    </ol>
    <p>Does this make the test pass? Let&#8217;s find out.
    <pre class='screen cmdline'>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 romantest2.py -v</kbd>
    <samp>test_to_roman_known_values (__main__.KnownValues)
    to_roman should give known result with known input ... ok
    test_too_large (__main__.ToRomanBadInput)
    <a>to_roman should fail with large input ... ok                            <span class=u>&#x2460;</span></a>
    
    ----------------------------------------------------------------------
    Ran 2 tests in 0.000s
    
    OK</samp></pre>
    <ol>
    <li>Hooray! Both tests pass. Because you worked iteratively, bouncing back and forth between testing and coding, you can be sure that the two lines of code you just wrote were the cause of that one test going from &#8220;fail&#8221; to &#8220;pass.&#8221; That kind of confidence doesn&#8217;t come cheap, but it will pay for itself over the lifetime of your code.
    </ol>
    
    <p class=a>&#x2042;
    
    <h2 id=romantest3>More Halting, More Fire</h2>
    
    <p>Along with testing numbers that are too large, you need to test numbers that are too small. As <a href=#divingin>we noted in our functional requirements</a>, Roman numerals cannot express 0 or negative numbers.
    
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>import roman2</kbd>
    <samp class=p>>>> </samp><kbd class=pp>roman2.to_roman(0)</kbd>
    <samp class=pp>''</samp>
    <samp class=p>>>> </samp><kbd class=pp>roman2.to_roman(-1)</kbd>
    <samp class=pp>''</samp></pre>
    
    <p>Well <em>that&#8217;s</em> not good. Let&#8217;s add tests for each of these conditions.
    
    <p class=d>[<a href=examples/romantest3.py>download <code>romantest3.py</code></a>]
    <pre class=pp><code>class ToRomanBadInput(unittest.TestCase):
        def test_too_large(self):
            '''to_roman should fail with large input'''
    <a>        self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, 4000)  <span class=u>&#x2460;</span></a>
    
        def test_zero(self):
            '''to_roman should fail with 0 input'''
    <a>        self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, 0)     <span class=u>&#x2461;</span></a>
    
        def test_negative(self):
            '''to_roman should fail with negative input'''
    <a>        self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, -1)    <span class=u>&#x2462;</span></a></code></pre>
    <ol>
    <li>The <code>test_too_large()</code> method has not changed since the previous step. I&#8217;m including it here to show where the new code fits.
    <li>Here&#8217;s a new test: the <code>test_zero()</code> method. Like the <code>test_too_large()</code> method, it tells the <code>assertRaises()</code> method defined in <code>unittest.TestCase</code> to call our <code>to_roman()</code> function with a parameter of 0, and check that it raises the appropriate exception, <code>OutOfRangeError</code>.
    <li>The <code>test_negative()</code> method is almost identical, except it passes <code>-1</code> to the <code>to_roman()</code> function. If either of these new tests does <em>not</em> raise an <code>OutOfRangeError</code> (either because the function returns an actual value, or because it raises some other exception), the test is considered failed.
    </ol>
    
    <p>Now check that the tests fail:
    
    <pre class='nd screen cmdline'>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 romantest3.py -v</kbd>
    <samp>test_to_roman_known_values (__main__.KnownValues)
    to_roman should give known result with known input ... ok
    test_negative (__main__.ToRomanBadInput)
    to_roman should fail with negative input ... FAIL
    test_too_large (__main__.ToRomanBadInput)
    to_roman should fail with large input ... ok
    test_zero (__main__.ToRomanBadInput)
    to_roman should fail with 0 input ... FAIL
    
    ======================================================================
    FAIL: to_roman should fail with negative input
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "romantest3.py", line 86, in test_negative
        self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, -1)
    AssertionError: OutOfRangeError not raised by to_roman
    
    ======================================================================
    FAIL: to_roman should fail with 0 input
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "romantest3.py", line 82, in test_zero
        self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, 0)
    AssertionError: OutOfRangeError not raised by to_roman
    
    ----------------------------------------------------------------------
    Ran 4 tests in 0.000s
    
    FAILED (failures=2)</samp></pre>
    
    <p>Excellent. Both tests failed, as expected. Now let&#8217;s switch over to the code and see what we can do to make them pass.
    
    <p class=d>[<a href=examples/roman3.py>download <code>roman3.py</code></a>]
    <pre class=pp><code>def to_roman(n):
        '''convert integer to Roman numeral'''
    <a>    if not (0 &lt; n &lt; 4000):                                              <span class=u>&#x2460;</span></a>
    <a>        raise OutOfRangeError('number out of range (must be 1..3999)')  <span class=u>&#x2461;</span></a>
    
        result = ''
        for numeral, integer in roman_numeral_map:
            while n >= integer:
                result += numeral
                n -= integer
        return result</code></pre>
    <ol>
    <li>This is a nice Pythonic shortcut: multiple comparisons at once. This is equivalent to <code>if not ((0 &lt; n) and (n &lt; 4000))</code>, but it&#8217;s much easier to read. This one line of code should catch inputs that are too large, negative, or zero.
    <li>If you change your conditions, make sure to update your human-readable error strings to match. The <code>unittest</code> framework won&#8217;t care, but it&#8217;ll make it difficult to do manual debugging if your code is throwing incorrectly-described exceptions.
    </ol>
    
    <p>I could show you a whole series of unrelated examples to show that the multiple-comparisons-at-once shortcut works, but instead I&#8217;ll just run the unit tests and prove it.
    
    <pre class='nd screen cmdline'>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 romantest3.py -v</kbd>
    <samp>test_to_roman_known_values (__main__.KnownValues)
    to_roman should give known result with known input ... ok
    test_negative (__main__.ToRomanBadInput)
    to_roman should fail with negative input ... ok
    test_too_large (__main__.ToRomanBadInput)
    to_roman should fail with large input ... ok
    test_zero (__main__.ToRomanBadInput)
    to_roman should fail with 0 input ... ok
    
    ----------------------------------------------------------------------
    Ran 4 tests in 0.016s
    
    OK</samp></pre>
    
    <p class=a>&#x2042;
    
    <h2 id=romantest4>And One More Thing&hellip;</h2>
    
    <p>There was one more <a href=#divingin>functional requirement</a> for converting numbers to Roman numerals: dealing with non-integers.
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>import roman3</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>roman3.to_roman(0.5)</kbd>  <span class=u>&#x2460;</span></a>
    <samp class=pp>''</samp>
    <a><samp class=p>>>> </samp><kbd class=pp>roman3.to_roman(1.0)</kbd>  <span class=u>&#x2461;</span></a>
    <samp class=pp>'I'</samp></pre>
    <ol>
    <li>Oh, that&#8217;s bad.
    <li>Oh, that&#8217;s even worse. Both of these cases should raise an exception. Instead, they give bogus results.
    </ol>
    
    <p>Testing for non-integers is not difficult. First, define a <code>NotIntegerError</code> exception.
    
    <pre class='nd pp'><code># roman4.py
    class OutOfRangeError(ValueError): pass
    <mark>class NotIntegerError(ValueError): pass</mark></code></pre>
    
    <p>Next, write a test case that checks for the <code>NotIntegerError</code> exception.
    
    <pre class='nd pp'><code>class ToRomanBadInput(unittest.TestCase):
        .
        .
        .
        def test_non_integer(self):
            '''to_roman should fail with non-integer input'''
    <mark>        self.assertRaises(roman4.NotIntegerError, roman4.to_roman, 0.5)</mark></code></pre>
    
    <p>Now check that the test fails properly.
    
    <pre class='nd screen cmdline'>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 romantest4.py -v</kbd>
    <samp>test_to_roman_known_values (__main__.KnownValues)
    to_roman should give known result with known input ... ok
    test_negative (__main__.ToRomanBadInput)
    to_roman should fail with negative input ... ok
    test_non_integer (__main__.ToRomanBadInput)
    to_roman should fail with non-integer input ... FAIL
    test_too_large (__main__.ToRomanBadInput)
    to_roman should fail with large input ... ok
    test_zero (__main__.ToRomanBadInput)
    to_roman should fail with 0 input ... ok
    
    ======================================================================
    FAIL: to_roman should fail with non-integer input
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "romantest4.py", line 90, in test_non_integer
        self.assertRaises(roman4.NotIntegerError, roman4.to_roman, 0.5)
    <mark>AssertionError: NotIntegerError not raised by to_roman</mark>
    
    ----------------------------------------------------------------------
    Ran 5 tests in 0.000s
    
    FAILED (failures=1)</samp></pre>
    
    <p>Write the code that makes the test pass.
    
    <pre class=pp><code>def to_roman(n):
        '''convert integer to Roman numeral'''
        if not (0 &lt; n &lt; 4000):
            raise OutOfRangeError('number out of range (must be 1..3999)')
    <a>    if not isinstance(n, int):                                          <span class=u>&#x2460;</span></a>
    <a>        raise NotIntegerError('non-integers can not be converted')      <span class=u>&#x2461;</span></a>
    
        result = ''
        for numeral, integer in roman_numeral_map:
            while n >= integer:
                result += numeral
                n -= integer
        return result</code></pre>
    <ol>
    <li>The built-in <code>isinstance()</code> function tests whether a variable is a particular type (or, technically, any descendant type).
    <li>If the argument <var>n</var> is not an <code>int</code>, raise our newly minted <code>NotIntegerError</code> exception.
    </ol>
    
    <p>Finally, check that the code does indeed make the test pass.
    
    <pre class='nd screen cmdline'>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 romantest4.py -v</kbd>
    <samp>test_to_roman_known_values (__main__.KnownValues)
    to_roman should give known result with known input ... ok
    test_negative (__main__.ToRomanBadInput)
    to_roman should fail with negative input ... ok
    test_non_integer (__main__.ToRomanBadInput)
    to_roman should fail with non-integer input ... ok
    test_too_large (__main__.ToRomanBadInput)
    to_roman should fail with large input ... ok
    test_zero (__main__.ToRomanBadInput)
    to_roman should fail with 0 input ... ok
    
    ----------------------------------------------------------------------
    Ran 5 tests in 0.000s
    
    OK</samp></pre>
    
    <p>The <code>to_roman()</code> function passes all of its tests, and I can&#8217;t think of any more tests, so it&#8217;s time to move on to <code>from_roman()</code>.
    
    <p class=a>&#x2042;
    
    <h2 id=romantest5>A Pleasing Symmetry</h2>
    
    <p>Converting a string from a Roman numeral to an integer sounds more difficult than converting an integer to a Roman numeral. Certainly there is the issue of validation. It&#8217;s easy to check if an integer is greater than 0, but a bit harder to check whether a string is a valid Roman numeral. But we already constructed <a href=regular-expressions.html#romannumerals>a regular expression to check for Roman numerals</a>, so that part is done.
    
    <p>That leaves the problem of converting the string itself. As we&#8217;ll see in a minute, thanks to the rich data structure we defined to map individual Roman numerals to integer values, the nitty-gritty of the <code>from_roman()</code> function is as straightforward as the <code>to_roman()</code> function.
    
    <p>But first, the tests. We&#8217;ll need a &#8220;known values&#8221; test to spot-check for accuracy. Our test suite already contains <a href=#romantest1>a mapping of known values</a>; let&#8217;s reuse that.
    
    <pre class='nd pp'><code>    def test_from_roman_known_values(self):
            '''from_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman5.from_roman(numeral)
                self.assertEqual(integer, result)</code></pre>
    
    <p>There&#8217;s a pleasing symmetry here. The <code>to_roman()</code> and <code>from_roman()</code> functions are inverses of each other. The first converts integers to specially-formatted strings, the second converts specially-formated strings to integers. In theory, we should be able to &#8220;round-trip&#8221; a number by passing to the <code>to_roman()</code> function to get a string, then passing that string to the <code>from_roman()</code> function to get an integer, and end up with the same number.
    
    <pre class='nd pp'><code>n = from_roman(to_roman(n)) for all values of n</code></pre>
    
    <p>In this case, &#8220;all values&#8221; means any number between <code>1..3999</code>, since that is the valid range of inputs to the <code>to_roman()</code> function. We can express this symmetry in a test case that runs through all the values <code>1..3999</code>, calls <code>to_roman()</code>, calls <code>from_roman()</code>, and checks that the output is the same as the original input.
    
    <pre class='nd pp'><code>class RoundtripCheck(unittest.TestCase):
        def test_roundtrip(self):
            '''from_roman(to_roman(n))==n for all n'''
            for integer in range(1, 4000):
                numeral = roman5.to_roman(integer)
                result = roman5.from_roman(numeral)
                self.assertEqual(integer, result)</code></pre>
    
    <p>These new tests won&#8217;t even fail yet. We haven&#8217;t defined a <code>from_roman()</code> function at all, so they&#8217;ll just raise errors.
    
    <pre class='nd screen cmdline'>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 romantest5.py</kbd>
    <samp>E.E....
    ======================================================================
    ERROR: test_from_roman_known_values (__main__.KnownValues)
    from_roman should give known result with known input
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "romantest5.py", line 78, in test_from_roman_known_values
        result = roman5.from_roman(numeral)
    AttributeError: 'module' object has no attribute 'from_roman'
    
    ======================================================================
    ERROR: test_roundtrip (__main__.RoundtripCheck)
    from_roman(to_roman(n))==n for all n
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "romantest5.py", line 103, in test_roundtrip
        result = roman5.from_roman(numeral)
    AttributeError: 'module' object has no attribute 'from_roman'
    
    ----------------------------------------------------------------------
    Ran 7 tests in 0.019s
    
    FAILED (errors=2)</samp></pre>
    
    <p>A quick stub function will solve that problem.
    
    <pre class='nd pp'><code># roman5.py
    def from_roman(s):
        '''convert Roman numeral to integer'''</code></pre>
    
    <p>(Hey, did you notice that? I defined a function with nothing but a <a href=your-first-python-program.html#docstrings>docstring</a>. That&#8217;s legal Python. In fact, some programmers swear by it. &#8220;Don&#8217;t stub; document!&#8221;)
    
    <p>Now the test cases will actually fail.
    
    <pre class='nd screen cmdline'>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 romantest5.py</kbd>
    <samp>F.F....
    ======================================================================
    FAIL: test_from_roman_known_values (__main__.KnownValues)
    from_roman should give known result with known input
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "romantest5.py", line 79, in test_from_roman_known_values
        self.assertEqual(integer, result)
    AssertionError: 1 != None
    
    ======================================================================
    FAIL: test_roundtrip (__main__.RoundtripCheck)
    from_roman(to_roman(n))==n for all n
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "romantest5.py", line 104, in test_roundtrip
        self.assertEqual(integer, result)
    AssertionError: 1 != None
    
    ----------------------------------------------------------------------
    Ran 7 tests in 0.002s
    
    FAILED (failures=2)</samp></pre>
    
    <p>Now it&#8217;s time to write the <code>from_roman()</code> function.
    
    <pre class=pp><code>def from_roman(s):
        """convert Roman numeral to integer"""
        result = 0
        index = 0
        for numeral, integer in roman_numeral_map:
    <a>        while s[index:index+len(numeral)] == numeral:  <span class=u>&#x2460;</span></a>
                result += integer
                index += len(numeral)
        return result</code></pre>
    <ol>
    <li>The pattern here is the same as the <a href=#romantest1><code>to_roman()</code></a> function. You iterate through your Roman numeral data structure (a tuple of tuples), but instead of matching the highest integer values as often as possible, you match the &#8220;highest&#8221; Roman numeral character strings as often as possible.
    </ol>
    
    <p>If you're not clear how <code>from_roman()</code> works, add a <code>print</code> statement to the end of the <code>while</code> loop:
    
    <pre><code>def from_roman(s):
        """convert Roman numeral to integer"""
        result = 0
        index = 0
        for numeral, integer in roman_numeral_map:
            while s[index:index+len(numeral)] == numeral:
                result += integer
                index += len(numeral)
    <mark>            print('found', numeral, 'of length', len(numeral), ', adding', integer)</mark></code></pre>
    
    <pre class='nd screen'>
    <samp class=p>>>> </samp><kbd class=pp>import roman5</kbd>
    <samp class=p>>>> </samp><kbd class=pp>roman5.from_roman('MCMLXXII')</kbd>
    <samp class=pp>found M of length 1, adding 1000
    found CM of length 2, adding 900
    found L of length 1, adding 50
    found X of length 1, adding 10
    found X of length 1, adding 10
    found I of length 1, adding 1
    found I of length 1, adding 1
    1972</samp></pre>
    
    <p>Time to re-run the tests.
    
    <pre class='nd screen cmdline'>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 romantest5.py</kbd>
    <samp>.......
    ----------------------------------------------------------------------
    Ran 7 tests in 0.060s
    
    OK</samp></pre>
    
    <p>Two pieces of exciting news here. The first is that the <code>from_roman()</code> function works for good input, at least for all the <a href=#romantest1>known values</a>. The second is that the &#8220;round trip&#8221; test also passed. Combined with the known values tests, you can be reasonably sure that both the <code>to_roman()</code> and <code>from_roman()</code> functions work properly for all possible good values. (This is not guaranteed; it is theoretically possible that <code>to_roman()</code> has a bug that produces the wrong Roman numeral for some particular set of inputs, <em>and</em> that <code>from_roman()</code> has a reciprocal bug that produces the same wrong integer values for exactly that set of Roman numerals that <code>to_roman()</code> generated incorrectly. Depending on your application and your requirements, this possibility may bother you; if so, write more comprehensive test cases until it doesn't bother you.)
    
    <p class=a>&#x2042;
    
    <h2 id=romantest6>More Bad Input</h2>
    
    <p>Now that the <code>from_roman()</code> function works properly with good input, it's time to fit in the last piece of the puzzle: making it work properly with bad input. That means finding a way to look at a string and determine if it's a valid Roman numeral. This is inherently more difficult than <a href=#romantest3>validating numeric input</a> in the <code>to_roman()</code> function, but you have a powerful tool at your disposal: regular expressions. (If you&#8217;re not familiar with regular expressions, now would be a good time to read <a href=regular-expressions.html>the regular expressions chapter</a>.)
    
    <p>As you saw in <a href=regular-expressions.html#romannumerals>Case Study: Roman Numerals</a>, there are several simple rules for constructing a Roman numeral, using the letters <code>M</code>, <code>D</code>, <code>C</code>, <code>L</code>, <code>X</code>, <code>V</code>, and <code>I</code>. Let's review the rules:
    
    <ul>
    <li>Sometimes characters are additive. <code>I</code> is <code>1</code>, <code>II</code> is <code>2</code>, and <code>III</code> is <code>3</code>. <code>VI</code> is <code>6</code> (literally, &#8220;<code>5</code> and <code>1</code>&#8221;), <code>VII</code> is <code>7</code>, and <code>VIII</code> is <code>8</code>.
    <li>The tens characters (<code>I</code>, <code>X</code>, <code>C</code>, and <code>M</code>) can be repeated up to three times. At <code>4</code>, you need to subtract from the next highest fives character. You can't represent <code>4</code> as <code>IIII</code>; instead, it is represented as <code>IV</code> (&#8220;<code>1</code> less than <code>5</code>&#8221;). <code>40</code> is written as <code>XL</code> (&#8220;<code>10</code> less than <code>50</code>&#8221;), <code>41</code> as <code>XLI</code>, <code>42</code> as <code>XLII</code>, <code>43</code> as <code>XLIII</code>, and then <code>44</code> as <code>XLIV</code> (&#8220;<code>10</code> less than <code>50</code>, then <code>1</code> less than <code>5</code>&#8221;).
    <li>Sometimes characters are&hellip; the opposite of additive. By putting certain characters before others, you subtract from the final value. For example, at <code>9</code>, you need to subtract from the next highest tens character: <code>8</code> is <code>VIII</code>, but <code>9</code> is <code>IX</code> (&#8220;<code>1</code> less than <code>10</code>&#8221;), not <code>VIIII</code> (since the <code>I</code> character can not be repeated four times). <code>90</code> is <code>XC</code>, <code>900</code> is <code>CM</code>.
    <li>The fives characters can not be repeated. <code>10</code> is always represented as <code>X</code>, never as <code>VV</code>. <code>100</code> is always <code>C</code>, never <code>LL</code>.
    <li>Roman numerals are read left to right, so the order of characters matters very much. <code>DC</code> is <code>600</code>; <code>CD</code> is a completely different number (<code>400</code>, &#8220;<code>100</code> less than <code>500</code>&#8221;). <code>CI</code> is <code>101</code>; <code>IC</code> is not even a valid Roman numeral (because you can't subtract <code>1</code> directly from <code>100</code>; you would need to write it as <code>XCIX</code>, &#8220;<code>10</code> less than <code>100</code>, then <code>1</code> less than <code>10</code>&#8221;).
    </ul>
    
    <p>Thus, one useful test would be to ensure that the <code>from_roman()</code> function should fail when you pass it a string with too many repeated numerals. How many is &#8220;too many&#8221; depends on the numeral.
    
    <pre class='nd pp'><code>class FromRomanBadInput(unittest.TestCase):
        def test_too_many_repeated_numerals(self):
            '''from_roman should fail with too many repeated numerals'''
            for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
                self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)</code></pre>
    
    <p>Another useful test would be to check that certain patterns aren&#8217;t repeated. For example, <code>IX</code> is <code>9</code>, but <code>IXIX</code> is never valid.
    
    <pre class='nd pp'><code>    def test_repeated_pairs(self):
            '''from_roman should fail with repeated pairs of numerals'''
            for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
                self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)</code></pre>
    
    <p>A third test could check that numerals appear in the correct order, from highest to lowest value. For example, <code>CL</code> is <code>150</code>, but <code>LC</code> is never valid, because the numeral for <code>50</code> can never come before the numeral for <code>100</code>. This test includes a randomly chosen set of invalid antecedents: <code>I</code> before <code>M</code>, <code>V</code> before <code>X</code>, and so on.
    
    <pre class='nd pp'><code>    def test_malformed_antecedents(self):
            '''from_roman should fail with malformed antecedents'''
            for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
                      'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
                self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)</code></pre>
    
    <p>Each of these tests relies the <code>from_roman()</code> function raising a new exception, <code>InvalidRomanNumeralError</code>, which we haven&#8217;t defined yet.
    
    <pre class='nd pp'><code># roman6.py
    class InvalidRomanNumeralError(ValueError): pass</code></pre>
    
    <p>All three of these tests should fail, since the <code>from_roman()</code> function doesn&#8217;t currently have any validity checking. (If they don&#8217;t fail now, then what the heck are they testing?)
    
    <pre class='nd screen cmdline'>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 romantest6.py</kbd>
    <samp>FFF.......
    ======================================================================
    FAIL: test_malformed_antecedents (__main__.FromRomanBadInput)
    from_roman should fail with malformed antecedents
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "romantest6.py", line 113, in test_malformed_antecedents
        self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)
    AssertionError: InvalidRomanNumeralError not raised by from_roman
    
    ======================================================================
    FAIL: test_repeated_pairs (__main__.FromRomanBadInput)
    from_roman should fail with repeated pairs of numerals
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "romantest6.py", line 107, in test_repeated_pairs
        self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)
    AssertionError: InvalidRomanNumeralError not raised by from_roman
    
    ======================================================================
    FAIL: test_too_many_repeated_numerals (__main__.FromRomanBadInput)
    from_roman should fail with too many repeated numerals
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "romantest6.py", line 102, in test_too_many_repeated_numerals
        self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)
    AssertionError: InvalidRomanNumeralError not raised by from_roman
    
    ----------------------------------------------------------------------
    Ran 10 tests in 0.058s
    
    FAILED (failures=3)</samp></pre>
    
    <p>Good deal. Now, all we need to do is add the <a href=regular-expressions.html#romannumerals>regular expression to test for valid Roman numerals</a> into the <code>from_roman()</code> function.
    
    <pre class='nd pp'><code>roman_numeral_pattern = re.compile('''
        ^                   # beginning of string
        M{0,3}              # thousands - 0 to 3 Ms
        (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 Cs),
                            #            or 500-800 (D, followed by 0 to 3 Cs)
        (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 Xs),
                            #        or 50-80 (L, followed by 0 to 3 Xs)
        (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 Is),
                            #        or 5-8 (V, followed by 0 to 3 Is)
        $                   # end of string
        ''', re.VERBOSE)
    
    def from_roman(s):
        '''convert Roman numeral to integer'''
    <mark>    if not roman_numeral_pattern.search(s):
            raise InvalidRomanNumeralError('Invalid Roman numeral: {0}'.format(s))</mark>
    
        result = 0
        index = 0
        for numeral, integer in roman_numeral_map:
            while s[index : index + len(numeral)] == numeral:
                result += integer
                index += len(numeral)
        return result</code></pre>
    
    <p>And re-run the tests&hellip;
    
    <pre class='nd screen cmdline'>
    <samp class=p>you@localhost:~/diveintopython3/examples$ </samp><kbd>python3 romantest7.py</kbd>
    <samp>..........
    ----------------------------------------------------------------------
    Ran 10 tests in 0.066s
    
    OK</samp></pre>
    
    <p>And the anticlimax award of the year goes to&hellip; the word &#8220;<code>OK</code>&#8221;, which is printed by the <code>unittest</code> module when all the tests pass.
    
    <p class=v><a href=advanced-iterators.html rel=prev title='back to &#8220;Advanced Iterators&#8221;'><span class=u>&#x261C;</span></a> <a href=refactoring.html rel=next title='onward to &#8220;Refactoring&#8221;'><span class=u>&#x261E;</span></a>
    <p class=c>&copy; 2001&ndash;11 <a href=about.html>Mark Pilgrim</a>
    <script src=j/jquery.js></script>
    <script src=j/prettify.js></script>
    <script src=j/dip3.js></script>
    �������������������diveintopython3-20110517-77958af.orig/special-method-names.html�������������������������������������0000644�0000000�0000000�00000145604�11773544727�022507� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE html>
    <meta charset=utf-8>
    <title>Special Method Names - Dive Into Python 3</title>
    <!--[if IE]><script src=j/html5.js></script><![endif]-->
    <link rel=stylesheet href=dip3.css>
    <style>
    </style>
    <link rel=stylesheet media='only screen and (max-device-width: 480px)' href=mobile.css>
    <link rel=stylesheet media=print href=print.css>
    <meta name=viewport content='initial-scale=1.0'>
    <body id=appb>
    <form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:l5eihuescdw><input type=hidden name=ie value=UTF-8>&nbsp;<input type=search name=q size=25 placeholder="powered by Google&trade;">&nbsp;<input type=submit name=sa value=Search></div></form>
    <p>You are here: <a href=index.html>Home</a> <span class=u>&#8227;</span> <a href=table-of-contents.html#special-method-names>Dive Into Python 3</a> <span class=u>&#8227;</span>
    <p id=level>Difficulty level: <span class=u title=pro>&#x2666;&#x2666;&#x2666;&#x2666;&#x2666;</span>
    <h1>Special Method Names</h1>
    <blockquote class=q>
    <p><span class=u>&#x275D;</span> My specialty is being right when other people are wrong. <span class=u>&#x275E;</span><br>&mdash; <a href=http://en.wikiquote.org/wiki/George_Bernard_Shaw>George Bernard Shaw</a>
    </blockquote>
    <p id=toc>&nbsp;
    <h2 id=divingin>Diving In</h2>
    <p class=f>Throughout this book, you&#8217;ve seen examples of &#8220;special methods&#8221;&nbsp;&mdash;&nbsp;certain &#8220;magic&#8221; methods that Python invokes when you use certain syntax. Using special methods, your classes can act like sets, like dictionaries, like functions, like iterators, or even like numbers. This appendix serves both as a reference for the special methods we&#8217;ve seen already and a brief introduction to some of the more esoteric ones.
    
    <h2 id=basics>Basics</h2>
    
    <p>If you&#8217;ve read the <a href=iterators.html#divingin>introduction to classes</a>, you&#8217;ve already seen the most common special method: the <code>__init__()</code> method. The majority of classes I write end up needing some initialization. There are also a few other basic special methods that are especially useful for debugging your custom classes.
    
    <table>
    <tr><th>Notes
    <th>You Want&hellip;
    <th>So You Write&hellip;
    <th>And Python Calls&hellip;
    <tr><th>&#x2460;
    <td>to initialize an instance
    <td><code class=pp>x = MyClass()</code>
    <td><a href=http://docs.python.org/3.1/reference/datamodel.html#object.__init__><code>x.<dfn>__init__</dfn>()</code></a>
    <tr><th>&#x2461;
    <td>the &#8220;official&#8221; representation as a string
    <td><code class=pp><dfn>repr</dfn>(x)</code>
    <td><a href=http://docs.python.org/3.1/reference/datamodel.html#object.__repr__><code>x.<dfn>__repr__</dfn>()</code></a>
    <tr><th>&#x2462;
    <td>the &#8220;informal&#8221; value as a string
    <td><a href=http://docs.python.org/3.1/reference/datamodel.html#object.__str__><code><dfn>str</dfn>(x)</code></a>
    <td><code class=pp>x.<dfn>__str__</dfn>()</code>
    <tr><th>&#x2463;
    <td>the &#8220;informal&#8221; value as a byte array
    <td><code class=pp><dfn>bytes</dfn>(x)</code>
    <td><code class=pp>x.<dfn>__bytes__</dfn>()</code>
    <tr><th>&#x2464;
    <td>the value as a formatted string
    <td><code class=pp>format(x, <var>format_spec</var>)</code>
    <td><a href=http://docs.python.org/3.1/reference/datamodel.html#object.__format__><code>x.<dfn>__format__</dfn>(<var>format_spec</var>)</code></a>
    </table>
    <ol>
    <li>The <code>__init__()</code> method is called <em>after</em> the instance is created. If you want to control the actual creation process, use <a href=#esoterica>the <code>__new__()</code> method</a>.
    <li>By convention, the <code>__repr__()</code> method should return a string that is a valid Python expression.
    <li>The <code>__str__()</code> method is also called when you <code>print(x)</code>.
    <li><em>New in Python 3</em>, since the <code>bytes</code> type was introduced.
    <li>By convention, <var>format_spec</var> should conform to the <a href=http://www.python.org/doc/3.1/library/string.html#formatspec>Format Specification Mini-Language</a>. <code>decimal.py</code> in the Python standard library provides its own <code>__format__()</code> method.
    </ol>
    
    <h2 id=acts-like-iterator>Classes That Act Like Iterators</h2>
    
    <p>In <a href=iterators.html>the Iterators chapter</a>, you saw how to build an iterator from the ground up using the <code>__iter__()</code> and <code>__next__()</code> methods.
    
    <table>
    <tr><th>Notes
    <th>You Want&hellip;
    <th>So You Write&hellip;
    <th>And Python Calls&hellip;
    <tr><th>&#x2460;
    <td>to iterate through a sequence
    <td><code class=pp><dfn>iter</dfn>(seq)</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__iter__><code>seq.<dfn>__iter__</dfn>()</code></a>
    <tr><th>&#x2461;
    <td>to get the next value from an iterator
    <td><code class=pp><dfn>next</dfn>(seq)</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__next__><code>seq.<dfn>__next__</dfn>()</code></a>
    <tr><th>&#x2462;
    <td>to create an iterator in reverse order
    <td><code class=pp><dfn>reversed</dfn>(seq)</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__reversed__><code>seq.<dfn>__reversed__</dfn>()</code></a>
    </table>
    <ol>
    <li>The <code>__iter__()</code> method is called whenever you create a new iterator. It&#8217;s a good place to initialize the iterator with initial values.
    <li>The <code>__next__()</code> method is called whenever you retrieve the next value from an iterator.
    <li>The <code>__reversed__()</code> method is uncommon. It takes an existing sequence and returns an iterator that yields the items in the sequence in reverse order, from last to first.
    </ol>
    
    <p>As you saw in <a href=iterators.html#a-fibonacci-iterator>the Iterators chapter</a>, a <code>for</code> loop can act on an iterator. In this loop:
    
    <pre class='nd pp'><code>for x in seq:
        print(x)</code></pre>
    
    <p>Python 3 will call <code>seq.__iter__()</code> to create an iterator, then call the <code>__next__()</code> method on that iterator to get each value of <var>x</var>. When the <code>__next__()</code> method raises a <code>StopIteration</code> exception, the <code>for</code> loop ends gracefully.
    
    <h2 id=computed-attributes>Computed Attributes</h2>
    
    <table>
    <tr><th>Notes
    <th>You Want&hellip;
    <th>So You Write&hellip;
    <th>And Python Calls&hellip;
    <tr><th>&#x2460;
    <td>to get a computed attribute (unconditionally)
    <td><code class=pp>x.my_property</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__getattribute__><code>x.<dfn>__getattribute__</dfn>(<var>'my_property'</var>)</code></a>
    <tr><th>&#x2461;
    <td>to get a computed attribute (fallback)
    <td><code class=pp>x.my_property</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__getattr__><code>x.<dfn>__getattr__</dfn>(<var>'my_property'</var>)</code></a>
    <tr><th>&#x2462;
    <td>to set an attribute
    <td><code class=pp>x.my_property = value</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__setattr__><code>x.<dfn>__setattr__</dfn>(<var>'my_property'</var>, <var>value</var>)</code></a>
    <tr><th>&#x2463;
    <td>to delete an attribute
    <td><code class=pp>del x.my_property</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__delattr__><code>x.<dfn>__delattr__</dfn>(<var>'my_property'</var>)</code></a>
    <tr><th>&#x2464;
    <td>to list all attributes and methods
    <td><code class=pp>dir(x)</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__dir__><code>x.<dfn>__dir__</dfn>()</code></a>
    </table>
    <ol>
    <li>If your class defines a <code>__getattribute__()</code> method, Python will call it on <em>every reference to any attribute or method name</em> (except special method names, since that would cause an unpleasant infinite loop).
    <li>If your class defines a <code>__getattr__()</code> method, Python will call it only after looking for the attribute in all the normal places. If an instance <var>x</var> defines an attribute <var>color</var>, <code>x.color</code> will <em>not</em> call <code>x.__getattr__('color')</code>; it will simply return the already-defined value of <var>x.color</var>.
    <li>The <code>__setattr__()</code> method is called whenever you assign a value to an attribute.
    <li>The <code>__delattr__()</code> method is called whenever you delete an attribute.
    <li>The <code>__dir__()</code> method is useful if you define a <code>__getattr__()</code> or <code>__getattribute__()</code> method. Normally, calling <code>dir(x)</code> would only list the regular attributes and methods. If your <code>__getattr__()</code> method handles a <var>color</var> attribute dynamically, <code>dir(x)</code> would not list <var>color</var> as one of the available attributes. Overriding the <code>__dir__()</code> method allows you to list <var>color</var> as an available attribute, which is helpful for other people who wish to use your class without digging into the internals of it.
    </ol>
    
    <p>The distinction between the <code>__getattr__()</code> and <code>__getattribute__()</code> methods is subtle but important. I can explain it with two examples:
    
    <pre class=screen>
    <code>class Dynamo:
        def __getattr__(self, key):
    <a>        if key == 'color':         <span class=u>&#x2460;</span></a>
                return 'PapayaWhip'
            else:
    <a>            raise AttributeError   <span class=u>&#x2461;</span></a></code>
    
    <samp class=p>>>> </samp><kbd class=pp>dyn = Dynamo()</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>dyn.color</kbd>                      <span class=u>&#x2462;</span></a>
    <samp class=pp>'PapayaWhip'</samp>
    <samp class=p>>>> </samp><kbd class=pp>dyn.color = 'LemonChiffon'</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>dyn.color</kbd>                      <span class=u>&#x2463;</span></a>
    <samp class=pp>'LemonChiffon'</samp></pre>
    <ol>
    <li>The attribute name is passed into the <code>__getattr__()</code> method as a string.  If the name is <code>'color'</code>, the method returns a value. (In this case, it&#8217;s just a hard-coded string, but you would normally do some sort of computation and return the result.)
    <li>If the attribute name is unknown, the <code>__getattr__()</code> method needs to raise an <code>AttributeError</code> exception, otherwise your code will silently fail when accessing undefined attributes. (Technically, if the method doesn&#8217;t raise an exception or explicitly return a value, it returns <code>None</code>, the Python null value. This means that <em>all</em> attributes not explicitly defined will be <code>None</code>, which is almost certainly not what you want.)
    <li>The <var>dyn</var> instance does not have an attribute named <var>color</var>, so the <code>__getattr__()</code> method is called to provide a computed value.
    <li>After explicitly setting <var>dyn.color</var>, the <code>__getattr__()</code> method will no longer be called to provide a value for <var>dyn.color</var>, because <var>dyn.color</var> is already defined on the instance.
    </ol>
    
    <p>On the other hand, the <code>__getattribute__()</code> method is absolute and unconditional.
    
    <pre class=screen>
    <code>class SuperDynamo:
        def __getattribute__(self, key):
            if key == 'color':
                return 'PapayaWhip'
            else:
                raise AttributeError</code>
    
    <samp class=p>>>> </samp><kbd class=pp>dyn = SuperDynamo()</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>dyn.color</kbd>                      <span class=u>&#x2460;</span></a>
    <samp class=pp>'PapayaWhip'</samp>
    <samp class=p>>>> </samp><kbd class=pp>dyn.color = 'LemonChiffon'</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>dyn.color</kbd>                      <span class=u>&#x2461;</span></a>
    <samp class=pp>'PapayaWhip'</samp></pre>
    <ol>
    <li>The <code>__getattribute__()</code> method is called to provide a value for <var>dyn.color</var>.
    <li>Even after explicitly setting <var>dyn.color</var>, the <code>__getattribute__()</code> method <em>is still called</em> to provide a value for <var>dyn.color</var>. If present, the <code>__getattribute__()</code> method <em>is called unconditionally</em> for every attribute and method lookup, even for attributes that you explicitly set after creating an instance.
    </ol>
    
    <blockquote class=note>
    <p><span class=u>&#x261E;</span>If your class defines a <code>__getattribute__()</code> method, you probably also want to define a <code>__setattr__()</code> method and coordinate between them to keep track of attribute values. Otherwise, any attributes you set after creating an instance will disappear into a black hole.
    </blockquote>
    
    <p>You need to be extra careful with the <code>__getattribute__()</code> method, because it is also called when Python looks up a method name on your class.
    
    <pre class=screen>
    <code>class Rastan:
        def __getattribute__(self, key):
    <a>        raise AttributeError           <span class=u>&#x2460;</span></a>
        def swim(self):
            pass</code>
    
    <samp class=p>>>> </samp><kbd class=pp>hero = Rastan()</kbd>
    <a><samp class=p>>>> </samp><kbd class=pp>hero.swim()</kbd>                        <span class=u>&#x2461;</span></a>
    <samp class=traceback>Traceback (most recent call last):
      File "&lt;stdin>", line 1, in &lt;module>
      File "&lt;stdin>", line 3, in __getattribute__
    AttributeError</samp></pre>
    <ol>
    <li>This class defines a <code>__getattribute__()</code> method which always raises an <code>AttributeError</code> exception. No attribute or method lookups will succeed.
    <li>When you call <code>hero.swim()</code>, Python looks for a <code>swim()</code> method in the <code>Rastan</code> class. This lookup goes through the <code>__getattribute__()</code> method, <em>because all attribute and method lookups go through the <code>__getattribute__()</code> method</em>. In this case, the <code>__getattribute__()</code> method raises an <code>AttributeError</code> exception, so the method lookup fails, so the method call fails.
    </ol>
    
    <h2 id=acts-like-function>Classes That Act Like Functions</h2>
    
    <p>You can make an instance of a class callable&nbsp;&mdash;&nbsp;exactly like a function is callable&nbsp;&mdash;&nbsp;by defining the <code>__call__()</code> method.
    
    <table>
    <tr><th>Notes
    <th>You Want&hellip;
    <th>So You Write&hellip;
    <th>And Python Calls&hellip;
    <tr><th>
    <td>to &#8220;call&#8221; an instance like a function
    <td><code class=pp>my_instance()</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__call__><code>my_instance.<dfn>__call__</dfn>()</code></a>
    </table>
    
    <p>The <a href=http://docs.python.org/3.1/library/zipfile.html><code>zipfile</code> module</a> uses this to define a class that can <dfn>decrypt</dfn> an <dfn>encrypted</dfn> <dfn>zip</dfn> file with a given password. The zip <dfn>decryption</dfn> algorithm requires you to store state during decryption. Defining the decryptor as a class allows you to maintain this state within a single instance of the decryptor class.  The state is initialized in the <code>__init__()</code> method and updated as the file is <dfn>decrypted</dfn>. But since the class is also &#8220;callable&#8221; like a function, you can pass the instance as the first argument of the <code>map()</code> function, like so:
    
    <pre class=pp><code># excerpt from zipfile.py
    class _ZipDecrypter:
    .
    .
    .
        def __init__(self, pwd):
    <a>        self.key0 = 305419896               <span class=u>&#x2460;</span></a>
            self.key1 = 591751049
            self.key2 = 878082192
            for p in pwd:
                self._UpdateKeys(p)
    
    <a>    def __call__(self, c):                  <span class=u>&#x2461;</span></a>
            assert isinstance(c, int)
            k = self.key2 | 2
            c = c ^ (((k * (k^1)) >> 8) &amp; 255)
            self._UpdateKeys(c)
            return c
    .
    .
    .
    <a>zd = _ZipDecrypter(pwd)                    <span class=u>&#x2462;</span></a>
    bytes = zef_file.read(12)
    <a>h = list(map(zd, bytes[0:12]))             <span class=u>&#x2463;</span></a></code></pre>
    <ol>
    <li>The <code>_ZipDecryptor</code> class maintains state in the form of three rotating keys, which are later updated in the <code>_UpdateKeys()</code> method (not shown here).
    <li>The class defines a <code>__call__()</code> method, which makes class instances callable like functions. In this case, the <code>__call__()</code> method decrypts a single byte of the zip file, then updates the rotating keys based on the byte that was decrypted.
    <li><var>zd</var> is an instance of the <code>_ZipDecryptor</code> class. The <var>pwd</var> variable is passed to the <code>__init__()</code> method, where it is stored and used to update the rotating keys for the first time.
    <li>Given the first 12 bytes of a zip file, decrypt them by mapping the bytes to <var>zd</var>, in effect &#8220;calling&#8221; <var>zd</var> 12 times, which invokes the <code>__call__()</code> method 12 times, which updates its internal state and returns a resulting byte 12 times.
    </ol>
    
    <h2 id=acts-like-set>Classes That Act Like Sets</h2>
    
    <p>If your class acts as a container for a set of values&nbsp;&mdash;&nbsp;that is, if it makes sense to ask whether your class &#8220;contains&#8221; a value&nbsp;&mdash;&nbsp;then it should probably define the following special methods that make it act like a set.
    
    <table>
    <tr><th>Notes
    <th>You Want&hellip;
    <th>So You Write&hellip;
    <th>And Python Calls&hellip;
    <tr><th>
    <td>the number of items
    <td><code class=pp><dfn>len</dfn>(s)</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__len__><code>s.<dfn>__len__</dfn>()</code></a>
    <tr><th>
    <td>to know whether it contains a specific value
    <td><code class=pp>x in s</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__contains__><code>s.<dfn>__contains__</dfn>(<var>x</var>)</code></a>
    </table>
    
    <p id=acts-like-set-example>The <a href=http://docs.python.org/3.1/library/cgi.html><code>cgi</code> module</a> uses these methods in its <code>FieldStorage</code> class, which represents all of the form fields or query parameters submitted to a dynamic web page.
    
    <pre class=pp><code># A script which responds to http://example.com/search?q=cgi
    import cgi
    fs = cgi.FieldStorage()
    <a>if 'q' in fs:                                               <span class=u>&#x2460;</span></a>
      do_search()
    
    # An excerpt from cgi.py that explains how that works
    class FieldStorage:
    .
    .
    .
    <a>    def __contains__(self, key):                            <span class=u>&#x2461;</span></a>
            if self.list is None:
                raise TypeError('not indexable')
    <a>        return any(item.name == key for item in self.list)  <span class=u>&#x2462;</span></a>
    
    <a>    def __len__(self):                                      <span class=u>&#x2463;</span></a>
    <a>        return len(self.keys())                             <span class=u>&#x2464;</span></a></code></pre>
    <ol>
    <li>Once you create an instance of the <code>cgi.FieldStorage</code> class, you can use the &#8220;<code>in</code>&#8221; operator to check whether a particular parameter was included in the query string.
    <li>The <code>__contains__()</code> method is the magic that makes this work. When you say <code>if 'q' in fs</code>, Python looks for the <code>__contains__()</code> method on the <var>fs</var> object, which is defined in <code>cgi.py</code>. The value <code>'q'</code> is passed into the <code>__contains__()</code> method as the <var>key</var> argument.
    <li>The <code>any()</code> function takes a <a href=advanced-iterators.html#generator-expressions>generator expression</a> and returns <code>True</code> if the generator spits out any items. The <code>any()</code> function is smart enough to stop as soon as the first match is found.
    <li>The same <code>FieldStorage</code> class also supports returning its length, so you can say <code>len(<var>fs</var>)</code> and it will call the <code>__len__()</code> method on the <code>FieldStorage</code> class to return the number of query parameters that it identified.
    <li>The <code>self.keys()</code> method checks whether <code>self.list is None</code>, so the <code>__len__</code> method doesn&#8217;t need to duplicate this error checking.
    </ol>
    
    <h2 id=acts-like-dict>Classes That Act Like Dictionaries</h2>
    
    <p>Extending the previous section a bit, you can define classes that not only respond to the &#8220;<code>in</code>&#8221; operator and the <code>len()</code> function, but they act like full-blown dictionaries, returning values based on keys.
    
    <table>
    <tr><th>Notes
    <th>You Want&hellip;
    <th>So You Write&hellip;
    <th>And Python Calls&hellip;
    <tr><th>
    <td>to get a value by its key
    <td><code class=pp>x[key]</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__getitem__><code>x.<dfn>__getitem__</dfn>(<var>key</var>)</code></a>
    <tr><th>
    <td>to set a value by its key
    <td><code class=pp>x[key] = value</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__setitem__><code>x.<dfn>__setitem__</dfn>(<var>key</var>, <var>value</var>)</code></a>
    <tr><th>
    <td>to delete a key-value pair
    <td><code class=pp>del x[key]</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__delitem__><code>x.<dfn>__delitem__</dfn>(<var>key</var>)</code></a>
    <tr><th>
    <td>to provide a default value for missing keys
    <td><code class=pp>x[nonexistent_key]</code>
    <td><a href=http://docs.python.org/3.1/library/collections.html#collections.defaultdict.__missing__><code>x.<dfn>__missing__</dfn>(<var>nonexistent_key</var>)</code></a>
    </table>
    
    <p>The <a href=#acts-like-set-example><code>FieldStorage</code> class</a> from the <a href=http://docs.python.org/3.1/library/cgi.html><code>cgi</code> module</a> also defines these special methods, which means you can do things like this:
    
    <pre class=pp><code># A script which responds to http://example.com/search?q=cgi
    import cgi
    fs = cgi.FieldStorage()
    if 'q' in fs:
    <a>  do_search(fs['q'])                              <span class=u>&#x2460;</span></a>
    
    # An excerpt from cgi.py that shows how it works
    class FieldStorage:
    .
    .
    .
    <a>    def __getitem__(self, key):                   <span class=u>&#x2461;</span></a>
            if self.list is None:
                raise TypeError('not indexable')
            found = []
            for item in self.list:
                if item.name == key: found.append(item)
            if not found:
                raise KeyError(key)
            if len(found) == 1:
                return found[0]
            else:
                return found</code></pre>
    <ol>
    <li>The <var>fs</var> object is an instance of <code>cgi.FieldStorage</code>, but you can still evaluate expressions like <code>fs['q']</code>.
    <li><code>fs['q']</code> invokes the <code>__getitem__()</code> method with the <var>key</var> parameter set to <code>'q'</code>. It then looks up in its internally maintained list of query parameters (<var>self.list</var>) for an item whose <code>.name</code> matches the given key.
    </ol>
    
    <h2 id=acts-like-number>Classes That Act Like Numbers</h2>
    
    <p>Using the appropriate special methods, you can define your own classes that act like numbers. That is, you can add them, subtract them, and perform other mathematical operations on them. This is how <dfn>fractions</dfn> are implemented&nbsp;&mdash;&nbsp;the <code><dfn>Fraction</dfn></code> class implements these special methods, then you can do things like this:
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>from fractions import Fraction</kbd>
    <samp class=p>>>> </samp><kbd class=pp>x = Fraction(1, 3)</kbd>
    <samp class=p>>>> </samp><kbd class=pp>x / 3</kbd>
    <samp class=pp>Fraction(1, 9)</samp></pre>
    
    <p>Here is the comprehensive list of special methods you need to implement a number-like class.
    
    <table>
    <tr><th>Notes
    <th>You Want&hellip;
    <th>So You Write&hellip;
    <th>And Python Calls&hellip;
    <tr><th>
    <td>addition
    <td><code class=pp>x + y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__add__><code>x.<dfn>__add__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>subtraction
    <td><code class=pp>x - y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__sub__><code>x.<dfn>__sub__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>multiplication
    <td><code class=pp>x * y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__mul__><code>x.<dfn>__mul__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>division
    <td><code class=pp>x / y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__truediv__><code>x.<dfn>__truediv__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>floor division
    <td><code>x // y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__floordiv__><code>x.<dfn>__floordiv__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>modulo (remainder)
    <td><code class=pp>x % y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__mod__><code>x.<dfn>__mod__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>floor division <i class=baa>&amp;</i> modulo
    <td><code class=pp>divmod(x, y)</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__divmod__><code>x.<dfn>__divmod__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>raise to power
    <td><code class=pp>x ** y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__pow__><code>x.<dfn>__pow__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>left bit-shift
    <td><code class=pp>x &lt;&lt; y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__lshift__><code>x.<dfn>__lshift__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>right bit-shift
    <td><code class=pp>x >> y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rshift__><code>x.<dfn>__rshift__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>bitwise <code>and</code>
    <td><code class=pp>x &amp; y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__and__><code>x.<dfn>__and__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>bitwise <code>xor</code>
    <td><code class=pp>x ^ y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__xor__><code>x.<dfn>__xor__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>bitwise <code>or</code>
    <td><code class=pp>x | y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__or__><code>x.<dfn>__or__</dfn>(<var>y</var>)</code></a>
    </table>
    
    <p>That&#8217;s all well and good if <var>x</var> is an instance of a class that implements those methods. But what if it doesn&#8217;t implement one of them? Or worse, what if it implements it, but it can&#8217;t handle certain kinds of arguments? For example:
    
    <pre class=screen>
    <samp class=p>>>> </samp><kbd class=pp>from fractions import Fraction</kbd>
    <samp class=p>>>> </samp><kbd class=pp>x = Fraction(1, 3)</kbd>
    <samp class=p>>>> </samp><kbd class=pp>1 / x</kbd>
    <samp class=pp>Fraction(3, 1)</samp></pre>
    
    <p>This is <em>not</em> a case of taking a <code>Fraction</code> and dividing it by an integer (as in the previous example). That case was straightforward: <code>x / 3</code> calls <code>x.__truediv__(3)</code>, and the <code>__truediv__()</code> method of the <code>Fraction</code> class handles all the math. But integers don&#8217;t &#8220;know&#8221; how to do arithmetic operations with fractions. So why does this example work?
    
    <p>There is a second set of arithmetic special methods with <i>reflected operands</i>. Given an arithmetic operation that takes two operands (<i>e.g.</i> <code>x / y</code>), there are two ways to go about it:
    
    <ol>
    <li>Tell <var>x</var> to divide itself by <var>y</var>, or
    <li>Tell <var>y</var> to divide itself into <var>x</var>
    </ol>
    
    <p>The set of special methods above take the first approach: given <code>x / y</code>, they provide a way for <var>x</var> to say &#8220;I know how to divide myself by <var>y</var>.&#8221; The following set of special methods tackle the second approach: they provide a way for <var>y</var> to say &#8220;I know how to be the denominator and divide myself into <var>x</var>.&#8221;
    
    <table>
    <tr><th>Notes
    <th>You Want&hellip;
    <th>So You Write&hellip;
    <th>And Python Calls&hellip;
    <tr><th>
    <td>addition
    <td><code class=pp>x + y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__radd__><code>y.<dfn>__radd__</dfn>(<var>x</var>)</code></a>
    <tr><th>
    <td>subtraction
    <td><code class=pp>x - y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rsub__><code>y.<dfn>__rsub__</dfn>(<var>x</var>)</code></a>
    <tr><th>
    <td>multiplication
    <td><code class=pp>x * y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rmul__><code>y.<dfn>__rmul__</dfn>(<var>x</var>)</code></a>
    <tr><th>
    <td>division
    <td><code class=pp>x / y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rtruediv__><code>y.<dfn>__rtruediv__</dfn>(<var>x</var>)</code></a>
    <tr><th>
    <td>floor division
    <td><code>x // y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rfloordiv__><code>y.<dfn>__rfloordiv__</dfn>(<var>x</var>)</code></a>
    <tr><th>
    <td>modulo (remainder)
    <td><code class=pp>x % y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rmod__><code>y.<dfn>__rmod__</dfn>(<var>x</var>)</code></a>
    <tr><th>
    <td>floor division <i class=baa>&amp;</i> modulo
    <td><code class=pp>divmod(x, y)</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rdivmod__><code>y.<dfn>__rdivmod__</dfn>(<var>x</var>)</code></a>
    <tr><th>
    <td>raise to power
    <td><code class=pp>x ** y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rpow__><code>y.<dfn>__rpow__</dfn>(<var>x</var>)</code></a>
    <tr><th>
    <td>left bit-shift
    <td><code class=pp>x &lt;&lt; y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rlshift__><code>y.<dfn>__rlshift__</dfn>(<var>x</var>)</code></a>
    <tr><th>
    <td>right bit-shift
    <td><code class=pp>x >> y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rrshift__><code>y.<dfn>__rrshift__</dfn>(<var>x</var>)</code></a>
    <tr><th>
    <td>bitwise <code>and</code>
    <td><code class=pp>x &amp; y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rand__><code>y.<dfn>__rand__</dfn>(<var>x</var>)</code></a>
    <tr><th>
    <td>bitwise <code>xor</code>
    <td><code class=pp>x ^ y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__rxor__><code>y.<dfn>__rxor__</dfn>(<var>x</var>)</code></a>
    <tr><th>
    <td>bitwise <code>or</code>
    <td><code class=pp>x | y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ror__><code>y.<dfn>__ror__</dfn>(<var>x</var>)</code></a>
    </table>
    
    <p>But wait! There&#8217;s more! If you&#8217;re doing &#8220;in-place&#8221; operations, like <code>x /= 3</code>, there are even more special methods you can define.
    
    <table>
    <tr><th>Notes
    <th>You Want&hellip;
    <th>So You Write&hellip;
    <th>And Python Calls&hellip;
    <tr><th>
    <td>in-place addition
    <td><code class=pp>x += y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__iadd__><code>x.<dfn>__iadd__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>in-place subtraction
    <td><code class=pp>x -= y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__isub__><code>x.<dfn>__isub__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>in-place multiplication
    <td><code class=pp>x *= y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__imul__><code>x.<dfn>__imul__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>in-place division
    <td><code class=pp>x /= y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__itruediv__><code>x.<dfn>__itruediv__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>in-place floor division
    <td><code>x //= y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ifloordiv__><code>x.<dfn>__ifloordiv__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>in-place modulo
    <td><code class=pp>x %= y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__imod__><code>x.<dfn>__imod__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>in-place raise to power
    <td><code class=pp>x **= y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ipow__><code>x.<dfn>__ipow__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>in-place left bit-shift
    <td><code class=pp>x &lt;&lt;= y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ilshift__><code>x.<dfn>__ilshift__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>in-place right bit-shift
    <td><code class=pp>x >>= y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__irshift__><code>x.<dfn>__irshift__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>in-place bitwise <code>and</code>
    <td><code class=pp>x &amp;= y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__iand__><code>x.<dfn>__iand__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>in-place bitwise <code>xor</code>
    <td><code class=pp>x ^= y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ixor__><code>x.<dfn>__ixor__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>in-place bitwise <code>or</code>
    <td><code class=pp>x |= y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ior__><code>x.<dfn>__ior__</dfn>(<var>y</var>)</code></a>
    </table>
    
    <p>Note: for the most part, the in-place operation methods are not required. If you don&#8217;t define an in-place method for a particular operation, Python will try the methods. For example, to execute the expression <code>x /= y</code>, Python will:
    
    <ol>
    <li>Try calling <code>x.__itruediv__(<var>y</var>)</code>. If this method is defined and returns a value other than <code>NotImplemented</code>, we&#8217;re done.
    <li>Try calling <code>x.__truediv__(<var>y</var>)</code>. If this method is defined and returns a value other than <code>NotImplemented</code>, the old value of <var>x</var> is discarded and replaced with the return value, just as if you had done <code> x = x / y</code> instead.
    <li>Try calling <code>y.__rtruediv__(<var>x</var>)</code>. If this method is defined and returns a value other than <code>NotImplemented</code>, the old value of <var>x</var> is discarded and replaced with the return value.
    </ol>
    
    <p>So you only need to define in-place methods like the <code>__itruediv__()</code> method if you want to do some special optimization for in-place operands. Otherwise Python will essentially reformulate the in-place operand to use a regular operand + a variable assignment.
    
    <p>There are also a few &#8220;unary&#8221; mathematical operations you can perform on number-like objects by themselves.
    
    <table>
    <tr><th>Notes
    <th>You Want&hellip;
    <th>So You Write&hellip;
    <th>And Python Calls&hellip;
    <tr><th>
    <td>negative number
    <td><code class=pp>-x</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__neg__><code>x.<dfn>__neg__</dfn>()</code></a>
    <tr><th>
    <td>positive number
    <td><code class=pp>+x</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__pos__><code>x.<dfn>__pos__</dfn>()</code></a>
    <tr><th>
    <td>absolute value
    <td><code class=pp>abs(x)</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__abs__><code>x.<dfn>__abs__</dfn>()</code></a>
    <tr><th>
    <td>inverse
    <td><code class=pp>~x</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__invert__><code>x.<dfn>__invert__</dfn>()</code></a>
    <tr><th>
    <td>complex number
    <td><code class=pp>complex(x)</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__complex__><code>x.<dfn>__complex__</dfn>()</code></a>
    <tr><th>
    <td>integer
    <td><code class=pp>int(x)</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__int__><code>x.<dfn>__int__</dfn>()</code></a>
    <tr><th>
    <td>floating point number
    <td><code class=pp>float(x)</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__float__><code>x.<dfn>__float__</dfn>()</code></a>
    <tr><th>
    <td>number rounded to nearest integer
    <td><code class=pp>round(x)</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__round__><code>x.<dfn>__round__</dfn>()</code></a>
    <tr><th>
    <td>number rounded to nearest <var>n</var> digits
    <td><code class=pp>round(x, n)</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__round__><code>x.<dfn>__round__</dfn>(n)</code></a>
    <tr><th>
    <td>smallest integer <code>>= x</code>
    <td><code class=pp>math.ceil(x)</code>
    <td><a href=http://docs.python.org/3.1/library/math.html#math.ceil><code>x.<dfn>__ceil__</dfn>()</code></a>
    <tr><th>
    <td>largest integer <code>&lt;= x</code>
    <td><code class=pp>math.floor(x)</code>
    <td><a href=http://docs.python.org/3.1/library/math.html#math.floor><code>x.<dfn>__floor__</dfn>()</code></a>
    <tr><th>
    <td>truncate <code>x</code> to nearest integer toward 0
    <td><code class=pp>math.trunc(x)</code>
    <td><a href=http://docs.python.org/3.1/library/math.html#math.trunc><code>x.<dfn>__trunc__</dfn>()</code></a>
    <tr><th><span class=inherit><a href=http://www.python.org/dev/peps/pep-0357/>PEP 357</a></span>
    <td>number as a list index
    <td><code class=pp>a_list[<var>x</var>]</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__index__><code>a_list[x.<dfn>__index__</dfn>()]</code></a>
    </table>
    
    <h2 id=rich-comparisons>Classes That Can Be Compared</h2>
    
    <p>I broke this section out from the previous one because comparisons are not strictly the purview of numbers. Many datatypes can be compared&nbsp;&mdash;&nbsp;strings, lists, even dictionaries. If you&#8217;re creating your own class and it makes sense to compare your objects to other objects, you can use the following special methods to implement comparisons.
    
    <table>
    <tr><th>Notes
    <th>You Want&hellip;
    <th>So You Write&hellip;
    <th>And Python Calls&hellip;
    <tr><th>
    <td>equality
    <td><code class=pp>x == y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__eq__><code>x.<dfn>__eq__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>inequality
    <td><code class=pp>x != y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ne__><code>x.<dfn>__ne__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>less than
    <td><code class=pp>x &lt; y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__lt__><code>x.<dfn>__lt__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>less than or equal to
    <td><code class=pp>x &lt;= y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__le__><code>x.<dfn>__le__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>greater than
    <td><code class=pp>x >  y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__gt__><code>x.<dfn>__gt__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>greater than or equal to
    <td><code class=pp>x >= y</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__ge__><code>x.<dfn>__ge__</dfn>(<var>y</var>)</code></a>
    <tr><th>
    <td>truth value in a boolean context
    <td><code class=pp>if x:</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__bool__><code>x.<dfn>__bool__</dfn>()</code></a>
    </table>
    
    <blockquote class=note>
    <p><span class=u>&#x261E;</span>If you define a <code>__lt__()</code> method but no <code>__gt__()</code> method, Python will use the <code>__lt__()</code> method with operands swapped. However, Python will not combine methods. For example, if you define a <code>__lt__()</code> method and a <code>__eq__()</code> method and try to test whether <code>x &lt;= y</code>, Python will not call <code>__lt__()</code> and <code>__eq__()</code> in sequence. It will only call the <code>__le__()</code> method.
    </blockquote>
    
    <h2 id=pickle>Classes That Can Be Serialized</h2>
    <!--see http://docs.python.org/3.1/library/pickle.html:-->
    
    <p>Python supports <a href=serializing.html>serializing and unserializing arbitrary objects</a>. (Most Python references call this process &#8220;pickling&#8221; and &#8220;unpickling.&#8221;) This can be useful for saving state to a file and restoring it later. All of the <a href=native-datatypes.html>native datatypes</a> support pickling already. If you create a custom class that you want to be able to pickle, read up on <a href=http://docs.python.org/3.1/library/pickle.html>the pickle protocol</a> to see when and how the following special methods are called.
    
    <table>
    <tr><th>Notes
    <th>You Want&hellip;
    <th>So You Write&hellip;
    <th>And Python Calls&hellip;
    <tr><th>
    <td>a custom object copy
    <td><code class=pp>copy.copy(x)</code>
    <td><a href=http://docs.python.org/3.1/library/copy.html><code>x.<dfn>__copy__</dfn>()</code></a>
    <tr><th>
    <td>a custom object deepcopy
    <td><code class=pp>copy.deepcopy(x)</code>
    <td><a href=http://docs.python.org/3.1/library/copy.html><code>x.<dfn>__deepcopy__</dfn>()</code></a>
    <tr><th>*
    <td>to get an object&#8217;s state before pickling
    <td><code class=pp>pickle.dump(x, <var>file</var>)</code>
    <td><a href=http://docs.python.org/3.1/library/pickle.html#pickle-state><code>x.<dfn>__getstate__</dfn>()</code></a>
    <tr><th>*
    <td>to serialize an object
    <td><code class=pp>pickle.dump(x, <var>file</var>)</code>
    <td><a href=http://docs.python.org/3.1/library/pickle.html#pickling-class-instances><code>x.<dfn>__reduce__</dfn>()</code></a>
    <tr><th>*
    <td>to serialize an object (new pickling protocol)
    <td><code class=pp>pickle.dump(x, <var>file</var>, <var>protocol_version</var>)</code>
    <td><a href=http://docs.python.org/3.1/library/pickle.html#pickling-class-instances><code>x.<dfn>__reduce_ex__</dfn>(<var>protocol_version</var>)</code></a>
    <tr><th>*
    <td>control over how an object is created during unpickling
    <td><code class=pp>x = pickle.load(<var>file</var>)</code>
    <td><a href=http://docs.python.org/3.1/library/pickle.html#pickling-class-instances><code>x.<dfn>__getnewargs__</dfn>()</code></a>
    <tr><th>*
    <td>to restore an object&#8217;s state after unpickling
    <td><code class=pp>x = pickle.load(<var>file</var>)</code>
    <td><a href=http://docs.python.org/3.1/library/pickle.html#pickle-state><code>x.<dfn>__setstate__</dfn>()</code></a>
    </table>
    
    <p>* To recreate a serialized object, Python needs to create a new object that looks like the serialized object, then set the values of all the attributes on the new object. The <code>__getnewargs__()</code> method controls how the object is created, then the <code>__setstate__()</code> method controls how the attribute values are restored.
    
    <h2 id=context-managers>Classes That Can Be Used in a <code>with</code> Block</h2>
    
    <p>A <code>with</code> block defines a <a href=http://www.python.org/doc/3.1/library/stdtypes.html#typecontextmanager>runtime context</a>; you &#8220;enter&#8221; the context when you execute the <code>with</code> statement, and you &#8220;exit&#8221; the context after you execute the last statement in the block.
    
    <table>
    <tr><th>Notes
    <th>You Want&hellip;
    <th>So You Write&hellip;
    <th>And Python Calls&hellip;
    <tr><th>
    <td>do something special when entering a <code>with</code> block
    <td><code class=pp>with x:</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__enter__><code>x.<dfn>__enter__</dfn>()</code></a>
    <tr><th>
    <td>do something special when leaving a <code>with</code> block
    <td><code class=pp>with x:</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__exit__><code>x.<dfn>__exit__</dfn>(<var>exc_type</var>, <var>exc_value</var>, <var>traceback</var>)</code></a>
    </table>
    
    <p>This is how the <a href=files.html#with><code>with <var>file</var></code> idiom</a> works.
    
    <pre class=pp><code># excerpt from io.py:
    def _checkClosed(self, msg=None):
        '''Internal: raise an ValueError if file is closed
        '''
        if self.closed:
            raise ValueError('I/O operation on closed file.'
                             if msg is None else msg)
    
    def __enter__(self):
        '''Context management protocol.  Returns self.'''
    <a>    self._checkClosed()                                <span class=u>&#x2460;</span></a>
    <a>    return self                                        <span class=u>&#x2461;</span></a>
    
    def __exit__(self, *args):
        '''Context management protocol.  Calls close()'''
    <a>    self.close()                                       <span class=u>&#x2462;</span></a></code></pre>
    <ol>
    <li>The file object defines both an <code>__enter__()</code> and an <code>__exit__()</code> method. The <code>__enter__()</code> method checks that the file is open; if it&#8217;s not, the <code>_checkClosed()</code> method raises an exception.
    <li>The <code>__enter__()</code> method should almost always return <var>self</var>&nbsp;&mdash;&nbsp;this is the object that the <code>with</code> block will use to dispatch properties and methods.
    <li>After the <code>with</code> block, the file object automatically closes. How? In the <code>__exit__()</code> method, it calls <code>self.close()</code>.
    </ol>
    
    <blockquote class=note>
    <p><span class=u>&#x261E;</span>The <code>__exit__()</code> method will always be called, even if an exception is raised inside the <code>with</code> block. In fact, if an exception is raised, the exception information will be passed to the <code>__exit__()</code> method. See <a href=http://www.python.org/doc/3.1/reference/datamodel.html#with-statement-context-managers>With Statement Context Managers</a> for more details.
    </blockquote>
    
    <p>For more on context managers, see <a href=files.html#with>Closing Files Automatically</a> and <a href=files.html#redirect>Redirecting Standard Output</a>.
    
    <h2 id=esoterica>Really Esoteric Stuff</h2>
    
    <p>If you know what you&#8217;re doing, you can gain almost complete control over how classes are compared, how attributes are defined, and what kinds of classes are considered subclasses of your class.
    
    <table>
    <tr><th>Notes
    <th>You Want&hellip;
    <th>So You Write&hellip;
    <th>And Python Calls&hellip;
    <tr><th>
    <td>a class constructor
    <td><code class=pp>x = MyClass()</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__new__><code>x.<dfn>__new__</dfn>()</code></a>
    <tr><th>*
    <td>a class destructor
    <td><code class=pp>del x</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__del__><code>x.<dfn>__del__</dfn>()</code></a>
    <tr><th>
    <td>only a specific set of attributes to be defined
    <td>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__slots__><code>x.<dfn>__slots__</dfn>()</code></a>
    <tr><th>
    <td>a custom hash value
    <td><code class=pp>hash(x)</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__hash__><code>x.<dfn>__hash__</dfn>()</code></a>
    <tr><th>
    <td>to get a property&#8217;s value
    <td><code class=pp>x.color</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__get__><code>type(x).<dfn>__dict__</dfn>['color'].__get__(x, type(x))</code></a>
    <tr><th>
    <td>to set a property&#8217;s value
    <td><code class=pp>x.color = 'PapayaWhip'</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__set__><code>type(x).<dfn>__dict__</dfn>['color'].__set__(x, 'PapayaWhip')</code></a>
    <tr><th>
    <td>to delete a property
    <td><code class=pp>del x.color</code>
    <td><a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__delete__><code>type(x).<dfn>__dict__</dfn>['color'].__del__(x)</code></a>
    <tr><th>
    <td>to control whether an object is an instance of your class
    <td><code class=pp>isinstance(x, MyClass)</code>
    <td><a href=http://www.python.org/dev/peps/pep-3119/#overloading-isinstance-and-issubclass><code>MyClass.<dfn>__instancecheck__</dfn>(x)</code></a>
    <tr><th>
    <td>to control whether a class is a subclass of your class
    <td><code class=pp>issubclass(C, MyClass)</code>
    <td><a href=http://www.python.org/dev/peps/pep-3119/#overloading-isinstance-and-issubclass><code>MyClass.<dfn>__subclasscheck__</dfn>(C)</code></a>
    <tr><th>
    <td>to control whether a class is a subclass of your abstract base class
    <td><code class=pp>issubclass(C, MyABC)</code>
    <td><a href=http://docs.python.org/3.1/library/abc.html#abc.ABCMeta.__subclasshook__><code>MyABC.<dfn>__subclasshook__</dfn>(C)</code></a>
    </table>
    
    <p><sup>*</sup> Exactly when Python calls the <code>__del__()</code> special method <a href=http://www.python.org/doc/3.1/reference/datamodel.html#object.__del__>is incredibly complicated</a>. To fully understand it, you need to know how <a href=http://www.python.org/doc/3.1/reference/datamodel.html#objects-values-and-types>Python keeps track of objects in memory</a>. Here&#8217;s a good article on <a href=http://www.electricmonk.nl/log/2008/07/07/python-destructor-and-garbage-collection-notes/>Python garbage collection and class destructors</a>. You should also read about <a href=http://mindtrove.info/articles/python-weak-references/>weak references</a>, the <a href=http://docs.python.org/3.1/library/weakref.html><code>weakref</code> module</a>, and probably the <a href=http://www.python.org/doc/3.1/library/gc.html><code>gc</code> module</a> for good measure.
    
    <h2 id=furtherreading>Further Reading</h2>
    
    <p>Modules mentioned in this appendix:
    
    <ul>
    <li><a href=http://docs.python.org/3.1/library/zipfile.html><code>zipfile</code> module</a>
    <li><a href=http://docs.python.org/3.1/library/cgi.html><code>cgi</code> module</a>
    <li><a href=http://www.python.org/doc/3.1/library/collections.html><code>collections</code> module</a>
    <li><a href=http://docs.python.org/3.1/library/math.html><code>math</code> module</a>
    <li><a href=http://docs.python.org/3.1/library/pickle.html><code>pickle</code> module</a>
    <li><a href=http://docs.python.org/3.1/library/copy.html><code>copy</code> module</a>
    <li><a href=http://docs.python.org/3.1/library/abc.html><code>abc</code> (&#8220;Abstract Base Classes&#8221;) module</a>
    </ul>
    
    <p>Other light reading:
    
    <ul>
    <li><a href=http://www.python.org/doc/3.1/library/string.html#formatspec>Format Specification Mini-Language</a>
    <li><a href=http://www.python.org/doc/3.1/reference/datamodel.html>Python data model</a>
    <li><a href=http://www.python.org/doc/3.1/library/stdtypes.html>Built-in types</a>
    <li><a href=http://www.python.org/dev/peps/pep-0357/><abbr>PEP</abbr> 357: Allowing Any Object to be Used for Slicing</a>
    <li><a href=http://www.python.org/dev/peps/pep-3119/><abbr>PEP</abbr> 3119: Introducing Abstract Base Classes</a>
    </ul>
    
    <p class=v><a href=porting-code-to-python-3-with-2to3.html rel=prev title='back to &#8220;Porting code to Python 3 with 2to3&#8221;'><span class=u>&#x261C;</span></a> <a rel=next href=where-to-go-from-here.html title='onward to &#8220;Where To Go From Here&#8221;'><span class=u>&#x261E;</span></a>
    <p class=c>&copy; 2001&ndash;11 <a href=about.html>Mark Pilgrim</a>
    <script src=j/jquery.js></script>
    <script src=j/prettify.js></script>
    <script src=j/dip3.js></script>
    ����������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/�����������������������������������������������������0000755�0000000�0000000�00000000000�11773544727�017426� 5����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/romantest7.py����������������������������������������0000644�0000000�0000000�00000014240�11773544727�022104� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for roman1.py
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    
    import roman7
    import unittest
    
    class KnownValues(unittest.TestCase):
        known_values = ( (1, 'I'),
                         (2, 'II'),
                         (3, 'III'),
                         (4, 'IV'),
                         (5, 'V'),
                         (6, 'VI'),
                         (7, 'VII'),
                         (8, 'VIII'),
                         (9, 'IX'),
                         (10, 'X'),
                         (50, 'L'),
                         (100, 'C'),
                         (500, 'D'),
                         (1000, 'M'),
                         (31, 'XXXI'),
                         (148, 'CXLVIII'),
                         (294, 'CCXCIV'),
                         (312, 'CCCXII'),
                         (421, 'CDXXI'),
                         (528, 'DXXVIII'),
                         (621, 'DCXXI'),
                         (782, 'DCCLXXXII'),
                         (870, 'DCCCLXX'),
                         (941, 'CMXLI'),
                         (1043, 'MXLIII'),
                         (1110, 'MCX'),
                         (1226, 'MCCXXVI'),
                         (1301, 'MCCCI'),
                         (1485, 'MCDLXXXV'),
                         (1509, 'MDIX'),
                         (1607, 'MDCVII'),
                         (1754, 'MDCCLIV'),
                         (1832, 'MDCCCXXXII'),
                         (1993, 'MCMXCIII'),
                         (2074, 'MMLXXIV'),
                         (2152, 'MMCLII'),
                         (2212, 'MMCCXII'),
                         (2343, 'MMCCCXLIII'),
                         (2499, 'MMCDXCIX'),
                         (2574, 'MMDLXXIV'),
                         (2646, 'MMDCXLVI'),
                         (2723, 'MMDCCXXIII'),
                         (2892, 'MMDCCCXCII'),
                         (2975, 'MMCMLXXV'),
                         (3051, 'MMMLI'),
                         (3185, 'MMMCLXXXV'),
                         (3250, 'MMMCCL'),
                         (3313, 'MMMCCCXIII'),
                         (3408, 'MMMCDVIII'),
                         (3501, 'MMMDI'),
                         (3610, 'MMMDCX'),
                         (3743, 'MMMDCCXLIII'),
                         (3844, 'MMMDCCCXLIV'),
                         (3888, 'MMMDCCCLXXXVIII'),
                         (3940, 'MMMCMXL'),
                         (3999, 'MMMCMXCIX'))
    
        def test_to_roman_known_values(self):
            '''to_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman7.to_roman(integer)
                self.assertEqual(numeral, result)
    
        def test_from_roman_known_values(self):
            '''from_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman7.from_roman(numeral)
                self.assertEqual(integer, result)
    
    class ToRomanBadInput(unittest.TestCase):
        def test_too_large(self):
            '''to_roman should fail with large input'''
            self.assertRaises(roman7.OutOfRangeError, roman7.to_roman, 4000)
    
        def test_zero(self):
            '''to_roman should fail with 0 input'''
            self.assertRaises(roman7.OutOfRangeError, roman7.to_roman, 0)
    
        def test_negative(self):
            '''to_roman should fail with negative input'''
            self.assertRaises(roman7.OutOfRangeError, roman7.to_roman, -1)
    
        def test_non_integer(self):
            '''to_roman should fail with non-integer input'''
            self.assertRaises(roman7.NotIntegerError, roman7.to_roman, 0.5)
    
    class FromRomanBadInput(unittest.TestCase):
        def test_too_many_repeated_numerals(self):
            '''from_roman should fail with too many repeated numerals'''
            for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
                self.assertRaises(roman7.InvalidRomanNumeralError, roman7.from_roman, s)
    
        def test_repeated_pairs(self):
            '''from_roman should fail with repeated pairs of numerals'''
            for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
                self.assertRaises(roman7.InvalidRomanNumeralError, roman7.from_roman, s)
    
        def test_malformed_antecedents(self):
            '''from_roman should fail with malformed antecedents'''
            for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
                      'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
                self.assertRaises(roman7.InvalidRomanNumeralError, roman7.from_roman, s)
    
        def test_non_string(self):
            '''from_roman should fail with non-string input'''
            self.assertRaises(roman7.InvalidRomanNumeralError, roman7.from_roman, 1)
    
    class RoundtripCheck(unittest.TestCase):
        def test_roundtrip(self):
            '''from_roman(to_roman(n))==n for all n'''
            for integer in range(1, 4000):
                numeral = roman7.to_roman(integer)
                result = roman7.from_roman(numeral)
                self.assertEqual(integer, result)
    
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/pluraltest6.py���������������������������������������0000644�0000000�0000000�00000013670�11773544727�022274� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for plural6.py'''
    
    import plural6
    import unittest
    
    class KnownValues(unittest.TestCase):
        def test_sxz(self):
            'words ending in S, X, and Z'
            nouns = {
                'bass': 'basses',
                'bus': 'buses',
                'walrus': 'walruses',
                'box': 'boxes',
                'fax': 'faxes',
                'suffix': 'suffixes',
                'mailbox': 'mailboxes',
                'buzz': 'buzzes',
                'waltz': 'waltzes'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural6.plural(singular), plural)
    
        def test_h(self):
            'words ending in H'
            nouns = {
                'coach': 'coaches',
                'glitch': 'glitches',
                'rash': 'rashes',
                'watch': 'watches',
                'cheetah': 'cheetahs',
                'cough': 'coughs'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural6.plural(singular), plural)
    
        def test_y(self):
            'words ending in Y'
            nouns = {
                'utility': 'utilities',
                'vacancy': 'vacancies',
                'boy': 'boys',
                'day': 'days'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural6.plural(singular), plural)
    
        def test_ouce(self):
            'words ending in OUSE'
            nouns = {
                 'mouse': 'mice',
                 'louse': 'lice'
                 }
            for singular, plural in nouns.items():
                self.assertEqual(plural6.plural(singular), plural)
    
        def test_child(self):
            'special case: child'
            nouns = {
                 'child': 'children'
                 }
            for singular, plural in nouns.items():
                self.assertEqual(plural6.plural(singular), plural)
    
        def test_oot(self):
            'special case: foot'
            nouns = {
                 'foot': 'feet'
                 }
            for singular, plural in nouns.items():
                self.assertEqual(plural6.plural(singular), plural)
    
        def test_ooth(self):
            'words ending in OOTH'
            nouns = {
                 'booth': 'booths',
                 'tooth': 'teeth'
                 }
            for singular, plural in nouns.items():
                self.assertEqual(plural6.plural(singular), plural)
    
        def test_f_ves(self):
            'words ending in F that become VES'
            nouns = {
                 'leaf': 'leaves',
                 'loaf': 'loaves'
                 }
            for singular, plural in nouns.items():
                self.assertEqual(plural6.plural(singular), plural)
    
        def test_sis(self):
            'words ending in SIS'
            nouns = {
                 'thesis': 'theses'
                 }
            for singular, plural in nouns.items():
                self.assertEqual(plural6.plural(singular), plural)
    
        def test_man(self):
            'words ending in MAN'
            nouns = {
                 'man': 'men',
                 'mailman': 'mailmen',
                 'human': 'humans',
                 'roman': 'romans'
                 }
            for singular, plural in nouns.items():
                self.assertEqual(plural6.plural(singular), plural)
    
        def test_ife(self):
            'words ending in IFE'
            nouns = {
                 'knife': 'knives',
                 'wife': 'wives',
                 'lowlife': 'lowlifes'
                 }
            for singular, plural in nouns.items():
                self.assertEqual(plural6.plural(singular), plural)
    
        def test_eau(self):
            'words ending in EAU'
            nouns = {
                 'tableau': 'tableaux'
                 }
            for singular, plural in nouns.items():
                self.assertEqual(plural6.plural(singular), plural)
    
        def test_elf(self):
            'words ending in ELF'
            nouns = {
                 'elf': 'elves',
                 'shelf': 'shelves',
                 'delf': 'delfs',
                 'pelf': 'pelfs'
                 }
            for singular, plural in nouns.items():
                self.assertEqual(plural6.plural(singular), plural)
    
        def test_same(self):
            'words that are their own plural'
            nouns = {
                 'sheep': 'sheep',
                 'deer': 'deer',
                 'fish': 'fish',
                 'moose': 'moose',
                 'aircraft': 'aircraft',
                 'series': 'series',
                 'haiku': 'haiku'
                 }
            for singular, plural in nouns.items():
                self.assertEqual(plural6.plural(singular), plural)
    
        def test_default(self):
            'unexceptional words'
            nouns = {
                'papaya': 'papayas',
                'whip': 'whips',
                'palimpsest': 'palimpsests'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural6.plural(singular), plural)
            
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/entry-pretty.json������������������������������������0000644�0000000�0000000�00000001001�11773544727�022777� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{
      "comments_link": null, 
      "internal_id": {
        "__class__": "bytes", 
        "__value__": [
          222, 
          213, 
          180, 
          248
        ]
      }, 
      "title": "Dive into history, 2009 edition", 
      "tags": [
        "diveintopython", 
        "docbook", 
        "html"
      ], 
      "article_link": "http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition", 
      "published_date": {
        "__class__": "time.asctime", 
        "__value__": "Fri Mar 27 22:20:42 2009"
      }, 
      "published": true
    }�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/romantest2.py����������������������������������������0000644�0000000�0000000�00000010206�11773544727�022075� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for roman1.py
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    
    import roman2
    import unittest
    
    class KnownValues(unittest.TestCase):
        known_values = ( (1, 'I'),
                         (2, 'II'),
                         (3, 'III'),
                         (4, 'IV'),
                         (5, 'V'),
                         (6, 'VI'),
                         (7, 'VII'),
                         (8, 'VIII'),
                         (9, 'IX'),
                         (10, 'X'),
                         (50, 'L'),
                         (100, 'C'),
                         (500, 'D'),
                         (1000, 'M'),
                         (31, 'XXXI'),
                         (148, 'CXLVIII'),
                         (294, 'CCXCIV'),
                         (312, 'CCCXII'),
                         (421, 'CDXXI'),
                         (528, 'DXXVIII'),
                         (621, 'DCXXI'),
                         (782, 'DCCLXXXII'),
                         (870, 'DCCCLXX'),
                         (941, 'CMXLI'),
                         (1043, 'MXLIII'),
                         (1110, 'MCX'),
                         (1226, 'MCCXXVI'),
                         (1301, 'MCCCI'),
                         (1485, 'MCDLXXXV'),
                         (1509, 'MDIX'),
                         (1607, 'MDCVII'),
                         (1754, 'MDCCLIV'),
                         (1832, 'MDCCCXXXII'),
                         (1993, 'MCMXCIII'),
                         (2074, 'MMLXXIV'),
                         (2152, 'MMCLII'),
                         (2212, 'MMCCXII'),
                         (2343, 'MMCCCXLIII'),
                         (2499, 'MMCDXCIX'),
                         (2574, 'MMDLXXIV'),
                         (2646, 'MMDCXLVI'),
                         (2723, 'MMDCCXXIII'),
                         (2892, 'MMDCCCXCII'),
                         (2975, 'MMCMLXXV'),
                         (3051, 'MMMLI'),
                         (3185, 'MMMCLXXXV'),
                         (3250, 'MMMCCL'),
                         (3313, 'MMMCCCXIII'),
                         (3408, 'MMMCDVIII'),
                         (3501, 'MMMDI'),
                         (3610, 'MMMDCX'),
                         (3743, 'MMMDCCXLIII'),
                         (3844, 'MMMDCCCXLIV'),
                         (3888, 'MMMDCCCLXXXVIII'),
                         (3940, 'MMMCMXL'),
                         (3999, 'MMMCMXCIX'))
    
        def test_to_roman_known_values(self):
            '''to_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman2.to_roman(integer)
                self.assertEqual(numeral, result)
    
    class ToRomanBadInput(unittest.TestCase):
        def test_too_large(self):
            '''to_roman should fail with large input'''
            self.assertRaises(roman2.OutOfRangeError, roman2.to_roman, 4000)
    
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/pluraltest4.py���������������������������������������0000644�0000000�0000000�00000005653�11773544727�022274� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for plural1.py'''
    
    import plural4
    import unittest
    
    class KnownValues(unittest.TestCase):
        def test_sxz(self):
            'words ending in S, X, and Z'
            nouns = {
                'bass': 'basses',
                'bus': 'buses',
                'walrus': 'walruses',
                'box': 'boxes',
                'fax': 'faxes',
                'suffix': 'suffixes',
                'mailbox': 'mailboxes',
                'buzz': 'buzzes',
                'waltz': 'waltzes'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural4.plural(singular), plural)
    
        def test_h(self):
            'words ending in H'
            nouns = {
                'coach': 'coaches',
                'glitch': 'glitches',
                'rash': 'rashes',
                'watch': 'watches',
                'cheetah': 'cheetahs',
                'cough': 'coughs'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural4.plural(singular), plural)
    
        def test_y(self):
            'words ending in Y'
            nouns = {
                'utility': 'utilities',
                'vacancy': 'vacancies',
                'boy': 'boys',
                'day': 'days'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural4.plural(singular), plural)
    
        def test_default(self):
            'unexceptional words'
            nouns = {
                'papaya': 'papayas',
                'whip': 'whips',
                'palimpsest': 'palimpsests'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural4.plural(singular), plural)
            
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    �������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/alphametics.py���������������������������������������0000644�0000000�0000000�00000004757�11773544727�022307� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Find solutions to alphametic equations.
    
    >>> alphametics.solve('SEND + MORE == MONEY')
    '9567 + 1085 == 10652'
    '''
    
    import re
    import itertools
    
    def solve(puzzle):
        words = re.findall('[A-Z]+', puzzle.upper())
        unique_characters = set(''.join(words))
        assert len(unique_characters) <= 10, 'Too many letters'
        first_letters = {word[0] for word in words}
        n = len(first_letters)
        sorted_characters = ''.join(first_letters) + \
            ''.join(unique_characters - first_letters)
        characters = tuple(ord(c) for c in sorted_characters)
        digits = tuple(ord(c) for c in '0123456789')
        zero = digits[0]
        for guess in itertools.permutations(digits, len(characters)):
            if zero not in guess[:n]:
                equation = puzzle.translate(dict(zip(characters, guess)))
                if eval(equation):
                    return equation
    
    if __name__ == '__main__':
        import sys
        for puzzle in sys.argv[1:]:
            print(puzzle)
            solution = solve(puzzle)
            if solution:
                print(solution)
    
    # Copyright (c) 2009, Raymond Hettinger, All rights reserved.
    # Ported to Python 3 and modified by Mark Pilgrim
    # original: http://code.activestate.com/recipes/576615/
    # 
    # 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.
    # 
    # 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.
    �����������������diveintopython3-20110517-77958af.orig/examples/plural4.py�������������������������������������������0000644�0000000�0000000�00000004326�11773544727�021370� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Pluralize English nouns (stage 4)
    
    Command line usage:
    $ python plural4.py noun
    nouns
    '''
    
    import re
    
    def build_match_and_apply_functions(pattern, search, replace):
        def matches_rule(word):
            return re.search(pattern, word)
        def apply_rule(word):
            return re.sub(search, replace, word)
        return (matches_rule, apply_rule)
    
    rules = []
    with open('plural4-rules.txt', encoding='utf-8') as pattern_file:
        for line in pattern_file:
            pattern, search, replace = line.split(None, 3)
            rules.append(build_match_and_apply_functions(
                    pattern, search, replace))
    
    def plural(noun):
        for matches_rule, apply_rule in rules:
            if matches_rule(noun):
                return apply_rule(noun)
    
    if __name__ == '__main__':
        import sys
        if sys.argv[1:]:
            print(plural(sys.argv[1]))
        else:
            print(__doc__)
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/romantest9.py����������������������������������������0000644�0000000�0000000�00000014754�11773544727�022120� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for roman1.py
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    
    import roman9
    import unittest
    
    class KnownValues(unittest.TestCase):
        known_values = ( (1, 'I'),
                         (2, 'II'),
                         (3, 'III'),
                         (4, 'IV'),
                         (5, 'V'),
                         (6, 'VI'),
                         (7, 'VII'),
                         (8, 'VIII'),
                         (9, 'IX'),
                         (10, 'X'),
                         (50, 'L'),
                         (100, 'C'),
                         (500, 'D'),
                         (1000, 'M'),
                         (31, 'XXXI'),
                         (148, 'CXLVIII'),
                         (294, 'CCXCIV'),
                         (312, 'CCCXII'),
                         (421, 'CDXXI'),
                         (528, 'DXXVIII'),
                         (621, 'DCXXI'),
                         (782, 'DCCLXXXII'),
                         (870, 'DCCCLXX'),
                         (941, 'CMXLI'),
                         (1043, 'MXLIII'),
                         (1110, 'MCX'),
                         (1226, 'MCCXXVI'),
                         (1301, 'MCCCI'),
                         (1485, 'MCDLXXXV'),
                         (1509, 'MDIX'),
                         (1607, 'MDCVII'),
                         (1754, 'MDCCLIV'),
                         (1832, 'MDCCCXXXII'),
                         (1993, 'MCMXCIII'),
                         (2074, 'MMLXXIV'),
                         (2152, 'MMCLII'),
                         (2212, 'MMCCXII'),
                         (2343, 'MMCCCXLIII'),
                         (2499, 'MMCDXCIX'),
                         (2574, 'MMDLXXIV'),
                         (2646, 'MMDCXLVI'),
                         (2723, 'MMDCCXXIII'),
                         (2892, 'MMDCCCXCII'),
                         (2975, 'MMCMLXXV'),
                         (3051, 'MMMLI'),
                         (3185, 'MMMCLXXXV'),
                         (3250, 'MMMCCL'),
                         (3313, 'MMMCCCXIII'),
                         (3408, 'MMMCDVIII'),
                         (3501, 'MMMDI'),
                         (3610, 'MMMDCX'),
                         (3743, 'MMMDCCXLIII'),
                         (3844, 'MMMDCCCXLIV'),
                         (3888, 'MMMDCCCLXXXVIII'),
                         (3940, 'MMMCMXL'),
                         (3999, 'MMMCMXCIX'),
                         (4000, 'MMMM'),
                         (4500, 'MMMMD'),
                         (4888, 'MMMMDCCCLXXXVIII'),
                         (4999, 'MMMMCMXCIX'))
    
        def test_to_roman_known_values(self):
            '''to_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman9.to_roman(integer)
                self.assertEqual(numeral, result)
    
        def test_from_roman_known_values(self):
            '''from_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman9.from_roman(numeral)
                self.assertEqual(integer, result)
    
    class ToRomanBadInput(unittest.TestCase):
        def test_too_large(self):
            '''to_roman should fail with large input'''
            self.assertRaises(roman9.OutOfRangeError, roman9.to_roman, 5000)
    
        def test_zero(self):
            '''to_roman should fail with 0 input'''
            self.assertRaises(roman9.OutOfRangeError, roman9.to_roman, 0)
    
        def test_negative(self):
            '''to_roman should fail with negative input'''
            self.assertRaises(roman9.OutOfRangeError, roman9.to_roman, -1)
    
        def test_non_integer(self):
            '''to_roman should fail with non-integer input'''
            self.assertRaises(roman9.NotIntegerError, roman9.to_roman, 0.5)
    
    class FromRomanBadInput(unittest.TestCase):
        def test_too_many_repeated_numerals(self):
            '''from_roman should fail with too many repeated numerals'''
            for s in ('MMMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
                self.assertRaises(roman9.InvalidRomanNumeralError, roman9.from_roman, s)
    
        def test_repeated_pairs(self):
            '''from_roman should fail with repeated pairs of numerals'''
            for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
                self.assertRaises(roman9.InvalidRomanNumeralError, roman9.from_roman, s)
    
        def test_malformed_antecedents(self):
            '''from_roman should fail with malformed antecedents'''
            for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
                      'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
                self.assertRaises(roman9.InvalidRomanNumeralError, roman9.from_roman, s)
    
        def test_blank(self):
            '''from_roman should fail with blank string'''
            self.assertRaises(roman9.InvalidRomanNumeralError, roman9.from_roman, '')
    
        def test_non_string(self):
            '''from_roman should fail with non-string input'''
            self.assertRaises(roman9.InvalidRomanNumeralError, roman9.from_roman, 1)
    
    class RoundtripCheck(unittest.TestCase):
        def test_roundtrip(self):
            '''from_roman(to_roman(n))==n for all n'''
            for integer in range(1, 5000):
                numeral = roman9.to_roman(integer)
                result = roman9.from_roman(numeral)
                self.assertEqual(integer, result)
    
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ��������������������diveintopython3-20110517-77958af.orig/examples/pluraltest3.py���������������������������������������0000644�0000000�0000000�00000005653�11773544727�022273� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for plural1.py'''
    
    import plural3
    import unittest
    
    class KnownValues(unittest.TestCase):
        def test_sxz(self):
            'words ending in S, X, and Z'
            nouns = {
                'bass': 'basses',
                'bus': 'buses',
                'walrus': 'walruses',
                'box': 'boxes',
                'fax': 'faxes',
                'suffix': 'suffixes',
                'mailbox': 'mailboxes',
                'buzz': 'buzzes',
                'waltz': 'waltzes'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural3.plural(singular), plural)
    
        def test_h(self):
            'words ending in H'
            nouns = {
                'coach': 'coaches',
                'glitch': 'glitches',
                'rash': 'rashes',
                'watch': 'watches',
                'cheetah': 'cheetahs',
                'cough': 'coughs'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural3.plural(singular), plural)
    
        def test_y(self):
            'words ending in Y'
            nouns = {
                'utility': 'utilities',
                'vacancy': 'vacancies',
                'boy': 'boys',
                'day': 'days'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural3.plural(singular), plural)
    
        def test_default(self):
            'unexceptional words'
            nouns = {
                'papaya': 'papayas',
                'whip': 'whips',
                'palimpsest': 'palimpsests'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural3.plural(singular), plural)
            
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    �������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/plural5.py�������������������������������������������0000644�0000000�0000000�00000004512�11773544727�021366� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Pluralize English nouns (stage 5)
    
    Command line usage:
    $ python plural5.py noun
    nouns
    '''
    
    import re
    
    def build_match_and_apply_functions(pattern, search, replace):
        def matches_rule(word):
            return re.search(pattern, word)
        def apply_rule(word):
            return re.sub(search, replace, word)
        return [matches_rule, apply_rule]
    
    def rules(rules_filename):
        with open(rules_filename, encoding='utf-8') as pattern_file:
            for line in pattern_file:
                pattern, search, replace = line.split(None, 3)
                yield build_match_and_apply_functions(pattern, search, replace)
    
    def plural(noun, rules_filename='plural5-rules.txt'):
        for matches_rule, apply_rule in rules(rules_filename):
            if matches_rule(noun):
                return apply_rule(noun)
        raise ValueError('no matching rule for {0}'.format(noun))
    
    if __name__ == '__main__':
        import sys
        if sys.argv[1:]:
            print(plural(sys.argv[1]))
        else:
            print(__doc__)
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/plural2.py�������������������������������������������0000644�0000000�0000000�00000004375�11773544727�021372� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Pluralize English nouns (stage 2)
    
    Command line usage:
    $ python plural2.py noun
    nouns
    '''
    
    import re
    
    def match_sxz(noun):
        return re.search('[sxz]$', noun)
    
    def apply_sxz(noun):
        return re.sub('$', 'es', noun)
    
    def match_h(noun):
        return re.search('[^aeioudgkprt]h$', noun)
    
    def apply_h(noun):
        return re.sub('$', 'es', noun)
    
    def match_y(noun):
        return re.search('[^aeiou]y$', noun)
            
    def apply_y(noun):
        return re.sub('y$', 'ies', noun)
    
    def match_default(noun):
        return True
    
    def apply_default(noun):
        return noun + 's'
    
    rules = ((match_sxz, apply_sxz),
             (match_h, apply_h),
             (match_y, apply_y),
             (match_default, apply_default)
             )
    
    def plural(noun):
        for matches_rule, apply_rule in rules:
            if matches_rule(noun):
                return apply_rule(noun)
    
    if __name__ == '__main__':
        import sys
        if sys.argv[1:]:
            print(plural(sys.argv[1]))
        else:
            print(__doc__)
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/feed-broken.xml��������������������������������������0000644�0000000�0000000�00000006002�11773544727�022327� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version='1.0' encoding='utf-8'?>
    <feed xmlns='http://www.w3.org/2005/Atom' xml:lang='en'>
      <title>dive into &hellip;</title>
      <subtitle>currently between addictions</subtitle>
      <id>tag:diveintomark.org,2001-07-29:/</id>
      <updated>2009-03-27T21:56:07Z</updated>
      <link rel='alternate' type='text/html' href='http://diveintomark.org/'/>
      <entry>
        <author>
          <name>Mark</name>
          <uri>http://diveintomark.org/</uri>
        </author>
        <title>Dive into history, 2009 edition</title>
        <link rel='alternate' type='text/html'
          href='http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition'/>
        <id>tag:diveintomark.org,2009-03-27:/archives/20090327172042</id>
        <updated>2009-03-27T21:56:07Z</updated>
        <published>2009-03-27T17:20:42Z</published>
        <category scheme='http://diveintomark.org' term='diveintopython'/>
        <category scheme='http://diveintomark.org' term='docbook'/>
        <category scheme='http://diveintomark.org' term='html'/>
        <summary type='html'>Putting an entire chapter on one page sounds
          bloated, but consider this &amp;mdash; my longest chapter so far
          would be 75 printed pages, and it loads in under 5 seconds&amp;hellip;
          On dialup.</summary>
      </entry>
      <entry>
        <author>
          <name>Mark</name>
          <uri>http://diveintomark.org/</uri>
        </author>
        <title>Accessibility is a harsh mistress</title>
        <link rel='alternate' type='text/html'
          href='http://diveintomark.org/archives/2009/03/21/accessibility-is-a-harsh-mistress'/>
        <id>tag:diveintomark.org,2009-03-21:/archives/20090321200928</id>
        <updated>2009-03-22T01:05:37Z</updated>
        <published>2009-03-21T20:09:28Z</published>
        <category scheme='http://diveintomark.org' term='accessibility'/>
        <summary type='html'>The accessibility orthodoxy does not permit people to
          question the value of features that are rarely useful and rarely used.</summary>
      </entry>
      <entry>
        <author>
          <name>Mark</name>
        </author>
        <title>A gentle introduction to video encoding, part 1: container formats</title>
        <link rel='alternate' type='text/html'
          href='http://diveintomark.org/archives/2008/12/18/give-part-1-container-formats'/>
        <id>tag:diveintomark.org,2008-12-18:/archives/20081218155422</id>
        <updated>2009-01-11T19:39:22Z</updated>
        <published>2008-12-18T15:54:22Z</published>
        <category scheme='http://diveintomark.org' term='asf'/>
        <category scheme='http://diveintomark.org' term='avi'/>
        <category scheme='http://diveintomark.org' term='encoding'/>
        <category scheme='http://diveintomark.org' term='flv'/>
        <category scheme='http://diveintomark.org' term='GIVE'/>
        <category scheme='http://diveintomark.org' term='mp4'/>
        <category scheme='http://diveintomark.org' term='ogg'/>
        <category scheme='http://diveintomark.org' term='video'/>
        <summary type='html'>These notes will eventually become part of a
          tech talk on video encoding.</summary>
      </entry>
    </feed>
    ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/roman3.py��������������������������������������������0000644�0000000�0000000�00000004433�11773544727�021203� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Convert to and from Roman numerals
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    class OutOfRangeError(ValueError): pass
    
    roman_numeral_map = (('M',  1000),
                         ('CM', 900),
                         ('D',  500),
                         ('CD', 400),
                         ('C',  100),
                         ('XC', 90),
                         ('L',  50),
                         ('XL', 40),
                         ('X',  10),
                         ('IX', 9),
                         ('V',  5),
                         ('IV', 4),
                         ('I',  1))
    
    def to_roman(n):
        '''convert integer to Roman numeral'''
        if not (0 < n < 4000):
            raise OutOfRangeError('number out of range (must be 1..3999)')
    
        result = ''
        for numeral, integer in roman_numeral_map:
            while n >= integer:
                result += numeral
                n -= integer
        return result
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/customserializer.py����������������������������������0000644�0000000�0000000�00000003344�11773544727�023410� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������import pickle
    import json
    import time
    
    def to_json(python_object):
        if isinstance(python_object, time.struct_time):
            return {'__class__': 'time.asctime',
                    '__value__': time.asctime(python_object)}
        if isinstance(python_object, bytes):
            return {'__class__': 'bytes',
                    '__value__': list(python_object)}
        raise TypeError(repr(python_object) + ' is not JSON serializable')
    
    def from_json(json_object):
        if '__class__' in json_object:
            if json_object['__class__'] == 'time.asctime':
                return time.strptime(json_object['__value__'])
            if json_object['__class__'] == 'bytes':
                return bytes(json_object['__value__'])
        return json_object
    
    if __name__ == '__main__':
        entry = {}
        entry['title'] = 'Dive into history, 2009 edition'
        entry['article_link'] = 'http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition'
        entry['comments_link'] = None
        entry['internal_id'] = b'\xDE\xD5\xB4\xF8'
        entry['tags'] = ('diveintopython', 'docbook', 'html')
        entry['published'] = True
        entry['published_date'] = time.strptime('Fri Mar 27 22:20:42 2009')
        
        with open('entry.pickle', 'wb') as f:
            pickle.dump(entry, f)
    
        with open('entry.pickle', 'rb') as f:
            entry2 = pickle.load(f)
    
        print(entry == entry2)
        print(type(entry['tags']))
        print(type(entry2['tags']))
    
        with open('entry.json', 'w', encoding='utf-8') as f:
            json.dump(entry, f, default=to_json)
    
        with open('entry.json', 'r', encoding='utf-8') as f:
            entry2 = json.load(f, object_hook=from_json)
    
        print(entry == entry2)
        print(type(entry['tags']))
        print(type(entry2['tags']))
    ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/romantest1.py����������������������������������������0000644�0000000�0000000�00000007700�11773544727�022101� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for roman1.py
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    
    import roman1
    import unittest
    
    class KnownValues(unittest.TestCase):
        known_values = ( (1, 'I'),
                         (2, 'II'),
                         (3, 'III'),
                         (4, 'IV'),
                         (5, 'V'),
                         (6, 'VI'),
                         (7, 'VII'),
                         (8, 'VIII'),
                         (9, 'IX'),
                         (10, 'X'),
                         (50, 'L'),
                         (100, 'C'),
                         (500, 'D'),
                         (1000, 'M'),
                         (31, 'XXXI'),
                         (148, 'CXLVIII'),
                         (294, 'CCXCIV'),
                         (312, 'CCCXII'),
                         (421, 'CDXXI'),
                         (528, 'DXXVIII'),
                         (621, 'DCXXI'),
                         (782, 'DCCLXXXII'),
                         (870, 'DCCCLXX'),
                         (941, 'CMXLI'),
                         (1043, 'MXLIII'),
                         (1110, 'MCX'),
                         (1226, 'MCCXXVI'),
                         (1301, 'MCCCI'),
                         (1485, 'MCDLXXXV'),
                         (1509, 'MDIX'),
                         (1607, 'MDCVII'),
                         (1754, 'MDCCLIV'),
                         (1832, 'MDCCCXXXII'),
                         (1993, 'MCMXCIII'),
                         (2074, 'MMLXXIV'),
                         (2152, 'MMCLII'),
                         (2212, 'MMCCXII'),
                         (2343, 'MMCCCXLIII'),
                         (2499, 'MMCDXCIX'),
                         (2574, 'MMDLXXIV'),
                         (2646, 'MMDCXLVI'),
                         (2723, 'MMDCCXXIII'),
                         (2892, 'MMDCCCXCII'),
                         (2975, 'MMCMLXXV'),
                         (3051, 'MMMLI'),
                         (3185, 'MMMCLXXXV'),
                         (3250, 'MMMCCL'),
                         (3313, 'MMMCCCXIII'),
                         (3408, 'MMMCDVIII'),
                         (3501, 'MMMDI'),
                         (3610, 'MMMDCX'),
                         (3743, 'MMMDCCXLIII'),
                         (3844, 'MMMDCCCXLIV'),
                         (3888, 'MMMDCCCLXXXVIII'),
                         (3940, 'MMMCMXL'),
                         (3999, 'MMMCMXCIX'))
    
        def test_to_roman_known_values(self):
            '''to_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman1.to_roman(integer)
                self.assertEqual(numeral, result)
    
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ����������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/roman7.py��������������������������������������������0000644�0000000�0000000�00000007104�11773544727�021205� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Convert to and from Roman numerals
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    import re
    
    class OutOfRangeError(ValueError): pass
    class NotIntegerError(ValueError): pass
    class InvalidRomanNumeralError(ValueError): pass
    
    roman_numeral_map = (('M',  1000),
                         ('CM', 900),
                         ('D',  500),
                         ('CD', 400),
                         ('C',  100),
                         ('XC', 90),
                         ('L',  50),
                         ('XL', 40),
                         ('X',  10),
                         ('IX', 9),
                         ('V',  5),
                         ('IV', 4),
                         ('I',  1))
    
    roman_numeral_pattern = re.compile('''
        ^                   # beginning of string
        M{0,3}              # thousands - 0 to 3 M's
        (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
                            #            or 500-800 (D, followed by 0 to 3 C's)
        (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
                            #        or 50-80 (L, followed by 0 to 3 X's)
        (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
                            #        or 5-8 (V, followed by 0 to 3 I's)
        $                   # end of string
        ''', re.VERBOSE)
    
    def to_roman(n):
        '''convert integer to Roman numeral'''
        if not (0 < n < 4000):
            raise OutOfRangeError('number out of range (must be 1..3999)')
        if not isinstance(n, int):
            raise NotIntegerError('non-integers can not be converted')
    
        result = ''
        for numeral, integer in roman_numeral_map:
            while n >= integer:
                result += numeral
                n -= integer
        return result
    
    def from_roman(s):
        '''convert Roman numeral to integer'''
        if not isinstance(s, str):
            raise InvalidRomanNumeralError('Input must be a string')
        if not roman_numeral_pattern.search(s):
            raise InvalidRomanNumeralError('Invalid Roman numeral: {0}'.format(s))
    
        result = 0
        index = 0
        for numeral, integer in roman_numeral_map:
            while s[index : index + len(numeral)] == numeral:
                result += integer
                index += len(numeral)
        return result
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/beauregard.jpg���������������������������������������0000644�0000000�0000000�00000006116�11773544727�022235� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������JFIF��H�H���fExif��II*���������>�������F���(�������1����N�������H������H������Paint.NET v3.36��C�
    
    
    		
    %# , #&')*)-0-(0%()(�C
    
    
    
    (((((((((((((((((((((((((((((((((((((((((((((((((((��d�d"������������	
    ����}�!1AQa"q2#BR$3br	
    %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz��������	
    ���w�!1AQaq"2B	#3Rbr
    $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz���?�-v3qWYHqs}뚛
    	$�;8d`S.$F7^՗{,aVjE^ʼn&U=rhV>՞ǽY>x;ShE4L1̐ɎV8}@41՘�㦽c%
    ?^]=-?V??zw4iE^d-j!�[{?gFeaJT�ƨx-!Oֹϊk]d)E֣:Hy<SL�Wxpv~+	F!WMyį35j'ul&15x+6j`"`?ZZWb)&(Rjk ~$7M{Fv6?Khl s]}#8v>|N{P	*^f[ʕ9eB~)7Vc%l
    ʞzz<;gʶ+|i2G5ItWy5�	 +Fe(へu3Zx+s]E"Ōcv5:=neS4]v0'?ҷ5Ʈ^jl(�3y2O+<#BXJUK݆Oj)7Rv*Aצm	^jFJ"gQ@l{ՐF{GB.mZO6S#k'i6\hŲAH|~GZD_6aq9Op5<M}.E	aäEXDP6v˕"?;-j>f3ӎ檮1vzϞJcK{EP{Z[گ$}˽ΣY.<okfmI
    -H]p#n䎧#MgJ\ۍ{.�
    I*GEgkc(	CuT5uKb{w.j~-qP<Auۅu+u?$ϏuB}K{uRMEyLjo.._|�1�ڽ<<Ӈ-cAsw&7QGa++]"֦PsR\NG|b,8^/mckELGًw#
    e)6{r+iX6ڠKCc,z].D#˘	\px�&K)^*-At6ܓixgSfI$J4yGN;אk	<xS:a`;5x]\qW;uUG
    R}NGZw`eUϰWj$O,L̢Fܰt:ǥ_#IXI*M)l(?|Z{CplwV49ɾf=L!4|#
    Ԭ ĩ9A׭z),nGsk6w3[7' }:mDZ(M8'pT\][B3?cdWX\uSSl⦊E!n)0Eh�'ӥiƸ};UJ#Xw#-[iʪs@<y/(�}vns~ΩmddG)|F}ҽbo6h25>J[~XQzִʣz*֍5ʷ<
    6-P/.$
    !ct'⾞闬VkQ
    x?Lׄ`!cQ
    ҙ3!;XWfBB[Tj;J_h<v	GҾpn5}W;X$!'e
    SdՇ:)G4ys8c��!VS4&GGl-FȖX@b>	Wqa}zzd{zjwc}yvx0UR5J%6\`E?J*}|F,6鏼¬la�J~vpx&HЂ0jvqqI\|UئN4H{
    j새eV8?}ImxrAU 75xS1%Dc
    u291T\(wi럲O)$YQTDi�ޝ˪kĜ9zRH~?ҹqjPtLtsW`z~x)l&\FOnn&qQUe��kd5u$#rŲA֖E_:ĠڠJj7Oڊ+aJF{@4Q\pI<ɖHO֥ST"v5+{h1{TfWtQTcrEQLG��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/fibonacci.py�����������������������������������������0000644�0000000�0000000�00000002715�11773544727�021722� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Fibonacci generator'''
    
    def fib(max):
        a, b = 0, 1
        while a < max:
            yield a
            a, b = b, a + b
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ���������������������������������������������������diveintopython3-20110517-77958af.orig/examples/roman2.py��������������������������������������������0000644�0000000�0000000�00000004434�11773544727�021203� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Convert to and from Roman numerals
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    class OutOfRangeError(ValueError):
        pass
    
    roman_numeral_map = (('M',  1000),
                         ('CM', 900),
                         ('D',  500),
                         ('CD', 400),
                         ('C',  100),
                         ('XC', 90),
                         ('L',  50),
                         ('XL', 40),
                         ('X',  10),
                         ('IX', 9),
                         ('V',  5),
                         ('IV', 4),
                         ('I',  1))
    
    def to_roman(n):
        '''convert integer to Roman numeral'''
        if n > 3999:
            raise OutOfRangeError('number out of range (must be less than 4000)')
    
        result = ''
        for numeral, integer in roman_numeral_map:
            while n >= integer:
                result += numeral
                n -= integer
        return result
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/feed-ns0.xml�����������������������������������������0000644�0000000�0000000�00000006472�11773544727�021562� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version='1.0' encoding='utf-8'?>
    <ns0:feed xmlns:ns0='http://www.w3.org/2005/Atom' xml:lang='en'>
      <ns0:title>dive into mark</ns0:title>
      <ns0:subtitle>currently between addictions</ns0:subtitle>
      <ns0:id>tag:diveintomark.org,2001-07-29:/</ns0:id>
      <ns0:updated>2009-03-27T21:56:07Z</ns0:updated>
      <ns0:link rel='alternate' type='text/html' href='http://diveintomark.org/'/>
      <ns0:entry>
        <ns0:author>
          <ns0:name>Mark</ns0:name>
          <ns0:uri>http://diveintomark.org/</ns0:uri>
        </ns0:author>
        <ns0:title>Dive into history, 2009 edition</ns0:title>
        <ns0:link rel='alternate' type='text/html'
          href='http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition'/>
        <ns0:id>tag:diveintomark.org,2009-03-27:/archives/20090327172042</ns0:id>
        <ns0:updated>2009-03-27T21:56:07Z</ns0:updated>
        <ns0:published>2009-03-27T17:20:42Z</ns0:published>
        <ns0:category scheme='http://diveintomark.org' term='diveintopython'/>
        <ns0:category scheme='http://diveintomark.org' term='docbook'/>
        <ns0:category scheme='http://diveintomark.org' term='html'/>
        <ns0:summary type='html'>Putting an entire chapter on one page sounds
          bloated, but consider this &amp;mdash; my longest chapter so far
          would be 75 printed pages, and it loads in under 5 seconds&amp;hellip;
          On dialup.</ns0:summary>
      </ns0:entry>
      <ns0:entry>
        <ns0:author>
          <ns0:name>Mark</ns0:name>
          <ns0:uri>http://diveintomark.org/</ns0:uri>
        </ns0:author>
        <ns0:title>Accessibility is a harsh mistress</ns0:title>
        <ns0:link rel='alternate' type='text/html'
          href='http://diveintomark.org/archives/2009/03/21/accessibility-is-a-harsh-mistress'/>
        <ns0:id>tag:diveintomark.org,2009-03-21:/archives/20090321200928</ns0:id>
        <ns0:updated>2009-03-22T01:05:37Z</ns0:updated>
        <ns0:published>2009-03-21T20:09:28Z</ns0:published>
        <ns0:category scheme='http://diveintomark.org' term='accessibility'/>
        <ns0:summary type='html'>The accessibility orthodoxy does not permit people to
          question the value of features that are rarely useful and rarely used.</ns0:summary>
      </ns0:entry>
      <ns0:entry>
        <ns0:author>
          <ns0:name>Mark</ns0:name>
        </ns0:author>
        <ns0:title>A gentle introduction to video encoding, part 1: container formats</ns0:title>
        <ns0:link rel='alternate' type='text/html'
          href='http://diveintomark.org/archives/2008/12/18/give-part-1-container-formats'/>
        <ns0:id>tag:diveintomark.org,2008-12-18:/archives/20081218155422</ns0:id>
        <ns0:updated>2009-01-11T19:39:22Z</ns0:updated>
        <ns0:published>2008-12-18T15:54:22Z</ns0:published>
        <ns0:category scheme='http://diveintomark.org' term='asf'/>
        <ns0:category scheme='http://diveintomark.org' term='avi'/>
        <ns0:category scheme='http://diveintomark.org' term='encoding'/>
        <ns0:category scheme='http://diveintomark.org' term='flv'/>
        <ns0:category scheme='http://diveintomark.org' term='GIVE'/>
        <ns0:category scheme='http://diveintomark.org' term='mp4'/>
        <ns0:category scheme='http://diveintomark.org' term='ogg'/>
        <ns0:category scheme='http://diveintomark.org' term='video'/>
        <ns0:summary type='html'>These notes will eventually become part of a
          tech talk on video encoding.</ns0:summary>
      </ns0:entry>
    </ns0:feed>
    ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/romantest6.py����������������������������������������0000644�0000000�0000000�00000013764�11773544727�022115� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for roman1.py
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    
    import roman6
    import unittest
    
    class KnownValues(unittest.TestCase):
        known_values = ( (1, 'I'),
                         (2, 'II'),
                         (3, 'III'),
                         (4, 'IV'),
                         (5, 'V'),
                         (6, 'VI'),
                         (7, 'VII'),
                         (8, 'VIII'),
                         (9, 'IX'),
                         (10, 'X'),
                         (50, 'L'),
                         (100, 'C'),
                         (500, 'D'),
                         (1000, 'M'),
                         (31, 'XXXI'),
                         (148, 'CXLVIII'),
                         (294, 'CCXCIV'),
                         (312, 'CCCXII'),
                         (421, 'CDXXI'),
                         (528, 'DXXVIII'),
                         (621, 'DCXXI'),
                         (782, 'DCCLXXXII'),
                         (870, 'DCCCLXX'),
                         (941, 'CMXLI'),
                         (1043, 'MXLIII'),
                         (1110, 'MCX'),
                         (1226, 'MCCXXVI'),
                         (1301, 'MCCCI'),
                         (1485, 'MCDLXXXV'),
                         (1509, 'MDIX'),
                         (1607, 'MDCVII'),
                         (1754, 'MDCCLIV'),
                         (1832, 'MDCCCXXXII'),
                         (1993, 'MCMXCIII'),
                         (2074, 'MMLXXIV'),
                         (2152, 'MMCLII'),
                         (2212, 'MMCCXII'),
                         (2343, 'MMCCCXLIII'),
                         (2499, 'MMCDXCIX'),
                         (2574, 'MMDLXXIV'),
                         (2646, 'MMDCXLVI'),
                         (2723, 'MMDCCXXIII'),
                         (2892, 'MMDCCCXCII'),
                         (2975, 'MMCMLXXV'),
                         (3051, 'MMMLI'),
                         (3185, 'MMMCLXXXV'),
                         (3250, 'MMMCCL'),
                         (3313, 'MMMCCCXIII'),
                         (3408, 'MMMCDVIII'),
                         (3501, 'MMMDI'),
                         (3610, 'MMMDCX'),
                         (3743, 'MMMDCCXLIII'),
                         (3844, 'MMMDCCCXLIV'),
                         (3888, 'MMMDCCCLXXXVIII'),
                         (3940, 'MMMCMXL'),
                         (3999, 'MMMCMXCIX'))
    
        def test_to_roman_known_values(self):
            '''to_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman6.to_roman(integer)
                self.assertEqual(numeral, result)
    
        def test_from_roman_known_values(self):
            '''from_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman6.from_roman(numeral)
                self.assertEqual(integer, result)
    
    class ToRomanBadInput(unittest.TestCase):
        def test_too_large(self):
            '''to_roman should fail with large input'''
            self.assertRaises(roman6.OutOfRangeError, roman6.to_roman, 4000)
    
        def test_zero(self):
            '''to_roman should fail with 0 input'''
            self.assertRaises(roman6.OutOfRangeError, roman6.to_roman, 0)
    
        def test_negative(self):
            '''to_roman should fail with negative input'''
            self.assertRaises(roman6.OutOfRangeError, roman6.to_roman, -1)
    
        def test_non_integer(self):
            '''to_roman should fail with non-integer input'''
            self.assertRaises(roman6.NotIntegerError, roman6.to_roman, 0.5)
    
    class FromRomanBadInput(unittest.TestCase):
        def test_too_many_repeated_numerals(self):
            '''from_roman should fail with too many repeated numerals'''
            for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
                self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)
    
        def test_repeated_pairs(self):
            '''from_roman should fail with repeated pairs of numerals'''
            for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
                self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)
    
        def test_malformed_antecedents(self):
            '''from_roman should fail with malformed antecedents'''
            for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
                      'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
                self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)
    
    class RoundtripCheck(unittest.TestCase):
        def test_roundtrip(self):
            '''from_roman(to_roman(n))==n for all n'''
            for integer in range(1, 4000):
                numeral = roman6.to_roman(integer)
                result = roman6.from_roman(numeral)
                self.assertEqual(integer, result)
    
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ������������diveintopython3-20110517-77958af.orig/examples/humansize.py�����������������������������������������0000644�0000000�0000000�00000004740�11773544727�022010� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Convert file sizes to human-readable form.
    
    Available functions:
    approximate_size(size, a_kilobyte_is_1024_bytes)
        takes a file size and returns a human-readable string
    
    Examples:
    >>> approximate_size(1024)
    '1.0 KiB'
    >>> approximate_size(1000, False)
    '1.0 KB'
    
    '''
    
    SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
                1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
    
    def approximate_size(size, a_kilobyte_is_1024_bytes=True):
        '''Convert a file size to human-readable form.
    
        Keyword arguments:
        size -- file size in bytes
        a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
                                    if False, use multiples of 1000
    
        Returns: string
    
        '''
        if size < 0:
            raise ValueError('number must be non-negative')
    
        multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
        for suffix in SUFFIXES[multiple]:
            size /= multiple
            if size < multiple:
                return '{0:.1f} {1}'.format(size, suffix)
    
        raise ValueError('number too large')
    
    if __name__ == '__main__':
        print(approximate_size(1000000000000, False))
        print(approximate_size(1000000000000))
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ��������������������������������diveintopython3-20110517-77958af.orig/examples/roman8.py��������������������������������������������0000644�0000000�0000000�00000007223�11773544727�021210� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Convert to and from Roman numerals
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    import re
    
    class OutOfRangeError(ValueError): pass
    class NotIntegerError(ValueError): pass
    class InvalidRomanNumeralError(ValueError): pass
    
    roman_numeral_map = (('M',  1000),
                         ('CM', 900),
                         ('D',  500),
                         ('CD', 400),
                         ('C',  100),
                         ('XC', 90),
                         ('L',  50),
                         ('XL', 40),
                         ('X',  10),
                         ('IX', 9),
                         ('V',  5),
                         ('IV', 4),
                         ('I',  1))
    
    roman_numeral_pattern = re.compile('''
        ^                   # beginning of string
        M{0,3}              # thousands - 0 to 3 M's
        (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
                            #            or 500-800 (D, followed by 0 to 3 C's)
        (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
                            #        or 50-80 (L, followed by 0 to 3 X's)
        (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
                            #        or 5-8 (V, followed by 0 to 3 I's)
        $                   # end of string
        ''', re.VERBOSE)
    
    def to_roman(n):
        '''convert integer to Roman numeral'''
        if not (0 < n < 4000):
            raise OutOfRangeError('number out of range (must be 1..3999)')
        if not isinstance(n, int):
            raise NotIntegerError('non-integers can not be converted')
    
        result = ''
        for numeral, integer in roman_numeral_map:
            while n >= integer:
                result += numeral
                n -= integer
        return result
    
    def from_roman(s):
        '''convert Roman numeral to integer'''
        if not isinstance(s, str):
            raise InvalidRomanNumeralError('Input must be a string')
        if not s:
            raise InvalidRomanNumeralError('Input can not be blank')
        if not roman_numeral_pattern.search(s):
            raise InvalidRomanNumeralError('Invalid Roman numeral: {0}'.format(s))
    
        result = 0
        index = 0
        for numeral, integer in roman_numeral_map:
            while s[index : index + len(numeral)] == numeral:
                result += integer
                index += len(numeral)
        return result
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/entry.pickle�����������������������������������������0000644�0000000�0000000�00000000546�11773544727�021765� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������}q�(X���published_dateqctime
    struct_time
    q(MKKKKK*KKVJtq}qqRqX
    ���comments_linkqNX���internal_idqCմq	X���tagsq
    X���diveintopythonqX���docbookqX���htmlq
    qX���titleqX���Dive into history, 2009 editionqX���article_linkqXJ���http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-editionqX	���publishedqu.����������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/roman5.py��������������������������������������������0000644�0000000�0000000�00000005274�11773544727�021211� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Convert to and from Roman numerals
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    class OutOfRangeError(ValueError): pass
    class NotIntegerError(ValueError): pass
    
    roman_numeral_map = (('M',  1000),
                         ('CM', 900),
                         ('D',  500),
                         ('CD', 400),
                         ('C',  100),
                         ('XC', 90),
                         ('L',  50),
                         ('XL', 40),
                         ('X',  10),
                         ('IX', 9),
                         ('V',  5),
                         ('IV', 4),
                         ('I',  1))
    
    def to_roman(n):
        '''convert integer to Roman numeral'''
        if not (0 < n < 4000):
            raise OutOfRangeError('number out of range (must be 1..3999)')
        if not isinstance(n, int):
            raise NotIntegerError('non-integers can not be converted')
    
        result = ''
        for numeral, integer in roman_numeral_map:
            while n >= integer:
                result += numeral
                n -= integer
        return result
    
    def from_roman(s):
        '''convert Roman numeral to integer'''
        result = 0
        index = 0
        for numeral, integer in roman_numeral_map:
            while s[index : index + len(numeral)] == numeral:
                result += integer
                index += len(numeral)
        return result
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/oneline.py�������������������������������������������0000644�0000000�0000000�00000000316�11773544727�021431� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������line_number = 1
    with open('examples/favorite-people.txt', encoding='utf-8') as a_file:
        for a_line in a_file:
            print('{:>4} {}'.format(line_number, a_line.rstrip()))
            line_number += 1
    ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/entry.json�������������������������������������������0000644�0000000�0000000�00000000607�11773544727�021465� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"published_date": {"__class__": "time.asctime", "__value__": "Fri Mar 27 22:20:42 2009"}, "comments_link": null, "internal_id": {"__class__": "bytes", "__value__": [222, 213, 180, 248]}, "tags": ["diveintopython", "docbook", "html"], "title": "Dive into history, 2009 edition", "article_link": "http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition", "published": true}�������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/plural4-rules.txt������������������������������������0000644�0000000�0000000�00000000103�11773544727�022674� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[sxz]$			$		es
    [^aeioudgkprt]h$	$		es
    [^aeiou]y$		y$		ies
    $			$		s
    �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/roman6.py��������������������������������������������0000644�0000000�0000000�00000006744�11773544727�021215� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Convert to and from Roman numerals
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    import re
    
    class OutOfRangeError(ValueError): pass
    class NotIntegerError(ValueError): pass
    class InvalidRomanNumeralError(ValueError): pass
    
    roman_numeral_map = (('M',  1000),
                         ('CM', 900),
                         ('D',  500),
                         ('CD', 400),
                         ('C',  100),
                         ('XC', 90),
                         ('L',  50),
                         ('XL', 40),
                         ('X',  10),
                         ('IX', 9),
                         ('V',  5),
                         ('IV', 4),
                         ('I',  1))
    
    roman_numeral_pattern = re.compile('''
        ^                   # beginning of string
        M{0,3}              # thousands - 0 to 3 M's
        (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
                            #            or 500-800 (D, followed by 0 to 3 C's)
        (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
                            #        or 50-80 (L, followed by 0 to 3 X's)
        (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
                            #        or 5-8 (V, followed by 0 to 3 I's)
        $                   # end of string
        ''', re.VERBOSE)
    
    def to_roman(n):
        '''convert integer to Roman numeral'''
        if not (0 < n < 4000):
            raise OutOfRangeError('number out of range (must be 1..3999)')
        if not isinstance(n, int):
            raise NotIntegerError('non-integers can not be converted')
    
        result = ''
        for numeral, integer in roman_numeral_map:
            while n >= integer:
                result += numeral
                n -= integer
        return result
    
    def from_roman(s):
        '''convert Roman numeral to integer'''
        if not roman_numeral_pattern.search(s):
            raise InvalidRomanNumeralError('Invalid Roman numeral: {0}'.format(s))
    
        result = 0
        index = 0
        for numeral, integer in roman_numeral_map:
            while s[index : index + len(numeral)] == numeral:
                result += integer
                index += len(numeral)
        return result
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ����������������������������diveintopython3-20110517-77958af.orig/examples/basic.json�������������������������������������������0000644�0000000�0000000�00000000220�11773544727�021374� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{"published": true, "tags": ["diveintopython", "docbook", "html"], "comments_link": null, "id": 256, "title": "Dive into history, 2009 edition"}��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/plural1.py�������������������������������������������0000644�0000000�0000000�00000003515�11773544727�021364� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Pluralize English nouns (stage 1)
    
    Command line usage:
    $ python3 plural.py noun
    nouns
    '''
    
    import re
    
    def plural(noun):
        if re.search('[sxz]$', noun):
            return re.sub('$', 'es', noun)
        elif re.search('[^aeioudgkprt]h$', noun):
            return re.sub('$', 'es', noun)
        elif re.search('[^aeiou]y$', noun):
            return re.sub('y$', 'ies', noun)
        else:
            return noun + 's'
    
    if __name__ == '__main__':
        import sys
        if sys.argv[1:]:
            print(plural(sys.argv[1]))
        else:
            print(__doc__)
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/pluraltest1.py���������������������������������������0000644�0000000�0000000�00000005653�11773544727�022271� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for plural1.py'''
    
    import plural1
    import unittest
    
    class KnownValues(unittest.TestCase):
        def test_sxz(self):
            'words ending in S, X, and Z'
            nouns = {
                'bass': 'basses',
                'bus': 'buses',
                'walrus': 'walruses',
                'box': 'boxes',
                'fax': 'faxes',
                'suffix': 'suffixes',
                'mailbox': 'mailboxes',
                'buzz': 'buzzes',
                'waltz': 'waltzes'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural1.plural(singular), plural)
    
        def test_h(self):
            'words ending in H'
            nouns = {
                'coach': 'coaches',
                'glitch': 'glitches',
                'rash': 'rashes',
                'watch': 'watches',
                'cheetah': 'cheetahs',
                'cough': 'coughs'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural1.plural(singular), plural)
    
        def test_y(self):
            'words ending in Y'
            nouns = {
                'utility': 'utilities',
                'vacancy': 'vacancies',
                'boy': 'boys',
                'day': 'days'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural1.plural(singular), plural)
    
        def test_default(self):
            'unexceptional words'
            nouns = {
                'papaya': 'papayas',
                'whip': 'whips',
                'palimpsest': 'palimpsests'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural1.plural(singular), plural)
            
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    �������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/roman4.py��������������������������������������������0000644�0000000�0000000�00000004645�11773544727�021211� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Convert to and from Roman numerals
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    class OutOfRangeError(ValueError): pass
    class NotIntegerError(ValueError): pass
    
    roman_numeral_map = (('M',  1000),
                         ('CM', 900),
                         ('D',  500),
                         ('CD', 400),
                         ('C',  100),
                         ('XC', 90),
                         ('L',  50),
                         ('XL', 40),
                         ('X',  10),
                         ('IX', 9),
                         ('V',  5),
                         ('IV', 4),
                         ('I',  1))
    
    def to_roman(n):
        '''convert integer to Roman numeral'''
        if not (0 < n < 4000):
            raise OutOfRangeError('number out of range (must be 1..3999)')
        if not isinstance(n, int):
            raise NotIntegerError('non-integers can not be converted')
    
        result = ''
        for numeral, integer in roman_numeral_map:
            while n >= integer:
                result += numeral
                n -= integer
        return result
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    �������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/plural3.py�������������������������������������������0000644�0000000�0000000�00000004372�11773544727�021370� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Pluralize English nouns (stage 3)
    
    Command line usage:
    $ python plural3.py noun
    nouns
    '''
    
    import re
    
    def build_match_and_apply_functions(pattern, search, replace):
        def matches_rule(word):
            return re.search(pattern, word)
        def apply_rule(word):
            return re.sub(search, replace, word)
        return (matches_rule, apply_rule)
    
    patterns = \
      (
        ('[sxz]$',           '$',  'es'),
        ('[^aeioudgkprt]h$', '$',  'es'),
        ('(qu|[^aeiou])y$',  'y$', 'ies'),
        ('$',                '$',  's')
      )
    rules = [build_match_and_apply_functions(pattern, search, replace)
             for (pattern, search, replace) in patterns]
    
    def plural(noun):
        for matches_rule, apply_rule in rules:
            if matches_rule(noun):
                return apply_rule(noun)
    
    if __name__ == '__main__':
        import sys
        if sys.argv[1:]:
            print(plural(sys.argv[1]))
        else:
            print(__doc__)
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/pickleversion.py�������������������������������������0000644�0000000�0000000�00000000322�11773544727�022652� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������import pickletools
    
    def protocol_version(file_object):
        maxproto = -1
        for opcode, arg, pos in pickletools.genops(file_object):
            maxproto = max(maxproto, opcode.proto)
        return maxproto
    
    ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/plural6-rules.txt������������������������������������0000644�0000000�0000000�00000000560�11773544727�022705� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������^(sheep|deer|fish|moose|aircraft|series|haiku)$	($)	\1
    [ml]ouse$		ouse$		ice
    child$			$		ren
    booth$			$		s
    foot$			oot$		eet
    ooth$			ooth$		eeth
    l[eo]af$		af$		aves
    sis$			sis$		ses
    ^(hu|ro)man$		$		s
    man$			man$		men
    ^lowlife$		$		s
    ife$			ife$		ives
    eau$			$		x
    ^[dp]elf$		$		s
    lf$			lf$		lves
    [sxz]$			$		es
    [^aeioudgkprt]h$	$		es
    (qu|[^aeiou])y$		y$		ies
    $			$		s
    ������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/fibonacci2.py����������������������������������������0000644�0000000�0000000�00000003400�11773544727�021774� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Fibonacci iterator'''
    
    class Fib:
        '''iterator that yields numbers in the Fibonacci sequence'''
    
        def __init__(self, max):
            self.max = max
    
        def __iter__(self):
            self.a = 0
            self.b = 1
            return self
    
        def __next__(self):
            fib = self.a
            if fib > self.max:
                raise StopIteration
            self.a, self.b = self.b, self.a + self.b
            return fib
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/favorite-people.txt����������������������������������0000644�0000000�0000000�00000000103�11773544727�023262� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Dora
    Ethan
    Wesley
    John
    Anne
    Mike
    Chris
    Sarah
    Alex
    Lizzie
    �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/feed.xml���������������������������������������������0000644�0000000�0000000�00000005776�11773544727�021072� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version='1.0' encoding='utf-8'?>
    <feed xmlns='http://www.w3.org/2005/Atom' xml:lang='en'>
      <title>dive into mark</title>
      <subtitle>currently between addictions</subtitle>
      <id>tag:diveintomark.org,2001-07-29:/</id>
      <updated>2009-03-27T21:56:07Z</updated>
      <link rel='alternate' type='text/html' href='http://diveintomark.org/'/>
      <entry>
        <author>
          <name>Mark</name>
          <uri>http://diveintomark.org/</uri>
        </author>
        <title>Dive into history, 2009 edition</title>
        <link rel='alternate' type='text/html'
          href='http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition'/>
        <id>tag:diveintomark.org,2009-03-27:/archives/20090327172042</id>
        <updated>2009-03-27T21:56:07Z</updated>
        <published>2009-03-27T17:20:42Z</published>
        <category scheme='http://diveintomark.org' term='diveintopython'/>
        <category scheme='http://diveintomark.org' term='docbook'/>
        <category scheme='http://diveintomark.org' term='html'/>
        <summary type='html'>Putting an entire chapter on one page sounds
          bloated, but consider this &amp;mdash; my longest chapter so far
          would be 75 printed pages, and it loads in under 5 seconds&amp;hellip;
          On dialup.</summary>
      </entry>
      <entry>
        <author>
          <name>Mark</name>
          <uri>http://diveintomark.org/</uri>
        </author>
        <title>Accessibility is a harsh mistress</title>
        <link rel='alternate' type='text/html'
          href='http://diveintomark.org/archives/2009/03/21/accessibility-is-a-harsh-mistress'/>
        <id>tag:diveintomark.org,2009-03-21:/archives/20090321200928</id>
        <updated>2009-03-22T01:05:37Z</updated>
        <published>2009-03-21T20:09:28Z</published>
        <category scheme='http://diveintomark.org' term='accessibility'/>
        <summary type='html'>The accessibility orthodoxy does not permit people to
          question the value of features that are rarely useful and rarely used.</summary>
      </entry>
      <entry>
        <author>
          <name>Mark</name>
        </author>
        <title>A gentle introduction to video encoding, part 1: container formats</title>
        <link rel='alternate' type='text/html'
          href='http://diveintomark.org/archives/2008/12/18/give-part-1-container-formats'/>
        <id>tag:diveintomark.org,2008-12-18:/archives/20081218155422</id>
        <updated>2009-01-11T19:39:22Z</updated>
        <published>2008-12-18T15:54:22Z</published>
        <category scheme='http://diveintomark.org' term='asf'/>
        <category scheme='http://diveintomark.org' term='avi'/>
        <category scheme='http://diveintomark.org' term='encoding'/>
        <category scheme='http://diveintomark.org' term='flv'/>
        <category scheme='http://diveintomark.org' term='GIVE'/>
        <category scheme='http://diveintomark.org' term='mp4'/>
        <category scheme='http://diveintomark.org' term='ogg'/>
        <category scheme='http://diveintomark.org' term='video'/>
        <summary type='html'>These notes will eventually become part of a
          tech talk on video encoding.</summary>
      </entry>
    </feed>
    ��diveintopython3-20110517-77958af.orig/examples/roman10.py�������������������������������������������0000644�0000000�0000000�00000006507�11773544727�021265� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Convert to and from Roman numerals
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    
    class OutOfRangeError(ValueError): pass
    class NotIntegerError(ValueError): pass
    class InvalidRomanNumeralError(ValueError): pass
    
    roman_numeral_map = (('M',  1000),
                         ('CM', 900),
                         ('D',  500),
                         ('CD', 400),
                         ('C',  100),
                         ('XC', 90),
                         ('L',  50),
                         ('XL', 40),
                         ('X',  10),
                         ('IX', 9),
                         ('V',  5),
                         ('IV', 4),
                         ('I',  1))
    
    to_roman_table = [ None ]
    from_roman_table = {}
    
    def to_roman(n):
        '''convert integer to Roman numeral'''
        if int(n) != n:
            raise NotIntegerError('non-integers can not be converted')
        if not (0 < n < 5000):
            raise OutOfRangeError('number out of range (must be 1..4999)')
        return to_roman_table[n]
    
    def from_roman(s):
        '''convert Roman numeral to integer'''
        if not isinstance(s, str):
            raise InvalidRomanNumeralError('Input must be a string')
        if not s:
            raise InvalidRomanNumeralError('Input can not be blank')
        if s not in from_roman_table:
            raise InvalidRomanNumeralError('Invalid Roman numeral: {0}'.format(s))
        return from_roman_table[s]
    
    def build_lookup_tables():
        def to_roman(n):
            result = ''
            for numeral, integer in roman_numeral_map:
                if n >= integer:
                    result = numeral
                    n -= integer
                    break
            if n > 0:
                result += to_roman_table[n]
            return result
    
        for integer in range(1, 5000):
            roman_numeral = to_roman(integer)
            to_roman_table.append(roman_numeral)
            from_roman_table[roman_numeral] = integer
    
    build_lookup_tables()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/alphameticstest.py�����������������������������������0000644�0000000�0000000�00000004715�11773544727�023201� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������from alphametics import solve
    import unittest
    
    class KnownValues(unittest.TestCase):
        def test_out(self):
            '''TO + GO == OUT'''
            self.assertEqual(solve('TO + GO == OUT'), '21 + 81 == 102')
    
        def test_too(self):
            '''I + DID == TOO'''
            self.assertEqual(solve('I + DID == TOO'), '9 + 191 == 200')
    
        def test_mom(self):
            '''AS + A == MOM'''
            self.assertEqual(solve('AS + A == MOM'), '92 + 9 == 101')
    
        def test_best(self):
            '''HES + THE == BEST'''
            self.assertEqual(solve('HES + THE == BEST'), '426 + 842 == 1268')
    
        def test_late(self):
            '''NO + NO + TOO == LATE'''
            self.assertEqual(solve('NO + NO + TOO == LATE'), '74 + 74 + 944 == 1092')
    
        def test_onze(self):
            '''UN + UN + NEUF == ONZE'''
            self.assertEqual(solve('UN + UN + NEUF == ONZE'), '81 + 81 + 1987 == 2149')
    
        def test_deux(self):
            '''UN + DEUX + DEUX + DEUX + DEUX == NEUF'''
            self.assertEqual(solve('UN + DEUX + DEUX + DEUX + DEUX == NEUF'), '25 + 1326 + 1326 + 1326 + 1326 == 5329')
    
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ���������������������������������������������������diveintopython3-20110517-77958af.orig/examples/romantest8.py����������������������������������������0000644�0000000�0000000�00000014504�11773544727�022110� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for roman1.py
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    
    import roman8
    import unittest
    
    class KnownValues(unittest.TestCase):
        known_values = ( (1, 'I'),
                         (2, 'II'),
                         (3, 'III'),
                         (4, 'IV'),
                         (5, 'V'),
                         (6, 'VI'),
                         (7, 'VII'),
                         (8, 'VIII'),
                         (9, 'IX'),
                         (10, 'X'),
                         (50, 'L'),
                         (100, 'C'),
                         (500, 'D'),
                         (1000, 'M'),
                         (31, 'XXXI'),
                         (148, 'CXLVIII'),
                         (294, 'CCXCIV'),
                         (312, 'CCCXII'),
                         (421, 'CDXXI'),
                         (528, 'DXXVIII'),
                         (621, 'DCXXI'),
                         (782, 'DCCLXXXII'),
                         (870, 'DCCCLXX'),
                         (941, 'CMXLI'),
                         (1043, 'MXLIII'),
                         (1110, 'MCX'),
                         (1226, 'MCCXXVI'),
                         (1301, 'MCCCI'),
                         (1485, 'MCDLXXXV'),
                         (1509, 'MDIX'),
                         (1607, 'MDCVII'),
                         (1754, 'MDCCLIV'),
                         (1832, 'MDCCCXXXII'),
                         (1993, 'MCMXCIII'),
                         (2074, 'MMLXXIV'),
                         (2152, 'MMCLII'),
                         (2212, 'MMCCXII'),
                         (2343, 'MMCCCXLIII'),
                         (2499, 'MMCDXCIX'),
                         (2574, 'MMDLXXIV'),
                         (2646, 'MMDCXLVI'),
                         (2723, 'MMDCCXXIII'),
                         (2892, 'MMDCCCXCII'),
                         (2975, 'MMCMLXXV'),
                         (3051, 'MMMLI'),
                         (3185, 'MMMCLXXXV'),
                         (3250, 'MMMCCL'),
                         (3313, 'MMMCCCXIII'),
                         (3408, 'MMMCDVIII'),
                         (3501, 'MMMDI'),
                         (3610, 'MMMDCX'),
                         (3743, 'MMMDCCXLIII'),
                         (3844, 'MMMDCCCXLIV'),
                         (3888, 'MMMDCCCLXXXVIII'),
                         (3940, 'MMMCMXL'),
                         (3999, 'MMMCMXCIX'))
    
        def test_to_roman_known_values(self):
            '''to_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman8.to_roman(integer)
                self.assertEqual(numeral, result)
    
        def test_from_roman_known_values(self):
            '''from_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman8.from_roman(numeral)
                self.assertEqual(integer, result)
    
    class ToRomanBadInput(unittest.TestCase):
        def test_too_large(self):
            '''to_roman should fail with large input'''
            self.assertRaises(roman8.OutOfRangeError, roman8.to_roman, 4000)
    
        def test_zero(self):
            '''to_roman should fail with 0 input'''
            self.assertRaises(roman8.OutOfRangeError, roman8.to_roman, 0)
    
        def test_negative(self):
            '''to_roman should fail with negative input'''
            self.assertRaises(roman8.OutOfRangeError, roman8.to_roman, -1)
    
        def test_non_integer(self):
            '''to_roman should fail with non-integer input'''
            self.assertRaises(roman8.NotIntegerError, roman8.to_roman, 0.5)
    
    class FromRomanBadInput(unittest.TestCase):
        def test_too_many_repeated_numerals(self):
            '''from_roman should fail with too many repeated numerals'''
            for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
                self.assertRaises(roman8.InvalidRomanNumeralError, roman8.from_roman, s)
    
        def test_repeated_pairs(self):
            '''from_roman should fail with repeated pairs of numerals'''
            for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
                self.assertRaises(roman8.InvalidRomanNumeralError, roman8.from_roman, s)
    
        def test_malformed_antecedents(self):
            '''from_roman should fail with malformed antecedents'''
            for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
                      'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
                self.assertRaises(roman8.InvalidRomanNumeralError, roman8.from_roman, s)
    
        def test_blank(self):
            '''from_roman should fail with blank string'''
            self.assertRaises(roman8.InvalidRomanNumeralError, roman8.from_roman, '')
    
        def test_non_string(self):
            '''from_roman should fail with non-string input'''
            self.assertRaises(roman8.InvalidRomanNumeralError, roman8.from_roman, 1)
    
    class RoundtripCheck(unittest.TestCase):
        def test_roundtrip(self):
            '''from_roman(to_roman(n))==n for all n'''
            for integer in range(1, 4000):
                numeral = roman8.to_roman(integer)
                result = roman8.from_roman(numeral)
                self.assertEqual(integer, result)
    
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/plural5-rules.txt������������������������������������0000644�0000000�0000000�00000000103�11773544727�022675� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[sxz]$			$		es
    [^aeioudgkprt]h$	$		es
    [^aeiou]y$		y$		ies
    $			$		s
    �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/pluraltest5.py���������������������������������������0000644�0000000�0000000�00000005653�11773544727�022275� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for plural5.py'''
    
    import plural5
    import unittest
    
    class KnownValues(unittest.TestCase):
        def test_sxz(self):
            'words ending in S, X, and Z'
            nouns = {
                'bass': 'basses',
                'bus': 'buses',
                'walrus': 'walruses',
                'box': 'boxes',
                'fax': 'faxes',
                'suffix': 'suffixes',
                'mailbox': 'mailboxes',
                'buzz': 'buzzes',
                'waltz': 'waltzes'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural5.plural(singular), plural)
    
        def test_h(self):
            'words ending in H'
            nouns = {
                'coach': 'coaches',
                'glitch': 'glitches',
                'rash': 'rashes',
                'watch': 'watches',
                'cheetah': 'cheetahs',
                'cough': 'coughs'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural5.plural(singular), plural)
    
        def test_y(self):
            'words ending in Y'
            nouns = {
                'utility': 'utilities',
                'vacancy': 'vacancies',
                'boy': 'boys',
                'day': 'days'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural5.plural(singular), plural)
    
        def test_default(self):
            'unexceptional words'
            nouns = {
                'papaya': 'papayas',
                'whip': 'whips',
                'palimpsest': 'palimpsests'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural5.plural(singular), plural)
            
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    �������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/romantest4.py����������������������������������������0000644�0000000�0000000�00000011125�11773544727�022100� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for roman1.py
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    
    import roman4
    import unittest
    
    class KnownValues(unittest.TestCase):
        known_values = ( (1, 'I'),
                         (2, 'II'),
                         (3, 'III'),
                         (4, 'IV'),
                         (5, 'V'),
                         (6, 'VI'),
                         (7, 'VII'),
                         (8, 'VIII'),
                         (9, 'IX'),
                         (10, 'X'),
                         (50, 'L'),
                         (100, 'C'),
                         (500, 'D'),
                         (1000, 'M'),
                         (31, 'XXXI'),
                         (148, 'CXLVIII'),
                         (294, 'CCXCIV'),
                         (312, 'CCCXII'),
                         (421, 'CDXXI'),
                         (528, 'DXXVIII'),
                         (621, 'DCXXI'),
                         (782, 'DCCLXXXII'),
                         (870, 'DCCCLXX'),
                         (941, 'CMXLI'),
                         (1043, 'MXLIII'),
                         (1110, 'MCX'),
                         (1226, 'MCCXXVI'),
                         (1301, 'MCCCI'),
                         (1485, 'MCDLXXXV'),
                         (1509, 'MDIX'),
                         (1607, 'MDCVII'),
                         (1754, 'MDCCLIV'),
                         (1832, 'MDCCCXXXII'),
                         (1993, 'MCMXCIII'),
                         (2074, 'MMLXXIV'),
                         (2152, 'MMCLII'),
                         (2212, 'MMCCXII'),
                         (2343, 'MMCCCXLIII'),
                         (2499, 'MMCDXCIX'),
                         (2574, 'MMDLXXIV'),
                         (2646, 'MMDCXLVI'),
                         (2723, 'MMDCCXXIII'),
                         (2892, 'MMDCCCXCII'),
                         (2975, 'MMCMLXXV'),
                         (3051, 'MMMLI'),
                         (3185, 'MMMCLXXXV'),
                         (3250, 'MMMCCL'),
                         (3313, 'MMMCCCXIII'),
                         (3408, 'MMMCDVIII'),
                         (3501, 'MMMDI'),
                         (3610, 'MMMDCX'),
                         (3743, 'MMMDCCXLIII'),
                         (3844, 'MMMDCCCXLIV'),
                         (3888, 'MMMDCCCLXXXVIII'),
                         (3940, 'MMMCMXL'),
                         (3999, 'MMMCMXCIX'))
    
        def test_to_roman_known_values(self):
            '''to_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman4.to_roman(integer)
                self.assertEqual(numeral, result)
    
    class ToRomanBadInput(unittest.TestCase):
        def test_too_large(self):
            '''to_roman should fail with large input'''
            self.assertRaises(roman4.OutOfRangeError, roman4.to_roman, 4000)
    
        def test_zero(self):
            '''to_roman should fail with 0 input'''
            self.assertRaises(roman4.OutOfRangeError, roman4.to_roman, 0)
    
        def test_negative(self):
            '''to_roman should fail with negative input'''
            self.assertRaises(roman4.OutOfRangeError, roman4.to_roman, -1)
    
        def test_non_integer(self):
            '''to_roman should fail with non-integer input'''
            self.assertRaises(roman4.NotIntegerError, roman4.to_roman, 0.5)
    
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/basic-pretty.json������������������������������������0000644�0000000�0000000�00000000274�11773544727�022732� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{
      "published": true, 
      "tags": [
        "diveintopython", 
        "docbook", 
        "html"
      ], 
      "comments_link": null, 
      "id": 256, 
      "title": "Dive into history, 2009 edition"
    }������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/romantest10.py���������������������������������������0000644�0000000�0000000�00000015003�11773544727�022154� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for roman1.py
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    
    import roman10
    import unittest
    
    class KnownValues(unittest.TestCase):
        known_values = ( (1, 'I'),
                         (2, 'II'),
                         (3, 'III'),
                         (4, 'IV'),
                         (5, 'V'),
                         (6, 'VI'),
                         (7, 'VII'),
                         (8, 'VIII'),
                         (9, 'IX'),
                         (10, 'X'),
                         (50, 'L'),
                         (100, 'C'),
                         (500, 'D'),
                         (1000, 'M'),
                         (31, 'XXXI'),
                         (148, 'CXLVIII'),
                         (294, 'CCXCIV'),
                         (312, 'CCCXII'),
                         (421, 'CDXXI'),
                         (528, 'DXXVIII'),
                         (621, 'DCXXI'),
                         (782, 'DCCLXXXII'),
                         (870, 'DCCCLXX'),
                         (941, 'CMXLI'),
                         (1043, 'MXLIII'),
                         (1110, 'MCX'),
                         (1226, 'MCCXXVI'),
                         (1301, 'MCCCI'),
                         (1485, 'MCDLXXXV'),
                         (1509, 'MDIX'),
                         (1607, 'MDCVII'),
                         (1754, 'MDCCLIV'),
                         (1832, 'MDCCCXXXII'),
                         (1993, 'MCMXCIII'),
                         (2074, 'MMLXXIV'),
                         (2152, 'MMCLII'),
                         (2212, 'MMCCXII'),
                         (2343, 'MMCCCXLIII'),
                         (2499, 'MMCDXCIX'),
                         (2574, 'MMDLXXIV'),
                         (2646, 'MMDCXLVI'),
                         (2723, 'MMDCCXXIII'),
                         (2892, 'MMDCCCXCII'),
                         (2975, 'MMCMLXXV'),
                         (3051, 'MMMLI'),
                         (3185, 'MMMCLXXXV'),
                         (3250, 'MMMCCL'),
                         (3313, 'MMMCCCXIII'),
                         (3408, 'MMMCDVIII'),
                         (3501, 'MMMDI'),
                         (3610, 'MMMDCX'),
                         (3743, 'MMMDCCXLIII'),
                         (3844, 'MMMDCCCXLIV'),
                         (3888, 'MMMDCCCLXXXVIII'),
                         (3940, 'MMMCMXL'),
                         (3999, 'MMMCMXCIX'),
                         (4000, 'MMMM'),
                         (4500, 'MMMMD'),
                         (4888, 'MMMMDCCCLXXXVIII'),
                         (4999, 'MMMMCMXCIX'))
    
        def test_to_roman_known_values(self):
            '''to_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman10.to_roman(integer)
                self.assertEqual(numeral, result)
    
        def test_from_roman_known_values(self):
            '''from_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman10.from_roman(numeral)
                self.assertEqual(integer, result)
    
    class ToRomanBadInput(unittest.TestCase):
        def test_too_large(self):
            '''to_roman should fail with large input'''
            self.assertRaises(roman10.OutOfRangeError, roman10.to_roman, 5000)
    
        def test_zero(self):
            '''to_roman should fail with 0 input'''
            self.assertRaises(roman10.OutOfRangeError, roman10.to_roman, 0)
    
        def test_negative(self):
            '''to_roman should fail with negative input'''
            self.assertRaises(roman10.OutOfRangeError, roman10.to_roman, -1)
    
        def test_non_integer(self):
            '''to_roman should fail with non-integer input'''
            self.assertRaises(roman10.NotIntegerError, roman10.to_roman, 0.5)
    
    class FromRomanBadInput(unittest.TestCase):
        def test_too_many_repeated_numerals(self):
            '''from_roman should fail with too many repeated numerals'''
            for s in ('MMMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
                self.assertRaises(roman10.InvalidRomanNumeralError, roman10.from_roman, s)
    
        def test_repeated_pairs(self):
            '''from_roman should fail with repeated pairs of numerals'''
            for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
                self.assertRaises(roman10.InvalidRomanNumeralError, roman10.from_roman, s)
    
        def test_malformed_antecedents(self):
            '''from_roman should fail with malformed antecedents'''
            for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
                      'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
                self.assertRaises(roman10.InvalidRomanNumeralError, roman10.from_roman, s)
    
        def test_blank(self):
            '''from_roman should fail with blank string'''
            self.assertRaises(roman10.InvalidRomanNumeralError, roman10.from_roman, '')
    
        def test_non_string(self):
            '''from_roman should fail with non-string input'''
            self.assertRaises(roman10.InvalidRomanNumeralError, roman10.from_roman, 1)
    
    class RoundtripCheck(unittest.TestCase):
        def test_roundtrip(self):
            '''from_roman(to_roman(n))==n for all n'''
            for integer in range(1, 5000):
                numeral = roman10.to_roman(integer)
                result = roman10.from_roman(numeral)
                self.assertEqual(integer, result)
    
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/roman9.py��������������������������������������������0000644�0000000�0000000�00000007223�11773544727�021211� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Convert to and from Roman numerals
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    import re
    
    class OutOfRangeError(ValueError): pass
    class NotIntegerError(ValueError): pass
    class InvalidRomanNumeralError(ValueError): pass
    
    roman_numeral_map = (('M',  1000),
                         ('CM', 900),
                         ('D',  500),
                         ('CD', 400),
                         ('C',  100),
                         ('XC', 90),
                         ('L',  50),
                         ('XL', 40),
                         ('X',  10),
                         ('IX', 9),
                         ('V',  5),
                         ('IV', 4),
                         ('I',  1))
    
    roman_numeral_pattern = re.compile('''
        ^                   # beginning of string
        M{0,4}              # thousands - 0 to 4 M's
        (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
                            #            or 500-800 (D, followed by 0 to 3 C's)
        (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
                            #        or 50-80 (L, followed by 0 to 3 X's)
        (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
                            #        or 5-8 (V, followed by 0 to 3 I's)
        $                   # end of string
        ''', re.VERBOSE)
    
    def to_roman(n):
        '''convert integer to Roman numeral'''
        if not isinstance(n, int):
            raise NotIntegerError('non-integers can not be converted')
        if not (0 < n < 5000):
            raise OutOfRangeError('number out of range (must be 1..4999)')
    
        result = ''
        for numeral, integer in roman_numeral_map:
            while n >= integer:
                result += numeral
                n -= integer
        return result
    
    def from_roman(s):
        '''convert Roman numeral to integer'''
        if not isinstance(s, str):
            raise InvalidRomanNumeralError('Input must be a string')
        if not s:
            raise InvalidRomanNumeralError('Input can not be blank')
        if not roman_numeral_pattern.search(s):
            raise InvalidRomanNumeralError('Invalid Roman numeral: {0}'.format(s))
    
        result = 0
        index = 0
        for numeral, integer in roman_numeral_map:
            while s[index : index + len(numeral)] == numeral:
                result += integer
                index += len(numeral)
        return result
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/regression.py����������������������������������������0000644�0000000�0000000�00000000722�11773544727�022161� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/python3
    
    import unittest
    import os
    import glob
    
    def regressionTest():
        filenames = glob.glob('*test*.py')
        module_names = [os.path.splitext(os.path.basename(f))[0] for f in filenames]
        modules = [__import__(name) for name in module_names]
        tests = [unittest.defaultTestLoader.loadTestsFromModule(m) for m in modules]
        return unittest.TestSuite(tests)
    
    if __name__ == '__main__':
        unittest.main(defaultTest='regressionTest')����������������������������������������������diveintopython3-20110517-77958af.orig/examples/roman1.py��������������������������������������������0000644�0000000�0000000�00000004220�11773544727�021173� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Convert to and from Roman numerals
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    
    roman_numeral_map = (('M',  1000),
                         ('CM', 900),
                         ('D',  500),
                         ('CD', 400),
                         ('C',  100),
                         ('XC', 90),
                         ('L',  50),
                         ('XL', 40),
                         ('X',  10),
                         ('IX', 9),
                         ('V',  5),
                         ('IV', 4),
                         ('I',  1))
    
    def to_roman(n):
        '''convert integer to Roman numeral'''
        result = ''
        for numeral, integer in roman_numeral_map:
            while n >= integer:
                result += numeral
                n -= integer
        return result
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/stdout.py��������������������������������������������0000644�0000000�0000000�00000000621�11773544727�021321� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������import sys
    
    class RedirectStdoutTo:
        def __init__(self, out_new):
            self.out_new = out_new
    
        def __enter__(self):
            self.out_old = sys.stdout
            sys.stdout = self.out_new
    
        def __exit__(self, *args):
            sys.stdout = self.out_old
    
    print('A')
    with open('out.log', mode='w', encoding='utf-8') as a_file, RedirectStdoutTo(a_file):
        print('B')
    print('C')
    ���������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/romantest3.py����������������������������������������0000644�0000000�0000000�00000010662�11773544727�022104� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for roman1.py
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    
    import roman3
    import unittest
    
    class KnownValues(unittest.TestCase):
        known_values = ( (1, 'I'),
                         (2, 'II'),
                         (3, 'III'),
                         (4, 'IV'),
                         (5, 'V'),
                         (6, 'VI'),
                         (7, 'VII'),
                         (8, 'VIII'),
                         (9, 'IX'),
                         (10, 'X'),
                         (50, 'L'),
                         (100, 'C'),
                         (500, 'D'),
                         (1000, 'M'),
                         (31, 'XXXI'),
                         (148, 'CXLVIII'),
                         (294, 'CCXCIV'),
                         (312, 'CCCXII'),
                         (421, 'CDXXI'),
                         (528, 'DXXVIII'),
                         (621, 'DCXXI'),
                         (782, 'DCCLXXXII'),
                         (870, 'DCCCLXX'),
                         (941, 'CMXLI'),
                         (1043, 'MXLIII'),
                         (1110, 'MCX'),
                         (1226, 'MCCXXVI'),
                         (1301, 'MCCCI'),
                         (1485, 'MCDLXXXV'),
                         (1509, 'MDIX'),
                         (1607, 'MDCVII'),
                         (1754, 'MDCCLIV'),
                         (1832, 'MDCCCXXXII'),
                         (1993, 'MCMXCIII'),
                         (2074, 'MMLXXIV'),
                         (2152, 'MMCLII'),
                         (2212, 'MMCCXII'),
                         (2343, 'MMCCCXLIII'),
                         (2499, 'MMCDXCIX'),
                         (2574, 'MMDLXXIV'),
                         (2646, 'MMDCXLVI'),
                         (2723, 'MMDCCXXIII'),
                         (2892, 'MMDCCCXCII'),
                         (2975, 'MMCMLXXV'),
                         (3051, 'MMMLI'),
                         (3185, 'MMMCLXXXV'),
                         (3250, 'MMMCCL'),
                         (3313, 'MMMCCCXIII'),
                         (3408, 'MMMCDVIII'),
                         (3501, 'MMMDI'),
                         (3610, 'MMMDCX'),
                         (3743, 'MMMDCCXLIII'),
                         (3844, 'MMMDCCCXLIV'),
                         (3888, 'MMMDCCCLXXXVIII'),
                         (3940, 'MMMCMXL'),
                         (3999, 'MMMCMXCIX'))
    
        def test_to_roman_known_values(self):
            '''to_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman3.to_roman(integer)
                self.assertEqual(numeral, result)
    
    class ToRomanBadInput(unittest.TestCase):
        def test_too_large(self):
            '''to_roman should fail with large input'''
            self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, 4000)
    
        def test_zero(self):
            '''to_roman should fail with 0 input'''
            self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, 0)
    
        def test_negative(self):
            '''to_roman should fail with negative input'''
            self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, -1)
    
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/plural6.py�������������������������������������������0000644�0000000�0000000�00000005464�11773544727�021376� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Pluralize English nouns (stage 6)
    
    Command line usage:
    $ python plural6.py noun
    nouns
    '''
    
    import re
    
    def build_match_and_apply_functions(pattern, search, replace):
        def matches_rule(word):
            return re.search(pattern, word)
        def apply_rule(word):
            return re.sub(search, replace, word)
        return [matches_rule, apply_rule]
    
    class LazyRules:
        rules_filename = 'plural6-rules.txt'
    
        def __init__(self):
            self.pattern_file = open(self.rules_filename, encoding='utf-8')
            self.cache = []
    
        def __iter__(self):
            self.cache_index = 0
            return self
    
        def __next__(self):
            self.cache_index += 1
            if len(self.cache) >= self.cache_index:
                return self.cache[self.cache_index - 1]
    
            if self.pattern_file.closed:
                raise StopIteration
    
            line = self.pattern_file.readline()
            if not line:
                self.pattern_file.close()
                raise StopIteration
    
            pattern, search, replace = line.split(None, 3)
            funcs = build_match_and_apply_functions(
                pattern, search, replace)
            self.cache.append(funcs)
            return funcs
    
    rules = LazyRules()
            
    def plural(noun):
        for matches_rule, apply_rule in rules:
            if matches_rule(noun):
                return apply_rule(noun)
    
    if __name__ == '__main__':
        import sys
        if sys.argv[1:]:
            print(plural(sys.argv[1]))
        else:
            print(__doc__)
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/pluraltest2.py���������������������������������������0000644�0000000�0000000�00000005653�11773544727�022272� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for plural2.py'''
    
    import plural2
    import unittest
    
    class KnownValues(unittest.TestCase):
        def test_sxz(self):
            'words ending in S, X, and Z'
            nouns = {
                'bass': 'basses',
                'bus': 'buses',
                'walrus': 'walruses',
                'box': 'boxes',
                'fax': 'faxes',
                'suffix': 'suffixes',
                'mailbox': 'mailboxes',
                'buzz': 'buzzes',
                'waltz': 'waltzes'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural2.plural(singular), plural)
    
        def test_h(self):
            'words ending in H'
            nouns = {
                'coach': 'coaches',
                'glitch': 'glitches',
                'rash': 'rashes',
                'watch': 'watches',
                'cheetah': 'cheetahs',
                'cough': 'coughs'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural2.plural(singular), plural)
    
        def test_y(self):
            'words ending in Y'
            nouns = {
                'utility': 'utilities',
                'vacancy': 'vacancies',
                'boy': 'boys',
                'day': 'days'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural2.plural(singular), plural)
    
        def test_default(self):
            'unexceptional words'
            nouns = {
                'papaya': 'papayas',
                'whip': 'whips',
                'palimpsest': 'palimpsests'
                }
            for singular, plural in nouns.items():
                self.assertEqual(plural2.plural(singular), plural)
            
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    �������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/chinese.txt������������������������������������������0000644�0000000�0000000�00000000113�11773544727�021600� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Dive Into Python 是为有经验的程序员编写的一本 Python 书。
    �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diveintopython3-20110517-77958af.orig/examples/romantest5.py����������������������������������������0000644�0000000�0000000�00000012205�11773544727�022101� 0����������������������������������������������������������������������������������������������������ustar  �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''Unit test for roman1.py
    
    This program is part of 'Dive Into Python 3', a free Python book for
    experienced programmers.  Visit http://diveintopython3.org/ for the
    latest version.
    '''
    
    import roman5
    import unittest
    
    class KnownValues(unittest.TestCase):
        known_values = ( (1, 'I'),
                         (2, 'II'),
                         (3, 'III'),
                         (4, 'IV'),
                         (5, 'V'),
                         (6, 'VI'),
                         (7, 'VII'),
                         (8, 'VIII'),
                         (9, 'IX'),
                         (10, 'X'),
                         (50, 'L'),
                         (100, 'C'),
                         (500, 'D'),
                         (1000, 'M'),
                         (31, 'XXXI'),
                         (148, 'CXLVIII'),
                         (294, 'CCXCIV'),
                         (312, 'CCCXII'),
                         (421, 'CDXXI'),
                         (528, 'DXXVIII'),
                         (621, 'DCXXI'),
                         (782, 'DCCLXXXII'),
                         (870, 'DCCCLXX'),
                         (941, 'CMXLI'),
                         (1043, 'MXLIII'),
                         (1110, 'MCX'),
                         (1226, 'MCCXXVI'),
                         (1301, 'MCCCI'),
                         (1485, 'MCDLXXXV'),
                         (1509, 'MDIX'),
                         (1607, 'MDCVII'),
                         (1754, 'MDCCLIV'),
                         (1832, 'MDCCCXXXII'),
                         (1993, 'MCMXCIII'),
                         (2074, 'MMLXXIV'),
                         (2152, 'MMCLII'),
                         (2212, 'MMCCXII'),
                         (2343, 'MMCCCXLIII'),
                         (2499, 'MMCDXCIX'),
                         (2574, 'MMDLXXIV'),
                         (2646, 'MMDCXLVI'),
                         (2723, 'MMDCCXXIII'),
                         (2892, 'MMDCCCXCII'),
                         (2975, 'MMCMLXXV'),
                         (3051, 'MMMLI'),
                         (3185, 'MMMCLXXXV'),
                         (3250, 'MMMCCL'),
                         (3313, 'MMMCCCXIII'),
                         (3408, 'MMMCDVIII'),
                         (3501, 'MMMDI'),
                         (3610, 'MMMDCX'),
                         (3743, 'MMMDCCXLIII'),
                         (3844, 'MMMDCCCXLIV'),
                         (3888, 'MMMDCCCLXXXVIII'),
                         (3940, 'MMMCMXL'),
                         (3999, 'MMMCMXCIX'))
    
        def test_to_roman_known_values(self):
            '''to_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman5.to_roman(integer)
                self.assertEqual(numeral, result)
    
        def test_from_roman_known_values(self):
            '''from_roman should give known result with known input'''
            for integer, numeral in self.known_values:
                result = roman5.from_roman(numeral)
                self.assertEqual(integer, result)
    
    class ToRomanBadInput(unittest.TestCase):
        def test_too_large(self):
            '''to_roman should fail with large input'''
            self.assertRaises(roman5.OutOfRangeError, roman5.to_roman, 4000)
    
        def test_zero(self):
            '''to_roman should fail with 0 input'''
            self.assertRaises(roman5.OutOfRangeError, roman5.to_roman, 0)
    
        def test_negative(self):
            '''to_roman should fail with negative input'''
            self.assertRaises(roman5.OutOfRangeError, roman5.to_roman, -1)
    
        def test_non_integer(self):
            '''to_roman should fail with non-integer input'''
            self.assertRaises(roman5.NotIntegerError, roman5.to_roman, 0.5)
    
    class RoundtripCheck(unittest.TestCase):
        def test_roundtrip(self):
            '''from_roman(to_roman(n))==n for all n'''
            for integer in range(1, 4000):
                numeral = roman5.to_roman(integer)
                result = roman5.from_roman(numeral)
                self.assertEqual(integer, result)
    
    if __name__ == '__main__':
        unittest.main()
    
    # Copyright (c) 2009, Mark Pilgrim, 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.
    # 
    # 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.
    �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������