Jelajahi Sumber

first commit

honghaitzz11 6 tahun lalu
melakukan
03a8f76d59
100 mengubah file dengan 2273 tambahan dan 0 penghapusan
  1. 15 0
      .vscode/launch.json
  2. 52 0
      01/01.py
  3. 15 0
      02/02_1.py
  4. 27 0
      02/02_2.py
  5. 28 0
      02/02_3.py
  6. 8 0
      02/02_4.py
  7. TEMPAT SAMPAH
      beginning-python-3ed-master/9781484200292.jpg
  8. 34 0
      beginning-python-3ed-master/Chapter02/listing2-1.py
  9. 6 0
      beginning-python-3ed-master/Chapter02/listing2-2.py
  10. 16 0
      beginning-python-3ed-master/Chapter02/listing2-3.py
  11. 13 0
      beginning-python-3ed-master/Chapter02/listing2-4.py
  12. 23 0
      beginning-python-3ed-master/Chapter03/listing3-1.py
  13. 43 0
      beginning-python-3ed-master/Chapter04/listing4-1.py
  14. 25 0
      beginning-python-3ed-master/Chapter04/listing4-2.py
  15. 2 0
      beginning-python-3ed-master/Chapter10/listing10-1.py
  16. 6 0
      beginning-python-3ed-master/Chapter10/listing10-10.py
  17. 32 0
      beginning-python-3ed-master/Chapter10/listing10-11.py
  18. 3 0
      beginning-python-3ed-master/Chapter10/listing10-12.txt
  19. 3 0
      beginning-python-3ed-master/Chapter10/listing10-13.txt
  20. 13 0
      beginning-python-3ed-master/Chapter10/listing10-14.txt
  21. 3 0
      beginning-python-3ed-master/Chapter10/listing10-2.py
  22. 7 0
      beginning-python-3ed-master/Chapter10/listing10-3.py
  23. 8 0
      beginning-python-3ed-master/Chapter10/listing10-4.py
  24. 5 0
      beginning-python-3ed-master/Chapter10/listing10-5.py
  25. 8 0
      beginning-python-3ed-master/Chapter10/listing10-6.py
  26. 54 0
      beginning-python-3ed-master/Chapter10/listing10-8.py
  27. 6 0
      beginning-python-3ed-master/Chapter11/listing11-1.py
  28. 3 0
      beginning-python-3ed-master/Chapter11/listing11-10.py
  29. 3 0
      beginning-python-3ed-master/Chapter11/listing11-11.py
  30. 3 0
      beginning-python-3ed-master/Chapter11/listing11-12.py
  31. 2 0
      beginning-python-3ed-master/Chapter11/listing11-13.py
  32. 2 0
      beginning-python-3ed-master/Chapter11/listing11-2.txt
  33. 3 0
      beginning-python-3ed-master/Chapter11/listing11-3.txt
  34. 3 0
      beginning-python-3ed-master/Chapter11/listing11-4.txt
  35. 3 0
      beginning-python-3ed-master/Chapter11/listing11-5.txt
  36. 5 0
      beginning-python-3ed-master/Chapter11/listing11-6.py
  37. 5 0
      beginning-python-3ed-master/Chapter11/listing11-7.py
  38. 5 0
      beginning-python-3ed-master/Chapter11/listing11-8.py
  39. 3 0
      beginning-python-3ed-master/Chapter11/listing11-9.py
  40. 25 0
      beginning-python-3ed-master/Chapter12/listing12-1.py
  41. 37 0
      beginning-python-3ed-master/Chapter13/listing13-1.py
  42. 13 0
      beginning-python-3ed-master/Chapter13/listing13-2.py
  43. 14 0
      beginning-python-3ed-master/Chapter14/listing14-1.py
  44. 9 0
      beginning-python-3ed-master/Chapter14/listing14-2.py
  45. 11 0
      beginning-python-3ed-master/Chapter14/listing14-3.py
  46. 13 0
      beginning-python-3ed-master/Chapter14/listing14-4.py
  47. 13 0
      beginning-python-3ed-master/Chapter14/listing14-5.py
  48. 29 0
      beginning-python-3ed-master/Chapter14/listing14-6.py
  49. 30 0
      beginning-python-3ed-master/Chapter14/listing14-7.py
  50. 19 0
      beginning-python-3ed-master/Chapter14/listing14-8.py
  51. 21 0
      beginning-python-3ed-master/Chapter14/listing14-9.py
  52. 6 0
      beginning-python-3ed-master/Chapter15/listing15-1.py
  53. 35 0
      beginning-python-3ed-master/Chapter15/listing15-2.py
  54. 11 0
      beginning-python-3ed-master/Chapter15/listing15-3.py
  55. 6 0
      beginning-python-3ed-master/Chapter15/listing15-4.py
  56. 9 0
      beginning-python-3ed-master/Chapter15/listing15-5.py
  57. 10 0
      beginning-python-3ed-master/Chapter15/listing15-6.py
  58. 24 0
      beginning-python-3ed-master/Chapter15/listing15-7.py
  59. 9 0
      beginning-python-3ed-master/Chapter16/listing16-1.py
  60. 19 0
      beginning-python-3ed-master/Chapter16/listing16-2.py
  61. 18 0
      beginning-python-3ed-master/Chapter16/listing16-3.py
  62. 7 0
      beginning-python-3ed-master/Chapter17/listing17-1.java
  63. 10 0
      beginning-python-3ed-master/Chapter17/listing17-2.cs
  64. 9 0
      beginning-python-3ed-master/Chapter17/listing17-3.c
  65. 6 0
      beginning-python-3ed-master/Chapter17/listing17-4.py
  66. 7 0
      beginning-python-3ed-master/Chapter17/listing17-5.i
  67. 48 0
      beginning-python-3ed-master/Chapter17/listing17-6.c
  68. 7 0
      beginning-python-3ed-master/Chapter18/listing18-1.py
  69. 9 0
      beginning-python-3ed-master/Chapter19/listing19-1.cfg
  70. 21 0
      beginning-python-3ed-master/Chapter19/listing19-2.py
  71. 13 0
      beginning-python-3ed-master/Chapter19/listing19-3.py
  72. 36 0
      beginning-python-3ed-master/Chapter20/listing20-1.txt
  73. 12 0
      beginning-python-3ed-master/Chapter20/listing20-2.py
  74. 19 0
      beginning-python-3ed-master/Chapter20/listing20-3.py
  75. 64 0
      beginning-python-3ed-master/Chapter20/listing20-4.py
  76. 72 0
      beginning-python-3ed-master/Chapter20/listing20-5.py
  77. 52 0
      beginning-python-3ed-master/Chapter20/listing20-6.py
  78. 9 0
      beginning-python-3ed-master/Chapter21/listing21-1.py
  79. 31 0
      beginning-python-3ed-master/Chapter21/listing21-2.py
  80. 41 0
      beginning-python-3ed-master/Chapter21/listing21-3.py
  81. 31 0
      beginning-python-3ed-master/Chapter22/listing22-1.xml
  82. 32 0
      beginning-python-3ed-master/Chapter22/listing22-2.py
  83. 76 0
      beginning-python-3ed-master/Chapter22/listing22-3.py
  84. 23 0
      beginning-python-3ed-master/Chapter23/listing23-1.py
  85. 160 0
      beginning-python-3ed-master/Chapter23/listing23-2.py
  86. 7 0
      beginning-python-3ed-master/Chapter24/listing24-1.py
  87. 14 0
      beginning-python-3ed-master/Chapter24/listing24-2.py
  88. 22 0
      beginning-python-3ed-master/Chapter24/listing24-3.py
  89. 39 0
      beginning-python-3ed-master/Chapter24/listing24-4.py
  90. 65 0
      beginning-python-3ed-master/Chapter24/listing24-5.py
  91. 192 0
      beginning-python-3ed-master/Chapter24/listing24-6.py
  92. 26 0
      beginning-python-3ed-master/Chapter25/listing25-1.py
  93. 34 0
      beginning-python-3ed-master/Chapter25/listing25-2.py
  94. 29 0
      beginning-python-3ed-master/Chapter25/listing25-3.py
  95. 7 0
      beginning-python-3ed-master/Chapter26/listing26-1.sql
  96. 8 0
      beginning-python-3ed-master/Chapter26/listing26-2.sql
  97. 7 0
      beginning-python-3ed-master/Chapter26/listing26-3.sql
  98. 51 0
      beginning-python-3ed-master/Chapter26/listing26-4.py
  99. 53 0
      beginning-python-3ed-master/Chapter26/listing26-5.py
  100. 48 0
      beginning-python-3ed-master/Chapter26/listing26-6.py

+ 15 - 0
.vscode/launch.json

@@ -0,0 +1,15 @@
+{
+  // 使用 IntelliSense 了解相关属性。 
+  // 悬停以查看现有属性的描述。
+  // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "name": "Python: 当前文件",
+      "type": "python",
+      "request": "launch",
+      "program": "${file}",
+      "console": "integratedTerminal"
+    }
+  ]
+}

+ 52 - 0
01/01.py

@@ -0,0 +1,52 @@
+#!/usr/bin/env python3.7
+# function
+
+# pow(2, 3) === 2 ** 3 == 2的3次方
+
+# abs(-10) 取正
+
+# print(round(2 / 3))
+# 2.7 ==> 0.0
+# 3.7 ==> 1
+
+
+# import math
+
+# print(math.floor(32.9)) # 32  向下取整
+# or
+# int(32.9) # 32
+
+# math.ceil(32.3) # 33 向上取整
+# math.ceil(32) # 32
+
+# math.sqrt(9)  # 3.0 计算平方根
+
+# name = input("What is your name? ")
+# print("Hello, " + name + "!")
+
+
+# print(str("Hello,\nworld!"))
+# input("Press <enter>")
+
+# from turtle import *
+# forward(100)
+# left(120)
+# forward(100)
+# left(120)
+# forward(100)
+
+
+# print(r'C:\Program Files\foo\bar' '\\')
+# print(r'C:\nowhere')
+# print('C:\nowhere')
+# print('\u00C6')
+# print('\U0001F60A')
+# print('\N{cat}')
+
+
+# 编码转换
+# print(len("Hello, world!".encode("ASCII"))) # 13
+# print(len("Hello, world!".encode("UTF-8"))) # 13
+# print(len("Hello, world!".encode("UTF-32"))) # 56
+
+print(help('sys'))

+ 15 - 0
02/02_1.py

