diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 00000000..9542d354 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +training.python_web \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 00000000..e206d70d --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..39c829f6 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..743ed207 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 00000000..922003b8 --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/training.python_web.iml b/.idea/training.python_web.iml new file mode 100644 index 00000000..18de24d8 --- /dev/null +++ b/.idea/training.python_web.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..c80f2198 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 00000000..9712306f --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,1141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1388873604217 + 1388873604217 + + + 1389405667962 + 1389405667962 + + + 1389405693782 + 1389405693782 + + + 1390005771551 + 1390005771551 + + + 1391378089674 + 1391378089674 + + + 1391470598118 + 1391470598118 + + + 1392084369507 + 1392084369507 + + + 1392584650845 + 1392584650845 + + + 1392952139382 + 1392952139382 + + + 1393092633097 + 1393092633097 + + + 1393125188986 + 1393125188986 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assignments/session01/echo_client.py b/assignments/session01/echo_client.py index 61616c36..2dbc0a9c 100644 --- a/assignments/session01/echo_client.py +++ b/assignments/session01/echo_client.py @@ -6,16 +6,20 @@ def client(msg, log_buffer=sys.stderr): server_address = ('localhost', 10000) # TODO: Replace the following line with your code which will instantiate # a TCP socket with IPv4 Addressing, call the socket you make 'sock' - sock = None + sock = socket.socket( + socket.AF_INET, + socket.SOCK_STREAM, + socket.IPPROTO_IP) + print >>log_buffer, 'connecting to {0} port {1}'.format(*server_address) # TODO: connect your socket to the server here. - + sock.connect(server_address) # this try/finally block exists purely to allow us to close the socket # when we are finished with it try: print >>log_buffer, 'sending "{0}"'.format(msg) # TODO: send your message to the server here. - + sock.sendall(msg) # TODO: the server should be sending you back your message as a series # of 16-byte chunks. You will want to log them as you receive # each one. You will also need to check to make sure that @@ -24,12 +28,20 @@ def client(msg, log_buffer=sys.stderr): # # Make sure that you log each chunk you receive. Use the print # statement below to do it. (The tests expect this log format) - chunk = '' - print >>log_buffer, 'received "{0}"'.format(chunk) + amount_received = 0 + amount_expected = len(msg) + while amount_received < amount_expected: + chunk = sock.recv(16) + amount_received += len(chunk) + print >>log_buffer, 'received "{0}"'.format(chunk) + + + finally: # TODO: after you break out of the loop receiving echoed chunks from # the server you will want to close your client socket. print >>log_buffer, 'closing socket' + sock.close() if __name__ == '__main__': diff --git a/assignments/session01/echo_server.py b/assignments/session01/echo_server.py index 217380fb..927237c9 100644 --- a/assignments/session01/echo_server.py +++ b/assignments/session01/echo_server.py @@ -7,16 +7,21 @@ def server(log_buffer=sys.stderr): address = ('127.0.0.1', 10000) # TODO: Replace the following line with your code which will instantiate # a TCP socket with IPv4 Addressing, call the socket you make 'sock' - sock = None + sock = socket.socket( + socket.AF_INET, + socket.SOCK_STREAM, + socket.IPPROTO_TCP + ) # TODO: Set an option to allow the socket address to be reused immediately # see the end of http://docs.python.org/2/library/socket.html - + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # log that we are building a server print >>log_buffer, "making a server on {0}:{1}".format(*address) # TODO: bind your new sock 'sock' to the address above and begin to listen # for incoming connections - + sock.bind(address) + sock.listen(1) try: # the outer loop controls the creation of new connection sockets. The # server will handle each incoming connection one at a time. @@ -28,9 +33,10 @@ def server(log_buffer=sys.stderr): # the client so we can report it below. Replace the # following line with your code. It is only here to prevent # syntax errors - addr = ('bar', 'baz') + #addr = ('bar', 'baz') + conn, client_address = sock.accept() try: - print >>log_buffer, 'connection - {0}:{1}'.format(*addr) + print >>log_buffer, 'connection - {0}:{1}'.format(*client_address) # the inner loop will receive messages sent by the client in # buffers. When a complete message has been received, the @@ -41,12 +47,17 @@ def server(log_buffer=sys.stderr): # following line with your code. It's only here as # a placeholder to prevent an error in string # formatting - data = '' + data = conn.recv(16) print >>log_buffer, 'received "{0}"'.format(data) # TODO: you will need to check here to see if any data was # received. If so, send the data you got back to # the client. If not, exit the inner loop and wait # for a new connection from a client + if not data: + break + conn.send(data) + + finally: # TODO: When the inner loop exits, this 'finally' clause will @@ -54,14 +65,15 @@ def server(log_buffer=sys.stderr): # created above when a client connected. Replace the # call to `pass` below, which is only there to prevent # syntax problems - pass + conn.close() except KeyboardInterrupt: # TODO: Use the python KeyboardIntterupt exception as a signal to # close the server socket and exit from the server function. # Replace the call to `pass` below, which is only there to # prevent syntax problems - pass + sock.close() + sys.exit() if __name__ == '__main__': diff --git a/assignments/session02/http_server.py b/assignments/session02/http_server.py index 12cbfeba..1aff7f28 100644 --- a/assignments/session02/http_server.py +++ b/assignments/session02/http_server.py @@ -1,14 +1,21 @@ import socket import sys +import mimetypes -def response_ok(): +def response_ok(body, mimetyp): """returns a basic HTTP response""" + if not args: + body = "this is a pretty minimal response" + mimetype = "text/plain" + else: + body = args[0] + mimetype = args[1] resp = [] resp.append("HTTP/1.1 200 OK") - resp.append("Content-Type: text/plain") + resp.append("Content-Type:" + mimetype) resp.append("") - resp.append("this is a pretty minimal response") + resp.append(body) return "\r\n".join(resp) @@ -26,6 +33,10 @@ def parse_request(request): if method != "GET": raise NotImplementedError("We only accept GET") print >>sys.stderr, 'request is okay' + return uri + +def resolve_uri(uri): + mime_res = (mimetypes.guess_type(uri))[0] def server(): diff --git a/assignments/session02/http_server_1.py b/assignments/session02/http_server_1.py new file mode 100644 index 00000000..d9d11800 --- /dev/null +++ b/assignments/session02/http_server_1.py @@ -0,0 +1,74 @@ +import socket +import sys + + +def response_ok(): + """returns a basic HTTP response""" + resp = [] + resp.append("HTTP/1.1 200 OK") + resp.append("Content-Type: text/plain") + resp.append("") + resp.append("this is a pretty minimal response") + return "\r\n".join(resp) + + +def response_method_not_allowed(): + """returns a 405 Method Not Allowed response""" + resp = [] + resp.append("HTTP/1.1 405 Method Not Allowed") + resp.append("") + return "\r\n".join(resp) + + +def parse_request(request): + first_line = request.split("\r\n", 1)[0] + method, uri, protocol = first_line.split() + if method != "GET": + raise NotImplementedError("We only accept GET") + print >>sys.stderr, 'request is okay' + return uri + +def resolve_uri(uri): + + +def server(): + address = ('127.0.0.1', 10000) + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + print >>sys.stderr, "making a server on %s:%s" % address + sock.bind(address) + sock.listen(1) + + try: + while True: + print >>sys.stderr, 'waiting for a connection' + conn, addr = sock.accept() # blocking + try: + print >>sys.stderr, 'connection - %s:%s' % addr + request = "" + while True: + data = conn.recv(1024) + request += data + if len(data) < 1024 or not data: + break + + try: + parse_request(request) + except NotImplementedError: + response = response_method_not_allowed() + else: + response = response_ok() + + print >>sys.stderr, 'sending response' + conn.sendall(response) + finally: + conn.close() + + except KeyboardInterrupt: + sock.close() + return + + +if __name__ == '__main__': + server() + sys.exit(0) diff --git a/assignments/session02/tasks.txt b/assignments/session02/tasks.txt index fcf3e582..02248577 100644 --- a/assignments/session02/tasks.txt +++ b/assignments/session02/tasks.txt @@ -80,3 +80,4 @@ Optional Tasks: If you choose to take on any of these optional tasks, try start by writing tests in tests.py that demostrate what the task should accomplish. Then write code that makes the tests pass. + diff --git a/assignments/session03/.cache/api.eventful.com,json,events,search,q=cycling&l=Seattle&app_key=test_key,22de6f7c4f73ac9c59368db27552cd97 b/assignments/session03/.cache/api.eventful.com,json,events,search,q=cycling&l=Seattle&app_key=test_key,22de6f7c4f73ac9c59368db27552cd97 new file mode 100644 index 00000000..2878cf6c --- /dev/null +++ b/assignments/session03/.cache/api.eventful.com,json,events,search,q=cycling&l=Seattle&app_key=test_key,22de6f7c4f73ac9c59368db27552cd97 @@ -0,0 +1,8 @@ +status: 200 +content-length: 13688 +content-location: http://api.eventful.com/json//events/search?q=cycling&l=Seattle&app_key=test_key +server: lighttpd/1.4.28 +date: Tue, 28 Jan 2014 18:00:36 GMT +content-type: text/javascript; charset=utf-8 + +{"last_item":null,"total_items":"86","first_item":null,"page_number":"1","page_size":"10","page_items":null,"search_time":"0.028","page_count":"9","events":{"event":[{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":"98073","going_count":null,"all_day":"0","latitude":"47.6742","groups":null,"url":"http://seattle.eventful.com/events/cycling-event-redspoke-2014-/E0-001-064398941-3@2014071607?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-064398941-3@2014071607","privacy":"1","city_name":"Redmond","link_count":null,"longitude":"-122.121","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-07-16 07:30:00","tz_id":null,"description":" ","modified":"2014-01-24 08:11:36","venue_display":"1","tz_country":null,"performers":null,"title":"Cycling Event - RedSpoke 2014","venue_address":null,"geocode_type":"Zip Code Based GeoCodes","tz_olson_path":null,"recur_string":"daily until July 20, 2014","calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2013-12-03 23:58:17","venue_id":"V0-001-002355411-0","tz_city":null,"stop_time":null,"venue_name":"Redmond, WA to Spokane, WA","venue_url":"http://seattle.eventful.com/venues/redmond-wa-to-spokane-wa-/V0-001-002355411-0?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":"98198","going_count":null,"all_day":"2","latitude":"47.3861","groups":null,"url":"http://seattle.eventful.com/events/ladies-only-cycling-tour-cycling-san-juans-/E0-001-064407533-7?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-064407533-7","privacy":"1","city_name":"Seattle","link_count":null,"longitude":"-122.304","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-05-11 00:00:00","tz_id":null,"description":" ","modified":"2014-01-17 02:42:18","venue_display":"1","tz_country":null,"performers":null,"title":"Ladies Only Cycling Tour - Cycling the San Juans","venue_address":"20717 International Blvd","geocode_type":"Zip Code Based GeoCodes","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2013-12-04 03:14:57","venue_id":"V0-001-007518635-2","tz_city":null,"stop_time":"2014-05-16 00:00:00","venue_name":"San Juan Islands","venue_url":"http://seattle.eventful.com/venues/san-juan-islands-/V0-001-007518635-2?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":"98040","going_count":null,"all_day":"0","latitude":"47.5602","groups":null,"url":"http://seattle.eventful.com/events/path-pedal-against-trafficking-humans-ride-/E0-001-064399183-4?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-064399183-4","privacy":"1","city_name":"Mercer Island","link_count":null,"longitude":"-122.228","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-03-30 08:00:00","tz_id":null,"description":" ","modified":"2014-01-07 13:39:48","venue_display":"1","tz_country":null,"performers":null,"title":"PATH (Pedal Against Trafficking Humans) Ride","venue_address":"2750 77th Ave SE","geocode_type":"Zip Code Based GeoCodes","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2013-12-04 00:12:22","venue_id":"V0-001-007516834-7","tz_city":null,"stop_time":null,"venue_name":"Veloce Velo Bicycles","venue_url":"http://seattle.eventful.com/venues/veloce-velo-bicycles-/V0-001-007516834-7?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":null,"going_count":null,"all_day":"0","latitude":"47.6514320","groups":null,"url":"http://seattle.eventful.com/events/tour-pro-performance-cycling-/E0-001-066157804-4?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-066157804-4","privacy":"1","city_name":"Bellevue","link_count":null,"longitude":"-122.1451520","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-02-10 06:00:00","tz_id":null,"description":" Location:
Bellevue - Cycling Studio

Description:
Maximize your cycling performance & get the results you want! This challenging ride will motivate you to increase your speed, stamina, and strength on the bike.","modified":"2014-01-25 16:33:23","venue_display":"1","tz_country":null,"performers":null,"title":"Tour de PRO: Performance Cycling","venue_address":"4455 148th Avenue N E","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2014-01-25 16:33:23","venue_id":"V0-001-000610995-9","tz_city":null,"stop_time":null,"venue_name":"Pro Sports Club - Bellevue","venue_url":"http://seattle.eventful.com/venues/pro-sports-club-bellevue-/V0-001-000610995-9?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":null,"going_count":null,"all_day":"0","latitude":"47.6514320","groups":null,"url":"http://seattle.eventful.com/events/tour-pro-performance-cycling-/E0-001-066157802-6?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-066157802-6","privacy":"1","city_name":"Bellevue","link_count":null,"longitude":"-122.1451520","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-02-10 09:15:00","tz_id":null,"description":" Location:
Bellevue - Cycling Studio

Description:
Maximize your cycling performance & get the results you want! This challenging ride will motivate you to increase your speed, stamina, and strength on the bike.","modified":"2014-01-25 16:33:22","venue_display":"1","tz_country":null,"performers":null,"title":"Tour de PRO: Performance Cycling","venue_address":"4455 148th Avenue N E","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2014-01-25 16:33:22","venue_id":"V0-001-000610995-9","tz_city":null,"stop_time":null,"venue_name":"Pro Sports Club - Bellevue","venue_url":"http://seattle.eventful.com/venues/pro-sports-club-bellevue-/V0-001-000610995-9?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":null,"going_count":null,"all_day":"0","latitude":"47.6514320","groups":null,"url":"http://seattle.eventful.com/events/tour-pro-performance-cycling-/E0-001-066157817-8?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-066157817-8","privacy":"1","city_name":"Bellevue","link_count":null,"longitude":"-122.1451520","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-02-12 09:15:00","tz_id":null,"description":" Location:
Bellevue - Cycling Studio

Description:
Maximize your cycling performance & get the results you want! This challenging ride will motivate you to increase your speed, stamina, and strength on the bike.","modified":"2014-01-25 16:33:41","venue_display":"1","tz_country":null,"performers":null,"title":"Tour de PRO: Performance Cycling","venue_address":"4455 148th Avenue N E","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2014-01-25 16:33:41","venue_id":"V0-001-000610995-9","tz_city":null,"stop_time":null,"venue_name":"Pro Sports Club - Bellevue","venue_url":"http://seattle.eventful.com/venues/pro-sports-club-bellevue-/V0-001-000610995-9?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":null,"going_count":null,"all_day":"0","latitude":"47.6514320","groups":null,"url":"http://seattle.eventful.com/events/tour-pro-performance-cycling-/E0-001-066157815-0?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-066157815-0","privacy":"1","city_name":"Bellevue","link_count":null,"longitude":"-122.1451520","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-02-05 09:15:00","tz_id":null,"description":" Location:
Bellevue - Cycling Studio

Description:
Maximize your cycling performance & get the results you want! This challenging ride will motivate you to increase your speed, stamina, and strength on the bike.","modified":"2014-01-25 16:33:38","venue_display":"1","tz_country":null,"performers":null,"title":"Tour de PRO: Performance Cycling","venue_address":"4455 148th Avenue N E","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2014-01-25 16:33:38","venue_id":"V0-001-000610995-9","tz_city":null,"stop_time":null,"venue_name":"Pro Sports Club - Bellevue","venue_url":"http://seattle.eventful.com/venues/pro-sports-club-bellevue-/V0-001-000610995-9?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":null,"going_count":null,"all_day":"0","latitude":"47.6514320","groups":null,"url":"http://seattle.eventful.com/events/tour-pro-performance-cycling-/E0-001-066157812-3?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-066157812-3","privacy":"1","city_name":"Bellevue","link_count":null,"longitude":"-122.1451520","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-02-10 18:00:00","tz_id":null,"description":" Location:
Bellevue - Cycling Studio

Description:
Maximize your cycling performance & get the results you want! This challenging ride will motivate you to increase your speed, stamina, and strength on the bike.","modified":"2014-01-25 16:33:34","venue_display":"1","tz_country":null,"performers":null,"title":"Tour de PRO: Performance Cycling","venue_address":"4455 148th Avenue N E","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2014-01-25 16:33:34","venue_id":"V0-001-000610995-9","tz_city":null,"stop_time":null,"venue_name":"Pro Sports Club - Bellevue","venue_url":"http://seattle.eventful.com/venues/pro-sports-club-bellevue-/V0-001-000610995-9?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":null,"going_count":null,"all_day":"0","latitude":"47.6514320","groups":null,"url":"http://seattle.eventful.com/events/tour-pro-performance-cycling-/E0-001-065951104-6?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-065951104-6","privacy":"1","city_name":"Bellevue","link_count":null,"longitude":"-122.1451520","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-02-03 09:15:00","tz_id":null,"description":" Location:
Bellevue - Cycling Studio

Description:
Maximize your cycling performance & get the results you want! This challenging ride will motivate you to increase your speed, stamina, and strength on the bike.","modified":"2014-01-17 23:29:52","venue_display":"1","tz_country":null,"performers":null,"title":"Tour de PRO: Performance Cycling","venue_address":"4455 148th Avenue N E","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2014-01-17 23:29:52","venue_id":"V0-001-000610995-9","tz_city":null,"stop_time":null,"venue_name":"Pro Sports Club - Bellevue","venue_url":"http://seattle.eventful.com/venues/pro-sports-club-bellevue-/V0-001-000610995-9?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":null,"going_count":null,"all_day":"0","latitude":"47.6514320","groups":null,"url":"http://seattle.eventful.com/events/tour-pro-performance-cycling-/E0-001-065951115-2?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-065951115-2","privacy":"1","city_name":"Bellevue","link_count":null,"longitude":"-122.1451520","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-02-03 18:00:00","tz_id":null,"description":" Location:
Bellevue - Cycling Studio

Description:
Maximize your cycling performance & get the results you want! This challenging ride will motivate you to increase your speed, stamina, and strength on the bike.","modified":"2014-01-17 23:30:01","venue_display":"1","tz_country":null,"performers":null,"title":"Tour de PRO: Performance Cycling","venue_address":"4455 148th Avenue N E","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2014-01-17 23:30:01","venue_id":"V0-001-000610995-9","tz_city":null,"stop_time":null,"venue_name":"Pro Sports Club - Bellevue","venue_url":"http://seattle.eventful.com/venues/pro-sports-club-bellevue-/V0-001-000610995-9?utm_source=apis&utm_medium=apim&utm_campaign=apic"}]}} diff --git a/assignments/session03/.cache/api.eventful.com,json,events,search,q=cycling&l=WA&app_key=test_key,b807e82ce475840821922fab3fb6aded b/assignments/session03/.cache/api.eventful.com,json,events,search,q=cycling&l=WA&app_key=test_key,b807e82ce475840821922fab3fb6aded new file mode 100644 index 00000000..da3da59e --- /dev/null +++ b/assignments/session03/.cache/api.eventful.com,json,events,search,q=cycling&l=WA&app_key=test_key,b807e82ce475840821922fab3fb6aded @@ -0,0 +1,8 @@ +status: 200 +content-length: 161 +content-location: http://api.eventful.com/json//events/search?q=cycling&l=WA&app_key=test_key +server: lighttpd/1.4.28 +date: Tue, 28 Jan 2014 17:58:01 GMT +content-type: text/javascript; charset=utf-8 + +{"last_item":null,"total_items":"0","first_item":null,"page_number":"1","page_size":"10","page_items":null,"search_time":"0.018","page_count":"0","events":null} diff --git a/assignments/session03/.cache/api.eventful.com,json,events,search,q=music&l=San+Diego&app_key=test_key,e31b486f6c8afe2e0f4a3a994f47970c b/assignments/session03/.cache/api.eventful.com,json,events,search,q=music&l=San+Diego&app_key=test_key,e31b486f6c8afe2e0f4a3a994f47970c new file mode 100644 index 00000000..d9cd4ca0 --- /dev/null +++ b/assignments/session03/.cache/api.eventful.com,json,events,search,q=music&l=San+Diego&app_key=test_key,e31b486f6c8afe2e0f4a3a994f47970c @@ -0,0 +1,8 @@ +status: 200 +content-length: 21462 +content-location: http://api.eventful.com/json//events/search?q=music&l=San+Diego&app_key=test_key +server: lighttpd/1.4.28 +date: Sun, 26 Jan 2014 17:23:55 GMT +content-type: text/javascript; charset=utf-8 + +{"last_item":null,"total_items":"1851","first_item":null,"page_number":"1","page_size":"10","page_items":null,"search_time":"0.053","page_count":"186","events":{"event":[{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"CA","postal_code":"92101","going_count":null,"all_day":"0","latitude":"32.7314520","groups":null,"url":"http://sandiego.eventful.com/events/first-friday-films-music-room-jalsaghar-/E0-001-066123521-9?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-066123521-9","privacy":"1","city_name":"San Diego","link_count":null,"longitude":"-117.1512999","country_name":"United States","country_abbr":"USA","region_name":"California","start_time":"2014-03-07 19:00:00","tz_id":null,"description":"

7:00 p.m. Pre-Film Lecture | 8:00 p.m. Film

Satyaijt Ray (1921-1992) was a master of Indian cinema and his work continues to be studied and discovered by audiences around the world. The Music Room, also known by its original title Jalsaghar, follows an aristocrat's weakening grip on power and the destruction of his personal and public life during a radical shift in Indian society when the feudal system was outlawed. Set in West Bengal, the film's protagonist remains committed to tradition, pride, and above all, organizing concerts of beautiful Indian music in his home.

Prior to the film, scholar and professor Aditi Chandra, Ph.D., will deliver a lecture analyzing the ways in which historical Indian monuments can inform our ideas about the development of modern Indian society and its social relations. Chandra is Assistant Professor in the School of Social Sciences, Humanities and Art at University of California, Merced.

Charcuterie and a Movie Package for Two
Enjoy some nibbles and wine during the lecture and film.
$50 members | $60 nonmembers

Package includes:

To guarantee availability, reserve your package online or by calling 619.696.1935 by 4:00 p.m. on Wednesday, March 5, 2014.

","modified":"2014-01-24 15:34:33","venue_display":"1","tz_country":null,"performers":{"performer":{"creator":"themusicroomband","linker":"evdb","name":"The Music Room","url":"http://concerts.eventful.com/The-Music-Room?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"P0-001-000219393-2","short_bio":"Folk Rock, Rock, Acoustic, Folk"}},"title":"First Friday Films: The Music Room, or Jalsaghar","venue_address":"1450 El Prado Balboa Park","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":{"small":{"width":"48","url":"http://s3.evcdn.com/images/small/I0-001/002/779/294-9.jpeg_/the-music-room-94.jpeg","height":"48"},"width":"48","caption":null,"medium":{"width":"128","url":"http://s3.evcdn.com/images/medium/I0-001/002/779/294-9.jpeg_/the-music-room-94.jpeg","height":"128"},"url":"http://s3.evcdn.com/images/small/I0-001/002/779/294-9.jpeg_/the-music-room-94.jpeg","thumb":{"width":"48","url":"http://s3.evcdn.com/images/thumb/I0-001/002/779/294-9.jpeg_/the-music-room-94.jpeg","height":"48"},"height":"48"},"created":"2014-01-24 15:34:33","venue_id":"V0-001-000106700-1","tz_city":null,"stop_time":null,"venue_name":"The San Diego Museum of Art","venue_url":"http://sandiego.eventful.com/venues/the-san-diego-museum-of-art-/V0-001-000106700-1?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"CA","postal_code":null,"going_count":null,"all_day":"0","latitude":"32.8446120","groups":null,"url":"http://sandiego.eventful.com/events/la-jolla-music-society-presents-chamber-music-socie-/E0-001-059121063-6?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-059121063-6","privacy":"1","city_name":"La Jolla","link_count":null,"longitude":"-117.2779420","country_name":"United States","country_abbr":"USA","region_name":"California","start_time":"2014-03-22 20:00:00","tz_id":null,"description":" La Jolla Music Society presents: Mozart: Quartet for Flute and Strings no 1 in D major, K 285; Mozart: Duo for Violin and Viola no 1 in G major, K 423; Currier: New Work; Villa-Lobos: Choros no 2 p...\n","modified":"2013-07-13 11:22:00","venue_display":"1","tz_country":null,"performers":{"performer":{"creator":"SPAHouston","linker":"evdb","name":"Chamber Music Society of Lincoln Center","url":"http://eventful.com/performers/chamber-music-society-of-lincoln-center-/P0-001-000144637-8?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"P0-001-000144637-8","short_bio":"one of 12 constituents of Lincoln Center for the Performing Arts, the largest performing arts complex in the world"}},"title":"La Jolla Music Society presents Chamber Music Society of Lincoln Center - Mozart Connections","venue_address":"700 Prospect Street","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":{"small":{"width":"48","url":"http://s2.evcdn.com/images/small/I0-001/014/374/981-0.jpeg_/la-jolla-music-society-presents-chamber-music-soci-81.jpeg","height":"48"},"width":"48","caption":null,"medium":{"width":"128","url":"http://s2.evcdn.com/images/medium/I0-001/014/374/981-0.jpeg_/la-jolla-music-society-presents-chamber-music-soci-81.jpeg","height":"128"},"url":"http://s2.evcdn.com/images/small/I0-001/014/374/981-0.jpeg_/la-jolla-music-society-presents-chamber-music-soci-81.jpeg","thumb":{"width":"48","url":"http://s2.evcdn.com/images/thumb/I0-001/014/374/981-0.jpeg_/la-jolla-music-society-presents-chamber-music-soci-81.jpeg","height":"48"},"height":"48"},"created":"2013-07-13 11:22:00","venue_id":"V0-001-001046075-0","tz_city":null,"stop_time":null,"venue_name":"Sherwood Auditorium at MCASD","venue_url":"http://sandiego.eventful.com/venues/sherwood-auditorium-at-mcasd-/V0-001-001046075-0?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"CA","postal_code":null,"going_count":null,"all_day":"0","latitude":"32.8446120","groups":null,"url":"http://sandiego.eventful.com/events/la-jolla-music-society-presents-chamber-music-socie-/E0-001-059121076-0?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-059121076-0","privacy":"1","city_name":"La Jolla","link_count":null,"longitude":"-117.2779420","country_name":"United States","country_abbr":"USA","region_name":"California","start_time":"2014-04-26 20:00:00","tz_id":null,"description":" La Jolla Music Society presents: Beethoven: Piano Quartet in E-flat Major, Op. 16; Martinu: Madrigals (3) for Violin and Viola, H 313; Faur: Quartet for Piano and Strings no 1 in C minor, Op. 15\n","modified":"2013-07-13 11:24:04","venue_display":"1","tz_country":null,"performers":{"performer":{"creator":"SPAHouston","linker":"evdb","name":"Chamber Music Society of Lincoln Center","url":"http://eventful.com/performers/chamber-music-society-of-lincoln-center-/P0-001-000144637-8?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"P0-001-000144637-8","short_bio":"one of 12 constituents of Lincoln Center for the Performing Arts, the largest performing arts complex in the world"}},"title":"La Jolla Music Society presents Chamber Music Society of Lincoln Center - Defining Voices","venue_address":"700 Prospect Street","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":{"small":{"width":"48","url":"http://s4.evcdn.com/images/small/I0-001/014/374/987-4.jpeg_/la-jolla-music-society-presents-chamber-music-soci-87.jpeg","height":"48"},"width":"48","caption":null,"medium":{"width":"128","url":"http://s4.evcdn.com/images/medium/I0-001/014/374/987-4.jpeg_/la-jolla-music-society-presents-chamber-music-soci-87.jpeg","height":"128"},"url":"http://s4.evcdn.com/images/small/I0-001/014/374/987-4.jpeg_/la-jolla-music-society-presents-chamber-music-soci-87.jpeg","thumb":{"width":"48","url":"http://s4.evcdn.com/images/thumb/I0-001/014/374/987-4.jpeg_/la-jolla-music-society-presents-chamber-music-soci-87.jpeg","height":"48"},"height":"48"},"created":"2013-07-13 11:24:04","venue_id":"V0-001-001046075-0","tz_city":null,"stop_time":null,"venue_name":"Sherwood Auditorium at MCASD","venue_url":"http://sandiego.eventful.com/venues/sherwood-auditorium-at-mcasd-/V0-001-001046075-0?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"CA","postal_code":null,"going_count":null,"all_day":"0","latitude":"32.8446120","groups":null,"url":"http://sandiego.eventful.com/events/la-jolla-music-society-presents-chamber-music-socie-/E0-001-059121035-3?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-059121035-3","privacy":"1","city_name":"La Jolla","link_count":null,"longitude":"-117.2779420","country_name":"United States","country_abbr":"USA","region_name":"California","start_time":"2014-02-08 20:00:00","tz_id":null,"description":" La Jolla Music Society presents: Debussy: Nocturnes, for 2 pianos; Debussy: Suite for Piano "Pour le piano"; Debussy: Jeux; Bizet: Jeux d'enfants, Op. 22; Gershwin: An American in Paris (Arr. for 2...\n","modified":"2013-07-13 11:19:24","venue_display":"1","tz_country":null,"performers":{"performer":{"creator":"SPAHouston","linker":"evdb","name":"Chamber Music Society of Lincoln Center","url":"http://eventful.com/performers/chamber-music-society-of-lincoln-center-/P0-001-000144637-8?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"P0-001-000144637-8","short_bio":"one of 12 constituents of Lincoln Center for the Performing Arts, the largest performing arts complex in the world"}},"title":"La Jolla Music Society presents Chamber Music Society of Lincoln Center - An American in Paris","venue_address":"700 Prospect Street","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":{"small":{"width":"48","url":"http://s2.evcdn.com/images/small/I0-001/014/374/973-1.jpeg_/la-jolla-music-society-presents-chamber-music-soci-73.jpeg","height":"48"},"width":"48","caption":null,"medium":{"width":"128","url":"http://s2.evcdn.com/images/medium/I0-001/014/374/973-1.jpeg_/la-jolla-music-society-presents-chamber-music-soci-73.jpeg","height":"128"},"url":"http://s2.evcdn.com/images/small/I0-001/014/374/973-1.jpeg_/la-jolla-music-society-presents-chamber-music-soci-73.jpeg","thumb":{"width":"48","url":"http://s2.evcdn.com/images/thumb/I0-001/014/374/973-1.jpeg_/la-jolla-music-society-presents-chamber-music-soci-73.jpeg","height":"48"},"height":"48"},"created":"2013-07-13 11:19:24","venue_id":"V0-001-001046075-0","tz_city":null,"stop_time":null,"venue_name":"Sherwood Auditorium at MCASD","venue_url":"http://sandiego.eventful.com/venues/sherwood-auditorium-at-mcasd-/V0-001-001046075-0?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"CA","postal_code":"92071","going_count":null,"all_day":"2","latitude":"32.8482","groups":null,"url":"http://sandiego.eventful.com/events/early-childhood-music-/E0-001-066111239-8?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-066111239-8","privacy":"1","city_name":"Santee","link_count":null,"longitude":"-116.992","country_name":"United States","country_abbr":"USA","region_name":"California","start_time":"2014-01-25 00:00:00","tz_id":null,"description":" Event Overview

Early Childhood Music, in Santee, CA, takes place January 25, 2014 and ends on March 01, 2014. This event will be located at Staump Music School.

","modified":"2014-01-23 19:43:12","venue_display":"1","tz_country":null,"performers":null,"title":"Early Childhood Music","venue_address":"9530 Pathway St. #201","geocode_type":"Zip Code Based GeoCodes","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2014-01-23 19:32:51","venue_id":"V0-001-007520469-4","tz_city":null,"stop_time":"2014-03-01 00:00:00","venue_name":"Staump Music School","venue_url":"http://sandiego.eventful.com/venues/staump-music-school-/V0-001-007520469-4?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"CA","postal_code":"92071","going_count":null,"all_day":"0","latitude":"32.8482","groups":null,"url":"http://sandiego.eventful.com/events/early-childhood-music-/E0-001-064510428-3@2014012609?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-064510428-3@2014012609","privacy":"1","city_name":"Santee","link_count":null,"longitude":"-116.992","country_name":"United States","country_abbr":"USA","region_name":"California","start_time":"2014-01-26 09:00:00","tz_id":null,"description":" ","modified":"2013-12-06 01:11:14","venue_display":"1","tz_country":null,"performers":null,"title":"Early Childhood Music","venue_address":"9530 Pathway St. #201","geocode_type":"Zip Code Based GeoCodes","tz_olson_path":null,"recur_string":"daily until March 1, 2014","calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2013-12-06 01:11:14","venue_id":"V0-001-007520469-4","tz_city":null,"stop_time":null,"venue_name":"Staump Music School","venue_url":"http://sandiego.eventful.com/venues/staump-music-school-/V0-001-007520469-4?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"CA","postal_code":"92093","going_count":null,"all_day":"0","latitude":"32.87785316904055","groups":null,"url":"http://sandiego.eventful.com/events/camera-lucida-presents-myriad-trio-ii-/E0-001-063056563-9?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-063056563-9","privacy":"1","city_name":"La Jolla","link_count":null,"longitude":"-117.234994776799","country_name":"United States","country_abbr":"USA","region_name":"California","start_time":"2014-06-10 19:30:00","tz_id":null,"description":" Camera Lucida; Myriad Trio; San Diego Symphony; UCSD Music Department presents: Program TBA\n","modified":"2014-01-05 01:35:08","venue_display":"1","tz_country":null,"performers":null,"title":"CAMERA LUCIDA Presents Myriad Trio II","venue_address":"9500 Gilman Drive","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":{"small":{"width":"48","url":"http://s2.evcdn.com/images/small/I0-001/014/953/237-3.jpeg_/camera-lucida-presents-myriad-trio-ii-37.jpeg","height":"48"},"width":"48","caption":null,"medium":{"width":"128","url":"http://s2.evcdn.com/images/medium/I0-001/014/953/237-3.jpeg_/camera-lucida-presents-myriad-trio-ii-37.jpeg","height":"128"},"url":"http://s2.evcdn.com/images/small/I0-001/014/953/237-3.jpeg_/camera-lucida-presents-myriad-trio-ii-37.jpeg","thumb":{"width":"48","url":"http://s2.evcdn.com/images/thumb/I0-001/014/953/237-3.jpeg_/camera-lucida-presents-myriad-trio-ii-37.jpeg","height":"48"},"height":"48"},"created":"2013-11-01 02:28:21","venue_id":"V0-001-006031574-7","tz_city":null,"stop_time":null,"venue_name":"Conrad Prebys Music Center","venue_url":"http://sandiego.eventful.com/venues/conrad-prebys-music-center-/V0-001-006031574-7?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"CA","postal_code":null,"going_count":null,"all_day":"0","latitude":"32.7744363","groups":null,"url":"http://sandiego.eventful.com/events/music-lent-/E0-001-060700804-8?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-060700804-8","privacy":"1","city_name":"San Diego","link_count":null,"longitude":"-117.1837880","country_name":"United States","country_abbr":"USA","region_name":"California","start_time":"2014-03-30 16:00:00","tz_id":null,"description":" Angelus Early Music Series presents: Program TBA\n","modified":"2013-09-29 03:16:16","venue_display":"1","tz_country":null,"performers":null,"title":"Music for Lent","venue_address":"Jenny Craig Pavilion","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":{"small":{"width":"48","url":"http://s3.evcdn.com/images/small/I0-001/014/610/090-6.jpeg_/music-lent-90.jpeg","height":"48"},"width":"48","caption":null,"medium":{"width":"128","url":"http://s3.evcdn.com/images/medium/I0-001/014/610/090-6.jpeg_/music-lent-90.jpeg","height":"128"},"url":"http://s3.evcdn.com/images/small/I0-001/014/610/090-6.jpeg_/music-lent-90.jpeg","thumb":{"width":"48","url":"http://s3.evcdn.com/images/thumb/I0-001/014/610/090-6.jpeg_/music-lent-90.jpeg","height":"48"},"height":"48"},"created":"2013-08-31 01:37:38","venue_id":"V0-001-006049978-4","tz_city":null,"stop_time":null,"venue_name":"University of San Diego","venue_url":"http://sandiego.eventful.com/venues/university-of-san-diego-/V0-001-006049978-4?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"CA","postal_code":"92093","going_count":null,"all_day":"0","latitude":"32.87785316904055","groups":null,"url":"http://sandiego.eventful.com/events/camera-lucida-mozart-brahms-/E0-001-063056554-1?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-063056554-1","privacy":"1","city_name":"La Jolla","link_count":null,"longitude":"-117.234994776799","country_name":"United States","country_abbr":"USA","region_name":"California","start_time":"2014-02-03 19:30:00","tz_id":null,"description":" Camera Lucida; San Diego Symphony; UCSD Music Department presents: Mozart: Piano Trio No. 4 in E major, K. 542; Clarke: Sonata for Viola/Cello and Piano; Brahms: Trio for Clarinet, Cello and Piano ...\n","modified":"2013-11-04 01:41:31","venue_display":"1","tz_country":null,"performers":null,"title":"CAMERA LUCIDA / Mozart, Brahms","venue_address":"9500 Gilman Drive","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":{"small":{"width":"48","url":"http://s2.evcdn.com/images/small/I0-001/014/953/233-7.jpeg_/camera-lucida-mozart-brahms-33.jpeg","height":"48"},"width":"48","caption":null,"medium":{"width":"128","url":"http://s2.evcdn.com/images/medium/I0-001/014/953/233-7.jpeg_/camera-lucida-mozart-brahms-33.jpeg","height":"128"},"url":"http://s2.evcdn.com/images/small/I0-001/014/953/233-7.jpeg_/camera-lucida-mozart-brahms-33.jpeg","thumb":{"width":"48","url":"http://s2.evcdn.com/images/thumb/I0-001/014/953/233-7.jpeg_/camera-lucida-mozart-brahms-33.jpeg","height":"48"},"height":"48"},"created":"2013-11-01 02:28:01","venue_id":"V0-001-006031574-7","tz_city":null,"stop_time":null,"venue_name":"Conrad Prebys Music Center","venue_url":"http://sandiego.eventful.com/venues/conrad-prebys-music-center-/V0-001-006031574-7?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"CA","postal_code":"92093","going_count":null,"all_day":"0","latitude":"32.87785316904055","groups":null,"url":"http://sandiego.eventful.com/events/camera-lucida-dvork-sibelius-/E0-001-063056559-6?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-063056559-6","privacy":"1","city_name":"La Jolla","link_count":null,"longitude":"-117.234994776799","country_name":"United States","country_abbr":"USA","region_name":"California","start_time":"2014-06-02 19:30:00","tz_id":null,"description":" Camera Lucida; San Diego Symphony; UCSD Music Department presents: Kodly: Serenade for Two Violins and Viola; Dvorak: Trio for Piano and Strings no 3 in F minor, Op. 65/B 130; Sibelius: Quartet fo...\n","modified":"2013-11-04 01:41:37","venue_display":"1","tz_country":null,"performers":null,"title":"CAMERA LUCIDA / Dvork, Sibelius","venue_address":"9500 Gilman Drive","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":{"small":{"width":"48","url":"http://s1.evcdn.com/images/small/I0-001/014/953/236-4.jpeg_/camera-lucida-dvork-sibelius-36.jpeg","height":"48"},"width":"48","caption":null,"medium":{"width":"128","url":"http://s1.evcdn.com/images/medium/I0-001/014/953/236-4.jpeg_/camera-lucida-dvork-sibelius-36.jpeg","height":"128"},"url":"http://s1.evcdn.com/images/small/I0-001/014/953/236-4.jpeg_/camera-lucida-dvork-sibelius-36.jpeg","thumb":{"width":"48","url":"http://s1.evcdn.com/images/thumb/I0-001/014/953/236-4.jpeg_/camera-lucida-dvork-sibelius-36.jpeg","height":"48"},"height":"48"},"created":"2013-11-01 02:28:18","venue_id":"V0-001-006031574-7","tz_city":null,"stop_time":null,"venue_name":"Conrad Prebys Music Center","venue_url":"http://sandiego.eventful.com/venues/conrad-prebys-music-center-/V0-001-006031574-7?utm_source=apis&utm_medium=apim&utm_campaign=apic"}]}} diff --git a/assignments/session03/.cache/api.eventful.com,json,events,search,q=running&l=Seattle&app_key=test_key,44b43d8d27c899b633db930a9d0fb1d6 b/assignments/session03/.cache/api.eventful.com,json,events,search,q=running&l=Seattle&app_key=test_key,44b43d8d27c899b633db930a9d0fb1d6 new file mode 100644 index 00000000..85b3be38 --- /dev/null +++ b/assignments/session03/.cache/api.eventful.com,json,events,search,q=running&l=Seattle&app_key=test_key,44b43d8d27c899b633db930a9d0fb1d6 @@ -0,0 +1,8 @@ +status: 200 +content-length: 11930 +content-location: http://api.eventful.com/json//events/search?q=running&l=Seattle&app_key=test_key +server: lighttpd/1.4.28 +date: Wed, 29 Jan 2014 01:47:19 GMT +content-type: text/javascript; charset=utf-8 + +{"last_item":null,"total_items":"213","first_item":null,"page_number":"1","page_size":"10","page_items":null,"search_time":"0.036","page_count":"22","events":{"event":[{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":null,"going_count":null,"all_day":"2","latitude":"47.6064","groups":null,"url":"http://seattle.eventful.com/events/running-event-int-running-/E0-001-060455183-1?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-060455183-1","privacy":"1","city_name":"Seattle","link_count":null,"longitude":"-122.331","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-08-23 00:00:00","tz_id":null,"description":" ","modified":"2014-01-24 07:58:49","venue_display":"1","tz_country":null,"performers":null,"title":"Running Event - INT Running","venue_address":null,"geocode_type":"City Based GeoCodes","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2013-08-23 04:04:56","venue_id":"V0-001-007243812-0","tz_city":null,"stop_time":"2014-08-23 00:00:00","venue_name":"WA","venue_url":"http://seattle.eventful.com/venues/wa-/V0-001-007243812-0?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":"98208","going_count":null,"all_day":"0","latitude":"47.9015","groups":null,"url":"http://seattle.eventful.com/events/mill-creek-puddle-run-/E0-001-064399659-2?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-064399659-2","privacy":"1","city_name":"Everett","link_count":null,"longitude":"-122.184","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-02-02 08:30:00","tz_id":null,"description":" ","modified":"2013-12-19 13:55:35","venue_display":"1","tz_country":null,"performers":null,"title":"Mill Creek Puddle Run","venue_address":"13723 Puget Park Drive","geocode_type":"Zip Code Based GeoCodes","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2013-12-04 00:23:42","venue_id":"V0-001-007516927-6","tz_city":null,"stop_time":null,"venue_name":"Mill Creek Family YMCA","venue_url":"http://seattle.eventful.com/venues/mill-creek-family-ymca-/V0-001-007516927-6?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":"98103","going_count":null,"all_day":"2","latitude":"47.6798964","groups":null,"url":"http://seattle.eventful.com/events/superbowl-5k-runwalk-/E0-001-066202003-0?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-066202003-0","privacy":"1","city_name":"Seattle","link_count":null,"longitude":"-122.3281102","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-02-01 00:00:00","tz_id":null,"description":" ","modified":"2014-01-27 10:36:50","venue_display":"1","tz_country":null,"performers":null,"title":"SuperBowl 5k Run/Walk","venue_address":"7201 E Green Lake Drive N","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2014-01-27 10:36:50","venue_id":"V0-001-000402996-9","tz_city":null,"stop_time":"2014-02-01 00:00:00","venue_name":"Evans Pool","venue_url":"http://seattle.eventful.com/venues/evans-pool-/V0-001-000402996-9?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":"98421","going_count":null,"all_day":"2","latitude":"47.2363400","groups":null,"url":"http://seattle.eventful.com/events/color-run-tacoma-/E0-001-065225697-3?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-065225697-3","privacy":"1","city_name":"Tacoma","link_count":null,"longitude":"-122.4268340","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-08-10 00:00:00","tz_id":null,"description":" ","modified":"2014-01-05 01:29:57","venue_display":"1","tz_country":null,"performers":null,"title":"THE COLOR RUN TACOMA","venue_address":"2727 East D Street","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2013-12-27 12:24:00","venue_id":"V0-001-000144232-7","tz_city":null,"stop_time":"2014-08-10 00:00:00","venue_name":"Tacoma Dome","venue_url":"http://seattle.eventful.com/venues/tacoma-dome-/V0-001-000144232-7?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":"98373","going_count":null,"all_day":"0","latitude":"47.1402691","groups":null,"url":"http://seattle.eventful.com/events/rogers-reindeer-fun-run-/E0-001-064892349-4?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-064892349-4","privacy":"1","city_name":"Puyallup","link_count":null,"longitude":"-122.3091746","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-12-13 09:00:00","tz_id":null,"description":" ","modified":"2014-01-05 00:29:28","venue_display":"1","tz_country":null,"performers":null,"title":"Rogers Reindeer Fun Run","venue_address":"9010 128th Street E","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2013-12-15 12:17:53","venue_id":"V0-001-000549441-6","tz_city":null,"stop_time":"2014-12-13 00:00:00","venue_name":"Heritage Recreation Center","venue_url":"http://seattle.eventful.com/venues/heritage-recreation-center-/V0-001-000549441-6?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":"98103","going_count":null,"all_day":"2","latitude":"47.6468650","groups":null,"url":"http://seattle.eventful.com/events/emerald-city-run-/E0-001-061648024-4?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-061648024-4","privacy":"1","city_name":"Seattle","link_count":null,"longitude":"-122.3339155","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-05-25 00:00:00","tz_id":null,"description":" ","modified":"2014-01-04 13:20:49","venue_display":"1","tz_country":null,"performers":null,"title":"Emerald City Run","venue_address":"2101 N Northlake Way","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2013-09-24 13:12:40","venue_id":"V0-001-000256560-7","tz_city":null,"stop_time":"2014-05-25 00:00:00","venue_name":"Gas Works Park","venue_url":"http://seattle.eventful.com/venues/gas-works-park-/V0-001-000256560-7?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":"98106","going_count":null,"all_day":"2","latitude":"47.5498873","groups":null,"url":"http://seattle.eventful.com/events/seattle-run-series-revolution-run-2-3race-serie-/E0-001-064763538-9?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-064763538-9","privacy":"1","city_name":"Seattle","link_count":null,"longitude":"-122.2576880","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-02-23 00:00:00","tz_id":null,"description":" ","modified":"2014-01-09 01:42:49","venue_display":"1","tz_country":null,"performers":null,"title":"Seattle Run Series - Revolution Run (#2 of 3-Race Series)","venue_address":"5895 Lake Washington Blvd. S","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2013-12-12 02:27:25","venue_id":"V0-001-005947639-8","tz_city":null,"stop_time":"2014-02-23 00:00:00","venue_name":"Seward Park, Seattle, Shelter #2","venue_url":"http://seattle.eventful.com/venues/seward-park-seattle-shelter-2-/V0-001-005947639-8?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":"98106","going_count":null,"all_day":"2","latitude":"47.5498873","groups":null,"url":"http://seattle.eventful.com/events/seattle-run-series-evolution-run-3-3race-series-/E0-001-064763541-3?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-064763541-3","privacy":"1","city_name":"Seattle","link_count":null,"longitude":"-122.2576880","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-03-30 00:00:00","tz_id":null,"description":" ","modified":"2014-01-09 01:42:49","venue_display":"1","tz_country":null,"performers":null,"title":"Seattle Run Series - Evolution Run (#3 of 3-Race Series)","venue_address":"5895 Lake Washington Blvd. S","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2013-12-12 02:27:29","venue_id":"V0-001-005947639-8","tz_city":null,"stop_time":"2014-03-30 00:00:00","venue_name":"Seward Park, Seattle, Shelter #2","venue_url":"http://seattle.eventful.com/venues/seward-park-seattle-shelter-2-/V0-001-005947639-8?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":"98275","going_count":null,"all_day":"0","latitude":"47.8983820","groups":null,"url":"http://seattle.eventful.com/events/inspiring-hope-runwalk-2014-/E0-001-057746292-3?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-057746292-3","privacy":"1","city_name":"Mukilteo","link_count":null,"longitude":"-122.3003070","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-05-10 09:00:00","tz_id":null,"description":null,"modified":"2013-06-23 15:43:48","venue_display":"1","tz_country":null,"performers":null,"title":"Inspiring Hope Run/Walk 2014","venue_address":"10801 HARBOUR POINTE BLVD","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2013-05-27 01:10:56","venue_id":"V0-001-004573067-9","tz_city":null,"stop_time":null,"venue_name":"Kamiak High School","venue_url":"http://seattle.eventful.com/venues/kamiak-high-school-/V0-001-004573067-9?utm_source=apis&utm_medium=apim&utm_campaign=apic"},{"watching_count":null,"calendar_count":null,"comment_count":null,"region_abbr":"WA","postal_code":"98115","going_count":null,"all_day":"2","latitude":"47.6813531","groups":null,"url":"http://seattle.eventful.com/events/run-like-mother-seattle-wa-/E0-001-066165870-2?utm_source=apis&utm_medium=apim&utm_campaign=apic","id":"E0-001-066165870-2","privacy":"1","city_name":"Seattle","link_count":null,"longitude":"-122.2593355","country_name":"United States","country_abbr":"USA","region_name":"Washington","start_time":"2014-05-11 00:00:00","tz_id":null,"description":" ","modified":"2014-01-25 19:56:40","venue_display":"1","tz_country":null,"performers":null,"title":"Run Like A Mother - Seattle, WA","venue_address":"7400 Sand Point Way N.E.","geocode_type":"EVDB Geocoder","tz_olson_path":null,"recur_string":null,"calendars":null,"owner":"evdb","going":null,"country_abbr2":"US","image":null,"created":"2014-01-25 19:56:40","venue_id":"V0-001-000256403-3","tz_city":null,"stop_time":"2014-05-11 00:00:00","venue_name":"Warren G. Magnuson Park","venue_url":"http://seattle.eventful.com/venues/warren-g-magnuson-park-/V0-001-000256403-3?utm_source=apis&utm_medium=apim&utm_campaign=apic"}]}} diff --git a/assignments/session03/eventful.py b/assignments/session03/eventful.py new file mode 100644 index 00000000..5b98d618 --- /dev/null +++ b/assignments/session03/eventful.py @@ -0,0 +1,66 @@ +""" +eventful + +A Python interface to the Eventful API. + +""" + +__author__ = "Edward O'Connor " +__copyright__ = "Copyright 2005, 2006 Eventful Inc." +__license__ = "MIT" + +import md5 +import urllib + +import httplib2 +import simplejson + +__all__ = ['APIError', 'API'] + +class APIError(Exception): + pass + +class API: + def __init__(self, app_key, server='api.eventful.com', cache=None): + """Create a new Eventful API client instance. +If you don't have an application key, you can request one: + http://api.eventful.com/keys/""" + self.app_key = app_key + self.server = server + self.http = httplib2.Http(cache) + + def call(self, method, **args): + "Call the Eventful API's METHOD with ARGS." + # Build up the request + args['app_key'] = self.app_key + if hasattr(self, 'user_key'): + args['user'] = self.user + args['user_key'] = self.user_key + args = urllib.urlencode(args) + url = "http://%s/json/%s?%s" % (self.server, method, args) + + # Make the request + response, content = self.http.request(url, "GET") + + # Handle the response + status = int(response['status']) + if status == 200: + try: + return simplejson.loads(content) + except ValueError: + raise APIError("Unable to parse API response!") + elif status == 404: + raise APIError("Method not found: %s" % method) + else: + raise APIError("Non-200 HTTP response status: %s" % response['status']) + + def login(self, user, password): + "Login to the Eventful API as USER with PASSWORD." + nonce = self.call('/users/login')['nonce'] + response = md5.new(nonce + ':' + + md5.new(password).hexdigest()).hexdigest() + login = self.call('/users/login', user=user, nonce=nonce, + response=response) + self.user_key = login['user_key'] + self.user = user + return user diff --git a/assignments/session03/eventmap_mash.py b/assignments/session03/eventmap_mash.py new file mode 100644 index 00000000..3b7fd840 --- /dev/null +++ b/assignments/session03/eventmap_mash.py @@ -0,0 +1,60 @@ +__author__ = 'brianschmitz' + + + + +import eventful + +api = eventful.API('test_key', cache='.cache') +# api.login('username', 'password') +events = api.call('/events/search', q='running', l='Seattle', ) + +for event in events['events']['event']: + print "%s at %s" % (event['title'], event['venue_name'],) + print event['start_time'] + print event['description'] + +import requests + +URL = 'https://www.google.com/search?pz=1&cf=all&ned=us&hl=en&tbm=nws&gl=us&as_q={query}&as_occt=any&as_drrb=b&as_mindate={month}%2F%{from_day}%2F{year}&as_maxdate={month}%2F{to_day}%2F{year}&tbs=cdr%3A1%2Ccd_min%3A3%2F1%2F13%2Ccd_max%3A3%2F2%2F13&as_nsrc=Gulf%20Times&authuser=0' + + +def run(**params): + response = requests.get(URL.format(**params)) + print response.content, response.status_code + + +# run(query=event['description'], month=1, from_day=1, to_day=1, year=14) + +# -*- coding: utf-8 -*- +import urllib +import urllib2 +import json + +def main(event): + query = event + print bing_search(query, 'Web') + # print bing_search(query, 'Image') + +def bing_search(query, search_type): + #search_type: Web, Image, News, Video + key= 'fIXP2iI8QV2pPFpJBao3e5lfrMP8B27CtQ5c2UkKq3w' + query = urllib.quote(query) + # create credential for authentication + user_agent = 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; FDM; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 1.1.4322)' + credentials = (':%s' % key).encode('base64')[:-1] + auth = 'Basic %s' % credentials + url = 'https://api.datamarket.azure.com/Data.ashx/Bing/Search/'+search_type+'?Query=%27'+query+'%27&$top=5&$format=json' + request = urllib2.Request(url) + request.add_header('Authorization', auth) + request.add_header('User-Agent', user_agent) + request_opener = urllib2.build_opener() + response = request_opener.open(request) + response_data = response.read() + json_result = json.loads(response_data) + result_list = json_result['d']['results'] + print result_list + return result_list + +if __name__ == "__main__": + main(event['description']) \ No newline at end of file diff --git a/assignments/session04/sql/createdb.py b/assignments/session04/sql/createdb.py index 429bbdbf..e9d72ee2 100644 --- a/assignments/session04/sql/createdb.py +++ b/assignments/session04/sql/createdb.py @@ -1,11 +1,30 @@ import os import sqlite3 +from utils import show_table_metadata DB_FILENAME = 'books.db' DB_IS_NEW = not os.path.exists(DB_FILENAME) +DB_FILENAME = 'books.db' +SCHEMA_FILENAME = 'ddl.sql' # <- this is new +DB_IS_NEW = not os.path.exists(DB_FILENAME) + def main(): - pass + with sqlite3.connect(DB_FILENAME) as conn: # <- context mgr + if DB_IS_NEW: # A whole new if clause: + print 'Creating schema' + with open(SCHEMA_FILENAME, 'rt') as f: + schema = f.read() + conn.executescript(schema) + else: + # in the else clause, replace the print statement with this: + print "Database exists, introspecting:" + tablenames = ['author', 'book'] + cursor = conn.cursor() + for name in tablenames: + print "\n" + show_table_metadata(cursor, name) + # delete the `conn.close()` that was here. if __name__ == '__main__': main() \ No newline at end of file diff --git a/assignments/session04/sql/populatedb.py b/assignments/session04/sql/populatedb.py index 92baff4d..acdcff91 100644 --- a/assignments/session04/sql/populatedb.py +++ b/assignments/session04/sql/populatedb.py @@ -35,10 +35,36 @@ def show_books(conn): query = book_query show_query_results(conn, query) +def populate_db(conn): + authors = ([author] for author in AUTHORS_BOOKS.keys()) + cur = conn.cursor() + cur.executemany(author_insert, authors) + + for author in AUTHORS_BOOKS.keys(): + params = ([book, author] for book in AUTHORS_BOOKS[author]) + cur.executemany(book_insert, params) if __name__ == '__main__': if DB_IS_NEW: print "Database does not yet exist, please import `createdb` first" sys.exit(1) - print "Do something cool here" + with sqlite3.connect(DB_FILENAME) as conn1: + with sqlite3.connect(DB_FILENAME) as conn2: + try: + populate_db(conn1) + print "\nauthors and books on conn2 before commit:" + show_authors(conn2) + show_books(conn2) + except sqlite3.Error: + conn1.rollback() + print "\nauthors and books on conn2 after rollback:" + show_authors(conn2) + show_books(conn2) + raise + else: + conn1.commit() + print "\nauthors and books on conn2 after commit:" + show_authors(conn2) + show_books(conn2) + diff --git a/assignments/session04/sql/utils.py b/assignments/session04/sql/utils.py index 750669b1..8192ee2c 100644 --- a/assignments/session04/sql/utils.py +++ b/assignments/session04/sql/utils.py @@ -26,6 +26,6 @@ def show_table_metadata(cursor, tablename): 'China Mieville': ["Perdido Street Station", "The Scar", "King Rat"], 'Frank Herbert': ["Dune", "Hellstrom's Hive"], 'J.R.R. Tolkien': ["The Hobbit", "The Silmarillion"], - 'Susan Cooper': ["The Dark is Rising", ["The Greenwitch"]], + 'Susan Cooper': ["The Dark is Rising", "The Greenwitch"], 'Madeline L\'Engle': ["A Wrinkle in Time", "A Swiftly Tilting Planet"] } diff --git a/assignments/session05/microblog/.idea/.name b/assignments/session05/microblog/.idea/.name new file mode 100644 index 00000000..11ffb000 --- /dev/null +++ b/assignments/session05/microblog/.idea/.name @@ -0,0 +1 @@ +microblog \ No newline at end of file diff --git a/assignments/session05/microblog/.idea/encodings.xml b/assignments/session05/microblog/.idea/encodings.xml new file mode 100644 index 00000000..e206d70d --- /dev/null +++ b/assignments/session05/microblog/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/assignments/session05/microblog/.idea/inspectionProfiles/Project_Default.xml b/assignments/session05/microblog/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 00000000..4bb2e408 --- /dev/null +++ b/assignments/session05/microblog/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/assignments/session05/microblog/.idea/inspectionProfiles/profiles_settings.xml b/assignments/session05/microblog/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 00000000..3b312839 --- /dev/null +++ b/assignments/session05/microblog/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/assignments/session05/microblog/.idea/microblog.iml b/assignments/session05/microblog/.idea/microblog.iml new file mode 100644 index 00000000..82d7c357 --- /dev/null +++ b/assignments/session05/microblog/.idea/microblog.iml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + diff --git a/assignments/session05/microblog/.idea/misc.xml b/assignments/session05/microblog/.idea/misc.xml new file mode 100644 index 00000000..39c829f6 --- /dev/null +++ b/assignments/session05/microblog/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/assignments/session05/microblog/.idea/modules.xml b/assignments/session05/microblog/.idea/modules.xml new file mode 100644 index 00000000..ad8d82bd --- /dev/null +++ b/assignments/session05/microblog/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assignments/session05/microblog/.idea/scopes/scope_settings.xml b/assignments/session05/microblog/.idea/scopes/scope_settings.xml new file mode 100644 index 00000000..922003b8 --- /dev/null +++ b/assignments/session05/microblog/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/assignments/session05/microblog/.idea/sqldialects.xml b/assignments/session05/microblog/.idea/sqldialects.xml new file mode 100644 index 00000000..a4ded715 --- /dev/null +++ b/assignments/session05/microblog/.idea/sqldialects.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assignments/session05/microblog/.idea/vcs.xml b/assignments/session05/microblog/.idea/vcs.xml new file mode 100644 index 00000000..c80f2198 --- /dev/null +++ b/assignments/session05/microblog/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assignments/session05/microblog/.idea/workspace.xml b/assignments/session05/microblog/.idea/workspace.xml new file mode 100644 index 00000000..b3182726 --- /dev/null +++ b/assignments/session05/microblog/.idea/workspace.xml @@ -0,0 +1,746 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1391563782287 + 1391563782287 + + + 1392083636502 + 1392083636502 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assignments/session05/microblog/microblog.cfg b/assignments/session05/microblog/microblog.cfg index fda11a39..22dbf988 100644 --- a/assignments/session05/microblog/microblog.cfg +++ b/assignments/session05/microblog/microblog.cfg @@ -1,2 +1,5 @@ # application configuration for a Flask microblog DATABASE = 'microblog.db' +SECRET_KEY = "sooperseekritvaluenooneshouldknow" +USERNAME = 'admin' +PASSWORD = 'default' diff --git a/assignments/session05/microblog/microblog.db b/assignments/session05/microblog/microblog.db new file mode 100644 index 00000000..a5ee7198 Binary files /dev/null and b/assignments/session05/microblog/microblog.db differ diff --git a/assignments/session05/microblog/microblog.py b/assignments/session05/microblog/microblog.py index fae4888a..02d7df00 100644 --- a/assignments/session05/microblog/microblog.py +++ b/assignments/session05/microblog/microblog.py @@ -1,62 +1,63 @@ from flask import Flask +import sqlite3 +from contextlib import closing from flask import g from flask import render_template from flask import abort from flask import request from flask import url_for from flask import redirect -import sqlite3 -from contextlib import closing +from flask import session +from flask import flash app = Flask(__name__) app.config.from_pyfile('microblog.cfg') - def connect_db(): return sqlite3.connect(app.config['DATABASE']) - def init_db(): with closing(connect_db()) as db: with app.open_resource('schema.sql') as f: db.cursor().executescript(f.read()) db.commit() - def get_database_connection(): db = getattr(g, 'db', None) if db is None: g.db = db = connect_db() return db - @app.teardown_request def teardown_request(exception): db = getattr(g, 'db', None) if db is not None: db.close() - def write_entry(title, text): con = get_database_connection() - con.execute('insert into entries (title, text) values (?, ?)', - [title, text]) + con.execute('insert into entries (title, text) values (?, ?)', [title, text]) con.commit() - def get_all_entries(): con = get_database_connection() cur = con.execute('SELECT title, text FROM entries ORDER BY id DESC') return [dict(title=row[0], text=row[1]) for row in cur.fetchall()] +def do_login(usr, pwd): + if usr != app.config['USERNAME']: + raise ValueError + elif pwd != app.config['PASSWORD']: + raise ValueError + else: + session['logged_in'] = True @app.route('/') def show_entries(): entries = get_all_entries() return render_template('show_entries.html', entries=entries) - @app.route('/add', methods=['POST']) def add_entry(): try: @@ -65,6 +66,27 @@ def add_entry(): abort(500) return redirect(url_for('show_entries')) +@app.route('/login', methods=['GET', 'POST']) +def login(): + error = None + if request.method == 'POST': + try: + do_login(request.form['username'], + request.form['password']) + except ValueError: + error = "Invalid Login" + else: + flash('You were logged in') + return redirect(url_for('show_entries')) + return render_template('login.html', error=error) + + +@app.route('/logout') +def logout(): + session.pop('logged_in', None) + flash('You were logged out') + return redirect(url_for('show_entries')) + if __name__ == '__main__': app.run(debug=True) diff --git a/assignments/session05/microblog/microblog_tests.py b/assignments/session05/microblog/microblog_tests.py index 57a64f37..20983e3c 100644 --- a/assignments/session05/microblog/microblog_tests.py +++ b/assignments/session05/microblog/microblog_tests.py @@ -1,8 +1,10 @@ import os import tempfile import unittest -import microblog +from flask import session + +import microblog class MicroblogTestCase(unittest.TestCase): @@ -14,16 +16,27 @@ def setUp(self): self.app = microblog.app microblog.init_db() + def tearDown(self): os.close(self.db_fd) os.unlink(microblog.app.config['DATABASE']) + def test_database_setup(self): con = microblog.connect_db() cur = con.execute('PRAGMA table_info(entries);') rows = cur.fetchall() self.assertEquals(len(rows), 3) + def login(self, username, password): + return self.client.post('/login', data=dict( + username=username, + password=password + ), follow_redirects=True) + + def logout(self): + return self.client.get('/logout', follow_redirects=True) + def test_write_entry(self): expected = ("My Title", "My Text") with self.app.test_request_context('/'): @@ -72,6 +85,28 @@ def test_add_entries(self): self.assertTrue('Hello' in actual) self.assertTrue('This is a post' in actual) + def test_login_passes(self): + with self.app.test_request_context('/'): + microblog.do_login(microblog.app.config['USERNAME'], + microblog.app.config['PASSWORD']) + self.assertTrue(session.get('logged_in', False)) + + def test_login_fails(self): + with self.app.test_request_context('/'): + self.assertRaises(ValueError, + microblog.do_login, + microblog.app.config['USERNAME'], + 'incorrectpassword') + + def test_login_logout(self): + response = self.login('admin', 'default') + assert 'You were logged in' in response.data + response = self.logout() + assert 'You were logged out' in response.data + response = self.login('adminx', 'default') + assert 'Invalid username' in response.data + response = self.login('admin', 'defaultx') + assert 'Invalid password' in response.data if __name__ == '__main__': - unittest.main() + unittest.main() \ No newline at end of file diff --git a/assignments/session05/microblog/schema.sql b/assignments/session05/microblog/schema.sql index 71fe0588..81bce6ec 100644 --- a/assignments/session05/microblog/schema.sql +++ b/assignments/session05/microblog/schema.sql @@ -3,4 +3,4 @@ create table entries ( id integer primary key autoincrement, title string not null, text string not null -); +); \ No newline at end of file diff --git a/assignments/session05/microblog/static/style.css b/assignments/session05/microblog/static/style.css index 80218c4f..3c24310b 100644 --- a/assignments/session05/microblog/static/style.css +++ b/assignments/session05/microblog/static/style.css @@ -17,4 +17,4 @@ h2 { font-size: 1.4em; } margin-bottom: 1em; background: #fafafa; border: 1px solid #1E727F} .flash { width: 30%; background: #00B0CC; padding: 1em; border: 1px solid #1E727F; margin-bottom: 1em;} -.error { background: #F0D6D6; padding: 0.5em; } +.error { background: #F0D6D6; padding: 0.5em; } \ No newline at end of file diff --git a/assignments/session05/microblog/templates/layout.html b/assignments/session05/microblog/templates/layout.html index e13b1287..37fbbacb 100644 --- a/assignments/session05/microblog/templates/layout.html +++ b/assignments/session05/microblog/templates/layout.html @@ -1,13 +1,24 @@ - - Microblog! - - - -