@@ -0,0 +1,15 @@
+#!/usr/bin/env python3.7
+
+# 2.1序列概述
+# edward = ['Edward Gumby', 42]
+# john = ['John Smith', 50]
+# database = [edward, john]
+# print(database) # [['Edward Gumby', 42], ['John Smith', 50]]
+
+# 2.2
+## 索引
+# greeting = 'Hello'
+# print(greeting[0]) # H
+# print(greeting[3]) # l
+# fourth = input('Year: ')[3]
+# print(fourth)

+ 27 - 0
02/02_2.py

@@ -0,0 +1,27 @@
+#!/usr/bin/env python3
+# 将以数指定年、月、日的日期打印出来
+months = ['January', 'February', 'March', 'April', 'May', 'June',
+          'July', 'August', 'Septmber', 'October', 'November', 'December']
+
+# 一个列表,其中包含数1~31对应的结尾
+endings = ['st', 'nd', 'rd'] + 17 * ['th'] \
+    + ['st', 'nd', 'rd'] + 7 * ['th'] \
+    + ['st']
+
+year = input('Year: ')
+month = input('Month (1-12): ')
+day = input('Day (1-31): ')
+
+month_number = int(month)
+day_number = int(day)
+
+# 别忘了将表示月和日的数减1,这样才能得到正确的索引
+month_name = months[month_number-1]
+ordinal = day + endings[day_number-1]
+
+print(month_name + ' ' + ordinal + ', ' + year)
+
+# Year: 1974
+# Month (1-12): 8
+# Day (1-31): 16
+# August 16th, 1974

+ 28 - 0
02/02_3.py

@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+tag = '<a href="http://www.python.org">Python web site</a>'
+print(tag[9:30])  # http://www.python.org
+print(tag[32:-4])  # Python web site
+numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+print(numbers[3:6])  # [4, 5, 6]
+print(numbers[0:1])  # [1]
+print(numbers[7:10])  # [8,9,10]
+print(numbers[-3:-1])  # [8,9]
+print(numbers[-3:0])  # []
+print(numbers[-3:])  # [8,9,10]
+print(numbers[:3])  # [1,2,3]
+print(numbers[:])  # [1,2,3,4,5,6,7,8,9,10]
+print(numbers[0:10:1])  # [1,2,3,4,5,6,7,8,9,10]
+print(numbers[0:10:2])  # [1,3,5,7,9]
+print(numbers[3:6:3])  # [4]
+print(numbers[::4])  # [1,5,9]
+# 步长为负数时,列表的排序方式改变为倒序
+print(numbers[8:3:-1])  # [9, 8, 7, 6, 5]
+print(numbers[10:0:-2])  # [10, 8, 6, 4, 2]
+print(numbers[0:10:-2])  # []
+print(numbers[::-2])  # [10, 8, 6, 4, 2]
+print(numbers[5::-2])  # [ 6, 4, 2]
+print(numbers[:5:-2])  # [ 10,8]
+# 从类似于http://www.something.com的URL中提取域名
+# url = input('Please enter the URL:')
+# domain = url[11:-4]
+# print("Domain name:"+domain)

+ 8 - 0
02/02_4.py

@@ -0,0 +1,8 @@
+#!/usr/bin/env python3
+# 序列相加
+print([1, 2, 3, 4]+[6, 7, 8, 9])  # [1,2,3,4,5,6,7,8,9]
+
+# 乘法
+print([42]*10)  # [42, 42, 42, 42, 42, 42, 42, 42, 42, 42]
+
+# None、空列表和初始化

TEMPAT SAMPAH
beginning-python-3ed-master/9781484200292.jpg


+ 34 - 0
beginning-python-3ed-master/Chapter02/listing2-1.py

@@ -0,0 +1,34 @@
+# Print out a date, given year, month, and day as numbers
+
+months = [
+    'January',
+    'February',
+    'March',
+    'April',
+    'May',
+    'June',
+    'July',
+    'August',
+    'September',
+    'October',
+    'November',
+    'December'
+]
+
+# A list with one ending for each number from 1 to 31
+endings = ['st', 'nd', 'rd'] + 17 * ['th'] \
+        + ['st', 'nd', 'rd'] +  7 * ['th'] \
+        + ['st']
+
+year    = input('Year: ')
+month   = input('Month  (1-12): ')
+day     = input('Day (1-31): ')
+
+month_number = int(month)
+day_number = int(day)
+
+# Remember to subtract 1 from month and day to get a correct index
+month_name = months[month_number-1]
+ordinal = day + endings[day_number-1]
+
+print(month_name + ' ' + ordinal + ', ' + year)

+ 6 - 0
beginning-python-3ed-master/Chapter02/listing2-2.py

@@ -0,0 +1,6 @@
+# Split up a URL of the form http://www.something.com
+
+url = input('Please enter the URL:')
+domain = url[11:-4]
+
+print("Domain name: " + domain)

+ 16 - 0
beginning-python-3ed-master/Chapter02/listing2-3.py

@@ -0,0 +1,16 @@
+# Prints a sentence in a centered "box" of correct width
+
+sentence = input("Sentence: ")
+
+screen_width = 80
+text_width   = len(sentence)
+box_width    = text_width + 6
+left_margin  = (screen_width - box_width) // 2
+
+print()
+print(' ' * left_margin + '+'   + '-' * (box_width-2)  +   '+')
+print(' ' * left_margin + '|  ' + ' ' * text_width     + '  |')
+print(' ' * left_margin + '|  ' +       sentence       + '  |')
+print(' ' * left_margin + '|  ' + ' ' * text_width     + '  |')
+print(' ' * left_margin + '+'   + '-' * (box_width-2)  +   '+')
+print()

+ 13 - 0
beginning-python-3ed-master/Chapter02/listing2-4.py

@@ -0,0 +1,13 @@
+# Check a user name and PIN code
+
+database = [
+    ['albert',  '1234'],
+    ['dilbert', '4242'],
+    ['smith',   '7524'],
+    ['jones',   '9843']
+]
+
+username = input('User name: ')
+pin = input('PIN code: ')
+
+if [username, pin] in database: print('Access granted')

+ 23 - 0
beginning-python-3ed-master/Chapter03/listing3-1.py

@@ -0,0 +1,23 @@
+# Print a formatted price list with a given width
+
+width = int(input('Please enter width: '))
+
+price_width = 10
+item_width  = width - price_width
+
+header_fmt = '{{:{}}}{{:>{}}}'.format(item_width, price_width)
+fmt        = '{{:{}}}{{:>{}.2f}}'.format(item_width, price_width)
+
+print('=' * width)
+
+print(header_fmt.format('Item', 'Price'))
+
+print('-' * width)
+
+print(fmt.format('Apples', 0.4))
+print(fmt.format('Pears', 0.5))
+print(fmt.format('Cantaloupes', 1.92))
+print(fmt.format('Dried Apricots (16 oz.)', 8))
+print(fmt.format('Prunes (4 lbs.)', 12))
+
+print('=' * width)

+ 43 - 0
beginning-python-3ed-master/Chapter04/listing4-1.py

@@ -0,0 +1,43 @@
+# A simple database
+
+# A dictionary with person names as keys. Each person is represented as
+# another dictionary with the keys 'phone' and 'addr' referring to their phone
+# number and address, respectively.
+people = {
+
+    'Alice': {
+        'phone': '2341',
+        'addr': 'Foo drive 23'
+    },
+
+    'Beth': {
+        'phone': '9102',
+        'addr': 'Bar street 42'
+    },
+
+    'Cecil': {
+        'phone': '3158',
+        'addr': 'Baz avenue 90'
+    }
+
+}
+
+# Descriptive labels for the phone number and address. These will be used
+# when printing the output.
+labels = {
+    'phone': 'phone number',
+    'addr': 'address'
+}
+
+name = input('Name: ')
+
+# Are we looking for a phone number or an address?
+request = input('Phone number (p) or address (a)? ')
+
+# Use the correct key:
+if request == 'p': key = 'phone'
+if request == 'a': key = 'addr'
+
+# Only try to print information if the name is a valid key in
+# our dictionary:
+if name in people: print("{}'s {} is {}.".format(name, labels[key], people[name][key]))

+ 25 - 0
beginning-python-3ed-master/Chapter04/listing4-2.py

@@ -0,0 +1,25 @@
+# A simple database using get()
+
+# Insert database (people) from Listing 4-1 here.
+
+labels = {
+    'phone': 'phone number',
+    'addr': 'address'
+}
+
+name = input('Name: ')
+
+# Are we looking for a phone number or an address?
+request = input('Phone number (p) or address (a)? ')
+
+# Use the correct key:
+key = request # In case the request is neither 'p' nor 'a'
+if request == 'p': key = 'phone'
+if request == 'a': key = 'addr'
+
+# Use get to provide default values:
+person = people.get(name, {})
+label = labels.get(key, key)
+result = person.get(key, 'not available')
+
+print("{}'s {} is {}.".format(name, label, result))

+ 2 - 0
beginning-python-3ed-master/Chapter10/listing10-1.py

@@ -0,0 +1,2 @@
+# hello.py
+print("Hello, world!")

+ 6 - 0
beginning-python-3ed-master/Chapter10/listing10-10.py

@@ -0,0 +1,6 @@
+# find_sender.py
+import fileinput, re
+pat = re.compile('From: (.*) <.*?>$')
+for line in fileinput.input():
+    m = pat.match(line)
+    if m: print(m.group(1))

+ 32 - 0
beginning-python-3ed-master/Chapter10/listing10-11.py

@@ -0,0 +1,32 @@
+# templates.py
+
+import fileinput, re
+
+# Matches fields enclosed in square brackets:
+field_pat = re.compile(r'\[(.+?)\]')
+
+# We'll collect variables in this:
+scope = {}
+
+# This is used in re.sub:
+def replacement(match):
+    code = match.group(1)
+    try:
+        # If the field can be evaluated, return it:
+        return str(eval(code, scope))
+    except SyntaxError:
+        # Otherwise, execute the assignment in the same scope ...
+        exec code in scope
+        # ... and return an empty string:
+        return ''
+
+# Get all the text as a single string:
+
+# (There are other ways of doing this; see Chapter 11)
+lines = []
+for line in fileinput.input():
+    lines.append(line)
+text = ''.join(lines)
+
+# Substitute all the occurrences of the field pattern:
+print(field_pat.sub(replacement, text))

+ 3 - 0
beginning-python-3ed-master/Chapter10/listing10-12.txt

@@ -0,0 +1,3 @@
+[x = 2]
+[y = 3]
+The sum of [x] and [y] is [x + y].

+ 3 - 0
beginning-python-3ed-master/Chapter10/listing10-13.txt

@@ -0,0 +1,3 @@
+[name     = 'Magnus Lie Hetland' ]
+[email    = 'magnus@foo.bar'     ]
+[language = 'python'             ]

+ 13 - 0
beginning-python-3ed-master/Chapter10/listing10-14.txt

@@ -0,0 +1,13 @@
+[import time]
+Dear [name],
+
+I would like to learn how to program. I hear you use
+the [language] language a lot -- is it something I
+should consider?
+
+And, by the way, is [email] your correct email address?
+
+
+Fooville, [time.asctime()]
+
+Oscar Frozzbozz

+ 3 - 0
beginning-python-3ed-master/Chapter10/listing10-2.py

@@ -0,0 +1,3 @@
+# hello2.py
+def hello():
+    print("Hello, world!")

+ 7 - 0
beginning-python-3ed-master/Chapter10/listing10-3.py

@@ -0,0 +1,7 @@
+# hello3.py
+
+def hello():
+    print("Hello, world!")
+
+# A test:
+hello()

+ 8 - 0
beginning-python-3ed-master/Chapter10/listing10-4.py

@@ -0,0 +1,8 @@
+# hello4.py
+def hello():
+    print("Hello, world!")
+
+def test():
+    hello()
+
+if __name__ == '__main__': test()

+ 5 - 0
beginning-python-3ed-master/Chapter10/listing10-5.py

@@ -0,0 +1,5 @@
+# reverseargs.py
+import sys
+args = sys.argv[1:]
+args.reverse()
+print(' '.join(args))

+ 8 - 0
beginning-python-3ed-master/Chapter10/listing10-6.py

@@ -0,0 +1,8 @@
+# numberlines.py
+
+import fileinput
+
+for line in fileinput.input(inplace=True):
+    line = line.rstrip()
+    num  = fileinput.lineno()
+    print('{:<50} # {:2d}'.format(line, num))

+ 54 - 0
beginning-python-3ed-master/Chapter10/listing10-8.py

@@ -0,0 +1,54 @@
+# database.py
+import sys, shelve
+
+def store_person(db):
+    """
+    Query user for data and store it in the shelf object
+    """
+    pid = input('Enter unique ID number: ')
+    person = {}
+    person['name'] = input('Enter name: ')
+    person['age'] = input('Enter age: ')
+    person['phone'] = input('Enter phone number: ')
+    db[pid] = person
+
+def lookup_person(db):
+    """
+    Query user for ID and desired field, and fetch the corresponding data from
+    the shelf object
+    """
+    pid = input('Enter ID number: ')
+    field = input('What would you like to know? (name, age, phone) ')
+    field = field.strip().lower()
+
+    print(field.capitalize() + ':', db[pid][field])
+
+def print_help():
+    print('The available commands are:')
+    print('store  : Stores information about a person')
+    print('lookup : Looks up a person from ID number')
+    print('quit   : Save changes and exit')
+    print('?      : Prints this message')
+
+def enter_command():
+    cmd = input('Enter command (? for help): ')
+    cmd = cmd.strip().lower()
+    return cmd
+
+def main():
+    database = shelve.open('C:\\database.dat') # You may want to change this name
+    try:
+        while True:
+            cmd = enter_command()
+            if  cmd == 'store':
+                store_person(database)
+            elif cmd == 'lookup':
+                lookup_person(database)
+            elif cmd == '?':
+                print_help()
+            elif cmd == 'quit':
+                return
+    finally:
+        database.close()
+
+if name == '__main__': main()

+ 6 - 0
beginning-python-3ed-master/Chapter11/listing11-1.py

@@ -0,0 +1,6 @@
+# somescript.py
+import sys
+text = sys.stdin.read()
+words = text.split()
+wordcount = len(words)
+print('Wordcount:', wordcount)

+ 3 - 0
beginning-python-3ed-master/Chapter11/listing11-10.py

@@ -0,0 +1,3 @@
+with open(filename) as f:
+    for line in f.readlines():
+        process(line)

+ 3 - 0
beginning-python-3ed-master/Chapter11/listing11-11.py

@@ -0,0 +1,3 @@
+import fileinput
+for line in fileinput.input(filename):
+    process(line)

+ 3 - 0
beginning-python-3ed-master/Chapter11/listing11-12.py

@@ -0,0 +1,3 @@
+with open(filename) as f:
+    for line in f:
+        process(line)

+ 2 - 0
beginning-python-3ed-master/Chapter11/listing11-13.py

@@ -0,0 +1,2 @@
+for line in open(filename):
+    process(line)

+ 2 - 0
beginning-python-3ed-master/Chapter11/listing11-2.txt

@@ -0,0 +1,2 @@
+Your mother was a hamster and your
+father smelled of elderberries.

+ 3 - 0
beginning-python-3ed-master/Chapter11/listing11-3.txt

@@ -0,0 +1,3 @@
+Welcome to this file
+There is nothing here except
+This stupid haiku

+ 3 - 0
beginning-python-3ed-master/Chapter11/listing11-4.txt

@@ -0,0 +1,3 @@
+this
+is no
+haiku

+ 3 - 0
beginning-python-3ed-master/Chapter11/listing11-5.txt

@@ -0,0 +1,3 @@
+this
+isn't a
+haiku

+ 5 - 0
beginning-python-3ed-master/Chapter11/listing11-6.py

@@ -0,0 +1,5 @@
+with open(filename) as f:
+    char = f.read(1)
+    while char:
+        process(char)
+        char = f.read(1)

+ 5 - 0
beginning-python-3ed-master/Chapter11/listing11-7.py

@@ -0,0 +1,5 @@
+with open(filename) as f:
+    while True:
+        char = f.read(1)
+        if not char: break
+        process(char)

+ 5 - 0
beginning-python-3ed-master/Chapter11/listing11-8.py

@@ -0,0 +1,5 @@
+with open(filename) as f:
+    while True:
+        line = f.readline()
+        if not line: break
+        process(line)

+ 3 - 0
beginning-python-3ed-master/Chapter11/listing11-9.py

@@ -0,0 +1,3 @@
+with open(filename) as f:
+    for char in f.read():
+        process(char)

+ 25 - 0
beginning-python-3ed-master/Chapter12/listing12-1.py

@@ -0,0 +1,25 @@
+from tkinter import *
+from tkinter.scrolledtext import ScrolledText
+
+def load():
+    with open(filename.get()) as file:
+        contents.delete('1.0', END)
+        contents.insert(INSERT, file.read())
+
+def save():
+    with open(filename.get(), 'w') as file:
+        file.write(contents.get('1.0', END))
+
+top = Tk()
+top.title("Simple Editor")
+
+contents = ScrolledText()
+contents.pack(side=BOTTOM, expand=True, fill=BOTH)
+
+filename = Entry()
+filename.pack(side=LEFT, expand=True, fill=X)
+
+Button(text='Open', command=load).pack(side=LEFT)
+Button(text='Save', command=save).pack(side=LEFT)
+
+mainloop()

+ 37 - 0
beginning-python-3ed-master/Chapter13/listing13-1.py

@@ -0,0 +1,37 @@
+import sqlite3
+
+def convert(value):
+    if value.startswith('~'):
+        return value.strip('~')
+    if not value:
+        value = '0'
+    return float(value)
+
+conn = sqlite3.connect('food.db')
+curs = conn.cursor()
+
+curs.execute('''
+CREATE TABLE food (
+    id         TEXT PRIMARY KEY,
+    desc       TEXT,
+    water      FLOAT,
+    kcal       FLOAT,
+    protein    FLOAT,
+    fat        FLOAT,
+    ash        FLOAT,
+    carbs      FLOAT,
+    fiber      FLOAT,
+    sugar      FLOAT
+)
+''')
+
+query = 'INSERT INTO food VALUES (?,?,?,?,?,?,?,?,?,?)'
+field_count = 10
+
+for line in open('ABBREV.txt'):
+    fields = line.split('^')
+    vals = [convert(f) for f in fields[:field_count]]
+    curs.execute(query, vals)
+
+conn.commit()
+conn.close()

+ 13 - 0
beginning-python-3ed-master/Chapter13/listing13-2.py

@@ -0,0 +1,13 @@
+import sqlite3, sys
+
+conn = sqlite3.connect('food.db')
+curs = conn.cursor()
+
+query = 'SELECT * FROM food WHERE ' + sys.argv[1]
+print(query)
+curs.execute(query)
+names = [f[0] for f in curs.description]
+for row in curs.fetchall():
+    for pair in zip(names, row):
+        print('{}: {}'.format(*pair))
+    print()

+ 14 - 0
beginning-python-3ed-master/Chapter14/listing14-1.py