My Microblog

-
- {% block body %}{% endblock %} + + Flaskr + + + +

My Microblog

+
+ {% if not session.logged_in %} + log in + {% else %} + log_out + {% endif %}
- + {% for message in get_flashed_messages() %} +
{{ message }}
+ {% endfor %} +
+ {% block body %}{% endblock %} +
+ + diff --git a/assignments/session05/microblog/templates/login.html b/assignments/session05/microblog/templates/login.html new file mode 100644 index 00000000..86de3647 --- /dev/null +++ b/assignments/session05/microblog/templates/login.html @@ -0,0 +1,20 @@ +{% extends "layout.html" %} +{% block body %} +

Login

+ {% if error -%} +

Error {{ error }} + {%- endif %} +

+
+ + +
+
+ + +
+
+ +
+
+{% endblock %} \ No newline at end of file diff --git a/assignments/session05/microblog/templates/show_entries.html b/assignments/session05/microblog/templates/show_entries.html index 07738258..f44fd92b 100644 --- a/assignments/session05/microblog/templates/show_entries.html +++ b/assignments/session05/microblog/templates/show_entries.html @@ -1,5 +1,6 @@ {% extends "layout.html" %} {% block body %} + {% if session.logged_in %}
@@ -13,6 +14,7 @@
+ {% endif %}

Posts

-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/assignments/session07/mysite/myblog/admin.py b/assignments/session07/mysite/myblog/admin.py index 67aec2d6..b92aeb3d 100644 --- a/assignments/session07/mysite/myblog/admin.py +++ b/assignments/session07/mysite/myblog/admin.py @@ -1,6 +1,10 @@ from django.contrib import admin from myblog.models import Post from myblog.models import Category +from myblog.models import PostAdmin +from myblog.models import CategoryAdmin + +admin.site.register(Post, PostAdmin, ) +admin.site.register(Category, CategoryAdmin, ) + -admin.site.register(Post) -admin.site.register(Category) diff --git a/assignments/session07/mysite/myblog/models.py b/assignments/session07/mysite/myblog/models.py index 29b851c7..d3f97bd1 100644 --- a/assignments/session07/mysite/myblog/models.py +++ b/assignments/session07/mysite/myblog/models.py @@ -1,16 +1,20 @@ from django.db import models from django.contrib.auth.models import User +from django.contrib import admin + + class Post(models.Model): - title = models.CharField(max_length=128) - text = models.TextField(blank=True) - author = models.ForeignKey(User) - created_date = models.DateTimeField(auto_now_add=True) - modified_date = models.DateTimeField(auto_now=True) - published_date = models.DateTimeField(blank=True, null=True) + title = models.CharField(max_length=128) + text = models.TextField(blank=True) + author = models.ForeignKey(User) + created_date = models.DateTimeField(auto_now_add=True) + modified_date = models.DateTimeField(auto_now=True) + published_date = models.DateTimeField(blank=True, null=True) + + def __unicode__(self): + return self.title - def __unicode__(self): - return self.title class Category(models.Model): name = models.CharField(max_length=128) @@ -19,4 +23,29 @@ class Category(models.Model): related_name='categories') def __unicode__(self): - return self.name \ No newline at end of file + return self.name + + +class CategoryAdmin(admin.ModelAdmin): + + list_display = ('name', 'description') + exclude = ('posts', ) + + def __unicode__(self): + return self.name + + +class CategoryInline(admin.TabularInline): + model = Category + + +class PostAdmin(admin.ModelAdmin): + + list_display = ('title', 'author', 'created_date', 'modified_date', ) + inlines = [CategoryInline, ] + + def __unicode__(self): + return self.name + + + diff --git a/assignments/session07/mysite/mysite.db b/assignments/session07/mysite/mysite.db index 63c9e9a5..ae54a037 100644 Binary files a/assignments/session07/mysite/mysite.db and b/assignments/session07/mysite/mysite.db differ diff --git a/resources/session02/http_server.py b/resources/session02/http_server.py index cac6911a..b5ede259 100644 --- a/resources/session02/http_server.py +++ b/resources/session02/http_server.py @@ -9,7 +9,11 @@ def server(log_buffer=sys.stderr): print >>log_buffer, "making a server on {0}:{1}".format(*address) sock.bind(address) sock.listen(1) - + + def response_ok(): + resp.[] + resp.append("HTTP/1.1 200 OK') + try: while True: print >>log_buffer, 'waiting for a connection' @@ -17,9 +21,10 @@ def server(log_buffer=sys.stderr): try: print >>log_buffer, 'connection - {0}:{1}'.format(*addr) while True: - data = conn.recv(16) + data = conn.recv(1024) print >>log_buffer, 'received "{0}"'.format(data) - if data: + if len(data) > 1024: + msg = 'sending data back to client' print >>log_buffer, msg conn.sendall(data) diff --git a/resources/session03/mashup.py b/resources/session03/mashup.py index 5ebfc490..c10aba24 100644 --- a/resources/session03/mashup.py +++ b/resources/session03/mashup.py @@ -20,6 +20,7 @@ def fetch_search_results( def parse_source(html, encoding='utf-8'): + html = open('craigslist_results.html', 'r') parsed = BeautifulSoup(html, from_encoding=encoding) return parsed @@ -82,11 +83,20 @@ def add_walkscore(listing): if __name__ == '__main__': - html, encoding = fetch_search_results( - minAsk=500, maxAsk=1000, bedrooms=2 - ) + + # html, encoding = fetch_search_results( + # minAsk=500, maxAsk=1000, bedrooms=2 + #) + html = '' + encoding = 'utf-8' + doc = parse_source(html, encoding) - for listing in extract_listings(doc): - listing = add_address(listing) - listing = add_walkscore(listing) - pprint.pprint(listing) + listings = extract_listings(doc) + + #for listings in listings + print listings + #for listing in extract_listings(doc): + # listing = add_address(listing) + # listing = add_walkscore(listing) + # pprint.pprint(listing) + print doc.prettify() \ No newline at end of file diff --git a/resources/session04/cgi/cgi-bin/cgi_1.py b/resources/session04/cgi/cgi-bin/cgi_1.py index 7dfafcd2..27936f82 100755 --- a/resources/session04/cgi/cgi-bin/cgi_1.py +++ b/resources/session04/cgi/cgi-bin/cgi_1.py @@ -1,5 +1,11 @@ -#!/usr/bin/env python - +#!/usr/bin/python import cgi +import cgitb + + +cgitb.enable + + + cgi.test() diff --git a/resources/session04/cgi/cgi-bin/cgi_2.py b/resources/session04/cgi/cgi-bin/cgi_2.py index eb6f2702..8b9744c5 100755 --- a/resources/session04/cgi/cgi-bin/cgi_2.py +++ b/resources/session04/cgi/cgi-bin/cgi_2.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env/python import cgi import cgitb cgitb.enable() diff --git a/resources/session04/wsgi/bookapp.py b/resources/session04/wsgi/bookapp.py index f543adf1..c2eeead5 100644 --- a/resources/session04/wsgi/bookapp.py +++ b/resources/session04/wsgi/bookapp.py @@ -5,19 +5,65 @@ DB = BookDB() -def book(book_id): - return "

a book with id %s

" % book_id +def book(book_id): + page = """ +

{title}

+ + + + +
Author{author}
Publisher{publisher}
ISBN{isbn}
+Back to the list +""" + book = DB.title_info(book_id) + if book is None: + raise NameError + return page.format(**book) def books(): - return "

a list of books

" + all_books = DB.titles() + body = ['

My Bookshelf

', '') + return '\n'.join(body) def application(environ, start_response): - status = "200 OK" - headers = [('Content-type', 'text/html')] - start_response(status, headers) - return ["

No Progress Yet

", ] + headers = [("Content-type", "text/html")] + try: + path = environ.get('PATH_INFO', None) + if path is None: + raise NameError + func, args = resolve_path(path) + body = func(*args) + status = "200 OK" + except NameError: + status = "404 Not Found" + body = "

Not Found

" + except Exception: + status = "500 Internal Server Error" + body = "

Internal Server Error

" + finally: + headers.append(('Content-length', str(len(body)))) + start_response(status, headers) + return [body] + +def resolve_path(path): + urls = [(r'^$', books), + (r'^book/(id[\d]+)$', book)] + matchpath = path.lstrip('/') + for regexp, func in urls: + match = re.match(regexp, matchpath) + if match is None: + continue + args = match.groups([]) + return func, args + # we get here if no url matches + raise NameError + if __name__ == '__main__': diff --git a/resources/session05/sql/books.db b/resources/session05/sql/books.db new file mode 100644 index 00000000..3aaf9b71 Binary files /dev/null and b/resources/session05/sql/books.db differ diff --git a/resources/session06/microblog/.idea/.name b/resources/session06/microblog/.idea/.name new file mode 100644 index 00000000..11ffb000 --- /dev/null +++ b/resources/session06/microblog/.idea/.name @@ -0,0 +1 @@ +microblog \ No newline at end of file diff --git a/resources/session06/microblog/.idea/encodings.xml b/resources/session06/microblog/.idea/encodings.xml new file mode 100644 index 00000000..e206d70d --- /dev/null +++ b/resources/session06/microblog/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/session06/microblog/.idea/microblog.iml b/resources/session06/microblog/.idea/microblog.iml new file mode 100644 index 00000000..496ca957 --- /dev/null +++ b/resources/session06/microblog/.idea/microblog.iml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/resources/session06/microblog/.idea/misc.xml b/resources/session06/microblog/.idea/misc.xml new file mode 100644 index 00000000..480c2642 --- /dev/null +++ b/resources/session06/microblog/.idea/misc.xml @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/resources/session06/microblog/.idea/modules.xml b/resources/session06/microblog/.idea/modules.xml new file mode 100644 index 00000000..ad8d82bd --- /dev/null +++ b/resources/session06/microblog/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/resources/session06/microblog/.idea/scopes/scope_settings.xml b/resources/session06/microblog/.idea/scopes/scope_settings.xml new file mode 100644 index 00000000..922003b8 --- /dev/null +++ b/resources/session06/microblog/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/resources/session06/microblog/.idea/vcs.xml b/resources/session06/microblog/.idea/vcs.xml new file mode 100644 index 00000000..def6a6a1 --- /dev/null +++ b/resources/session06/microblog/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/session06/microblog/.idea/workspace.xml b/resources/session06/microblog/.idea/workspace.xml new file mode 100644 index 00000000..ec706091 --- /dev/null +++ b/resources/session06/microblog/.idea/workspace.xml @@ -0,0 +1,497 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1391967870977 + 1391967870977 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/session06/microblog/microblog_tests.py b/resources/session06/microblog/microblog_tests.py index 3e910226..350afa85 100644 --- a/resources/session06/microblog/microblog_tests.py +++ b/resources/session06/microblog/microblog_tests.py @@ -97,6 +97,7 @@ def test_login_logout(self): assert 'You were logged out' in response.data # verify that incorrect credentials get a proper message response = self.login('notadmin', 'secret') + #import pdb;pdb.set_trace() assert 'Invalid Login' in response.data response = self.login('admin', 'notsosecret') assert 'Invalid Login' in response.data diff --git a/resources/session09/wikitutorial/CHANGES.txt b/resources/session09/wikitutorial/CHANGES.txt new file mode 100644 index 00000000..35a34f33 --- /dev/null +++ b/resources/session09/wikitutorial/CHANGES.txt @@ -0,0 +1,4 @@ +0.0 +--- + +- Initial version diff --git a/resources/session09/wikitutorial/MANIFEST.in b/resources/session09/wikitutorial/MANIFEST.in new file mode 100644 index 00000000..8bf2ce54 --- /dev/null +++ b/resources/session09/wikitutorial/MANIFEST.in @@ -0,0 +1,2 @@ +include *.txt *.ini *.cfg *.rst +recursive-include wikitutorial *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml diff --git a/resources/session09/wikitutorial/README.txt b/resources/session09/wikitutorial/README.txt new file mode 100644 index 00000000..0d22b384 --- /dev/null +++ b/resources/session09/wikitutorial/README.txt @@ -0,0 +1 @@ +wikitutorial README diff --git a/resources/session09/wikitutorial/development.ini b/resources/session09/wikitutorial/development.ini new file mode 100644 index 00000000..9dc585f2 --- /dev/null +++ b/resources/session09/wikitutorial/development.ini @@ -0,0 +1,65 @@ +### +# app configuration +# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html +### + +[app:main] +use = egg:wikitutorial + +pyramid.reload_templates = true +pyramid.debug_authorization = false +pyramid.debug_notfound = false +pyramid.debug_routematch = false +pyramid.default_locale_name = en +pyramid.includes = + pyramid_debugtoolbar + pyramid_zodbconn + pyramid_tm + +tm.attempts = 3 +zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 + +# By default, the toolbar only appears for clients from IP addresses +# '127.0.0.1' and '::1'. +# debugtoolbar.hosts = 127.0.0.1 ::1 + +### +# wsgi server configuration +### + +[server:main] +use = egg:waitress#main +host = 0.0.0.0 +port = 6543 + +### +# logging configuration +# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html +### + +[loggers] +keys = root, wikitutorial + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = INFO +handlers = console + +[logger_wikitutorial] +level = DEBUG +handlers = +qualname = wikitutorial + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s diff --git a/resources/session09/wikitutorial/production.ini b/resources/session09/wikitutorial/production.ini new file mode 100644 index 00000000..2b952479 --- /dev/null +++ b/resources/session09/wikitutorial/production.ini @@ -0,0 +1,60 @@ +### +# app configuration +# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html +### + +[app:main] +use = egg:wikitutorial + +pyramid.reload_templates = false +pyramid.debug_authorization = false +pyramid.debug_notfound = false +pyramid.debug_routematch = false +pyramid.default_locale_name = en +pyramid.includes = + pyramid_tm + pyramid_zodbconn + +tm.attempts = 3 +zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 + +### +# wsgi server configuration +### + +[server:main] +use = egg:waitress#main +host = 0.0.0.0 +port = 6543 + +### +# logging configuration +# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html +### + +[loggers] +keys = root, wikitutorial + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console + +[logger_wikitutorial] +level = WARN +handlers = +qualname = wikitutorial + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s diff --git a/resources/session09/wikitutorial/setup.cfg b/resources/session09/wikitutorial/setup.cfg new file mode 100644 index 00000000..46289de6 --- /dev/null +++ b/resources/session09/wikitutorial/setup.cfg @@ -0,0 +1,27 @@ +[nosetests] +match=^test +nocapture=1 +cover-package=wikitutorial +with-coverage=1 +cover-erase=1 + +[compile_catalog] +directory = wikitutorial/locale +domain = wikitutorial +statistics = true + +[extract_messages] +add_comments = TRANSLATORS: +output_file = wikitutorial/locale/wikitutorial.pot +width = 80 + +[init_catalog] +domain = wikitutorial +input_file = wikitutorial/locale/wikitutorial.pot +output_dir = wikitutorial/locale + +[update_catalog] +domain = wikitutorial +input_file = wikitutorial/locale/wikitutorial.pot +output_dir = wikitutorial/locale +previous = true diff --git a/resources/session09/wikitutorial/setup.py b/resources/session09/wikitutorial/setup.py new file mode 100644 index 00000000..84321969 --- /dev/null +++ b/resources/session09/wikitutorial/setup.py @@ -0,0 +1,44 @@ +import os + +from setuptools import setup, find_packages + +here = os.path.abspath(os.path.dirname(__file__)) +README = open(os.path.join(here, 'README.txt')).read() +CHANGES = open(os.path.join(here, 'CHANGES.txt')).read() + +requires = [ + 'pyramid', + 'pyramid_zodbconn', + 'transaction', + 'pyramid_tm', + 'pyramid_debugtoolbar', + 'ZODB3', + 'waitress', + 'docutils', + ] + +setup(name='wikitutorial', + version='0.0', + description='wikitutorial', + long_description=README + '\n\n' + CHANGES, + classifiers=[ + "Programming Language :: Python", + "Framework :: Pyramid", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", + ], + author='', + author_email='', + url='', + keywords='web pylons pyramid', + packages=find_packages(), + include_package_data=True, + zip_safe=False, + install_requires=requires, + tests_require=requires, + test_suite="wikitutorial", + entry_points="""\ + [paste.app_factory] + main = wikitutorial:main + """, + ) diff --git a/resources/session09/wikitutorial/wikitutorial/__init__.py b/resources/session09/wikitutorial/wikitutorial/__init__.py new file mode 100644 index 00000000..c3bb87a6 --- /dev/null +++ b/resources/session09/wikitutorial/wikitutorial/__init__.py @@ -0,0 +1,17 @@ +from pyramid.config import Configurator +from pyramid_zodbconn import get_connection +from .models import appmaker + + +def root_factory(request): + conn = get_connection(request) + return appmaker(conn.root()) + + +def main(global_config, **settings): + """ This function returns a Pyramid WSGI application. + """ + config = Configurator(root_factory=root_factory, settings=settings) + config.add_static_view('static', 'static', cache_max_age=3600) + config.scan() + return config.make_wsgi_app() diff --git a/resources/session09/wikitutorial/wikitutorial/models.py b/resources/session09/wikitutorial/wikitutorial/models.py new file mode 100644 index 00000000..c62f3a86 --- /dev/null +++ b/resources/session09/wikitutorial/wikitutorial/models.py @@ -0,0 +1,27 @@ +from persistent.mapping import PersistentMapping +from persistent import Persistent + + +class Wiki(PersistentMapping): + + __name__ = None + __parent__ = None + + +class Page(Persistent): + + def __init__(self, data): + self.data = data + + +def appmaker(zodb_root): + if not 'app_root' in zodb_root: + app_root = Wiki() + frontpage = Page('This is the front page') + app_root['FrontPage'] = frontpage + frontpage.__name__ = 'FrontPage' + frontpage.__parent__ = app_root + zodb_root['app_root'] = app_root + import transaction + transaction.commit() + return zodb_root['app_root'] diff --git a/resources/session09/wikitutorial/wikitutorial/static/favicon.ico b/resources/session09/wikitutorial/wikitutorial/static/favicon.ico new file mode 100644 index 00000000..71f837c9 Binary files /dev/null and b/resources/session09/wikitutorial/wikitutorial/static/favicon.ico differ diff --git a/resources/session09/wikitutorial/wikitutorial/static/footerbg.png b/resources/session09/wikitutorial/wikitutorial/static/footerbg.png new file mode 100644 index 00000000..1fbc873d Binary files /dev/null and b/resources/session09/wikitutorial/wikitutorial/static/footerbg.png differ diff --git a/resources/session09/wikitutorial/wikitutorial/static/headerbg.png b/resources/session09/wikitutorial/wikitutorial/static/headerbg.png new file mode 100644 index 00000000..0596f202 Binary files /dev/null and b/resources/session09/wikitutorial/wikitutorial/static/headerbg.png differ diff --git a/resources/session09/wikitutorial/wikitutorial/static/ie6.css b/resources/session09/wikitutorial/wikitutorial/static/ie6.css new file mode 100644 index 00000000..b7c8493d --- /dev/null +++ b/resources/session09/wikitutorial/wikitutorial/static/ie6.css @@ -0,0 +1,8 @@ +* html img, +* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none", +this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')", +this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("https://github.com/','').replace('")',''), +this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')", +this.runtimeStyle.backgroundImage = "none")),this.pngSet=true) +);} +#wrap{display:table;height:100%} diff --git a/resources/session09/wikitutorial/wikitutorial/static/middlebg.png b/resources/session09/wikitutorial/wikitutorial/static/middlebg.png new file mode 100644 index 00000000..2369cfb7 Binary files /dev/null and b/resources/session09/wikitutorial/wikitutorial/static/middlebg.png differ diff --git a/resources/session09/wikitutorial/wikitutorial/static/pylons.css b/resources/session09/wikitutorial/wikitutorial/static/pylons.css new file mode 100644 index 00000000..4b1c017c --- /dev/null +++ b/resources/session09/wikitutorial/wikitutorial/static/pylons.css @@ -0,0 +1,372 @@ +html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td +{ + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-size: 100%; /* 16px */ + vertical-align: baseline; + background: transparent; +} + +body +{ + line-height: 1; +} + +ol, ul +{ + list-style: none; +} + +blockquote, q +{ + quotes: none; +} + +blockquote:before, blockquote:after, q:before, q:after +{ + content: ''; + content: none; +} + +:focus +{ + outline: 0; +} + +ins +{ + text-decoration: none; +} + +del +{ + text-decoration: line-through; +} + +table +{ + border-collapse: collapse; + border-spacing: 0; +} + +sub +{ + vertical-align: sub; + font-size: smaller; + line-height: normal; +} + +sup +{ + vertical-align: super; + font-size: smaller; + line-height: normal; +} + +ul, menu, dir +{ + display: block; + list-style-type: disc; + margin: 1em 0; + padding-left: 40px; +} + +ol +{ + display: block; + list-style-type: decimal-leading-zero; + margin: 1em 0; + padding-left: 40px; +} + +li +{ + display: list-item; +} + +ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl +{ + margin-top: 0; + margin-bottom: 0; +} + +ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir +{ + list-style-type: circle; +} + +ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir +{ + list-style-type: square; +} + +.hidden +{ + display: none; +} + +p +{ + line-height: 1.5em; +} + +h1 +{ + font-size: 1.75em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +h2 +{ + font-size: 1.5em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +h3 +{ + font-size: 1.25em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +h4 +{ + font-size: 1em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +html, body +{ + width: 100%; + height: 100%; +} + +body +{ + margin: 0; + padding: 0; + background-color: #fff; + position: relative; + font: 16px/24px NobileRegular, "Lucida Grande", Lucida, Verdana, sans-serif; +} + +a +{ + color: #1b61d6; + text-decoration: none; +} + +a:hover +{ + color: #e88f00; + text-decoration: underline; +} + +body h1, body h2, body h3, body h4, body h5, body h6 +{ + font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif; + font-weight: 400; + color: #373839; + font-style: normal; +} + +#wrap +{ + min-height: 100%; +} + +#header, #footer +{ + width: 100%; + color: #fff; + height: 40px; + position: absolute; + text-align: center; + line-height: 40px; + overflow: hidden; + font-size: 12px; + vertical-align: middle; +} + +#header +{ + background: #000; + top: 0; + font-size: 14px; +} + +#footer +{ + bottom: 0; + background: #000 url(https://github.com/footerbg.png) repeat-x 0 top; + position: relative; + margin-top: -40px; + clear: both; +} + +.header, .footer +{ + width: 750px; + margin-right: auto; + margin-left: auto; +} + +.wrapper +{ + width: 100%; +} + +#top, #top-small, #bottom +{ + width: 100%; +} + +#top +{ + color: #000; + height: 230px; + background: #fff url(https://github.com/headerbg.png) repeat-x 0 top; + position: relative; +} + +#top-small +{ + color: #000; + height: 60px; + background: #fff url(https://github.com/headerbg.png) repeat-x 0 top; + position: relative; +} + +#bottom +{ + color: #222; + background-color: #fff; +} + +.top, .top-small, .middle, .bottom +{ + width: 750px; + margin-right: auto; + margin-left: auto; +} + +.top +{ + padding-top: 40px; +} + +.top-small +{ + padding-top: 10px; +} + +#middle +{ + width: 100%; + height: 100px; + background: url(https://github.com/middlebg.png) repeat-x; + border-top: 2px solid #fff; + border-bottom: 2px solid #b2b2b2; +} + +.app-welcome +{ + margin-top: 25px; +} + +.app-name +{ + color: #000; + font-weight: 700; +} + +.bottom +{ + padding-top: 50px; +} + +#left +{ + width: 350px; + float: left; + padding-right: 25px; +} + +#right +{ + width: 350px; + float: right; + padding-left: 25px; +} + +.align-left +{ + text-align: left; +} + +.align-right +{ + text-align: right; +} + +.align-center +{ + text-align: center; +} + +ul.links +{ + margin: 0; + padding: 0; +} + +ul.links li +{ + list-style-type: none; + font-size: 14px; +} + +form +{ + border-style: none; +} + +fieldset +{ + border-style: none; +} + +input +{ + color: #222; + border: 1px solid #ccc; + font-family: sans-serif; + font-size: 12px; + line-height: 16px; +} + +input[type=text], input[type=password] +{ + width: 205px; +} + +input[type=submit] +{ + background-color: #ddd; + font-weight: 700; +} + +/*Opera Fix*/ +body:before +{ + content: ""; + height: 100%; + float: left; + width: 0; + margin-top: -32767px; +} diff --git a/resources/session09/wikitutorial/wikitutorial/static/pyramid-small.png b/resources/session09/wikitutorial/wikitutorial/static/pyramid-small.png new file mode 100644 index 00000000..a5bc0ade Binary files /dev/null and b/resources/session09/wikitutorial/wikitutorial/static/pyramid-small.png differ diff --git a/resources/session09/wikitutorial/wikitutorial/static/pyramid.png b/resources/session09/wikitutorial/wikitutorial/static/pyramid.png new file mode 100644 index 00000000..347e0554 Binary files /dev/null and b/resources/session09/wikitutorial/wikitutorial/static/pyramid.png differ diff --git a/resources/session09/wikitutorial/wikitutorial/static/transparent.gif b/resources/session09/wikitutorial/wikitutorial/static/transparent.gif new file mode 100644 index 00000000..0341802e Binary files /dev/null and b/resources/session09/wikitutorial/wikitutorial/static/transparent.gif differ diff --git a/resources/session09/wikitutorial/wikitutorial/templates/mytemplate.pt b/resources/session09/wikitutorial/wikitutorial/templates/mytemplate.pt new file mode 100644 index 00000000..5391509f --- /dev/null +++ b/resources/session09/wikitutorial/wikitutorial/templates/mytemplate.pt @@ -0,0 +1,76 @@ + + + + The Pyramid Web Application Development Framework + + + + + + + + + + +
+
+
+
pyramid
+
+
+
+
+

+ Welcome to ${project}, an application generated by
+ the Pyramid web application development framework. +

+
+
+
+
+
+

Search documentation

+
+ + +
+
+ +
+
+
+ + + diff --git a/resources/session09/wikitutorial/wikitutorial/templates/view.pt b/resources/session09/wikitutorial/wikitutorial/templates/view.pt new file mode 100644 index 00000000..e69de29b diff --git a/resources/session09/wikitutorial/wikitutorial/tests.py b/resources/session09/wikitutorial/wikitutorial/tests.py new file mode 100644 index 00000000..e168fba4 --- /dev/null +++ b/resources/session09/wikitutorial/wikitutorial/tests.py @@ -0,0 +1,78 @@ +import unittest + +from pyramid import testing + + +class WikiModelTests(unittest.TestCase): + + def _getTargetClass(self): + from wikitutorial.models import Wiki + return Wiki + + def _makeOne(self): + return self._getTargetClass()() + + def test_constructor(self): + wiki = self._makeOne() + self.assertEqual(wiki.__parent__, None) + self.assertEqual(wiki.__name__, None) + + +class PageModelTests(unittest.TestCase): + + def _getTargetClass(self): + from wikitutorial.models import Page + return Page + + def _makeOne(self, data=u'some data'): + return self._getTargetClass()(data=data) + + def test_constructor(self): + instance = self._makeOne() + self.assertEqual(instance.data, u'some data') + + +class AppmakerTests(unittest.TestCase): + + def _callFUT(self, zodb_root): + from wikitutorial.models import appmaker + return appmaker(zodb_root) + + def test_initialization(self): + root = {} + self._callFUT(root) + self.assertEqual(root['app_root']['FrontPage'].data, + 'This is the front page') + +class WikiViewTests(unittest.TestCase): + + def test_redirect(self): + from wikitutorial.views import view_wiki + context = testing.DummyResource() + request = testing.DummyRequest() + response = view_wiki(context, request) + self.assertEqual(response.location, + 'http://example.com/FrontPage') + + +class PageViewTests(unittest.TestCase): + def _callFUT(self, context, request): + from wikitutorial.views import view_page + return view_page(context, request) + + def test_it(self): + wiki = testing.DummyResource() + wiki['IDoExist'] = testing.DummyResource() #<- add this + context = testing.DummyResource(data='Hello CruelWorld IDoExist') + context.__parent__ = wiki + context.__name__ = 'thepage' + request = testing.DummyRequest() + info = self._callFUT(context, request) + self.assertTrue('
' in info['content']) + for word in context.data.split(): + self.assertTrue(word in info['content']) + for url in (request.resource_url(https://github.com/wiki['IDoExist']), + request.resource_url(https://github.com/wiki,%20'add_page',%20'CruelWorld')): + self.assertTrue(url in info['content']) + self.assertEqual(info['edit_url'], + 'http://example.com/thepage/edit_page') diff --git a/resources/session09/wikitutorial/wikitutorial/views.py b/resources/session09/wikitutorial/wikitutorial/views.py new file mode 100644 index 00000000..6f94a681 --- /dev/null +++ b/resources/session09/wikitutorial/wikitutorial/views.py @@ -0,0 +1,44 @@ +from pyramid.view import view_config +# one import +import re + +# and one module constant +WIKIWORDS = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") + +from pyramid.httpexceptions import HTTPFound +from pyramid.view import view_config # <- ALREADY THERE + +@view_config(context='.models.Wiki') +def view_wiki(context, request): + return HTTPFound(location=request.resource_url(context, + 'FrontPage')) +# an import +from docutils.core import publish_parts + +# and a method +@view_config(context='.models.Page', renderer='templates/view.pt') +def view_page(context, request): + wiki = context.__parent__ + + def check(match): + word = match.group(1) + if word in wiki: + page = wiki[word] + view_url = request.resource_url(https://github.com/page) + return '%s' % (view_url, word) + else: + add_url = request.application_url + '/add_page/' + word + return '%s' % (add_url, word) + + content = publish_parts( + context.data, writer_name='html')['html_body'] + content = WIKIWORDS.sub(check, content) #<- add this line + return #... <- this already exists + +def view_page(context, request): + #... + content = wikiwords.sub(check, content) #<- already there + edit_url = request.resource_url(https://github.com/context,%20'edit_page') #<- add + return dict(page=context, + content=content, + edit_url = edit_url) \ No newline at end of file diff --git a/resources/session10/wikitutorial/Data.fs b/resources/session10/wikitutorial/Data.fs new file mode 100644 index 00000000..5a0f422c Binary files /dev/null and b/resources/session10/wikitutorial/Data.fs differ diff --git a/resources/session10/wikitutorial/Data.fs.index b/resources/session10/wikitutorial/Data.fs.index new file mode 100644 index 00000000..3f4e73a5 Binary files /dev/null and b/resources/session10/wikitutorial/Data.fs.index differ diff --git a/resources/session10/wikitutorial/Data.fs.lock b/resources/session10/wikitutorial/Data.fs.lock new file mode 100644 index 00000000..c6891075 --- /dev/null +++ b/resources/session10/wikitutorial/Data.fs.lock @@ -0,0 +1 @@ + 2998 diff --git a/resources/session10/wikitutorial/Data.fs.tmp b/resources/session10/wikitutorial/Data.fs.tmp new file mode 100644 index 00000000..e69de29b diff --git a/resources/session10/wikitutorial/wikitutorial/templates/edit.pt b/resources/session10/wikitutorial/wikitutorial/templates/edit.pt index 9d6ef02a..a2ee38a2 100644 --- a/resources/session10/wikitutorial/wikitutorial/templates/edit.pt +++ b/resources/session10/wikitutorial/wikitutorial/templates/edit.pt @@ -4,8 +4,8 @@ Page Name Goes Here - - + +