@@ -0,0 +1,14 @@
+import socket
+
+s = socket.socket()
+
+host = socket.gethostname()
+port = 1234
+s.bind((host, port))
+
+s.listen(5)
+while True:
+    c, addr = s.accept()
+    print('Got connection from', addr
+    c.send('Thank you for connecting')
+    c.close()

+ 9 - 0
beginning-python-3ed-master/Chapter14/listing14-2.py

@@ -0,0 +1,9 @@
+import socket
+
+s = socket.socket()
+
+host = socket.gethostname()
+port = 1234
+
+s.connect((host, port))
+print(s.recv(1024))

+ 11 - 0
beginning-python-3ed-master/Chapter14/listing14-3.py

@@ -0,0 +1,11 @@
+from socketserver import TCPServer, StreamRequestHandler
+
+class Handler(StreamRequestHandler):
+
+    def handle(self):
+        addr = self.request.getpeername()
+        print('Got connection from', addr)
+        self.wfile.write('Thank you for connecting')
+
+server = TCPServer(('', 1234), Handler)
+server.serve_forever()

+ 13 - 0
beginning-python-3ed-master/Chapter14/listing14-4.py

@@ -0,0 +1,13 @@
+from socketserver import TCPServer, ForkingMixIn, StreamRequestHandler
+
+class Server(ForkingMixIn, TCPServer): pass
+
+class Handler(StreamRequestHandler):
+
+    def handle(self):
+        addr = self.request.getpeername()
+        print('Got connection from', addr)
+        self.wfile.write('Thank you for connecting')
+
+server = Server(('', 1234), Handler)
+server.serve_forever()

+ 13 - 0
beginning-python-3ed-master/Chapter14/listing14-5.py

@@ -0,0 +1,13 @@
+from socketserver import TCPServer, ThreadingMixIn, StreamRequestHandler
+
+class Server(ThreadingMixIn, TCPServer): pass
+
+class Handler(StreamRequestHandler):
+
+    def handle(self):
+        addr = self.request.getpeername()
+        print('Got connection from', addr)
+        self.wfile.write('Thank you for connecting')
+
+server = Server(('', 1234), Handler)
+server.serve_forever()

+ 29 - 0
beginning-python-3ed-master/Chapter14/listing14-6.py

@@ -0,0 +1,29 @@
+import socket, select
+
+s = socket.socket()
+
+host = socket.gethostname()
+port = 1234
+s.bind((host, port))
+
+s.listen(5)
+inputs = [s]
+while True:
+    rs, ws, es = select.select(inputs, [], [])
+    for r in rs:
+        if r is s:
+            c, addr = s.accept()
+            print('Got connection from', addr)
+            inputs.append(c)
+        else:
+            try:
+                data = r.recv(1024)
+                disconnected = not data
+            except socket.error:
+                disconnected = True
+
+            if disconnected:
+                print r.getpeername(), 'disconnected'
+                inputs.remove(r)
+            else:
+                print data

+ 30 - 0
beginning-python-3ed-master/Chapter14/listing14-7.py

@@ -0,0 +1,30 @@
+import socket, select
+
+s = socket.socket()
+
+host = socket.gethostname()
+port = 1234
+s.bind((host, port))
+
+fdmap = {s.fileno(): s}
+
+
+s.listen(5)
+p = select.poll()
+p.register(s)
+while True:
+    events = p.poll()
+    for fd, event in events:
+        if fd in fdmap:
+            c, addr = s.accept()
+            print 'Got connection from', addr
+            p.register(c)
+            fdmap[c.fileno()] = c
+        elif event & select.POLLIN:
+            data = fdmap[fd].recv(1024)
+            if not data: # No data -- connection closed
+                print fdmap[fd].getpeername(), 'disconnected'
+                p.unregister(fd)
+                del fdmap[fd]
+            else:
+                print data

+ 19 - 0
beginning-python-3ed-master/Chapter14/listing14-8.py

@@ -0,0 +1,19 @@
+from twisted.internet import reactor
+from twisted.internet.protocol import Protocol, Factory
+
+class SimpleLogger(Protocol):
+
+    def connectionMade(self):
+        print 'Got connection from', self.transport.client
+
+    def connectionLost(self, reason):
+        print self.transport.client, 'disconnected'
+
+    def dataReceived(self, data):
+        print data
+
+factory = Factory()
+factory.protocol = SimpleLogger
+
+reactor.listenTCP(1234, factory)
+reactor.run()

+ 21 - 0
beginning-python-3ed-master/Chapter14/listing14-9.py

@@ -0,0 +1,21 @@
+from twisted.internet import reactor
+from twisted.internet.protocol import Factory
+from twisted.protocols.basic import LineReceiver
+
+
+class SimpleLogger(LineReceiver):
+
+    def connectionMade(self):
+        print 'Got connection from', self.transport.client
+
+    def connectionLost(self, reason):
+        print self.transport.client, 'disconnected'
+
+    def lineReceived(self, line):
+        print line
+
+factory = Factory()
+factory.protocol = SimpleLogger
+
+reactor.listenTCP(1234, factory)
+reactor.run()

+ 6 - 0
beginning-python-3ed-master/Chapter15/listing15-1.py

@@ -0,0 +1,6 @@
+from urllib.request import urlopen
+import re
+p = re.compile('<a href="(/jobs/\\d+)/">(.*?)</a>')
+text = urlopen('http://python.org/jobs').read().decode()
+for url, name in p.findall(text):
+    print('{} ({})'.format(name, url))

+ 35 - 0
beginning-python-3ed-master/Chapter15/listing15-2.py

@@ -0,0 +1,35 @@
+from urllib.request import urlopen
+from html.parser import HTMLParser
+
+def isjob(url):
+    try:
+        a, b, c, d = url.split('/')
+    except ValueError:
+        return False
+    return a == d == '' and b == 'jobs' and c.isdigit()
+
+class Scraper(HTMLParser):
+
+    in_link = False
+
+    def handle_starttag(self, tag, attrs):
+        attrs = dict(attrs)
+        url = attrs.get('href', '')
+        if tag == 'a' and isjob(url):
+            self.url = url
+            self.in_link = True
+            self.chunks = []
+
+    def handle_data(self, data):
+        if self.in_link:
+            self.chunks.append(data)
+
+    def handle_endtag(self, tag):
+        if tag == 'a' and self.in_link:
+            print('{} ({})'.format(''.join(self.chunks), self.url))
+            self.in_link = False
+
+text = urlopen('http://python.org/jobs').read().decode()
+parser = Scraper()
+parser.feed(text)
+parser.close()

+ 11 - 0
beginning-python-3ed-master/Chapter15/listing15-3.py

@@ -0,0 +1,11 @@
+from urllib.request import urlopen
+from bs4 import BeautifulSoup
+
+text = urlopen('http://python.org/jobs').read()
+soup = BeautifulSoup(text, 'html.parser')
+
+jobs = set()
+for job in soup.body.section('h2'):
+    jobs.add('{} ({})'.format(job.a.string, job.a['href']))
+
+print('\n'.join(sorted(jobs, key=str.lower)))

+ 6 - 0
beginning-python-3ed-master/Chapter15/listing15-4.py

@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+
+print('Content-type: text/plain')
+print() # Prints an empty line, to end the headers
+
+print('Hello, world!')

+ 9 - 0
beginning-python-3ed-master/Chapter15/listing15-5.py

@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+
+import cgitb; cgitb.enable()
+
+print('Content-type: text/html\n')
+
+print(1/0)
+
+print('Hello, world!')

+ 10 - 0
beginning-python-3ed-master/Chapter15/listing15-6.py

@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+import cgi
+form = cgi.FieldStorage()
+
+name = form.getvalue('name', 'world')
+
+print('Content-type: text/plain\n')
+
+print('Hello, {}!'.format(name))

+ 24 - 0
beginning-python-3ed-master/Chapter15/listing15-7.py

@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+import cgi
+form = cgi.FieldStorage()
+
+name = form.getvalue('name', 'world')
+
+print("""Content-type: text/html
+
+<html>
+  <head>
+    <title>Greeting Page</title>
+  </head>
+  <body>
+    <h1>Hello, %s!</h1>
+
+
+    <form action='simple3.cgi'>
+    Change name <input type='text' name='name' />
+    <input type='submit' />
+    </form>
+  </body>
+</html>
+""".format(name))

+ 9 - 0
beginning-python-3ed-master/Chapter16/listing16-1.py

@@ -0,0 +1,9 @@
+from area import rect_area
+height = 3
+width = 4
+correct_answer = 12
+answer = rect_area(height, width)
+if answer == correct_answer:
+    print('Test passed ')
+else:
+    print('Test failed ')

+ 19 - 0
beginning-python-3ed-master/Chapter16/listing16-2.py

@@ -0,0 +1,19 @@
+import unittest, my_math
+
+class ProductTestCase(unittest.TestCase):
+
+    def test_integers(self):
+        for x in range(-10, 10):
+            for y in range(-10, 10):
+                p = my_math.product(x, y)
+                self.assertEqual(p, x * y, 'Integer multiplication failed')
+
+    def test_floats(self):
+        for x in range(-10, 10):
+            for y in range(-10, 10):
+                x = x / 10
+                y = y / 10
+                p = my_math.product(x, y)
+                self.assertEqual(p, x * y, 'Float multiplication failed')
+
+if __name__ == '__main__': unittest.main()

+ 18 - 0
beginning-python-3ed-master/Chapter16/listing16-3.py

@@ -0,0 +1,18 @@
+import unittest, my_math
+from subprocess import Popen, PIPE
+
+class ProductTestCase(unittest.TestCase):
+
+    # Insert previous tests here
+
+    def test_with_PyChecker(self):
+        cmd = 'pychecker', '-Q', my_math.__file__.rstrip('c')
+        pychecker = Popen(cmd, stdout=PIPE, stderr=PIPE)
+        self.assertEqual(pychecker.stdout.read(), '')
+
+    def test_with_PyLint(self):
+        cmd = 'pylint', '-rn', 'my_math'
+        pylint = Popen(cmd, stdout=PIPE, stderr=PIPE)
+        self.assertEqual(pylint.stdout.read(), '')
+
+if __name__ == '__main__': unittest.main()

+ 7 - 0
beginning-python-3ed-master/Chapter17/listing17-1.java

@@ -0,0 +1,7 @@
+public class JythonTest {
+
+   public void greeting() {
+      System.out.println("Hello, world!");
+   }
+
+}

+ 10 - 0
beginning-python-3ed-master/Chapter17/listing17-2.cs

@@ -0,0 +1,10 @@
+using System;
+namespace FePyTest {
+   public class IronPythonTest {
+
+      public void greeting() {
+         Console.WriteLine("Hello, world!");
+      }
+
+   }
+}

+ 9 - 0
beginning-python-3ed-master/Chapter17/listing17-3.c

@@ -0,0 +1,9 @@
+#include <string.h>
+
+int is_palindrome(char *text) {
+    int i, n = strlen(text);
+    for (i = 0; i <= n/2; ++i) {
+        if (text[i] != text[n-i-1]) return 0;
+    }
+    return 1;
+}

+ 6 - 0
beginning-python-3ed-master/Chapter17/listing17-4.py

@@ -0,0 +1,6 @@
+def is_palindrome(text):
+    n = len(text)
+    for i in range(len(text)//2):
+        if text[i] != text[n-i-1]:
+            return False
+    return True

+ 7 - 0
beginning-python-3ed-master/Chapter17/listing17-5.i

@@ -0,0 +1,7 @@
+%module palindrome
+
+%{
+#include <string.h>
+%}
+
+extern int is_palindrome(char *text);

+ 48 - 0
beginning-python-3ed-master/Chapter17/listing17-6.c

@@ -0,0 +1,48 @@
+#include <Python.h>
+
+static PyObject *is_palindrome(PyObject *self, PyObject *args) {
+    int i, n;
+    const char *text;
+    int result;
+    /* "s" means a single string: */
+    if (!PyArg_ParseTuple(args, "s", &text)) {
+        return NULL;
+    }
+    /* The old code, more or less: */
+    n=strlen(text);
+    result = 1;
+    for (i = 0; i <= n/2; ++i) {
+        if (text[i] != text[n-i-1]) {
+            result = 0;
+            break;
+        }
+    }
+    /* "i" means a single integer: */
+    return Py_BuildValue("i", result);
+}
+
+/* A listing of our methods/functions: */
+static PyMethodDef PalindromeMethods[] = {
+
+    /* name, function, argument type, docstring */
+    {"is_palindrome", is_palindrome, METH_VARARGS, "Detect palindromes"},
+    /* An end-of-listing sentinel: */
+    {NULL, NULL, 0, NULL}
+
+};
+
+static struct PyModuleDef palindrome =
+{
+    PyModuleDef_HEAD_INIT,
+    "palindrome", /* module name */
+    "",           /* docstring */
+    -1,           /* signals state kept in global variables */
+    PalindromeMethods
+};
+
+
+/* An initialization function for the module: */
+PyMODINIT_FUNC PyInit_palindrome(void)
+{
+    return PyModule_Create(&palindrome);
+}

+ 7 - 0
beginning-python-3ed-master/Chapter18/listing18-1.py

@@ -0,0 +1,7 @@
+from setuptools import setup
+
+setup(name='Hello',
+      version='1.0',
+      description='A simple example',
+      author='Magnus Lie Hetland',
+      py_modules=['hello'])

+ 9 - 0
beginning-python-3ed-master/Chapter19/listing19-1.cfg

@@ -0,0 +1,9 @@
+[numbers]
+
+pi: 3.1415926535897931
+
+[messages]
+
+greeting: Welcome to the area calculation program!
+question: Please enter the radius:
+result_message: The area is

+ 21 - 0
beginning-python-3ed-master/Chapter19/listing19-2.py

@@ -0,0 +1,21 @@
+from configparser import ConfigParser
+
+CONFIGFILE = "area.ini"
+
+config = ConfigParser()
+# Read the configuration file:
+config.read(CONFIGFILE)
+
+# Print out an initial greeting;
+# 'messages' is the section to look in:
+print(config['messages'].get('greeting'))
+
+# Read in the radius, using a question from the config file:
+radius = float(input(config['messages'].get('question') + ' '))
+
+# Print a result message from the config file;
+# end with a space to stay on same line:
+print(config['messages'].get('result_message'), end=' ')
+
+# getfloat() converts the config value to a float:
+print(config['numbers'].getfloat('pi') * radius**2)

+ 13 - 0
beginning-python-3ed-master/Chapter19/listing19-3.py

@@ -0,0 +1,13 @@
+import logging
+
+logging.basicConfig(level=logging.INFO, filename='mylog.log')
+
+logging.info('Starting program')
+
+logging.info('Trying to divide 1 by 0')
+
+print(1 / 0)
+
+logging.info('The division succeeded')
+
+logging.info('Ending program')

+ 36 - 0
beginning-python-3ed-master/Chapter20/listing20-1.txt

@@ -0,0 +1,36 @@
+
+
+
+Welcome to World Wide Spam, Inc.
+
+
+These are the corporate web pages of *World Wide Spam*, Inc. We hope
+you find your stay enjoyable, and that you will sample many of our
+products.
+
+A short history of the company
+
+World Wide Spam was started in the summer of 2000. The business
+concept was to ride the dot-com wave and to make money both through
+bulk email and by selling canned meat online.
+
+After receiving several complaints from customers who weren't
+satisfied by their bulk email, World Wide Spam altered their profile,
+and focused 100% on canned goods. Today, they rank as the world's
+13,892nd online supplier of SPAM.
+
+Destinations
+
+From this page you may visit several of our interesting web pages:
+
+  - What is SPAM? (http://wwspam.fu/whatisspam)
+
+  - How do they make it? (http://wwspam.fu/howtomakeit)
+
+  - Why should I eat it? (http://wwspam.fu/whyeatit)
+
+How to get in touch with us
+
+You can get in touch with us in *many* ways: By phone (555-1234), by
+email (wwspam@wwspam.fu) or by visiting our customer feedback page
+(http://wwspam.fu/feedback).

+ 12 - 0
beginning-python-3ed-master/Chapter20/listing20-2.py

@@ -0,0 +1,12 @@
+def lines(file):
+    for line in file: yield line
+    yield '\n'
+
+def blocks(file):
+    block = []
+    for line in lines(file):
+        if line.strip():
+            block.append(line)
+        elif block:
+            yield ''.join(block).strip()
+            block = []

+ 19 - 0
beginning-python-3ed-master/Chapter20/listing20-3.py

@@ -0,0 +1,19 @@
+import sys, re
+from util import *
+
+print('<html><head><title>...</title><body>')
+
+title = True
+for block in blocks(sys.stdin):
+    block = re.sub(r'\*(.+?)\*', r'<em>\1</em>', block)
+    if title:
+        print('<h1>')
+        print(block)
+        print('</h1>')
+        title = False
+    else:
+        print('<p>')
+        print(block)
+        print('</p>')
+
+print('</body></html>')

+ 64 - 0
beginning-python-3ed-master/Chapter20/listing20-4.py

@@ -0,0 +1,64 @@
+class Handler:
+    """
+    An object that handles method calls from the Parser.
+
+    The Parser will call the start() and end() methods at the
+    beginning of each block, with the proper block name as a
+    parameter. The sub() method will be used in regular expression
+    substitution. When called with a name such as 'emphasis', it will
+    return a proper substitution function.
+    """
+    def callback(self, prefix, name, *args):
+        method = getattr(self, prefix + name, None)
+        if callable(method): return method(*args)
+    def start(self, name):
+        self.callback('start_', name)
+    def end(self, name):
+        self.callback('end_', name)
+    def sub(self, name):
+        def substitution(match):
+            result = self.callback('sub_', name, match)
+            if result is None: match.group(0)
+            return result
+        return substitution
+
+class HTMLRenderer(Handler):
+    """
+    A specific handler used for rendering HTML.
+
+    The methods in HTMLRenderer are accessed from the superclass
+    Handler's start(), end(), and sub() methods. They implement basic
+    markup as used in HTML documents.
+    """
+    def start_document(self):
+        print('<html><head><title>...</title></head><body>')
+    def end_document(self):
+        print('</body></html>')
+    def start_paragraph(self):
+        print('<p>')
+    def end_paragraph(self):
+        print('</p>')
+    def start_heading(self):
+        print('<h2>')
+    def end_heading(self):
+        print('</h2>')
+    def start_list(self):
+        print('<ul>')
+    def end_list(self):
+        print('</ul>')
+    def start_listitem(self):
+        print('<li>')
+    def end_listitem(self):
+        print('</li>')
+    def start_title(self):
+        print('<h1>')
+    def end_title(self):
+        print('</h1>')
+    def sub_emphasis(self, match):
+        return '<em>{}</em>'.format(match.group(1))
+    def sub_url(self, match):
+        return '<a href="{}">{}</a>'.format(match.group(1), match.group(1))
+    def sub_mail(self, match):
+        return '<a href="mailto:{}">{}</a>'.format(match.group(1), match.group(1))
+    def feed(self, data):
+        print(data)

+ 72 - 0
beginning-python-3ed-master/Chapter20/listing20-5.py

@@ -0,0 +1,72 @@
+class Rule:
+    """
+    Base class for all rules.
+    """
+
+    def action(self, block, handler):
+        handler.start(self.type)
+        handler.feed(block)
+        handler.end(self.type)
+        return True
+
+class HeadingRule(Rule):
+    """
+    A heading is a single line that is at most 70 characters and
+    that doesn't end with a colon.
+    """
+    type = 'heading'
+    def condition(self, block):
+        return not '\n' in block and len(block) <= 70 and not block[-1] == ':'
+
+class TitleRule(HeadingRule):
+    """
+    The title is the first block in the document, provided that
+    it is a heading.
+    """
+    type = 'title'
+    first = True
+
+    def condition(self, block):
+        if not self.first: return False
+        self.first = False
+        return HeadingRule.condition(self, block)
+
+class ListItemRule(Rule):
+    """
+    A list item is a paragraph that begins with a hyphen. As part of the
+    formatting, the hyphen is removed.
+    """
+    type = 'listitem'
+    def condition(self, block):
+        return block[0] == '-'
+    def action(self, block, handler):
+        handler.start(self.type)
+        handler.feed(block[1:].strip())
+        handler.end(self.type)
+        return True
+
+class ListRule(ListItemRule):
+    """
+    A list begins between a block that is not a list item and a
+    subsequent list item. It ends after the last consecutive list item.
+    """
+    type = 'list'
+    inside = False
+    def condition(self, block):
+        return True
+    def action(self, block, handler):
+        if not self.inside and ListItemRule.condition(self, block):
+            handler.start(self.type)
+            self.inside = True
+        elif self.inside and not ListItemRule.condition(self, block):
+            handler.end(self.type)
+            self.inside = False
+        return False
+
+class ParagraphRule(Rule):
+    """
+    A paragraph is simply a block that isn't covered by any of the other rules.
+    """
+    type = 'paragraph'
+    def condition(self, block):
+        return True

+ 52 - 0
beginning-python-3ed-master/Chapter20/listing20-6.py

@@ -0,0 +1,52 @@
+import sys, re
+from handlers import *
+from util import *
+from rules import *
+
+class Parser:
+    """
+    A Parser reads a text file, applying rules and controlling a handler.
+    """
+    def __init__(self, handler):
+        self.handler = handler
+        self.rules = []
+        self.filters = []
+    def addRule(self, rule):
+        self.rules.append(rule)
+    def addFilter(self, pattern, name):
+        def filter(block, handler):
+            return re.sub(pattern, handler.sub(name), block)
+        self.filters.append(filter)
+
+    def parse(self, file):
+        self.handler.start('document')
+        for block in blocks(file):
+            for filter in self.filters:
+                block = filter(block, self.handler)
+                for rule in self.rules:
+                    if rule.condition(block):
+                        last = rule.action(block,
+                               self.handler)
+                        if last: break
+        self.handler.end('document')
+
+class BasicTextParser(Parser):
+    """
+    A specific Parser that adds rules and filters in its constructor.
+    """
+    def __init__(self, handler):
+        Parser.__init__(self, handler)
+        self.addRule(ListRule())
+        self.addRule(ListItemRule())
+        self.addRule(TitleRule())
+        self.addRule(HeadingRule())
+        self.addRule(ParagraphRule())
+
+        self.addFilter(r'\*(.+?)\*', 'emphasis')
+        self.addFilter(r'(http://[\.a-zA-Z/]+)', 'url')
+        self.addFilter(r'([\.a-zA-Z]+@[\.a-zA-Z]+[a-zA-Z]+)', 'mail')
+
+handler = HTMLRenderer()
+parser = BasicTextParser(handler)
+
+parser.parse(sys.stdin)

+ 9 - 0
beginning-python-3ed-master/Chapter21/listing21-1.py

@@ -0,0 +1,9 @@
+from reportlab.graphics.shapes import Drawing, String
+from reportlab.graphics import renderPDF
+
+d = Drawing(100, 100)
+s = String(50, 50, 'Hello, world!', textAnchor='middle')
+
+d.add(s)
+
+renderPDF.drawToFile(d, 'hello.pdf', 'A simple PDF file')

+ 31 - 0
beginning-python-3ed-master/Chapter21/listing21-2.py

@@ -0,0 +1,31 @@
+from reportlab.lib import colors
+from reportlab.graphics.shapes import *
+from reportlab.graphics import renderPDF
+
+data = [
+#    Year  Month   Predicted    High   Low
+    (2007, 8,      113.2,       114.2, 112.2),
+    (2007, 9,      112.8,       115.8, 109.8),
+    (2007, 10,     111.0,       116.0, 106.0),
+    (2007, 11,     109.8,       116.8, 102.8),
+    (2007, 12,     107.3,       115.3,  99.3),
+    (2008, 1,      105.2,       114.2,  96.2),
+    (2008, 2,      104.1,       114.1,  94.1),
+    (2008, 3,      99.9,        110.9,  88.9),
+    (2008, 4,      94.8,        106.8,  82.8),
+    (2008, 5,      91.2,        104.2,  78.2),
+    ]
+
+drawing = Drawing(200, 150)
+
+pred = [row[2]-40 for row in data]
+high = [row[3]-40 for row in data]
+low = [row[4]-40 for row in data]
+times = [200*((row[0] + row[1]/12.0) - 2007)-110 for row in data]
+
+drawing.add(PolyLine(list(zip(times, pred)), strokeColor=colors.blue))
+drawing.add(PolyLine(list(zip(times, high)), strokeColor=colors.red))
+drawing.add(PolyLine(list(zip(times, low)), strokeColor=colors.green))
+
+drawing.add(String(65, 115, 'Sunspots', fontSize=18, fillColor=colors.red))
+renderPDF.drawToFile(drawing, 'report1.pdf', 'Sunspots')

+ 41 - 0
beginning-python-3ed-master/Chapter21/listing21-3.py

@@ -0,0 +1,41 @@
+from urllib.request import urlopen
+from reportlab.graphics.shapes import *
+from reportlab.graphics.charts.lineplots import LinePlot
+from reportlab.graphics.charts.textlabels import Label
+from reportlab.graphics import renderPDF
+
+URL = 'ftp://ftp.swpc.noaa.gov/pub/weekly/Predict.txt'
+COMMENT_CHARS = '#:'
+
+
+drawing = Drawing(400, 200)
+data = []
+for line in urlopen(URL).readlines():
+    line = line.decode()
+    if not line.isspace() and line[0] not in COMMENT_CHARS:
+        data.append([float(n) for n in line.split()])
+
+pred = [row[2] for row in data]
+high = [row[3] for row in data]
+low = [row[4] for row in data]
+times = [row[0] + row[1]/12.0 for row in data]
+
+lp = LinePlot()
+lp.x = 50
+lp.y = 50
+lp.height = 125
+lp.width = 300
+lp.data = [list(zip(times, pred)),
+           list(zip(times, high)),
+           list(zip(times, low))]
+lp.lines[0].strokeColor = colors.blue
+lp.lines[1].strokeColor = colors.red
+lp.lines[2].strokeColor = colors.green
+
+drawing.add(lp)
+
+drawing.add(String(250, 150, 'Sunspots',
+            fontSize=14, fillColor=colors.red))
+
+
+renderPDF.drawToFile(drawing, 'report2.pdf', 'Sunspots')

+ 31 - 0
beginning-python-3ed-master/Chapter22/listing22-1.xml

@@ -0,0 +1,31 @@
+<website>
+  <page name="index" title="Home Page">
+    <h1>Welcome to My Home Page</h1>
+
+    <p>Hi, there. My name is Mr. Gumby, and this is my home page. Here
+    are some of my interests:</p>
+
+    <ul>
+      <li><a href="interests/shouting.html">Shouting</a></li>
+      <li><a href="interests/sleeping.html">Sleeping</a></li>
+      <li><a href="interests/eating.html">Eating</a></li>
+    </ul>
+  </page>
+  <directory name="interests">
+    <page name="shouting" title="Shouting">
+      <h1>Mr. Gumby's Shouting Page</h1>
+
+      <p>...</p>
+    </page>
+    <page name="sleeping" title="Sleeping">
+      <h1>Mr. Gumby's Sleeping Page</h1>
+
+      <p>...</p>
+    </page>
+    <page name="eating" title="Eating">
+      <h1>Mr. Gumby's Eating Page</h1>
+
+      <p>...</p>
+    </page>
+  </directory>
+</website>

+ 32 - 0
beginning-python-3ed-master/Chapter22/listing22-2.py

@@ -0,0 +1,32 @@
+from xml.sax.handler import ContentHandler
+from xml.sax import parse
+
+class PageMaker(ContentHandler):
+
+    passthrough = False
+
+    def startElement(self, name, attrs):
+        if name == 'page':
+            self.passthrough = True
+            self.out = open(attrs['name'] + '.html', 'w')
+            self.out.write('<html><head>\n')
+            self.out.write('<title>{}</title>\n'.format(attrs['title']))
+            self.out.write('</head><body>\n')
+        elif self.passthrough:
+            self.out.write('<' + name)
+            for key, val in attrs.items():
+                self.out.write(' {}="{}"'.format(key, val))
+            self.out.write('>')
+
+    def endElement(self, name):
+        if name == 'page':
+            self.passthrough = False
+            self.out.write('\n</body></html>\n')
+            self.out.close()
+        elif self.passthrough:
+            self.out.write('</{}>'.format(name))
+
+    def characters(self, chars):
+        if self.passthrough: self.out.write(chars)
+
+parse('website.xml', PageMaker())

+ 76 - 0
beginning-python-3ed-master/Chapter22/listing22-3.py

@@ -0,0 +1,76 @@
+from xml.sax.handler import ContentHandler
+from xml.sax import parse
+import os
+
+class Dispatcher:
+
+    def dispatch(self, prefix, name, attrs=None):
+        mname = prefix + name.capitalize()
+        dname = 'default' + prefix.capitalize()
+        method = getattr(self, mname, None)
+        if callable(method): args = ()
+        else:
+            method = getattr(self, dname, None)
+            args = name,
+        if prefix == 'start': args += attrs,
+        if callable(method): method(*args)
+
+    def startElement(self, name, attrs):
+        self.dispatch('start', name, attrs)
+
+    def endElement(self, name):
+        self.dispatch('end', name)
+
+class WebsiteConstructor(Dispatcher, ContentHandler):
+
+    passthrough = False
+
+    def __init__(self, directory):
+        self.directory = [directory]
+        self.ensureDirectory()
+
+    def ensureDirectory(self):
+        path = os.path.join(*self.directory)
+        os.makedirs(path, exist_ok=True)
+
+    def characters(self, chars):
+        if self.passthrough: self.out.write(chars)
+
+    def defaultStart(self, name, attrs):
+        if self.passthrough:
+            self.out.write('<' + name)
+            for key, val in attrs.items():
+                self.out.write(' {}="{}"'.format(key, val))
+            self.out.write('>')
+
+    def defaultEnd(self, name):
+        if self.passthrough:
+            self.out.write('</{}>'.format(name))
+
+    def startDirectory(self, attrs):
+        self.directory.append(attrs['name'])
+        self.ensureDirectory()
+
+    def endDirectory(self):
+        self.directory.pop()
+
+    def startPage(self, attrs):
+        filename = os.path.join(*self.directory + [attrs['name'] + '.html'])
+        self.out = open(filename, 'w')
+        self.writeHeader(attrs['title'])
+        self.passthrough = True
+
+    def endPage(self):
+        self.passthrough = False
+        self.writeFooter()
+        self.out.close()
+
+    def writeHeader(self, title):
+        self.out.write('<html>\n  <head>\n    <title>')
+        self.out.write(title)
+        self.out.write('</title>\n  </head>\n  <body>\n')
+
+    def writeFooter(self):
+        self.out.write('\n  </body>\n</html>\n')
+
+parse('website.xml', WebsiteConstructor('public_html'))

+ 23 - 0
beginning-python-3ed-master/Chapter23/listing23-1.py

@@ -0,0 +1,23 @@
+from nntplib import NNTP
+
+servername = 'news.foo.bar'
+group = 'comp.lang.python.announce'
+server = NNTP(servername)
+howmany = 10
+
+resp, count, first, last, name = server.group(group)
+
+start = last - howmany + 1
+
+resp, overviews = server.over((start, last))
+
+for id, over in overviews:
+    subject = over['subject']
+    resp, info = server.body(id)
+    print(subject)
+    print('-' * len(subject))
+    for line in info.lines:
+        print(line.decode('latin1'))
+    print()
+
+server.quit()

+ 160 - 0
beginning-python-3ed-master/Chapter23/listing23-2.py

@@ -0,0 +1,160 @@
+from nntplib import NNTP, decode_header
+from urllib.request import urlopen
+import textwrap
+import re
+
+class NewsAgent:
+    """
+    An object that can distribute news items from news sources to news
+    destinations.
+    """
+
+    def __init__(self):
+        self.sources = []
+        self.destinations = []
+
+    def add_source(self, source):
+        self.sources.append(source)
+
+    def addDestination(self, dest):
+        self.destinations.append(dest)
+
+    def distribute(self):
+        """
+        Retrieve all news items from all sources, and Distribute them to all
+        destinations.
+        """
+        items = []
+        for source in self.sources:
+            items.extend(source.get_items())
+        for dest in self.destinations:
+            dest.receive_items(items)
+
+class NewsItem:
+    """
+    A simple news item consisting of a title and body text.
+    """
+    def __init__(self, title, body):
+        self.title = title
+        self.body = body
+
+class NNTPSource:
+    """
+    A news source that retrieves news items from an NNTP group.
+    """
+    def __init__(self, servername, group, howmany):
+        self.servername = servername
+        self.group = group
+        self.howmany = howmany
+
+    def get_items(self):
+        server = NNTP(self.servername)
+        resp, count, first, last, name = server.group(self.group)
+        start = last - self.howmany + 1
+        resp, overviews = server.over((start, last))
+        for id, over in overviews:
+            title = decode_header(over['subject'])
+            resp, info = server.body(id)
+            body = '\n'.join(line.decode('latin')
+                             for line in info.lines) + '\n\n'
+            yield NewsItem(title, body)
+        server.quit()
+
+class SimpleWebSource:
+    """
+    A news source that extracts news items from a web page using regular
+    expressions.
+    """
+    def __init__(self, url, title_pattern, body_pattern, encoding='utf8'):
+        self.url = url
+        self.title_pattern = re.compile(title_pattern)
+        self.body_pattern = re.compile(body_pattern)
+        self.encoding = encoding
+
+    def get_items(self):
+        text = urlopen(self.url).read().decode(self.encoding)
+        titles = self.title_pattern.findall(text)
+        bodies = self.body_pattern.findall(text)
+        for title, body in zip(titles, bodies):
+            yield NewsItem(title, textwrap.fill(body) + '\n')
+
+class PlainDestination:
+    """
+    A news destination that formats all its news items as plain text.
+    """
+    def receive_items(self, items):
+        for item in items:
+            print(item.title)
+            print('-' * len(item.title))
+            print(item.body)
+
+class HTMLDestination:
+    """
+    A news destination that formats all its news items as HTML.
+    """
+    def __init__(self, filename):
+        self.filename = filename
+
+    def receive_items(self, items):
+
+        out = open(self.filename, 'w')
+        print("""
+        <html>
+          <head>
+            <title>Today's News</title>
+          </head>
+          <body>
+          <h1>Today's News</h1>
+        """, file=out)
+
+        print('<ul>', file=out)
+        id = 0
+        for item in items:
+            id += 1
+            print('  <li><a href="#{}">{}</a></li>'
+                    .format(id, item.title), file=out)
+        print('</ul>', file=out)
+
+        id = 0
+        for item in items:
+            id += 1
+            print('<h2><a name="{}">{}</a></h2>'
+                    .format(id, item.title), file=out)
+            print('<pre>{}</pre>'.format(item.body), file=out)
+
+        print("""
+          </body>
+        </html>
+        """, file=out)
+
+def runDefaultSetup():
+    """
+    A default setup of sources and destination. Modify to taste.
+    """
+    agent = NewsAgent()
+
+    # A SimpleWebSource that retrieves news from Reuters:
+    reuters_url = 'http://www.reuters.com/news/world'
+    reuters_title = r'<h2><a href="[^"]*"\s*>(.*?)</a>'
+    reuters_body = r'</h2><p>(.*?)</p>'
+    reuters = SimpleWebSource(reuters_url, reuters_title, reuters_body)
+
+    agent.add_source(reuters)
+
+    # An NNTPSource that retrieves news from comp.lang.python.announce:
+    clpa_server = 'news.foo.bar' # Insert real server name
+    clpa_server = 'news.ntnu.no'
+    clpa_group = 'comp.lang.python.announce'
+    clpa_howmany = 10
+    clpa = NNTPSource(clpa_server, clpa_group, clpa_howmany)
+
+    agent.add_source(clpa)
+
+    # Add plain-text destination and an HTML destination:
+    agent.addDestination(PlainDestination())
+    agent.addDestination(HTMLDestination('news.html'))
+
+    # Distribute the news items:
+    agent.distribute()
+
+if __name__ == '__main__': runDefaultSetup()

+ 7 - 0
beginning-python-3ed-master/Chapter24/listing24-1.py

@@ -0,0 +1,7 @@
+from asyncore import dispatcher
+import asyncore
+
+class ChatServer(dispatcher): pass
+
+s = ChatServer()
+asyncore.loop()

+ 14 - 0
beginning-python-3ed-master/Chapter24/listing24-2.py

@@ -0,0 +1,14 @@
+from asyncore import dispatcher
+import socket, asyncore
+
+class ChatServer(dispatcher):
+
+    def handle_accept(self):
+        conn, addr = self.accept()
+        print('Connection attempt from', addr[0])
+
+s = ChatServer()
+s.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+s.bind(('', 5005))
+s.listen(5)
+asyncore.loop()

+ 22 - 0
beginning-python-3ed-master/Chapter24/listing24-3.py

@@ -0,0 +1,22 @@
+from asyncore import dispatcher
+import socket, asyncore
+
+PORT = 5005
+
+class ChatServer(dispatcher):
+
+    def __init__(self, port):
+        dispatcher.__init__(self)
+        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.set_reuse_addr()
+        self.bind(('', port))
+        self.listen(5)
+
+    def handle_accept(self):
+        conn, addr = self.accept()
+        print('Connection attempt from', addr[0])
+
+if __name__ == '__main__':
+    s = ChatServer(PORT)
+    try: asyncore.loop()
+    except KeyboardInterrupt: pass

+ 39 - 0
beginning-python-3ed-master/Chapter24/listing24-4.py

@@ -0,0 +1,39 @@
+from asyncore import dispatcher
+from asynchat import async_chat
+import socket, asyncore
+
+PORT = 5005
+
+class ChatSession(async_chat):
+
+    def __init__(self, sock):
+        async_chat. init (self, sock)
+        self.set_terminator("\r\n")
+        self.data = []
+
+    def collect_incoming_data(self, data):
+        self.data.append(data)
+
+    def found_terminator(self):
+        line = ''.join(self.data)
+        self.data = []
+        # Do something with the line...
+        print(line)
+
+class ChatServer(dispatcher):
+
+    def __init__(self, port): dispatcher. init (self)
+        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.set_reuse_addr()
+        self.bind(('', port))
+        self.listen(5)
+        self.sessions = []
+
+    def handle_accept(self):
+        conn, addr = self.accept()
+        self.sessions.append(ChatSession(conn))
+
+if __name__ == '__main__':
+    s = ChatServer(PORT)
+    try: asyncore.loop()
+    except KeyboardInterrupt: print()

+ 65 - 0
beginning-python-3ed-master/Chapter24/listing24-5.py

@@ -0,0 +1,65 @@
+from asyncore import dispatcher
+from asynchat import async_chat
+import socket, asyncore
+
+PORT = 5005
+NAME = 'TestChat'
+
+class ChatSession(async_chat):
+    """
+    A class that takes care of a connection between the server and a single user.
+    """
+    def __init__(self, server, sock):
+        # Standard setup tasks:
+        async_chat. init (self, sock)
+        self.server = server
+        self.set_terminator("\r\n")
+        self.data = []
+        # Greet the user:
+        self.push('Welcome to %s\r\n' % self.server.name)
+
+    def collect_incoming_data(self, data):
+        self.data.append(data)
+
+    def found_terminator(self):
+        """
+        If a terminator is found, that means that a full
+        line has been read. Broadcast it to everyone.
+        """
+        line = ''.join(self.data)
+        self.data = []
+        self.server.broadcast(line)
+
+    def handle_close(self):
+        async_chat.handle_close(self)
+        self.server.disconnect(self)
+
+class ChatServer(dispatcher):
+    """
+    A class that receives connections and spawns individual
+    sessions. It also handles broadcasts to these sessions.
+    """
+    def __init__(self, port, name):
+        # Standard setup tasks dispatcher. init (self)
+        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.set_reuse_addr()
+        self.bind(('', port))
+        self.listen(5)
+        self.name = name
+        self.sessions = []
+
+    def disconnect(self, session):
+        self.sessions.remove(session)
+
+    def broadcast(self, line):
+        for session in self.sessions:
+            session.push(line + '\r\n')
+
+    def handle_accept(self):
+        conn, addr = self.accept()
+        self.sessions.append(ChatSession(self, conn))
+
+if __name__ == '__main__':
+    s = ChatServer(PORT, NAME)
+    try: asyncore.loop()
+    except KeyboardInterrupt: print()

+ 192 - 0
beginning-python-3ed-master/Chapter24/listing24-6.py

@@ -0,0 +1,192 @@
+from asyncore import dispatcher
+from asynchat import async_chat
+import socket, asyncore
+
+PORT = 5005
+NAME = 'TestChat'
+
+class EndSession(Exception): pass
+
+class CommandHandler:
+    """
+    Simple command handler similar to cmd.Cmd from the standard library.
+    """
+
+    def unknown(self, session, cmd):
+        'Respond to an unknown command'
+        session.push('Unknown command: {}s\r\n'.format(cmd))
+
+    def handle(self, session, line):
+        'Handle a received line from a given session'
+        if not line.strip(): return
+        # Split off the command:
+        parts = line.split(' ', 1)
+        cmd = parts[0]
+        try: line = parts[1].strip()
+        except IndexError: line = ''
+        # Try to find a handler:
+        meth = getattr(self, 'do_' + cmd, None)
+        try:
+            # Assume it's callable:
+            meth(session, line)
+        except TypeError:
+            # If it isn't, respond to the unknown command:
+            self.unknown(session, cmd)
+
+class Room(CommandHandler):
+    """
+    A generic environment that may contain one or more users (sessions).
+    It takes care of basic command handling and broadcasting.
+    """
+
+    def __init__(self, server):
+        self.server = server
+        self.sessions = []
+
+    def add(self, session):
+        'A session (user) has entered the room'
+        self.sessions.append(session)
+
+    def remove(self, session):
+        'A session (user) has left the room'
+        self.sessions.remove(session)
+
+    def broadcast(self, line):
+        'Send a line to all sessions in the room'
+        for session in self.sessions:
+            session.push(line)
+
+    def do_logout(self, session, line):
+        'Respond to the logout command'
+        raise EndSession
+
+class LoginRoom(Room):
+    """
+    A room meant for a single person who has just connected.
+    """
+
+    def add(self, session):
+        Room.add(self, session)
+        # When a user enters, greet him/her:
+        self.broadcast('Welcome to {}\r\n'.format(self.server.name))
+
+    def unknown(self, session, cmd):
+        # All unknown commands (anything except login or logout)
+        # results in a prodding:
+        session.push('Please log in\nUse "login <nick>"\r\n')
+
+    def do_login(self, session, line):
+        name = line.strip()
+        # Make sure the user has entered a name:
+        if not name:
+            session.push('Please enter a name\r\n')
+        # Make sure that the name isn't in use:
+        elif name in self.server.users:
+            session.push('The name "{}" is taken.\r\n'.format(name))
+            session.push('Please try again.\r\n')
+        else:
+            # The name is OK, so it is stored in the session, and
+            # the user is moved into the main room. session.name = name
+            session.enter(self.server.main_room)
+
+class ChatRoom(Room):
+    """
+    A room meant for multiple users who can chat with the others in the room.
+    """
+
+    def add(self, session):
+        # Notify everyone that a new user has entered:
+        self.broadcast(session.name + ' has entered the room.\r\n')
+        self.server.users[session.name] = session
+        super().add(session)
+
+    def remove(self, session):
+        Room.remove(self, session)
+        # Notify everyone that a user has left:
+        self.broadcast(session.name + ' has left the room.\r\n')
+
+    def do_say(self, session, line):
+        self.broadcast(session.name + ': ' + line + '\r\n')
+
+    def do_look(self, session, line):
+        'Handles the look command, used to see who is in a room'
+        session.push('The following are in this room:\r\n')
+        for other in self.sessions:
+            session.push(other.name + '\r\n')
+
+    def do_who(self, session, line):
+        'Handles the who command, used to see who is logged in'
+        session.push('The following are logged in:\r\n')
+        for name in self.server.users:
+            session.push(name + '\r\n')
+
+class LogoutRoom(Room):
+    """
+    A simple room for a single user. Its sole purpose is to remove the
+    user's name from the server.
+    """
+
+    def add(self, session):
+        # When a session (user) enters the LogoutRoom it is deleted
+        try: del self.server.users[session.name]
+        except KeyError: pass
+
+class ChatSession(async_chat):
+    """
+    A single session, which takes care of the communication with a single user.
+    """
+
+    def __init__(self, server, sock):
+        super().__init__(sock)
+        self.server = server
+        self.set_terminator("\r\n")
+        self.data = []
+        self.name = None
+        # All sessions begin in a separate LoginRoom:
+        self.enter(LoginRoom(server))
+
+    def enter(self, room):
+        # Remove self from current room and add self to
+        # next room...
+        try: cur = self.room
+        except AttributeError: pass
+        else: cur.remove(self)
+        self.room = room
+        room.add(self)
+
+    def collect_incoming_data(self, data):
+        self.data.append(data)
+
+    def found_terminator(self):
+        line = ''.join(self.data)
+        self.data = []
+        try: self.room.handle(self, line)
+        except EndSession: self.handle_close()
+
+    def handle_close(self):
+        async_chat.handle_close(self)
+        self.enter(LogoutRoom(self.server))
+
+class ChatServer(dispatcher):
+    """
+    A chat server with a single room.
+    """
+
+    def __init__(self, port, name):
+        super().__init__()
+        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.set_reuse_addr()
+        self.bind(('', port))
+        self.listen(5)
+        self.name = name
+        self.users = {}
+        self.main_room = ChatRoom(self)
+
+    def handle_accept(self):
+        conn, addr = self.accept()
+        ChatSession(self, conn)
+
+if __name__ == '__main__':
+    s = ChatServer(PORT, NAME)
+    try: asyncore.loop()
+    except KeyboardInterrupt: print()

+ 26 - 0
beginning-python-3ed-master/Chapter25/listing25-1.py

@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+import cgi
+form = cgi.FieldStorage()
+
+text = form.getvalue('text', open('simple_edit.dat').read())
+f = open('simple_edit.dat', 'w')
+f.write(text)
+f.close()
+
+
+print("""Content-type: text/html
+
+
+<html>
+  <head>
+     <title>A Simple Editor</title>
+  </head>
+  <body>
+     <form action='simple_edit.cgi' method='POST'>
+     <textarea rows='10' cols='20' name='text'>{}</textarea><br />
+     <input type='submit' />
+     </form>
+  </body>
+</html>
+""".format(text))

+ 34 - 0
beginning-python-3ed-master/Chapter25/listing25-2.py

@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+print('Content-type: text/html\n')
+
+from os.path import join, abspath
+import cgi, sys
+
+BASE_DIR = abspath('data')
+
+form = cgi.FieldStorage()
+filename = form.getvalue('filename')
+if not filename:
+    print('Please enter a file name')
+    sys.exit()
+text = open(join(BASE_DIR, filename)).read()
+
+print("""
+<html>
+    <head>
+        <title>Editing...</title>
+    </head>
+    <body>
+        <form action='save.cgi' method='POST'>
+            <b>File:</b> {}<br />
+            <input type='hidden' value='{}' name='filename' />
+            <b>Password:</b><br />
+            <input name='password' type='password' /><br />
+            <b>Text:</b><br />
+            <textarea name='text' cols='40' rows='20'>{}</textarea><br />
+            <input type='submit' value='Save' />
+        </form>
+    </body>
+</html>
+""".format(filename, filename, text))

+ 29 - 0
beginning-python-3ed-master/Chapter25/listing25-3.py

@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+print('Content-type: text/html\n')
+
+from os.path import join, abspath
+from hashlib import sha1
+import cgi, sys
+
+BASE_DIR = abspath('data')
+
+form = cgi.FieldStorage()
+
+text = form.getvalue('text')
+filename = form.getvalue('filename')
+password = form.getvalue('password')
+
+if not (filename and text and password):
+     print('Invalid parameters.')
+     sys.exit()
+
+if sha1(password.encode()).hexdigest() != '8843d7f92416211de9ebb963ff4ce28125932878':
+     print('Invalid password')
+     sys.exit()
+
+f = open(join(BASE_DIR,filename), 'w')
+f.write(text)
+f.close()
+
+print('The file has been saved.')

+ 7 - 0
beginning-python-3ed-master/Chapter26/listing26-1.sql

@@ -0,0 +1,7 @@
+CREATE TABLE messages (
+    id          SERIAL PRIMARY KEY,
+    subject     TEXT NOT NULL,
+    sender      TEXT NOT NULL,
+    reply_to    INTEGER REFERENCES messages,
+    text        TEXT NOT NULL
+);

+ 8 - 0
beginning-python-3ed-master/Chapter26/listing26-2.sql

@@ -0,0 +1,8 @@
+CREATE TABLE messages (
+    id          INT NOT NULL AUTO_INCREMENT,
+    subject     VARCHAR(100) NOT NULL,
+    sender      VARCHAR(15) NOT NULL,
+    reply_to    INT,
+    text        MEDIUMTEXT NOT NULL,
+    PRIMARY KEY(id)
+);

+ 7 - 0
beginning-python-3ed-master/Chapter26/listing26-3.sql

@@ -0,0 +1,7 @@
+create table messages (
+    id          integer primary key autoincrement,
+    subject     text not null,
+    sender      text not null,
+    reply_to    int,
+    text        text not null
+);

+ 51 - 0
beginning-python-3ed-master/Chapter26/listing26-4.py

@@ -0,0 +1,51 @@
+#!/usr/bin/python
+
+print('Content-type: text/html\n')
+
+import cgitb; cgitb.enable()
+
+import psycopg2
+conn = psycopg2.connect('user=foo password=bar dbname=baz')
+curs = conn.cursor()
+
+print("""
+<html>
+  <head>
+    <title>The FooBar Bulletin Board</title>
+  </head>
+  <body>
+    <h1>The FooBar Bulletin Board</h1>
+    """)
+
+curs.execute('SELECT * FROM messages')
+rows = curs.dictfetchall()
+
+toplevel = []
+children = {}
+
+for row in rows:
+    parent_id = row['reply_to']
+    if parent_id is None:
+        toplevel.append(row)
+    else:
+        children.setdefault(parent_id, []).append(row)
+    def format(row):
+        print(row['subject'])
+        try: kids = children[row['id']]
+        except KeyError: pass
+        else:
+            print('<blockquote>')
+            for kid in kids:
+                format(kid)
+            print('</blockquote>')
+
+    print('<p>')
+
+    for row in toplevel:
+        format(row)
+
+    print("""
+        </p>
+    </body>
+    </html>
+    """)

+ 53 - 0
beginning-python-3ed-master/Chapter26/listing26-5.py

@@ -0,0 +1,53 @@
+#!/usr/bin/python
+
+print('Content-type: text/html\n')
+
+import cgitb; cgitb.enable()
+
+import psycopg2
+conn = psycopg2.connect('user=foo password=bar dbname=baz')
+curs = conn.cursor()
+
+print("""
+<html>
+  <head>
+     <title>The FooBar Bulletin Board</title>
+  </head>
+     <body>
+       <h1>The FooBar Bulletin Board</h1>
+       """)
+
+curs.execute('SELECT * FROM messages')
+rows = curs.dictfetchall()
+
+toplevel = []
+children = {}
+
+for row in rows:
+    parent_id = row['reply_to']
+    if parent_id is None:
+        toplevel.append(row)
+    else:
+        children.setdefault(parent_id, []).append(row)
+
+def format(row):
+    print('<p><a href="view.cgi?id={id}i">{subject}</a></p>'.format(row))
+    try: kids = children[row['id']]
+    except KeyError: pass
+    else:
+        print('<blockquote>')
+        for kid in kids:
+            format(kid)
+        print('</blockquote>')
+    print('<p>')
+
+for row in toplevel:
+    format(row)
+
+print("""
+     </p>
+     <hr />
+     <p><a href="edit.cgi">Post message</a></p>
+  </body>
+</html>
+""")

+ 48 - 0
beginning-python-3ed-master/Chapter26/listing26-6.py

@@ -0,0 +1,48 @@
+#!/usr/bin/python
+
+print('Content-type: text/html\n')
+
+import cgitb; cgitb.enable()
+
+import psycopg2
+conn = psycopg2.connect('user=foo password=bar dbname=baz')
+curs = conn.cursor()
+
+import cgi, sys
+form = cgi.FieldStorage()
+id = form.getvalue('id')
+
+print("""
+<html>
+  <head>
+    <title>View Message</title>
+  </head>
+  <body>
+    <h1>View Message</h1>
+    """)
+
+try: id = int(id)
+except:
+     print('Invalid message ID')
+     sys.exit()
+
+curs.execute('SELECT * FROM messages WHERE id = %s', (format(id),))
+rows = curs.dictfetchall()
+
+if not rows:
+     print('Unknown message ID')
+     sys.exit()
+
+row = rows[0]
+
+print("""
+     <p><b>Subject:</b> {subject}<br />
+     <b>Sender:</b> {sender}<br />
+     <pre>{text}</pre>
+     </p>
+     <hr />
+     <a href='main.cgi'>Back to the main page</a>
+     | <a href="edit.cgi?reply_to={id}">Reply</a>
+  </body>
+</html>
+""".format(row))

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini