├── .gitignore
├── 2012-03
├── django_on_lighttpd
│ ├── README.md
│ ├── fcgi_demo
│ │ ├── __init__.py
│ │ ├── manage.py
│ │ ├── settings.py
│ │ ├── templates
│ │ │ └── hello.html
│ │ ├── urls.py
│ │ └── web
│ │ │ ├── __init__.py
│ │ │ ├── models.py
│ │ │ ├── tests.py
│ │ │ ├── urls.py
│ │ │ └── views.py
│ ├── lighttpd.conf
│ └── restart_fastcgi.sh
└── python_datetime
│ ├── Python datetime.ppt
│ └── README.txt
├── 2012-05
└── door-prize-meetup-api.py
├── 2012-07
├── pygame-intro
│ ├── Intro To PyGame.odp
│ ├── README.md
│ ├── images
│ │ ├── baddie.png
│ │ └── player.png
│ ├── part1.py
│ ├── part2.py
│ ├── part3.py
│ └── part4.py
└── readlines
│ ├── fileobject.c
│ ├── manylines.txt
│ ├── readlines_all.py
│ ├── readlines_buffersize.py
│ └── readlines_chunks.py
├── 2012-10
├── intro
│ ├── README.rst
│ ├── addresses.ldif
│ ├── extract_addr.py
│ ├── read1.py
│ ├── read2.py
│ └── words.py
└── sorting
│ ├── README.md
│ └── fun_with_sorting.pdf
├── 2012-11
├── heroku-flask
│ ├── Heroku Python Flask.pdf
│ └── README.md
└── intro_photocopy
│ ├── README.rst
│ ├── locator.py
│ ├── photo0.py
│ ├── photo1.py
│ ├── photo2.py
│ └── photocopy.py
├── 2013-02
└── intro_listifying
│ ├── 00_listifying.py
│ ├── 01_print_email.py
│ ├── 02_email_list.py
│ ├── 03_to_do.py
│ ├── 03b_answers_so_i_dont_forget.py
│ ├── 04_listing.py
│ ├── 05_please_sir_i_want_some_more.py
│ ├── 52_cards.py
│ ├── README.rst
│ └── addresses.ldif
├── 2013-04
├── cleaver
│ ├── Cleaver.key
│ ├── README
│ ├── after.py
│ ├── before.py
│ └── report.py
└── intro_taxes
│ ├── 01_csv2.py
│ ├── 01b_csv2.py
│ ├── 02_semantically_enhanced.py
│ ├── 02b_semantically_enhanced.py
│ ├── 03_split_by_bracket.txt
│ ├── README.rst
│ ├── brackets.py
│ ├── simple_brackets.csv
│ ├── split_by_bracket.py
│ ├── split_by_bracket_recursive.py
│ ├── tax.py
│ └── tax_table.py
├── 2013-05
├── IPython
│ ├── README.rst
│ ├── _images
│ │ ├── home.png
│ │ ├── module_path.png
│ │ ├── module_source.png
│ │ └── prompt.png
│ ├── _static
│ │ ├── ajax-loader.gif
│ │ ├── basic.css
│ │ ├── comment-bright.png
│ │ ├── comment-close.png
│ │ ├── comment.png
│ │ ├── common.js
│ │ ├── console.css
│ │ ├── console.js
│ │ ├── controller.js
│ │ ├── custom.css
│ │ ├── doctools.js
│ │ ├── down-pressed.png
│ │ ├── down.png
│ │ ├── file.png
│ │ ├── fonts
│ │ │ ├── droidsansmono-webfont.eot
│ │ │ ├── droidsansmono-webfont.svg
│ │ │ ├── droidsansmono-webfont.ttf
│ │ │ ├── droidsansmono-webfont.woff
│ │ │ ├── generator_config.txt
│ │ │ ├── opensans-italic-webfont.eot
│ │ │ ├── opensans-italic-webfont.svg
│ │ │ ├── opensans-italic-webfont.ttf
│ │ │ ├── opensans-italic-webfont.woff
│ │ │ ├── opensans-light-webfont.eot
│ │ │ ├── opensans-light-webfont.svg
│ │ │ ├── opensans-light-webfont.ttf
│ │ │ ├── opensans-light-webfont.woff
│ │ │ ├── opensans-lightitalic-webfont.eot
│ │ │ ├── opensans-lightitalic-webfont.svg
│ │ │ ├── opensans-lightitalic-webfont.ttf
│ │ │ ├── opensans-lightitalic-webfont.woff
│ │ │ ├── opensans-regular-webfont.eot
│ │ │ ├── opensans-regular-webfont.svg
│ │ │ ├── opensans-regular-webfont.ttf
│ │ │ ├── opensans-regular-webfont.woff
│ │ │ ├── opensans-semibold-webfont.eot
│ │ │ ├── opensans-semibold-webfont.svg
│ │ │ ├── opensans-semibold-webfont.ttf
│ │ │ ├── opensans-semibold-webfont.woff
│ │ │ ├── opensans-semibolditalic-webfont.eot
│ │ │ ├── opensans-semibolditalic-webfont.svg
│ │ │ ├── opensans-semibolditalic-webfont.ttf
│ │ │ ├── opensans-semibolditalic-webfont.woff
│ │ │ └── stylesheet.css
│ │ ├── home.png
│ │ ├── init.js
│ │ ├── jquery.js
│ │ ├── league.css
│ │ ├── leaguegothic
│ │ │ ├── LeagueGothic-CondensedItalic-webfont.eot
│ │ │ ├── LeagueGothic-CondensedItalic-webfont.svg
│ │ │ ├── LeagueGothic-CondensedItalic-webfont.ttf
│ │ │ ├── LeagueGothic-CondensedItalic-webfont.woff
│ │ │ ├── LeagueGothic-CondensedRegular-webfont.eot
│ │ │ ├── LeagueGothic-CondensedRegular-webfont.svg
│ │ │ ├── LeagueGothic-CondensedRegular-webfont.ttf
│ │ │ ├── LeagueGothic-CondensedRegular-webfont.woff
│ │ │ ├── LeagueGothic-Italic-webfont.eot
│ │ │ ├── LeagueGothic-Italic-webfont.svg
│ │ │ ├── LeagueGothic-Italic-webfont.ttf
│ │ │ ├── LeagueGothic-Italic-webfont.woff
│ │ │ ├── LeagueGothic-Regular-webfont.eot
│ │ │ ├── LeagueGothic-Regular-webfont.svg
│ │ │ ├── LeagueGothic-Regular-webfont.ttf
│ │ │ ├── LeagueGothic-Regular-webfont.woff
│ │ │ ├── SIL OFL Font License League Gothic.txt
│ │ │ └── stylesheet.css
│ │ ├── minus.png
│ │ ├── module_path.png
│ │ ├── module_source.png
│ │ ├── plus.png
│ │ ├── prompt.png
│ │ ├── pygments.css
│ │ ├── searchtools.js
│ │ ├── slides.css
│ │ ├── slides.js
│ │ ├── styles.css
│ │ ├── sync.js
│ │ ├── theme.css
│ │ ├── underscore.js
│ │ ├── up-pressed.png
│ │ ├── up.png
│ │ └── websupport.js
│ └── index.html
└── threading
│ ├── README.md
│ ├── barrier.py
│ ├── callback.py
│ └── producer_consumer.py
├── 2013-06
└── fizzbuzz
│ ├── 01_fizz_or_buzz.py
│ ├── 02_fizz_and_buzz.py
│ ├── 03_number.py
│ ├── boring.py
│ ├── clever.py
│ ├── fizzbuzz.py
│ ├── fizzbuzz_tweet.py
│ └── one-liner.sh
├── 2013-07
└── virtualenv
│ ├── Makefile
│ ├── requirements.txt
│ └── source
│ ├── _static
│ ├── .placeholder
│ └── custom.css
│ ├── _templates
│ └── .placeholder
│ ├── conf.py
│ ├── index.rst
│ └── virtualenv_output.txt
├── 2013-09
├── operator-overloading
│ ├── Makefile
│ └── source
│ │ ├── _static
│ │ └── custom.css
│ │ ├── conf.py
│ │ ├── index.rst
│ │ ├── sortable.py
│ │ └── unsorted.py
└── zmq
│ ├── README.rst
│ ├── fizzbuzz
│ ├── buzzer.py
│ ├── fb.py
│ ├── fizzer.py
│ └── ventilator.py
│ ├── hello
│ ├── hwclient.py
│ └── hwserver.py
│ └── image_farm
│ ├── cli_enqueue_images.py
│ ├── farmer.py
│ ├── resize_image.py
│ └── sink.py
├── 2013-10
├── flake8
│ ├── Makefile
│ ├── README.rst
│ └── source
│ │ ├── _static
│ │ └── custom.css
│ │ ├── clean.py
│ │ ├── commits-per-month.png
│ │ ├── conf.py
│ │ ├── contributors-per-month.png
│ │ ├── index.rst
│ │ ├── lines-of-code.png
│ │ └── messy.py
└── objects
│ ├── 15-puzzle_old_version.py
│ ├── NetworkX_sandbox.ipynb
│ ├── README.rst
│ ├── fifteen_puzzle
│ └── __init__.py
│ ├── setup.cfg
│ ├── setup.py
│ └── tests
│ ├── __init__.py
│ ├── conftest.py
│ ├── test_when_calculating_valid_moves.py
│ ├── test_when_create_new_puzzle.py
│ └── test_when_moving.py
├── 2014-08
└── micropython
│ ├── README.md
│ └── demo
│ ├── __init__.py
│ ├── accelerometer.py
│ ├── hello.py
│ ├── leds.py
│ ├── loop.py
│ └── switch.py
├── 2014-09
├── roman
│ ├── 500BC.rst
│ └── README.rst
└── stdlib-tour
│ ├── Makefile
│ ├── requirements.txt
│ └── source
│ ├── _static
│ └── custom.css
│ ├── conf.py
│ ├── dis_simple.py
│ ├── index.rst
│ ├── string_template.py
│ ├── time_info.py
│ ├── trace_main.py
│ └── trace_recurse.py
├── 2015-03
└── redacted-tweets
│ ├── README.md
│ └── redacted_twitter_nick_loadholtes.pdf
├── 2015-06
└── effective_python
│ ├── README.md
│ └── effective_python_presentation.pdf
├── 2015-09
└── help-on-irc
│ ├── README.md
│ └── help-on-irc.pdf
├── 2017-02
└── tcp-socket-file-sharing
│ ├── client
│ ├── helpme.jpg
│ └── serve.py
├── 2017-03-09
└── python-packaging
│ ├── README.md
│ ├── python_packaging.ipynb
│ └── python_packaging.slides.html
├── 2017-10-12
└── python-profiling
│ ├── 1.filesize.py
│ ├── 2.filesize.py
│ ├── 3.display_file.py
│ ├── 4.pstats.py
│ ├── 5.snakeviz.py
│ ├── 6.line_profiling.py
│ └── profiler.py
├── 2019-05-09
├── python_in_security
│ ├── CandidPythonAtlanta20190509-Final.pptx
│ └── README.md
└── responder-tour
│ ├── LICENSE
│ ├── Pipfile
│ ├── Pipfile.lock
│ ├── README.md
│ ├── client.py
│ ├── features.py
│ ├── greeting.py
│ └── templates
│ └── template.html
├── README-hieroglyph.rst
└── bin
└── dates.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *~
3 | build
4 | .venv
5 |
--------------------------------------------------------------------------------
/2012-03/django_on_lighttpd/README.md:
--------------------------------------------------------------------------------
1 | Installing Django on Lighttpd with FastCGI
2 | ==========================================
3 | Speaker: JR Rickerson
4 |
5 | This was a brief lightning talk and demo of the steps necessary to get Django
6 | running under Lighttpd and FastCGI. The process was gleaned from information
7 | on the Django documentation here:
8 | https://docs.djangoproject.com/en/1.3/howto/deployment/fastcgi/
9 |
10 | An example `lighttpd.conf` configuration file is provided here, as is a small,
11 | simple Django "Hello World!" project to test with. Additionally, a sample
12 | bash script for restarting the FastCGI processes is included. Please note that
13 | you will probably have to change several file paths to match your own install.
14 |
15 | Step 1: Installing Lighttpd
16 | ---------------------------
17 |
18 | Use your distro's package manager. For instance, on Ubuntu:
19 | apt-get install lighttpd
20 |
21 | Lighttpd comes with the fastcgi module, so it doesn't need to be installed
22 | separately.
23 |
24 |
25 | Step 2: Install Django and Flup
26 | -------------------------------
27 |
28 | pip install django
29 | pip install flup
30 |
31 |
32 | Step 3: Configure Lighttpd
33 | --------------------------
34 |
35 | - Enable `mod_rewrite` and `mod_fastcgi`
36 | - Set up a virtual host configuration for the right domain
37 | - Point fastcgi module to the appropriate socket file or host/port
38 | - Rewrite any urls you need to for static files
39 | - Restart lighttpd after any configuration changes:
40 | `/etc/init.d/lighttpd restart` on Ubuntu
41 |
42 |
43 | Step 4: Start the Django FastCGI process
44 | ----------------------------------------
45 |
46 | From within the django project, use:
47 | python manage.py runfcgi
48 | and provide whatever options to match your lighttpd configuration and
49 | needs. See here for available options:
50 | https://docs.djangoproject.com/en/1.3/ref/django-admin/#django-admin-runfcgi
51 |
52 | Note that any time you upload new python changes to the webserver, you will
53 | need to restart the FastCGI processes.
54 |
--------------------------------------------------------------------------------
/2012-03/django_on_lighttpd/fcgi_demo/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2012-03/django_on_lighttpd/fcgi_demo/__init__.py
--------------------------------------------------------------------------------
/2012-03/django_on_lighttpd/fcgi_demo/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from django.core.management import execute_manager
3 | import imp
4 | try:
5 | imp.find_module('settings') # Assumed to be in the same directory.
6 | except ImportError:
7 | import sys
8 | sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__)
9 | sys.exit(1)
10 |
11 | import settings
12 |
13 | if __name__ == "__main__":
14 | execute_manager(settings)
15 |
--------------------------------------------------------------------------------
/2012-03/django_on_lighttpd/fcgi_demo/settings.py:
--------------------------------------------------------------------------------
1 | # Django settings for fcgi_demo project.
2 |
3 | DEBUG = True
4 | TEMPLATE_DEBUG = DEBUG
5 |
6 | ADMINS = (
7 | # ('Your Name', 'your_email@example.com'),
8 | )
9 |
10 | MANAGERS = ADMINS
11 |
12 | DATABASES = {
13 | 'default': {
14 | 'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
15 | 'NAME': '', # Or path to database file if using sqlite3.
16 | 'USER': '', # Not used with sqlite3.
17 | 'PASSWORD': '', # Not used with sqlite3.
18 | 'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
19 | 'PORT': '', # Set to empty string for default. Not used with sqlite3.
20 | }
21 | }
22 |
23 | # Local time zone for this installation. Choices can be found here:
24 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
25 | # although not all choices may be available on all operating systems.
26 | # On Unix systems, a value of None will cause Django to use the same
27 | # timezone as the operating system.
28 | # If running in a Windows environment this must be set to the same as your
29 | # system time zone.
30 | TIME_ZONE = 'America/Chicago'
31 |
32 | # Language code for this installation. All choices can be found here:
33 | # http://www.i18nguy.com/unicode/language-identifiers.html
34 | LANGUAGE_CODE = 'en-us'
35 |
36 | SITE_ID = 1
37 |
38 | # If you set this to False, Django will make some optimizations so as not
39 | # to load the internationalization machinery.
40 | USE_I18N = True
41 |
42 | # If you set this to False, Django will not format dates, numbers and
43 | # calendars according to the current locale
44 | USE_L10N = True
45 |
46 | # Absolute filesystem path to the directory that will hold user-uploaded files.
47 | # Example: "/home/media/media.lawrence.com/media/"
48 | MEDIA_ROOT = ''
49 |
50 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a
51 | # trailing slash.
52 | # Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
53 | MEDIA_URL = ''
54 |
55 | # Absolute path to the directory static files should be collected to.
56 | # Don't put anything in this directory yourself; store your static files
57 | # in apps' "static/" subdirectories and in STATICFILES_DIRS.
58 | # Example: "/home/media/media.lawrence.com/static/"
59 | STATIC_ROOT = ''
60 |
61 | # URL prefix for static files.
62 | # Example: "http://media.lawrence.com/static/"
63 | STATIC_URL = '/static/'
64 |
65 | # URL prefix for admin static files -- CSS, JavaScript and images.
66 | # Make sure to use a trailing slash.
67 | # Examples: "http://foo.com/static/admin/", "/static/admin/".
68 | ADMIN_MEDIA_PREFIX = '/static/admin/'
69 |
70 | # Additional locations of static files
71 | STATICFILES_DIRS = (
72 | # Put strings here, like "/home/html/static" or "C:/www/django/static".
73 | # Always use forward slashes, even on Windows.
74 | # Don't forget to use absolute paths, not relative paths.
75 | )
76 |
77 | # List of finder classes that know how to find static files in
78 | # various locations.
79 | STATICFILES_FINDERS = (
80 | 'django.contrib.staticfiles.finders.FileSystemFinder',
81 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
82 | # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
83 | )
84 |
85 | # Make this unique, and don't share it with anybody.
86 | SECRET_KEY = '3=k6_crfkqhm08$=%44+uuf34nt-3luy9oe*_%3vdwa6%o=-t#'
87 |
88 | # List of callables that know how to import templates from various sources.
89 | TEMPLATE_LOADERS = (
90 | 'django.template.loaders.filesystem.Loader',
91 | 'django.template.loaders.app_directories.Loader',
92 | # 'django.template.loaders.eggs.Loader',
93 | )
94 |
95 | MIDDLEWARE_CLASSES = (
96 | 'django.middleware.common.CommonMiddleware',
97 | 'django.contrib.sessions.middleware.SessionMiddleware',
98 | 'django.middleware.csrf.CsrfViewMiddleware',
99 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
100 | 'django.contrib.messages.middleware.MessageMiddleware',
101 | )
102 |
103 | ROOT_URLCONF = 'fcgi_demo.urls'
104 |
105 | TEMPLATE_DIRS = (
106 | '/home/reddog/code/pyatl/django_lighttpd/templates',
107 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
108 | # Always use forward slashes, even on Windows.
109 | # Don't forget to use absolute paths, not relative paths.
110 | )
111 |
112 | INSTALLED_APPS = (
113 | 'django.contrib.auth',
114 | 'django.contrib.contenttypes',
115 | 'django.contrib.sessions',
116 | 'django.contrib.sites',
117 | 'django.contrib.messages',
118 | 'django.contrib.staticfiles',
119 | 'web',
120 | # Uncomment the next line to enable the admin:
121 | # 'django.contrib.admin',
122 | # Uncomment the next line to enable admin documentation:
123 | # 'django.contrib.admindocs',
124 | )
125 |
126 | FORCE_SCRIPT_NAME=''
127 |
128 | # A sample logging configuration. The only tangible logging
129 | # performed by this configuration is to send an email to
130 | # the site admins on every HTTP 500 error.
131 | # See http://docs.djangoproject.com/en/dev/topics/logging for
132 | # more details on how to customize your logging configuration.
133 | LOGGING = {
134 | 'version': 1,
135 | 'disable_existing_loggers': False,
136 | 'handlers': {
137 | 'mail_admins': {
138 | 'level': 'ERROR',
139 | 'class': 'django.utils.log.AdminEmailHandler'
140 | }
141 | },
142 | 'loggers': {
143 | 'django.request': {
144 | 'handlers': ['mail_admins'],
145 | 'level': 'ERROR',
146 | 'propagate': True,
147 | },
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/2012-03/django_on_lighttpd/fcgi_demo/templates/hello.html:
--------------------------------------------------------------------------------
1 |
2 |
Hello World
3 |
4 |
{{ greeting }}, World!
5 |
6 |
7 |
--------------------------------------------------------------------------------
/2012-03/django_on_lighttpd/fcgi_demo/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls.defaults import patterns, include, url
2 | from django.views.generic.simple import redirect_to
3 |
4 | # Uncomment the next two lines to enable the admin:
5 | # from django.contrib import admin
6 | # admin.autodiscover()
7 |
8 | urlpatterns = patterns('',
9 | url(r'^$', redirect_to, { 'url':'/web' }),
10 | url(r'^web/', include('fcgi_demo.web.urls')),
11 | # Examples:
12 | # url(r'^$', 'fcgi_demo.views.home', name='home'),
13 | # url(r'^fcgi_demo/', include('fcgi_demo.foo.urls')),
14 |
15 | # Uncomment the admin/doc line below to enable admin documentation:
16 | # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
17 |
18 | # Uncomment the next line to enable the admin:
19 | # url(r'^admin/', include(admin.site.urls)),
20 | )
21 |
--------------------------------------------------------------------------------
/2012-03/django_on_lighttpd/fcgi_demo/web/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2012-03/django_on_lighttpd/fcgi_demo/web/__init__.py
--------------------------------------------------------------------------------
/2012-03/django_on_lighttpd/fcgi_demo/web/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | # Create your models here.
4 |
--------------------------------------------------------------------------------
/2012-03/django_on_lighttpd/fcgi_demo/web/tests.py:
--------------------------------------------------------------------------------
1 | """
2 | This file demonstrates writing tests using the unittest module. These will pass
3 | when you run "manage.py test".
4 |
5 | Replace this with more appropriate tests for your application.
6 | """
7 |
8 | from django.test import TestCase
9 |
10 |
11 | class SimpleTest(TestCase):
12 | def test_basic_addition(self):
13 | """
14 | Tests that 1 + 1 always equals 2.
15 | """
16 | self.assertEqual(1 + 1, 2)
17 |
--------------------------------------------------------------------------------
/2012-03/django_on_lighttpd/fcgi_demo/web/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls.defaults import patterns, url
2 |
3 | urlpatterns = patterns('fcgi_demo.web.views',
4 | url(r'^$', 'hello', name='hello'),
5 | )
6 |
7 |
--------------------------------------------------------------------------------
/2012-03/django_on_lighttpd/fcgi_demo/web/views.py:
--------------------------------------------------------------------------------
1 | # Create your views here.
2 | from django.shortcuts import render_to_response
3 | from django.template import RequestContext
4 |
5 | def hello(request):
6 | return render_to_response('hello.html',
7 | context_instance=RequestContext(request, {
8 | 'greeting': 'Guten Abend'
9 | }))
10 |
11 |
--------------------------------------------------------------------------------
/2012-03/django_on_lighttpd/lighttpd.conf:
--------------------------------------------------------------------------------
1 | # Debian lighttpd configuration file
2 | #
3 |
4 | ############ Options you really have to take care of ####################
5 |
6 | ## modules to load
7 | # mod_access, mod_accesslog and mod_alias are loaded by default
8 | # all other module should only be loaded if neccesary
9 | # - saves some time
10 | # - saves memory
11 |
12 | server.modules = (
13 | "mod_access",
14 | "mod_alias",
15 | "mod_rewrite",
16 | "mod_fastcgi",
17 | "mod_accesslog",
18 | "mod_compress",
19 | # "mod_rewrite",
20 | # "mod_redirect",
21 | # "mod_evhost",
22 | # "mod_usertrack",
23 | # "mod_rrdtool",
24 | # "mod_webdav",
25 | # "mod_expire",
26 | # "mod_flv_streaming",
27 | # "mod_evasive"
28 | )
29 |
30 | ## a static document-root, for virtual-hosting take look at the
31 | ## server.virtual-* options
32 | server.document-root = "/var/www/"
33 |
34 | ## where to upload files to, purged daily.
35 | server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
36 |
37 | ## where to send error-messages to
38 | server.errorlog = "/var/log/lighttpd/error.log"
39 |
40 | ## files to check for if .../ is requested
41 | index-file.names = ( "index.php", "index.html",
42 | "index.htm", "default.htm",
43 | "index.lighttpd.html" )
44 |
45 |
46 | ## Use the "Content-Type" extended attribute to obtain mime type if possible
47 | # mimetype.use-xattr = "enable"
48 |
49 | #### accesslog module
50 | accesslog.filename = "/var/log/lighttpd/access.log"
51 |
52 | ## deny access the file-extensions
53 | #
54 | # ~ is for backupfiles from vi, emacs, joe, ...
55 | # .inc is often used for code includes which should in general not be part
56 | # of the document-root
57 | url.access-deny = ( "~", ".inc" )
58 |
59 | ##
60 | # which extensions should not be handle via static-file transfer
61 | #
62 | # .php, .pl, .fcgi are most often handled by mod_fastcgi or mod_cgi
63 | static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
64 |
65 |
66 | ######### Options that are good to be but not neccesary to be changed #######
67 |
68 | ## Use ipv6 only if available. (disabled for while, check #560837)
69 | #include_shell "/usr/share/lighttpd/use-ipv6.pl"
70 |
71 | ## bind to port (default: 80)
72 | server.port = 8888
73 |
74 | ## bind to localhost only (default: all interfaces)
75 | ## server.bind = "localhost"
76 |
77 | ## error-handler for status 404
78 | #server.error-handler-404 = "/error-handler.html"
79 | #server.error-handler-404 = "/error-handler.php"
80 |
81 | ## to help the rc.scripts
82 | server.pid-file = "/var/run/lighttpd.pid"
83 |
84 | ##
85 | ## Format: .html
86 | ## -> ..../status-404.html for 'File not found'
87 | #server.errorfile-prefix = "/var/www/"
88 |
89 | ## virtual directory listings
90 | dir-listing.encoding = "utf-8"
91 | server.dir-listing = "enable"
92 |
93 | ## send unhandled HTTP-header headers to error-log
94 | #debug.dump-unknown-headers = "enable"
95 |
96 | ### only root can use these options
97 | #
98 | # chroot() to directory (default: no chroot() )
99 | #server.chroot = "/"
100 |
101 | ## change uid to (default: don't care)
102 | server.username = "www-data"
103 |
104 | ## change uid to (default: don't care)
105 | server.groupname = "www-data"
106 |
107 | #### compress module
108 | compress.cache-dir = "/var/cache/lighttpd/compress/"
109 | compress.filetype = ("text/plain", "text/html", "application/x-javascript", "text/css")
110 |
111 |
112 | #### url handling modules (rewrite, redirect, access)
113 | # url.rewrite = ( "^/$" => "/server-status" )
114 | # url.redirect = ( "^/wishlist/(.+)" => "http://www.123.org/$1" )
115 |
116 | #
117 | # define a pattern for the host url finding
118 | # %% => % sign
119 | # %0 => domain name + tld
120 | # %1 => tld
121 | # %2 => domain name without tld
122 | # %3 => subdomain 1 name
123 | # %4 => subdomain 2 name
124 | #
125 | # evhost.path-pattern = "/home/storage/dev/www/%3/htdocs/"
126 |
127 | #### expire module
128 | # expire.url = ( "/buggy/" => "access 2 hours", "/asdhas/" => "access plus 1 seconds 2 minutes")
129 |
130 | #### rrdtool
131 | # rrdtool.binary = "/usr/bin/rrdtool"
132 | # rrdtool.db-name = "/var/www/lighttpd.rrd"
133 |
134 | #### variable usage:
135 | ## variable name without "." is auto prefixed by "var." and becomes "var.bar"
136 | #bar = 1
137 | #var.mystring = "foo"
138 |
139 | ## integer add
140 | #bar += 1
141 | ## string concat, with integer cast as string, result: "www.foo1.com"
142 | #server.name = "www." + mystring + var.bar + ".com"
143 | ## array merge
144 | #index-file.names = (foo + ".php") + index-file.names
145 | #index-file.names += (foo + ".php")
146 |
147 |
148 | #### external configuration files
149 | ## mimetype mapping
150 | include_shell "/usr/share/lighttpd/create-mime.assign.pl"
151 |
152 | ## load enabled configuration files,
153 | ## read /etc/lighttpd/conf-available/README first
154 | include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
155 |
156 | # local fcgi demo server
157 | $HTTP["host"] == "localhost" {
158 |
159 | server.document-root = "/home/reddog/code/pyatl/django_lighttpd/fcgi_demo"
160 |
161 | fastcgi.server = (
162 | "/fcgi_demo" => (
163 | "main" => (
164 | "socket" => "/home/reddog/code/pyatl/django_lighttpd/fcgi.sock",
165 | "check-local" => "disable",
166 | )
167 | ),
168 | )
169 |
170 | alias.url = (
171 | "/media" => "/home/reddog/code/pyatl/django_lighttpd/fcgi_demo/media",
172 | )
173 |
174 | url.rewrite-once = (
175 | "^(/media.*)$" => "$1",
176 | "^/favicon.ico$" => "static/images/favicon.ico",
177 | "^/robots.txt$" => "/static/robots.txt",
178 | "^(/.*)$" => "/fcgi_demo/$1",
179 | )
180 | }
181 |
182 | #### handle Debian Policy Manual, Section 11.5. urls
183 | ## by default allow them only from localhost
184 | ## (This must come last due to #445459)
185 | ## Note: =~ "127.0.0.1" works with ipv6 enabled, whereas == "127.0.0.1" doesn't
186 | $HTTP["remoteip"] =~ "127.0.0.1" {
187 | alias.url += (
188 | "/doc/" => "/usr/share/doc/",
189 | "/images/" => "/usr/share/images/"
190 | )
191 | $HTTP["url"] =~ "^/doc/|^/images/" {
192 | dir-listing.activate = "enable"
193 | }
194 | }
195 |
196 |
197 |
--------------------------------------------------------------------------------
/2012-03/django_on_lighttpd/restart_fastcgi.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | SCRIPTNAME="restart_fastcgi.sh"
4 |
5 | # Setup variables for the project
6 | PROJECTDIR="/home/reddog/code/pyatl/django_lighttpd"
7 | PROJECTPID="$PROJECTDIR/fcgi.pid"
8 | PROJECTSOCK="$PROJECTDIR/fcgi.sock"
9 |
10 | if [ -f $PROJECTPID ]; then
11 | /bin/kill `/bin/cat $PROJECTPID`
12 | /bin/rm -f $PROJECTPID
13 | fi
14 |
15 | $PROJECTDIR/manage.py runfcgi method=threaded socket=$PROJECTSOCK pidfile=$PROJECTPID maxchildren=3
16 |
17 | # This assumes the user lighttpd is running under and the user the FastCGI
18 | # process is running under are in the same group
19 | /bin/chmod 770 $PROJECTSOCK
20 |
--------------------------------------------------------------------------------
/2012-03/python_datetime/Python datetime.ppt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2012-03/python_datetime/Python datetime.ppt
--------------------------------------------------------------------------------
/2012-03/python_datetime/README.txt:
--------------------------------------------------------------------------------
1 | Python datetime library, adding things up
2 | Speaker: William Soukup
3 |
4 | Lightning Talk
5 |
--------------------------------------------------------------------------------
/2012-05/door-prize-meetup-api.py:
--------------------------------------------------------------------------------
1 | import os
2 | import json
3 | import time
4 | import urllib
5 | import urllib2
6 | import calendar
7 | import random
8 | from datetime import datetime, timedelta
9 |
10 | API_KEY = open('%s/etc/meetup.key' % os.environ['HOME']).read().strip()
11 | base = 'https://api.meetup.com/'
12 |
13 | def main():
14 | m = Meetup(API_KEY)
15 | # Find the event
16 | # after=datetime_to_timestamp(datetime(2012, 5, 10))
17 | # before=datetime_to_timestamp(datetime(2012, 5, 11))
18 | after=datetime_to_timestamp(datetime.now().date())
19 | before=datetime_to_timestamp(datetime.now().date() + timedelta(hours=24))
20 | events = list(
21 | m.events_for_group(
22 | 'python-atlanta',
23 | status='upcoming,past',
24 | time='%s000,%s000' % (after, before)))
25 | assert len(events) == 1
26 | event = events[0]
27 | print '%s at %s on %s' % (
28 | event['name'],
29 | event['venue']['name'],
30 | time.ctime(event['time']/1000))
31 | raw_input('Press enter to continue...')
32 | rsvps = m.member_rsvps(event['id'])
33 | in_drawing = [ member for member, response in rsvps if response == 'yes' ]
34 | for member in in_drawing:
35 | print member['name']
36 | while True:
37 | raw_input('And the winner is...')
38 | winner = random.choice(in_drawing)
39 | print winner['name']
40 |
41 |
42 | class Meetup(object):
43 |
44 | def __init__(self, api_key):
45 | self.api_key = api_key
46 |
47 | def __call__(self, endpoint, **kwargs):
48 | params = dict(kwargs)
49 | params.setdefault('key', self.api_key)
50 | # params.setdefault('page', 1)
51 | q = urllib.urlencode(params)
52 | url = base + endpoint + '.json/?' + q
53 | try:
54 | fp = urllib2.urlopen(url)
55 | text = fp.read()
56 | data = json.loads(text)
57 | except urllib2.HTTPError, e:
58 | print 'There was an error', e
59 | import pdb; pdb.set_trace()
60 | return data
61 |
62 | def member_rsvps(self, event_id):
63 | r = self('2/rsvps', event_id=event_id)
64 | for x in r['results']:
65 | yield x['member'], x['response']
66 |
67 | def events_for_group(self, group, **kwargs):
68 | r = self('2/events', group_urlname=group, **kwargs)
69 | for x in r['results']:
70 | yield x
71 |
72 |
73 | def datetime_to_timestamp(dt):
74 | return calendar.timegm(dt.timetuple())
75 |
76 | if __name__ == '__main__':
77 | main()
78 |
--------------------------------------------------------------------------------
/2012-07/pygame-intro/Intro To PyGame.odp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2012-07/pygame-intro/Intro To PyGame.odp
--------------------------------------------------------------------------------
/2012-07/pygame-intro/README.md:
--------------------------------------------------------------------------------
1 | "A Short Introduction to Pygame" by JR Rickerson
2 | ================================================
3 | A quick 30 minute talk to introduce the concept of PyGame, and sample files to
4 | build a simple game during the talk.
5 |
6 | Resources in this directory
7 | ---------------------------
8 | Slideshow (OpenOffice format): Intro to PyGame.odp
9 | Images: Provided by Invent Your Own Game with Python "Dodger" tutorial.
10 | Sample code: part1.py, part2.py, part3.py, part4.py
11 |
12 | Each sample file goes along with the 4 parts of building the game described
13 | in the "Writing the Code" slides in the slideshow.
14 |
15 | Web Resources from the final slide
16 | ----------------------------------
17 | * PyGame documentation: http://www.pygame.org
18 | * SDL documentation: http://www.libsdl.org
19 | * "Invent Your Own Games with Python" website and book:
20 | http://inventwithpython.com
21 | * Katie Cunningham's website: http://therealkatie.net
22 |
--------------------------------------------------------------------------------
/2012-07/pygame-intro/images/baddie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2012-07/pygame-intro/images/baddie.png
--------------------------------------------------------------------------------
/2012-07/pygame-intro/images/player.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2012-07/pygame-intro/images/player.png
--------------------------------------------------------------------------------
/2012-07/pygame-intro/part1.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import pygame
3 |
4 | from pygame.locals import QUIT
5 |
6 | # Constants
7 | WINDOWHEIGHT = 600
8 | WINDOWWIDTH = 800
9 | BACKGROUNDCOLOR = (15, 15, 15)
10 |
11 | FPS = 40
12 |
13 | def terminate():
14 | pygame.quit()
15 | sys.exit()
16 |
17 | def main():
18 | # Part 1: Initialize pygame, the clock, and the display surface
19 | pygame.init()
20 | mainClock = pygame.time.Clock()
21 | windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
22 | pygame.display.set_caption('Dodge!')
23 | pygame.mouse.set_visible(False)
24 |
25 | # Part 1: Load images
26 | player_sprite = pygame.image.load('images/player.png')
27 | player_rect = player_sprite.get_rect()
28 |
29 | # Part 1: Set Player start position
30 | player_rect.topleft = (WINDOWWIDTH / 2, WINDOWHEIGHT - 50)
31 |
32 | # Start the game loop
33 | while True:
34 | for event in pygame.event.get():
35 | if event.type == QUIT:
36 | terminate()
37 |
38 | # Render the scene
39 | windowSurface.fill(BACKGROUNDCOLOR)
40 | windowSurface.blit(player_sprite, player_rect)
41 |
42 | pygame.display.update()
43 |
44 | mainClock.tick(FPS)
45 |
46 | if __name__ == '__main__':
47 | main()
48 |
--------------------------------------------------------------------------------
/2012-07/pygame-intro/part2.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import pygame
3 |
4 | from pygame.locals import QUIT, \
5 | KEYDOWN, KEYUP, K_UP, K_DOWN, K_LEFT, K_RIGHT, K_ESCAPE
6 |
7 | # Constants
8 | WINDOWHEIGHT = 600
9 | WINDOWWIDTH = 800
10 | BACKGROUNDCOLOR = (15, 15, 15)
11 |
12 | PLAYERSPEED = 5
13 |
14 | FPS = 40
15 |
16 | def terminate():
17 | pygame.quit()
18 | sys.exit()
19 |
20 | def main():
21 | # Part 1: Initialize pygame, the clock, and the display surface
22 | pygame.init()
23 | mainClock = pygame.time.Clock()
24 | windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
25 | pygame.display.set_caption('Dodge!')
26 | pygame.mouse.set_visible(False)
27 |
28 | # Part 1: Load images
29 | player_sprite = pygame.image.load('images/player.png')
30 | player_rect = player_sprite.get_rect()
31 |
32 | # Part 1: Set Player start position
33 | player_rect.topleft = (WINDOWWIDTH / 2, WINDOWHEIGHT - 50)
34 |
35 | # Set up player movement
36 | move_left = move_right = move_up = move_down = False
37 |
38 | # Start the game loop
39 | while True:
40 | for event in pygame.event.get():
41 | if event.type == QUIT:
42 | terminate()
43 | # Part 2: Handle keyboard input and movement
44 | elif event.type == KEYDOWN:
45 | if event.key == K_LEFT or event.key == ord('a'):
46 | move_right = False
47 | move_left = True
48 | elif event.key == K_RIGHT or event.key == ord('d'):
49 | move_left = False
50 | move_right = True
51 | elif event.key == K_UP or event.key == ord('w'):
52 | move_down = False
53 | move_up = True
54 | elif event.key == K_DOWN or event.key == ord('s'):
55 | move_up = False
56 | move_down = True
57 | elif event.type == KEYUP:
58 | if event.key == K_ESCAPE:
59 | terminate()
60 | elif event.key == K_LEFT or event.key == ord('a'):
61 | move_left = False
62 | elif event.key == K_RIGHT or event.key == ord('d'):
63 | move_right = False
64 | elif event.key == K_UP or event.key == ord('w'):
65 | move_up = False
66 | elif event.key == K_DOWN or event.key == ord('s'):
67 | move_down = False
68 |
69 | # Part 2: Handle player movememnt
70 | if move_left and player_rect.left > 0:
71 | player_rect.move_ip(-1 * PLAYERSPEED, 0)
72 | if move_right and player_rect.right < WINDOWWIDTH:
73 | player_rect.move_ip(PLAYERSPEED, 0)
74 | if move_up and player_rect.top > 0:
75 | player_rect.move_ip(0, -1 * PLAYERSPEED)
76 | if move_down and player_rect.bottom < WINDOWHEIGHT:
77 | player_rect.move_ip(0, PLAYERSPEED)
78 |
79 | # Part 1: Render the scene
80 | windowSurface.fill(BACKGROUNDCOLOR)
81 | windowSurface.blit(player_sprite, player_rect)
82 |
83 | pygame.display.update()
84 |
85 | mainClock.tick(FPS)
86 |
87 | if __name__ == '__main__':
88 | main()
89 |
--------------------------------------------------------------------------------
/2012-07/pygame-intro/part3.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import random
3 | import pygame
4 |
5 | from pygame.locals import QUIT, \
6 | KEYDOWN, KEYUP, K_UP, K_DOWN, K_LEFT, K_RIGHT, K_ESCAPE
7 |
8 | # Constants
9 | WINDOWHEIGHT = 600
10 | WINDOWWIDTH = 800
11 | BACKGROUNDCOLOR = (15, 15, 15)
12 |
13 | # Size of Baddie sprite
14 | BADDIE_WIDTH = 40
15 | BADDIE_HEIGHT = 40
16 | # Pixel move rate per loop iteration
17 | BADDIEMINSPEED = 1
18 | BADDIEMAXSPEED = 8
19 | # Number of loop iterations between adding new bombs
20 | NEWBADDIERATE = 6
21 |
22 | PLAYERSPEED = 5
23 |
24 | FPS = 40
25 |
26 | def terminate():
27 | pygame.quit()
28 | sys.exit()
29 |
30 | def main():
31 | # Part 1: Initialize pygame, the clock, and the display surface
32 | pygame.init()
33 | mainClock = pygame.time.Clock()
34 | windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
35 | pygame.display.set_caption('Dodge!')
36 | pygame.mouse.set_visible(False)
37 |
38 | # Part 1: Load images
39 | player_sprite = pygame.image.load('images/player.png')
40 | player_rect = player_sprite.get_rect()
41 | baddie_sprite = pygame.image.load('images/baddie.png')
42 |
43 | # Part 1: Set Player start position
44 | player_rect.topleft = (WINDOWWIDTH / 2, WINDOWHEIGHT - 50)
45 |
46 | # Set up player movement
47 | move_left = move_right = move_up = move_down = False
48 |
49 | baddies = []
50 | baddie_add_counter = 0
51 |
52 | # Start the game loop
53 | while True:
54 | for event in pygame.event.get():
55 | if event.type == QUIT:
56 | terminate()
57 | # Part 2: Handle keyboard input and movement
58 | elif event.type == KEYDOWN:
59 | if event.key == K_LEFT or event.key == ord('a'):
60 | move_right = False
61 | move_left = True
62 | elif event.key == K_RIGHT or event.key == ord('d'):
63 | move_left = False
64 | move_right = True
65 | elif event.key == K_UP or event.key == ord('w'):
66 | move_down = False
67 | move_up = True
68 | elif event.key == K_DOWN or event.key == ord('s'):
69 | move_up = False
70 | move_down = True
71 | elif event.type == KEYUP:
72 | if event.key == K_ESCAPE:
73 | terminate()
74 | elif event.key == K_LEFT or event.key == ord('a'):
75 | move_left = False
76 | elif event.key == K_RIGHT or event.key == ord('d'):
77 | move_right = False
78 | elif event.key == K_UP or event.key == ord('w'):
79 | move_up = False
80 | elif event.key == K_DOWN or event.key == ord('s'):
81 | move_down = False
82 |
83 | # Part 3: Managing addition of new enemies
84 | baddie_add_counter += 1
85 | if NEWBADDIERATE == baddie_add_counter:
86 | baddie_add_counter = 0
87 | new_baddie = {
88 | 'rect': pygame.Rect(
89 | random.randint(0, WINDOWWIDTH - BADDIE_WIDTH),
90 | 0 - BADDIE_HEIGHT,
91 | BADDIE_WIDTH,
92 | BADDIE_HEIGHT
93 | ),
94 | 'speed':random.randint(BADDIEMINSPEED, BADDIEMAXSPEED),
95 | 'surface': pygame.transform.scale(baddie_sprite,
96 | (BADDIE_WIDTH, BADDIE_HEIGHT))
97 | }
98 |
99 | baddies.append(new_baddie)
100 |
101 | # Part 2: Handle player movememnt
102 | if move_left and player_rect.left > 0:
103 | player_rect.move_ip(-1 * PLAYERSPEED, 0)
104 | if move_right and player_rect.right < WINDOWWIDTH:
105 | player_rect.move_ip(PLAYERSPEED, 0)
106 | if move_up and player_rect.top > 0:
107 | player_rect.move_ip(0, -1 * PLAYERSPEED)
108 | if move_down and player_rect.bottom < WINDOWHEIGHT:
109 | player_rect.move_ip(0, PLAYERSPEED)
110 |
111 | # Part 3: Move the baddies
112 | for baddie in baddies:
113 | baddie['rect'].move_ip(0, baddie['speed'])
114 |
115 | # Part 3: Remove any invisible baddies
116 | for baddie in baddies[:]:
117 | if baddie['rect'].top > WINDOWHEIGHT:
118 | baddies.remove(baddie)
119 |
120 | # Part 1: Render the scene
121 | windowSurface.fill(BACKGROUNDCOLOR)
122 | windowSurface.blit(player_sprite, player_rect)
123 |
124 | # Part 3: Add Baddies
125 | for baddie in baddies:
126 | windowSurface.blit(baddie['surface'], baddie['rect'])
127 |
128 | pygame.display.update()
129 |
130 | mainClock.tick(FPS)
131 |
132 | if __name__ == '__main__':
133 | main()
134 |
--------------------------------------------------------------------------------
/2012-07/pygame-intro/part4.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import random
3 | import pygame
4 |
5 | from pygame.locals import QUIT, \
6 | KEYDOWN, KEYUP, K_UP, K_DOWN, K_LEFT, K_RIGHT, K_ESCAPE
7 |
8 | # Constants
9 | WINDOWHEIGHT = 600
10 | WINDOWWIDTH = 800
11 | BACKGROUNDCOLOR = (15, 15, 15)
12 | TEXTCOLOR = (255, 255, 255)
13 |
14 | # Size of Baddie sprite
15 | BADDIE_WIDTH = 40
16 | BADDIE_HEIGHT = 40
17 | # Pixel move rate per loop iteration
18 | BADDIEMINSPEED = 1
19 | BADDIEMAXSPEED = 8
20 | # Number of loop iterations between adding new bombs
21 | NEWBADDIERATE = 6
22 |
23 | PLAYERSPEED = 5
24 |
25 | FPS = 40
26 |
27 | def terminate():
28 | pygame.quit()
29 | sys.exit()
30 |
31 | def main():
32 | # Part 1: Initialize pygame, the clock, and the display surface
33 | pygame.init()
34 | mainClock = pygame.time.Clock()
35 | windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
36 | pygame.display.set_caption('Dodge!')
37 | pygame.mouse.set_visible(False)
38 | # Part 4: Fonts
39 | font = pygame.font.SysFont(None, 48)
40 |
41 | # Part 1: Load images
42 | player_sprite = pygame.image.load('images/player.png')
43 | player_rect = player_sprite.get_rect()
44 | baddie_sprite = pygame.image.load('images/baddie.png')
45 |
46 | # Part 1: Set Player start position
47 | player_rect.topleft = (WINDOWWIDTH / 2, WINDOWHEIGHT - 50)
48 |
49 | # Set up player movement
50 | move_left = move_right = move_up = move_down = False
51 |
52 | baddies = []
53 | baddie_add_counter = 0
54 | # Part 4: Start the score at 0
55 | score = 0
56 |
57 | # Start the game loop
58 | while True:
59 | # Part 4: Increase the score the longer the player lasts
60 | score += 1
61 |
62 | for event in pygame.event.get():
63 | if event.type == QUIT:
64 | terminate()
65 | # Part 2: Handle keyboard input and movement
66 | elif event.type == KEYDOWN:
67 | if event.key == K_LEFT or event.key == ord('a'):
68 | move_right = False
69 | move_left = True
70 | elif event.key == K_RIGHT or event.key == ord('d'):
71 | move_left = False
72 | move_right = True
73 | elif event.key == K_UP or event.key == ord('w'):
74 | move_down = False
75 | move_up = True
76 | elif event.key == K_DOWN or event.key == ord('s'):
77 | move_up = False
78 | move_down = True
79 | elif event.type == KEYUP:
80 | if event.key == K_ESCAPE:
81 | terminate()
82 | elif event.key == K_LEFT or event.key == ord('a'):
83 | move_left = False
84 | elif event.key == K_RIGHT or event.key == ord('d'):
85 | move_right = False
86 | elif event.key == K_UP or event.key == ord('w'):
87 | move_up = False
88 | elif event.key == K_DOWN or event.key == ord('s'):
89 | move_down = False
90 |
91 | # Part 3: Managing addition of new enemies
92 | baddie_add_counter += 1
93 | if NEWBADDIERATE == baddie_add_counter:
94 | baddie_add_counter = 0
95 | new_baddie = {
96 | 'rect': pygame.Rect(
97 | random.randint(0, WINDOWWIDTH - BADDIE_WIDTH),
98 | 0 - BADDIE_HEIGHT,
99 | BADDIE_WIDTH,
100 | BADDIE_HEIGHT
101 | ),
102 | 'speed':random.randint(BADDIEMINSPEED, BADDIEMAXSPEED),
103 | 'surface': pygame.transform.scale(baddie_sprite,
104 | (BADDIE_WIDTH, BADDIE_HEIGHT))
105 | }
106 |
107 | baddies.append(new_baddie)
108 |
109 | # Part 2: Handle player movememnt
110 | if move_left and player_rect.left > 0:
111 | player_rect.move_ip(-1 * PLAYERSPEED, 0)
112 | if move_right and player_rect.right < WINDOWWIDTH:
113 | player_rect.move_ip(PLAYERSPEED, 0)
114 | if move_up and player_rect.top > 0:
115 | player_rect.move_ip(0, -1 * PLAYERSPEED)
116 | if move_down and player_rect.bottom < WINDOWHEIGHT:
117 | player_rect.move_ip(0, PLAYERSPEED)
118 |
119 | # Part 3: Move the baddies
120 | for baddie in baddies:
121 | baddie['rect'].move_ip(0, baddie['speed'])
122 |
123 | # Part 3: Remove any invisible baddies
124 | for baddie in baddies[:]:
125 | if baddie['rect'].top > WINDOWHEIGHT:
126 | baddies.remove(baddie)
127 |
128 | # Part 1: Render the scene
129 | windowSurface.fill(BACKGROUNDCOLOR)
130 |
131 | # Part 4: Show score
132 | score_text = font.render('Score: {0}'.format(score), 1, TEXTCOLOR)
133 | score_rect = score_text.get_rect()
134 | score_rect.topleft = (10, 0)
135 | windowSurface.blit(score_text, score_rect)
136 |
137 | windowSurface.blit(player_sprite, player_rect)
138 |
139 | # Part 3: Add Baddies
140 | for baddie in baddies:
141 | windowSurface.blit(baddie['surface'], baddie['rect'])
142 |
143 | pygame.display.update()
144 |
145 | # Check for collisions
146 | got_hit = False
147 | for baddie in baddies:
148 | if player_rect.colliderect(baddie['rect']):
149 | got_hit = True
150 | break
151 | if got_hit:
152 | break
153 |
154 | mainClock.tick(FPS)
155 |
156 | # Part 4: End the game
157 | gameover_text = font.render('GAME OVER!', 1, TEXTCOLOR)
158 | gameover_rect = gameover_text.get_rect()
159 | gameover_rect.topleft = ((WINDOWWIDTH / 3), (WINDOWHEIGHT / 3))
160 | windowSurface.blit(gameover_text, gameover_rect)
161 | pygame.display.update()
162 |
163 | while True:
164 | for event in pygame.event.get():
165 | if event.type == QUIT:
166 | terminate()
167 | elif event.type == KEYDOWN:
168 | if event.key == K_ESCAPE:
169 | terminate()
170 |
171 | if __name__ == '__main__':
172 | main()
173 |
--------------------------------------------------------------------------------
/2012-07/readlines/manylines.txt:
--------------------------------------------------------------------------------
1 | first line
2 | second line
3 | third line
4 | fourth line
5 | fifth line
6 | sixth line
7 | seventh line
8 |
--------------------------------------------------------------------------------
/2012-07/readlines/readlines_all.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | input_filename = '/Users/dhellmann/Dropbox/Org/dreamhost.org'
4 |
5 | body = open(input_filename, 'rt').read()
6 | total_bytes = len(body)
7 | total_lines = len(body.splitlines())
8 | print 'total bytes:', total_bytes
9 |
10 | with open(input_filename, 'rt') as f:
11 | lines = f.readlines()
12 | print 'total lines:', len(lines)
13 |
--------------------------------------------------------------------------------
/2012-07/readlines/readlines_buffersize.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import itertools
4 |
5 | input_filename = '/Users/dhellmann/Dropbox/Org/dreamhost.org'
6 |
7 | total_bytes = len(open(input_filename, 'rt').read())
8 |
9 | print '%10s %5s %5s %s' % ('bufsize', 'mult', 'lines', 'bytes')
10 |
11 | for i in itertools.chain(
12 | xrange(1, 1000, 200),
13 | xrange(1000, 6000, 1000),
14 | [8192],
15 | xrange(10000, total_bytes + 5000, 5000),
16 | ):
17 |
18 | with open(input_filename, 'rt') as f:
19 | lines = f.readlines(i)
20 | print '%10d %5d %5d %5d' % \
21 | (i, i / 8192, len(lines), len(''.join(lines)))
22 |
--------------------------------------------------------------------------------
/2012-07/readlines/readlines_chunks.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | input_filename = '/Users/dhellmann/Dropbox/Org/dreamhost.org'
4 |
5 | CHUNK = 5000
6 |
7 | with open(input_filename, 'rt') as f:
8 | num_lines = 0
9 | while True:
10 | lines = f.readlines(CHUNK)
11 | print ' ', len(lines)
12 | if not lines:
13 | break
14 | num_lines += len(lines)
15 |
16 | print 'total lines:', num_lines
17 |
--------------------------------------------------------------------------------
/2012-10/intro/README.rst:
--------------------------------------------------------------------------------
1 |
2 | =========================
3 | Intro to Python Scripting
4 | =========================
5 |
6 | :Author: Daniel J. Rocco, Ph.D.
7 |
8 |
9 | A short introduction to Python scripting basics using the example of
10 | extracting email addresses from a weird data file.
11 |
12 | Topics covered:
13 |
14 | * how to read in a file
15 | * objects: *know stuff* and *do stuff*
16 | * packaging code into *functions*—named, reusable blobs of code
17 | * working with *variables*, which are named handles to objects
18 |
19 |
20 | Organization
21 | ============
22 |
23 | ``read1.py``
24 | opening the file, reading its data, calculating the number of characters/words
25 |
26 | ``read2.py``
27 | package reading the file as a function, storing the result in a variable
28 |
29 | ``words.py``
30 | splitting the file's data into words
31 |
32 | ``extract_addr.py``
33 | put it all together, loop over the words in the file and print only the email addresses
34 |
35 |
36 | Resources
37 | =========
38 |
39 | * `The Python Tutorial `_
40 | * `Dive Into Python `_
41 |
--------------------------------------------------------------------------------
/2012-10/intro/addresses.ldif:
--------------------------------------------------------------------------------
1 | dn: mail=rockdj@cc.gatech.edu
2 | objectclass: top
3 | objectclass: person
4 | objectclass: organizationalPerson
5 | objectclass: inetOrgPerson
6 | objectclass: mozillaAbPersonObsolete
7 | mail: rockdj@cc.gatech.edu
8 | modifytimestamp: 0Z
9 |
10 | dn: mail=drocco@westga.edu
11 | objectclass: top
12 | objectclass: person
13 | objectclass: organizationalPerson
14 | objectclass: inetOrgPerson
15 | objectclass: mozillaAbPersonObsolete
16 | mail: drocco@westga.edu
17 | modifytimestamp: 0Z
18 |
19 |
--------------------------------------------------------------------------------
/2012-10/intro/extract_addr.py:
--------------------------------------------------------------------------------
1 | def read_file_data(filename):
2 | with open(filename) as f:
3 | return f.read()
4 |
5 | def words_in(data):
6 | return data.split()
7 |
8 |
9 | def print_email_addrs(filename):
10 | # get the file
11 | data = read_file_data(filename)
12 |
13 | # get the words out of the file
14 | words = words_in(data)
15 |
16 | # print out the email addresses
17 | for word in words:
18 | if '@' in word and '=' not in word:
19 | print word
20 |
21 | print_email_addrs('addresses.ldif')
22 |
23 |
24 |
--------------------------------------------------------------------------------
/2012-10/intro/read1.py:
--------------------------------------------------------------------------------
1 | with open('addresses.ldif') as f:
2 | print f.name
3 | data = f.read()
4 |
5 | print len(data)
6 |
7 | print len(data.split('\n'))
8 |
9 |
10 |
--------------------------------------------------------------------------------
/2012-10/intro/read2.py:
--------------------------------------------------------------------------------
1 | def read_file_data(filename):
2 | with open(filename) as f:
3 | return f.read()
4 |
5 | data = read_file_data('addresses.ldif')
6 |
7 |
--------------------------------------------------------------------------------
/2012-10/intro/words.py:
--------------------------------------------------------------------------------
1 | def read_file_data(filename):
2 | with open(filename) as f:
3 | return f.read()
4 |
5 | def words_in(data):
6 | return data.split()
7 |
8 | data = read_file_data('addresses.ldif')
9 | words = words_in(data)
10 |
11 |
12 |
--------------------------------------------------------------------------------
/2012-10/sorting/README.md:
--------------------------------------------------------------------------------
1 | "Fun with Sorting - How Python Makes it Easy to Sort a List of Dictionaries" by Cliff Kachinske
2 | ================================================
3 | A lightning talk on Python's sorting capabilties, including the "key" parameter of the "sorted" function. Discussion on how this can be used to merge results retrieved from different data sources.
4 |
5 | Resources in this directory
6 | ---------------------------
7 | Slideshow (PDF): fun_with_sorting.pdf
8 |
--------------------------------------------------------------------------------
/2012-10/sorting/fun_with_sorting.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2012-10/sorting/fun_with_sorting.pdf
--------------------------------------------------------------------------------
/2012-11/heroku-flask/Heroku Python Flask.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2012-11/heroku-flask/Heroku Python Flask.pdf
--------------------------------------------------------------------------------
/2012-11/heroku-flask/README.md:
--------------------------------------------------------------------------------
1 | "Free Python Hosting Heroku Ubuntu Flask" by William Soukup
2 | ================================================
3 | An introduction to use Heroku for hosting Python web projects, using the
4 | Flask web framework. Bill discusses the positive and negative aspects of
5 | using Heroku, and how for smaller projects, one can host applications for
6 | little to no cost.
7 |
8 |
9 | Resources in this directory
10 | ---------------------------
11 | Slideshow (PDF): Heroku Python Flask.pdf
12 |
--------------------------------------------------------------------------------
/2012-11/intro_photocopy/README.rst:
--------------------------------------------------------------------------------
1 |
2 | ====================
3 | How to Eat a Problem
4 | ====================
5 |
6 | :Author: Daniel J. Rocco, Ph.D.
7 |
8 |
9 | A demonstration of software development through iterative refinement: breaking
10 | a problem into logical chunks, coding a bit, testing, and repeating until the
11 | problem is solved.
12 |
13 | The example involved a Python script to copy files.
14 |
15 | Topics covered:
16 |
17 | * iterative software development
18 | * Python's ``if`` conditional and ``for`` looping control structures
19 | * reading arguments from the command line
20 | * OS file services, including copying files walking directory trees
21 |
22 |
23 | Organization
24 | ============
25 |
26 | ``photo0.py``
27 | getting an argument from the command line
28 |
29 | ``photo1.py``
30 | walking a directory tree
31 |
32 | ``photo2.py``
33 | put it all together, copying files from one location to another
34 |
35 | ``photocopy.py``
36 | the (somewhat rough) program that I actually use to do this task, which
37 | utilizes two external programs (``jhead`` and ``exiftool``), performs
38 | lossless, automatic image rotation based on the camera's rotation sensor,
39 | names photos by time stamp, and organizes photos by date.
40 |
41 | ``locator.py``
42 | Helper module used by ``photocopy.py`` based on a recipe on ActiveState.
43 | It demonstrates some more sophisticated directory traversal techniques.
44 |
45 | Resources
46 | =========
47 |
48 | * `The Python Tutorial `_
49 | * |The os module|_
50 | * `jhead `_
51 | * `ExifTool `_
52 |
53 | .. |The os module| replace:: The ``os`` module
54 | .. _The os module: http://docs.python.org/2/library/os.html
--------------------------------------------------------------------------------
/2012-11/intro_photocopy/locator.py:
--------------------------------------------------------------------------------
1 | import os
2 | import fnmatch
3 |
4 | # ====================================================================
5 | # file locator
6 |
7 | ### FIXME: need to move to a local site package
8 | def locate(pattern, root=os.curdir, absolute=True,
9 | excludeDirs=["CVS", ".svn", ".hg"]):
10 | """Locate all filenames matching supplied pattern in and below root.
11 |
12 | Given a UNIX-style filename pattern, locate all filenames in and below
13 | the supplied root directory that match the pattern. If ``root`` is
14 | omitted, ``os.curdir`` is used.
15 |
16 | Returns the absolute path of each matching filename. Change
17 | ``absolute`` to ``False`` to produce pathnames relative to ``root``
18 |
19 | Directories contained in ``excludeDirs`` are not searched; by default
20 | ``locate()`` excludes CVS and Subversion metadata directories from its
21 | search.
22 |
23 | Since this is a generator function, the results are lazy evaluated.
24 |
25 | From: http://code.activestate.com/recipes/499305/
26 |
27 | ----------
28 |
29 |
30 | To iterate over every matching file and do something to it, you would
31 | normally use a for loop, like so:
32 |
33 | >>> for filename in locate("query*", absolute=False):
34 | ... print filename
35 | ...
36 | .\query_tags.py
37 | ...
38 |
39 |
40 | Sometimes, however, it is helpful to work with the entire list of
41 | matches at once:
42 |
43 | >>> filenames = [name for name in locate("*.txt", absolute=False)]
44 | >>> len(filenames) == 30
45 | True
46 | >>> r".\\data\\photos\\2009_01_06\\tags.txt" in filenames
47 | True
48 | >>> r".\\query_tags.py" in filenames
49 | False
50 |
51 |
52 | Let's make sure ``locate()`` still works when fed bogus data:
53 |
54 | >>> [name for name in locate("nonexistent.*")]
55 | []
56 | >>> [name for name in locate("*.txt", root=".\\nonexistent")]
57 | []
58 | """
59 | if absolute:
60 | root = os.path.abspath(root)
61 |
62 | for path, dirs, files in os.walk(root):
63 |
64 | # remove excluded directories, helpful for skipping CVS/subversion
65 | # metadata files
66 | for directory in excludeDirs:
67 | if directory in dirs:
68 | dirs.remove(directory)
69 |
70 | for filename in fnmatch.filter(files, pattern):
71 | yield os.path.join(path, filename)
72 |
73 |
--------------------------------------------------------------------------------
/2012-11/intro_photocopy/photo0.py:
--------------------------------------------------------------------------------
1 | # tell python we need system services
2 | import sys
3 |
4 | # sys.argv[1] is the first argument to our script, e.g. 'e:\':
5 | #
6 | # % python photo0.py e:\
7 | #
8 | # what do you think this program will do if you forget it?
9 | #
10 | # % python photo0.py
11 | #
12 | source = sys.argv[1]
13 |
14 | print 'pretending to look for jpgs in', source
15 |
16 |
--------------------------------------------------------------------------------
/2012-11/intro_photocopy/photo1.py:
--------------------------------------------------------------------------------
1 | # tell python we need OS and system services
2 | import os
3 | import sys
4 |
5 |
6 | # get the location of the JPEGs to copy from the command line
7 | source = sys.argv[1]
8 |
9 | print 'looking for jpgs in', source
10 |
11 |
12 | # http://docs.python.org/2/library/os.html#os.walk
13 |
14 | # starting in source, looking each subdirectory for JPEGs
15 | #
16 | # path: what directory we are in on the filesystem
17 | # files: the list of all the files in that directory
18 | for path, subdirs, files in os.walk(source):
19 |
20 | # look at each file individually
21 | for filename in files:
22 |
23 | # if it is a JPEG
24 | if filename.endswith('jpg'):
25 |
26 | # combine the path (directory) with the file name to produce the
27 | # "absolute" location of the file
28 | fullname = os.path.join(path, filename)
29 | print fullname
30 |
31 |
--------------------------------------------------------------------------------
/2012-11/intro_photocopy/photo2.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | from shutil import copy
5 |
6 |
7 | source = sys.argv[1]
8 | target = '/tmp/photos/'
9 |
10 | print 'copying jpgs from', source, 'to', target
11 |
12 |
13 | # http://docs.python.org/2/library/os.html#os.walk
14 |
15 | # path: what directory we are in on the filesystem
16 | # files: the list of all the files in that directory
17 | for path, subdirs, files in os.walk(source):
18 | for filename in files:
19 | if filename.endswith('jpg'):
20 | fullname = os.path.join(path, filename)
21 | copy(fullname, target)
22 | print '.',
23 |
24 |
--------------------------------------------------------------------------------
/2012-11/intro_photocopy/photocopy.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | from os import remove, rmdir
3 |
4 | from shutil import copy
5 | from subprocess import call
6 | import sys
7 | from tempfile import mkdtemp
8 |
9 | from locator import locate
10 |
11 |
12 | source = sys.argv[1]
13 | tempdir = mkdtemp()
14 |
15 | print('creating temporary directory ' + tempdir)
16 |
17 | print('copying files', end='')
18 | count = 0
19 |
20 | match_pattern = '*.[jn][pe][gf]'
21 |
22 | for photo in locate(match_pattern, root=source):
23 | print('.', end='')
24 | count += 1
25 |
26 | copy(photo, tempdir)
27 |
28 | print(' done. Copied {0} files.'.format(count))
29 |
30 | print('auto rotate and date stamp photos...')
31 |
32 | call('jhead -ft -autorot {0}/*.jpg'.format(tempdir))
33 |
34 | print('copying photo files...')
35 |
36 | call('exiftool "-Filename`_
64 | * |The random module|_
65 |
66 | .. |The random module| replace:: The ``random`` module
67 | .. _The random module: http://docs.python.org/2/library/random.html
--------------------------------------------------------------------------------
/2013-02/intro_listifying/addresses.ldif:
--------------------------------------------------------------------------------
1 | n: mail=ooo what does this button do?
2 | objectclass: top
3 | objectclass: person
4 | objectclass: organizationalPerson
5 | objectclass: inetOrgPerson
6 | objectclass: mozillaAbPersonObsolete
7 | mail: i_am@pyatl.org
8 | modifytimestamp: 0Z
9 |
10 | dn: mail=drocco@westga.edu
11 | objectclass: top
12 | objectclass: person
13 | objectclass: organizationalPerson
14 | objectclass: inetOrgPerson
15 | objectclass: mozillaAbPersonObsolete
16 | mail: drocco@westga.edu
17 | modifytimestamp: 0Z
18 |
19 | dn: mail=rockdj@cc.gatech.edu
20 | objectclass: top
21 | objectclass: person
22 | objectclass: organizationalPerson
23 | objectclass: inetOrgPerson
24 | objectclass: mozillaAbPersonObsolete
25 | mail: rockdj@cc.gatech.edu
26 | modifytimestamp: 0Z
27 |
28 | dn: mail=whatever
29 | objectclass: top
30 | objectclass: person
31 | objectclass: organizationalPerson
32 | objectclass: inetOrgPerson
33 | objectclass: mozillaAbPersonObsolete
34 | mail: bored@pyatl.org
35 | modifytimestamp: 0Z
36 |
37 | dn: mail=whatever
38 | objectclass: top
39 | objectclass: person
40 | objectclass: organizationalPerson
41 | objectclass: inetOrgPerson
42 | objectclass: mozillaAbPersonObsolete
43 | mail: will_he_ever@shut.up
44 | modifytimestamp: 0Z
45 |
--------------------------------------------------------------------------------
/2013-04/cleaver/Cleaver.key:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-04/cleaver/Cleaver.key
--------------------------------------------------------------------------------
/2013-04/cleaver/README:
--------------------------------------------------------------------------------
1 | To run the experiments:
2 |
3 | $ pip install flask cleaver sqlalchemy
4 | $ python after.py
5 |
6 | ...and visit http://localhost:8080 in different browsers.
7 |
8 | To view the results:
9 | $ python report.py
10 |
11 | ...and visit http://localhost:8081.
12 |
--------------------------------------------------------------------------------
/2013-04/cleaver/after.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request
2 | from cleaver import SplitMiddleware
3 | from cleaver.backend.db import SQLAlchemyBackend
4 |
5 | app = Flask(__name__)
6 | app.wsgi_app = SplitMiddleware(
7 | app.wsgi_app,
8 | lambda environ: environ['HTTP_USER_AGENT'], # Track by browser
9 | SQLAlchemyBackend('sqlite:///experiment.data')
10 | )
11 |
12 | template = """
13 |
16 | """
17 |
18 | @app.route("/")
19 | def home():
20 | # Visiting / in a web browser will render a button
21 | return template % (
22 | request.environ['cleaver'](
23 | 'call-to-action',
24 | ('control', 'Click Here, Dummy!'),
25 | ('test', 'Free Puppies!')
26 | )
27 | )
28 |
29 | @app.route("/register", methods=['POST'])
30 | def register():
31 | # Submitting the form will go to /register to display a thank-you
32 | request.environ['cleaver'].score('call-to-action')
33 | return "Thanks for Signing Up!"
34 |
35 | if __name__ == '__main__':
36 | app.run(port=8080)
37 |
--------------------------------------------------------------------------------
/2013-04/cleaver/before.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 |
3 | app = Flask(__name__)
4 |
5 | template = """
6 |
9 | """
10 |
11 | @app.route("/")
12 | def home():
13 | # Visiting / in a web browser will render a button
14 | return template
15 |
16 | @app.route("/register", methods=['POST'])
17 | def register():
18 | return "Thanks for Signing Up!"
19 |
20 | if __name__ == '__main__':
21 | app.run(port=8080)
22 |
--------------------------------------------------------------------------------
/2013-04/cleaver/report.py:
--------------------------------------------------------------------------------
1 | from cleaver.reports.web import CleaverWebUI
2 | from cleaver.backend.db import SQLAlchemyBackend
3 |
4 | app = CleaverWebUI(SQLAlchemyBackend('sqlite:///experiment.data'))
5 |
6 | from wsgiref import simple_server
7 | print "Serving at 0.0.0.0:8081"
8 | simple_server.make_server('', 8081, app).serve_forever()
9 |
--------------------------------------------------------------------------------
/2013-04/intro_taxes/01_csv2.py:
--------------------------------------------------------------------------------
1 | import csv
2 |
3 | with open('simple_brackets.csv', 'rb') as f:
4 | reader = csv.reader(f)
5 | for row in reader:
6 | print ', '.join(row)
7 |
--------------------------------------------------------------------------------
/2013-04/intro_taxes/01b_csv2.py:
--------------------------------------------------------------------------------
1 | import csv
2 |
3 | with open('simple_brackets.csv', 'rb') as f:
4 | reader = csv.reader(f)
5 | brackets = list(reader)
6 |
7 | print brackets
8 |
--------------------------------------------------------------------------------
/2013-04/intro_taxes/02_semantically_enhanced.py:
--------------------------------------------------------------------------------
1 | import csv
2 | from collections import namedtuple
3 |
4 | # create a namedtuple to represent the rows of our csv file
5 | Bracket = namedtuple(
6 | 'Bracket',
7 | 'tax_rate single married_joint'
8 | )
9 |
10 | with open('simple_brackets.csv', 'rb') as f:
11 | reader = csv.reader(f)
12 |
13 | # map calls a function (Bracket._make) on each element of a list (or list-
14 | # like object). Roughly translated to English, this line reads "make a
15 | # Bracket object out of each row of the csv file, storing the list of
16 | # Brackets in the variable 'brackets'"
17 | brackets = map(Bracket._make, reader)
18 |
19 | print brackets
20 |
--------------------------------------------------------------------------------
/2013-04/intro_taxes/02b_semantically_enhanced.py:
--------------------------------------------------------------------------------
1 | import csv
2 | from collections import namedtuple
3 |
4 | Bracket = namedtuple(
5 | 'Bracket',
6 | 'tax_rate single married_joint'
7 | )
8 |
9 | with open('simple_brackets.csv', 'rb') as f:
10 | reader = csv.reader(f)
11 |
12 | # skip the header
13 | next(reader)
14 |
15 | brackets = map(Bracket._make, reader)
16 |
17 | print brackets
18 |
--------------------------------------------------------------------------------
/2013-04/intro_taxes/03_split_by_bracket.txt:
--------------------------------------------------------------------------------
1 |
2 | Great! Um... How do we do anything with this?
3 | ---------------------------------------------
4 |
5 | To compute tax:
6 |
7 | - Need: Brackets, Earnings, Filing Status
8 | - Steps:
9 |
10 | 1. Split earnings into brackets
11 | 2. Compute tax for each bracket
12 | 3. Sum
13 |
14 |
15 | split_by_bracket
16 | ----------------
17 |
18 | a. start w/ lowest bracket
19 | b. if earnings < bracket
20 | -> tax is earnings * tax rate
21 |
22 | c. else tax is
23 | tax for this bracket
24 | + tax on remaining earnings
25 |
26 |
--------------------------------------------------------------------------------
/2013-04/intro_taxes/README.rst:
--------------------------------------------------------------------------------
1 |
2 | ==================
3 | The Tax Man Cometh
4 | ==================
5 |
6 | ---------------------------
7 | Or: The Other Inevitability
8 | ---------------------------
9 |
10 |
11 | :Author: Daniel J. Rocco, Ph.D.
12 |
13 |
14 | Tax season gave me an excuse to look at the ``csv`` module to show how one
15 | could read in CSV data, manipulate it, and write out a CSV file using Python.
16 |
17 | Topics covered:
18 |
19 | * reading in a CSV file
20 | * creating a lightweight model of a tax bracket using ``namedtuple``
21 | * using ``map`` to call a function on each element of a list
22 | * massaging the string data from a CSV into a more useful numeric format with
23 | Python's ``Decimal`` class
24 | * problem analysis: breaking down the "compute tax" problem into a set of
25 | prerequisites and a list of smaller steps
26 | * review of some of Python's list mechanisms including comprehensions and the
27 | ``sum`` function
28 | * writing out a CSV file
29 |
30 |
31 | Organization
32 | ============
33 |
34 | ``01_csv2.py``
35 | read in a CSV file and print out its rows
36 |
37 | ``01b_csv2.py``
38 | read in a CSV file and convert its rows to a list
39 |
40 | ``02_semantically_enhanced.py``
41 | create a lightweight model of a tax bracket using ``namedtuple``; use the
42 | ``Bracket._make`` function to convert the rows of the CSV file to Bracket
43 | objects
44 |
45 | ``brackets.py``
46 | further process the input data by converting strings to ``Decimal`` objects
47 | more suited for mathematical calculations
48 |
49 | ``03_split_by_bracket.txt``
50 | sketches out the design of our tax calculator, which includes the
51 | prerequisite information needed to perform the calculation and the steps
52 | involved in the calculation itself
53 |
54 | ``split_by_bracket.py``
55 | implementation of 03 step 1, including some sample calculations
56 |
57 | ``tax.py``
58 | implementation of the tax calculator, including some sample calculations
59 |
60 | ``tax_table.py``
61 | uses ``tax.py`` to write out a tax table
62 |
63 | ``simple_brackets.csv``
64 | the example brackets, which present a simplified progressive tax model.
65 | Changing the values here (e.g. using tax schedule data available on the
66 | web) will update the brackets used by the examples above
67 |
68 |
69 | Running the Examples
70 | --------------------
71 |
72 | I've added support code to the example Python programs above to allow them to
73 | be run standalone. All you will need is a working Python installation; for
74 | example::
75 |
76 | $ python tax.py
77 | single $5000: 500.0
78 | single $11000: 1200.0
79 | single $24000: 4200.0
80 |
81 | married $7000: 700.0
82 | married $15000: 1500.0
83 | married $19000: 2300.0
84 | married $31000: 4800.0
85 |
86 |
87 | Recursive implementation of ``split_by_bracket``
88 | ------------------------------------------------
89 |
90 | Due to popular demand I have added a recursive implementation of
91 | ``split_by_bracket`` in ``split_by_bracket_recursive.py`` along with some
92 | example runs.
93 |
94 |
95 | Resources
96 | =========
97 |
98 | * `The Python Tutorial `_
99 | * `The csv module `_
100 | * `The collections module, home of namedtuple `_
101 | * `Python's Decimal `_
102 | * `Tax Bracket Article `_; source of the simple brackets used in the demo
103 |
--------------------------------------------------------------------------------
/2013-04/intro_taxes/brackets.py:
--------------------------------------------------------------------------------
1 | import csv
2 | from collections import namedtuple
3 | from decimal import Decimal
4 |
5 |
6 | Bracket = namedtuple(
7 | 'Bracket',
8 | 'tax_rate single married_joint'
9 | )
10 |
11 |
12 | def process_row(row):
13 | """Given a row of data, make a Bracket out of the row while converting each
14 | element to a Decimal
15 |
16 | >>> process_row(('0.1', '2', '3.4'))
17 | Bracket(tax_rate=Decimal('0.1'), single=Decimal('2'), married_joint=Decimal('3.4'))
18 |
19 | """
20 |
21 | return Bracket._make(map(Decimal, row))
22 |
23 |
24 | with open('simple_brackets.csv', 'rb') as f:
25 | reader = csv.reader(f)
26 |
27 | # skip the header
28 | next(reader)
29 |
30 | brackets = map(process_row, reader)
31 |
32 |
33 | # we will need the brackets list later; this next bit will print out the
34 | # brackets if you say
35 | #
36 | # python brackets
37 | #
38 | # from the command line but not if some other part of the program imports them
39 |
40 | if __name__ == '__main__':
41 | print brackets
42 |
--------------------------------------------------------------------------------
/2013-04/intro_taxes/simple_brackets.csv:
--------------------------------------------------------------------------------
1 | tax_bracket,single,married_jointly
2 | 0.1,10000,15000
3 | 0.2,20000,30000
4 | 0.3,0,0
5 |
--------------------------------------------------------------------------------
/2013-04/intro_taxes/split_by_bracket.py:
--------------------------------------------------------------------------------
1 | from brackets import brackets
2 |
3 |
4 | def split_by_bracket(earnings, filing_status):
5 | result = []
6 | already_taxed = 0
7 |
8 | for bracket in brackets:
9 | # pull out the max amount for this
10 | # bracket and filing_status
11 | bracket_amount = getattr(bracket, filing_status)
12 |
13 | if bracket_amount and earnings > bracket_amount:
14 | result.append((bracket_amount - already_taxed, bracket.tax_rate))
15 | already_taxed = bracket_amount
16 | else:
17 | result.append((earnings - already_taxed, bracket.tax_rate))
18 | break
19 |
20 | return result
21 |
22 |
23 |
24 | # as in brackets.py, this bit prints some examples if you run
25 | #
26 | # python split_by_bracket
27 | #
28 |
29 | if __name__ == '__main__':
30 | for amount in (5000, 11000, 24000):
31 | print 'single ${}:'.format(amount), \
32 | split_by_bracket(amount, 'single')
33 |
34 | print
35 |
36 | for amount in (7000, 15000, 19000, 31000):
37 | print 'married ${}:'.format(amount), \
38 | split_by_bracket(amount, 'married_joint')
39 |
--------------------------------------------------------------------------------
/2013-04/intro_taxes/split_by_bracket_recursive.py:
--------------------------------------------------------------------------------
1 | from brackets import brackets
2 |
3 |
4 | def split_by_bracket(earnings, filing_status, _i=0, _already_taxed=0):
5 | bracket = brackets[_i]
6 | bracket_amount = getattr(bracket, filing_status)
7 |
8 | if not bracket_amount or earnings <= bracket_amount:
9 | return [(earnings - _already_taxed, bracket.tax_rate)]
10 | else:
11 | return [(bracket_amount - _already_taxed, bracket.tax_rate)] + \
12 | split_by_bracket(earnings, filing_status,
13 | _i=_i + 1, _already_taxed=bracket_amount)
14 |
15 |
16 | if __name__ == '__main__':
17 | for amount in (5000, 11000, 24000):
18 | print 'single ${}:'.format(amount), \
19 | split_by_bracket(amount, 'single')
20 |
21 | print
22 |
23 | for amount in (7000, 15000, 19000, 31000):
24 | print 'married ${}:'.format(amount), \
25 | split_by_bracket(amount, 'married_joint')
26 |
--------------------------------------------------------------------------------
/2013-04/intro_taxes/tax.py:
--------------------------------------------------------------------------------
1 | from split_by_bracket import split_by_bracket
2 |
3 | def tax(earnings, filing_status):
4 | earnings_by_bracket = split_by_bracket(earnings, filing_status)
5 |
6 | tax_by_bracket = [amount * tax_rate
7 | for amount, tax_rate in earnings_by_bracket]
8 |
9 | return sum(tax_by_bracket)
10 |
11 |
12 |
13 | if __name__ == '__main__':
14 | for amount in (5000, 11000, 24000):
15 | print 'single ${}:'.format(amount), tax(amount, 'single')
16 |
17 | print
18 |
19 | for amount in (7000, 15000, 19000, 31000):
20 | print 'married ${}:'.format(amount), tax(amount, 'married_joint')
21 |
--------------------------------------------------------------------------------
/2013-04/intro_taxes/tax_table.py:
--------------------------------------------------------------------------------
1 | import csv
2 |
3 | from brackets import Bracket
4 | from tax import tax
5 |
6 |
7 | filename = 'simple_tax_table.csv'
8 |
9 |
10 | with open(filename, 'wb') as f:
11 | writer = csv.writer(f)
12 | writer.writerow(['earnings'] + list(Bracket._fields[1:]))
13 |
14 | for amount in xrange(5000, 100001, 5000):
15 |
16 | # first column: earnings amount
17 | data = [amount]
18 |
19 | data += [tax(amount, filing_status)
20 | for filing_status in Bracket._fields[1:]]
21 |
22 | writer.writerow(data)
23 |
24 |
25 | print 'tax table written to', filename
26 |
--------------------------------------------------------------------------------
/2013-05/IPython/README.rst:
--------------------------------------------------------------------------------
1 | ==========================
2 | IPython Changes Everything
3 | ==========================
4 |
5 | :Author: | Daniel J. Rocco, Ph.D.
6 | | @drocco007
7 |
8 | In this introductory talk, we explored how IPython fits into the modern
9 | Python/OS ecosystem and sampled some of its helpful tools for exploring
10 | Python objects, source, and the filesystem.
11 |
12 | **Resources**
13 |
14 | * `IPython homepage `_
15 | * `Raymond Hettinger's post on reading source `_
16 | * Slides created with `Hieroglyph `_, a Sphinx extension for creating HTML5 slides
--------------------------------------------------------------------------------
/2013-05/IPython/_images/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_images/home.png
--------------------------------------------------------------------------------
/2013-05/IPython/_images/module_path.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_images/module_path.png
--------------------------------------------------------------------------------
/2013-05/IPython/_images/module_source.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_images/module_source.png
--------------------------------------------------------------------------------
/2013-05/IPython/_images/prompt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_images/prompt.png
--------------------------------------------------------------------------------
/2013-05/IPython/_static/ajax-loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/ajax-loader.gif
--------------------------------------------------------------------------------
/2013-05/IPython/_static/comment-bright.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/comment-bright.png
--------------------------------------------------------------------------------
/2013-05/IPython/_static/comment-close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/comment-close.png
--------------------------------------------------------------------------------
/2013-05/IPython/_static/comment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/comment.png
--------------------------------------------------------------------------------
/2013-05/IPython/_static/common.js:
--------------------------------------------------------------------------------
1 | var PERMANENT_URL_PREFIX = DOCUMENTATION_OPTIONS.URL_ROOT + '_static/';
2 |
3 | var SLIDE_CLASSES = ['far-past', 'past', 'current', 'next', 'far-next'];
4 | var SLIDES_SELECTOR = 'section.slides > article';
5 |
6 | var PM_TOUCH_SENSITIVITY = 15;
7 | var TABLE_CLASS = 'table';
8 |
9 | /* ---------------------------------------------------------------------- */
10 | /* classList polyfill by Eli Grey
11 | * (http://purl.eligrey.com/github/classList.js/blob/master/classList.js) */
12 |
13 | if (typeof document !== "undefined" && !("classList" in document.createElement("a"))) {
14 |
15 | (function (view) {
16 |
17 | var
18 | classListProp = "classList"
19 | , protoProp = "prototype"
20 | , elemCtrProto = (view.HTMLElement || view.Element)[protoProp]
21 | , objCtr = Object
22 | strTrim = String[protoProp].trim || function () {
23 | return this.replace(/^\s+|\s+$/g, "");
24 | }
25 | , arrIndexOf = Array[protoProp].indexOf || function (item) {
26 | for (var i = 0, len = this.length; i < len; i++) {
27 | if (i in this && this[i] === item) {
28 | return i;
29 | }
30 | }
31 | return -1;
32 | }
33 | // Vendors: please allow content code to instantiate DOMExceptions
34 | , DOMEx = function (type, message) {
35 | this.name = type;
36 | this.code = DOMException[type];
37 | this.message = message;
38 | }
39 | , checkTokenAndGetIndex = function (classList, token) {
40 | if (token === "") {
41 | throw new DOMEx(
42 | "SYNTAX_ERR"
43 | , "An invalid or illegal string was specified"
44 | );
45 | }
46 | if (/\s/.test(token)) {
47 | throw new DOMEx(
48 | "INVALID_CHARACTER_ERR"
49 | , "String contains an invalid character"
50 | );
51 | }
52 | return arrIndexOf.call(classList, token);
53 | }
54 | , ClassList = function (elem) {
55 | var
56 | trimmedClasses = strTrim.call(elem.className)
57 | , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
58 | ;
59 | for (var i = 0, len = classes.length; i < len; i++) {
60 | this.push(classes[i]);
61 | }
62 | this._updateClassName = function () {
63 | elem.className = this.toString();
64 | };
65 | }
66 | , classListProto = ClassList[protoProp] = []
67 | , classListGetter = function () {
68 | return new ClassList(this);
69 | }
70 | ;
71 | // Most DOMException implementations don't allow calling DOMException's toString()
72 | // on non-DOMExceptions. Error's toString() is sufficient here.
73 | DOMEx[protoProp] = Error[protoProp];
74 | classListProto.item = function (i) {
75 | return this[i] || null;
76 | };
77 | classListProto.contains = function (token) {
78 | token += "";
79 | return checkTokenAndGetIndex(this, token) !== -1;
80 | };
81 | classListProto.add = function (token) {
82 | token += "";
83 | if (checkTokenAndGetIndex(this, token) === -1) {
84 | this.push(token);
85 | this._updateClassName();
86 | }
87 | };
88 | classListProto.remove = function (token) {
89 | token += "";
90 | var index = checkTokenAndGetIndex(this, token);
91 | if (index !== -1) {
92 | this.splice(index, 1);
93 | this._updateClassName();
94 | }
95 | };
96 | classListProto.toggle = function (token) {
97 | token += "";
98 | if (checkTokenAndGetIndex(this, token) === -1) {
99 | this.add(token);
100 | } else {
101 | this.remove(token);
102 | }
103 | };
104 | classListProto.toString = function () {
105 | return this.join(" ");
106 | };
107 |
108 | if (objCtr.defineProperty) {
109 | var classListPropDesc = {
110 | get: classListGetter
111 | , enumerable: true
112 | , configurable: true
113 | };
114 | try {
115 | objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
116 | } catch (ex) { // IE 8 doesn't support enumerable:true
117 | if (ex.number === -0x7FF5EC54) {
118 | classListPropDesc.enumerable = false;
119 | objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
120 | }
121 | }
122 | } else if (objCtr[protoProp].__defineGetter__) {
123 | elemCtrProto.__defineGetter__(classListProp, classListGetter);
124 | }
125 |
126 | }(self));
127 |
128 | }
129 | /* ---------------------------------------------------------------------- */
130 |
--------------------------------------------------------------------------------
/2013-05/IPython/_static/console.css:
--------------------------------------------------------------------------------
1 | #controls {
2 | text-align: center;
3 | width: 100%;
4 | margin: 10px;
5 | font-size: 1.5em;
6 | font-family: sans-serif;
7 | }
8 |
9 | .slides.table > article {
10 | display: inline-block;
11 | }
12 |
13 | article.placeholder {
14 | background: #ddd;
15 | }
16 |
17 | .slides.table > article {
18 | position: absolute;
19 | left: 50%;
20 | margin-left: -225px;
21 | }
22 |
23 | .slides.table > article.past {
24 | transform: translate(-325px);
25 | -o-transform: translate(-325px);
26 | -moz-transform: translate(-325px);
27 | -webkit-transform: translate3d(-325px, 0, 0);
28 |
29 | }
30 |
31 | .slides.table > article.next {
32 | transform: translate(475px);
33 | -o-transform: translate(475px);
34 | -moz-transform: translate(475px);
35 | -webkit-transform: translate3d(475px, 0, 0);
36 | }
37 |
38 | .slides > article.past,
39 | .slides > article.next {
40 | height: 230px;
41 | width: 300px;
42 |
43 | margin-top: 60px;
44 | }
45 |
--------------------------------------------------------------------------------
/2013-05/IPython/_static/console.js:
--------------------------------------------------------------------------------
1 | document.addEventListener('DOMContentLoaded', function() {
2 |
3 | var
4 |
5 | handleKey = function(event) {
6 | switch (event.keyCode) {
7 | case 39: // right arrow
8 | case 13: // Enter
9 | case 32: // space
10 | case 34: // PgDn
11 | nextSlide();
12 | event.preventDefault();
13 | break;
14 |
15 | case 37: // left arrow
16 | case 8: // Backspace
17 | case 33: // PgUp
18 | prevSlide();
19 | event.preventDefault();
20 | break;
21 | }
22 | },
23 |
24 | handleUpdateSlides = function(slide_index, prev_slide, cur_slide, next_slide) {
25 | document.querySelector('#cur_slide_num').innerHTML = Number(slide_index) + 1;
26 |
27 | // make sure we have a previous and next slide to show;
28 | // if not add dummy placeholders
29 | if (!prev_slide) {
30 | prev_slide = '';
31 | }
32 | if (!next_slide) {
33 | next_slide = '';
34 | }
35 |
36 | document.querySelector('#slide_container').innerHTML = prev_slide + cur_slide + next_slide;
37 |
38 | var slides = document.querySelector('section.slides > article');
39 | for (var i=0; i < slides.length; i++) {
40 |
41 | }
42 | },
43 |
44 | handleMessage = function(e) {
45 | switch (e.data.command) {
46 | case 'num_slides':
47 | document.querySelector('#num_slides').innerHTML = e.data.content;
48 | break;
49 | case 'cur_slide':
50 | handleUpdateSlides(e.data.content, e.data.prev_slide, e.data.slide, e.data.next_slide);
51 | break;
52 | }
53 | },
54 |
55 | nextSlide = function(e) {
56 | if (e) {
57 | e.preventDefault();
58 | }
59 | window.opener.postMessage({command: 'nextSlide'}, '*');
60 | },
61 |
62 | prevSlide = function(e) {
63 | if (e) {
64 | e.preventDefault();
65 | }
66 |
67 | window.opener.postMessage({command: 'prevSlide'}, '*');
68 | },
69 |
70 | init = function(e) {
71 | window.addEventListener('message', handleMessage, false);
72 | document.addEventListener('keydown', handleKey, false);
73 |
74 | document.querySelector('#next').addEventListener('click', nextSlide);
75 | document.querySelector('#prev').addEventListener('click', prevSlide);
76 |
77 | window.opener.postMessage({command: 'register'}, '*');
78 |
79 | };
80 |
81 | init();
82 |
83 | }, false);
--------------------------------------------------------------------------------
/2013-05/IPython/_static/controller.js:
--------------------------------------------------------------------------------
1 | var SlideController = (
2 | function(){
3 |
4 | var
5 | slidedeck,
6 |
7 | onKeyDown = function (event) {
8 |
9 | switch (event.keyCode) {
10 | case 39: // right arrow
11 | case 13: // Enter
12 | case 32: // space
13 | case 34: // PgDn
14 | slidedeck.nextSlide();
15 | event.preventDefault();
16 | break;
17 |
18 | case 37: // left arrow
19 | case 8: // Backspace
20 | case 33: // PgUp
21 | slidedeck.prevSlide();
22 | event.preventDefault();
23 | break;
24 |
25 | case 40: // down arrow
26 | if (isChromeVoxActive()) {
27 | slidedeck.speakNextItem();
28 | } else {
29 | slidedeck.nextSlide();
30 | }
31 | event.preventDefault();
32 | break;
33 |
34 | case 38: // up arrow
35 | if (isChromeVoxActive()) {
36 | slidedeck.speakPrevItem();
37 | } else {
38 | slidedeck.prevSlide();
39 | }
40 | event.preventDefault();
41 | break;
42 |
43 | }
44 | };
45 |
46 | init = function(slides) {
47 | slidedeck = slides;
48 |
49 | document.addEventListener('keydown', onKeyDown, false);
50 |
51 | };
52 |
53 | return {
54 | init: init
55 | };
56 |
57 | }());
58 |
--------------------------------------------------------------------------------
/2013-05/IPython/_static/custom.css:
--------------------------------------------------------------------------------
1 | #ipython-changes-everything {
2 | padding-left: 0;
3 | }
4 |
5 | #ipython-changes-everything h1 {
6 | padding: 20px 0 20px 60px;
7 | background-color: rgba(200, 200, 200, 0.7);
8 | font-size: 3em;
9 | line-height: 0.85;
10 | }
11 |
12 | #ipython-changes-everything th.field-name {
13 | display: none;
14 | }
15 |
16 | #ipython-changes-everything td {
17 | padding-left: 60px;
18 | }
19 |
20 | .slides > article {
21 | border: none;
22 | box-shadow: none;
23 | font: 44px/50px'LeagueGothicRegular', Arial, sans-serif;
24 | }
25 |
26 | .slide > h1,h2 {
27 | font: 60px/68px 'LeagueGothicRegular', Arial, sans-serif;
28 | }
29 |
30 | .slide > h2 {
31 | bottom: 0px;
32 | left: 0px;
33 | background-color: rgba(0,0,0, 0.1);
34 | padding: 10px 40px;
35 | }
36 |
37 | ul li::before {
38 | content: none;
39 | }
40 |
41 | .drop {
42 | position: relative;
43 | top: 0.25em;
44 | left: -0.125em;
45 | }
46 |
47 | div.sidebar {
48 | font-size: 0.7em;
49 | }
--------------------------------------------------------------------------------
/2013-05/IPython/_static/down-pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/down-pressed.png
--------------------------------------------------------------------------------
/2013-05/IPython/_static/down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/down.png
--------------------------------------------------------------------------------
/2013-05/IPython/_static/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/file.png
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/droidsansmono-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/droidsansmono-webfont.eot
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/droidsansmono-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/droidsansmono-webfont.ttf
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/droidsansmono-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/droidsansmono-webfont.woff
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/generator_config.txt:
--------------------------------------------------------------------------------
1 | # Font Squirrel Font-face Generator Configuration File
2 | # Upload this file to the generator to recreate the settings
3 | # you used to create these fonts.
4 |
5 | {"mode":"optimal","formats":["ttf","woff","eotz"],"tt_instructor":"default","fix_vertical_metrics":"Y","fix_gasp":"xy","add_spaces":"Y","add_hyphens":"Y","fallback":"none","fallback_custom":"100","options_subset":"basic","subset_custom":"","subset_custom_range":"","css_stylesheet":"stylesheet.css","filename_suffix":"-webfont","emsquare":"2048","spacing_adjustment":"0"}
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-italic-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-italic-webfont.eot
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-italic-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-italic-webfont.ttf
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-italic-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-italic-webfont.woff
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-light-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-light-webfont.eot
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-light-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-light-webfont.ttf
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-light-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-light-webfont.woff
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-lightitalic-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-lightitalic-webfont.eot
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-lightitalic-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-lightitalic-webfont.ttf
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-lightitalic-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-lightitalic-webfont.woff
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-regular-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-regular-webfont.eot
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-regular-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-regular-webfont.ttf
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-regular-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-regular-webfont.woff
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-semibold-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-semibold-webfont.eot
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-semibold-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-semibold-webfont.ttf
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-semibold-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-semibold-webfont.woff
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-semibolditalic-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-semibolditalic-webfont.eot
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-semibolditalic-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-semibolditalic-webfont.ttf
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/opensans-semibolditalic-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/fonts/opensans-semibolditalic-webfont.woff
--------------------------------------------------------------------------------
/2013-05/IPython/_static/fonts/stylesheet.css:
--------------------------------------------------------------------------------
1 | /* Generated by Font Squirrel (http://www.fontsquirrel.com) on June 8, 2012 */
2 |
3 |
4 |
5 | @font-face {
6 | font-family: 'Open Sans Italic';
7 | src: url('opensans-italic-webfont.eot');
8 | src: url('opensans-italic-webfont.eot?#iefix') format('embedded-opentype'),
9 | url('opensans-italic-webfont.woff') format('woff'),
10 | url('opensans-italic-webfont.ttf') format('truetype'),
11 | url('opensans-italic-webfont.svg#OpenSansItalic') format('svg');
12 | font-weight: normal;
13 | font-style: normal;
14 |
15 | }
16 |
17 |
18 |
19 |
20 | @font-face {
21 | font-family: 'Open Sans';
22 | src: url('opensans-regular-webfont.eot');
23 | src: url('opensans-regular-webfont.eot?#iefix') format('embedded-opentype'),
24 | url('opensans-regular-webfont.woff') format('woff'),
25 | url('opensans-regular-webfont.ttf') format('truetype'),
26 | url('opensans-regular-webfont.svg#OpenSansRegular') format('svg');
27 | font-weight: normal;
28 | font-style: normal;
29 |
30 | }
31 |
32 |
33 |
34 |
35 | @font-face {
36 | font-family: 'Open Sans Semibold';
37 | src: url('opensans-semibold-webfont.eot');
38 | src: url('opensans-semibold-webfont.eot?#iefix') format('embedded-opentype'),
39 | url('opensans-semibold-webfont.woff') format('woff'),
40 | url('opensans-semibold-webfont.ttf') format('truetype'),
41 | url('opensans-semibold-webfont.svg#OpenSansSemiboldRegular') format('svg');
42 | font-weight: normal;
43 | font-style: normal;
44 |
45 | }
46 |
47 |
48 |
49 |
50 | @font-face {
51 | font-family: 'Open Sans Semibold Italic';
52 | src: url('opensans-semibolditalic-webfont.eot');
53 | src: url('opensans-semibolditalic-webfont.eot?#iefix') format('embedded-opentype'),
54 | url('opensans-semibolditalic-webfont.woff') format('woff'),
55 | url('opensans-semibolditalic-webfont.ttf') format('truetype'),
56 | url('opensans-semibolditalic-webfont.svg#OpenSansSemiboldItalic') format('svg');
57 | font-weight: normal;
58 | font-style: normal;
59 |
60 | }
61 |
62 |
63 |
64 |
65 | @font-face {
66 | font-family: 'Droid Sans Mono';
67 | src: url('droidsansmono-webfont.eot');
68 | src: url('droidsansmono-webfont.eot?#iefix') format('embedded-opentype'),
69 | url('droidsansmono-webfont.woff') format('woff'),
70 | url('droidsansmono-webfont.ttf') format('truetype'),
71 | url('droidsansmono-webfont.svg#DroidSansMonoRegular') format('svg');
72 | font-weight: normal;
73 | font-style: normal;
74 |
75 | }
76 |
77 |
78 |
79 |
80 | @font-face {
81 | font-family: 'Open Sans Light';
82 | src: url('opensans-light-webfont.eot');
83 | src: url('opensans-light-webfont.eot?#iefix') format('embedded-opentype'),
84 | url('opensans-light-webfont.woff') format('woff'),
85 | url('opensans-light-webfont.ttf') format('truetype'),
86 | url('opensans-light-webfont.svg#OpenSansLightRegular') format('svg');
87 | font-weight: normal;
88 | font-style: normal;
89 |
90 | }
91 |
92 |
93 |
94 |
95 | @font-face {
96 | font-family: 'Open Sans Light Italic';
97 | src: url('opensans-lightitalic-webfont.eot');
98 | src: url('opensans-lightitalic-webfont.eot?#iefix') format('embedded-opentype'),
99 | url('opensans-lightitalic-webfont.woff') format('woff'),
100 | url('opensans-lightitalic-webfont.ttf') format('truetype'),
101 | url('opensans-lightitalic-webfont.svg#OpenSansLightItalic') format('svg');
102 | font-weight: normal;
103 | font-style: normal;
104 |
105 | }
--------------------------------------------------------------------------------
/2013-05/IPython/_static/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/home.png
--------------------------------------------------------------------------------
/2013-05/IPython/_static/init.js:
--------------------------------------------------------------------------------
1 | SlideSync.init(SlideDeck);
2 | SlideController.init(SlideSync);
3 |
--------------------------------------------------------------------------------
/2013-05/IPython/_static/league.css:
--------------------------------------------------------------------------------
1 | @import url(slides.css);
2 | @import url(leaguegothic/stylesheet.css);
3 |
4 | ::-webkit-scrollbar {
5 | display: none;
6 | }
7 |
8 | body {
9 | background: white;
10 | }
11 |
12 | .slides > article {
13 | font: 60px/68px 'LeagueGothicRegular', Arial, sans-serif;
14 | letter-spacing: 0;
15 | -webkit-font-smoothing: antialiased;
16 | }
17 |
18 | h1, h2 {
19 | font-weight: normal;
20 | }
--------------------------------------------------------------------------------
/2013-05/IPython/_static/leaguegothic/LeagueGothic-CondensedItalic-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/leaguegothic/LeagueGothic-CondensedItalic-webfont.eot
--------------------------------------------------------------------------------
/2013-05/IPython/_static/leaguegothic/LeagueGothic-CondensedItalic-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/leaguegothic/LeagueGothic-CondensedItalic-webfont.ttf
--------------------------------------------------------------------------------
/2013-05/IPython/_static/leaguegothic/LeagueGothic-CondensedItalic-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/leaguegothic/LeagueGothic-CondensedItalic-webfont.woff
--------------------------------------------------------------------------------
/2013-05/IPython/_static/leaguegothic/LeagueGothic-CondensedRegular-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/leaguegothic/LeagueGothic-CondensedRegular-webfont.eot
--------------------------------------------------------------------------------
/2013-05/IPython/_static/leaguegothic/LeagueGothic-CondensedRegular-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/leaguegothic/LeagueGothic-CondensedRegular-webfont.ttf
--------------------------------------------------------------------------------
/2013-05/IPython/_static/leaguegothic/LeagueGothic-CondensedRegular-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/leaguegothic/LeagueGothic-CondensedRegular-webfont.woff
--------------------------------------------------------------------------------
/2013-05/IPython/_static/leaguegothic/LeagueGothic-Italic-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/leaguegothic/LeagueGothic-Italic-webfont.eot
--------------------------------------------------------------------------------
/2013-05/IPython/_static/leaguegothic/LeagueGothic-Italic-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/leaguegothic/LeagueGothic-Italic-webfont.ttf
--------------------------------------------------------------------------------
/2013-05/IPython/_static/leaguegothic/LeagueGothic-Italic-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/leaguegothic/LeagueGothic-Italic-webfont.woff
--------------------------------------------------------------------------------
/2013-05/IPython/_static/leaguegothic/LeagueGothic-Regular-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/leaguegothic/LeagueGothic-Regular-webfont.eot
--------------------------------------------------------------------------------
/2013-05/IPython/_static/leaguegothic/LeagueGothic-Regular-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/leaguegothic/LeagueGothic-Regular-webfont.ttf
--------------------------------------------------------------------------------
/2013-05/IPython/_static/leaguegothic/LeagueGothic-Regular-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/leaguegothic/LeagueGothic-Regular-webfont.woff
--------------------------------------------------------------------------------
/2013-05/IPython/_static/leaguegothic/SIL OFL Font License League Gothic.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010, Caroline Hadilaksono & Micah Rich , with Reserved Font Name: "League Gothic".
2 |
3 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
4 | This license is copied below, and is also available with a FAQ at:
5 | http://scripts.sil.org/OFL
6 |
7 | Version 1.1 - 26 February 2007
8 |
9 |
10 | SIL Open Font License
11 | ====================================================
12 |
13 |
14 | Preamble
15 | ----------
16 |
17 | The goals of the Open Font License (OFL) are to stimulate worldwide
18 | development of collaborative font projects, to support the font creation
19 | efforts of academic and linguistic communities, and to provide a free and
20 | open framework in which fonts may be shared and improved in partnership
21 | with others.
22 |
23 | The OFL allows the licensed fonts to be used, studied, modified and
24 | redistributed freely as long as they are not sold by themselves. The
25 | fonts, including any derivative works, can be bundled, embedded,
26 | redistributed and/or sold with any software provided that any reserved
27 | names are not used by derivative works. The fonts and derivatives,
28 | however, cannot be released under any other type of license. The
29 | requirement for fonts to remain under this license does not apply
30 | to any document created using the fonts or their derivatives.
31 |
32 | Definitions
33 | -------------
34 |
35 | `"Font Software"` refers to the set of files released by the Copyright
36 | Holder(s) under this license and clearly marked as such. This may
37 | include source files, build scripts and documentation.
38 |
39 | `"Reserved Font Name"` refers to any names specified as such after the
40 | copyright statement(s).
41 |
42 | `"Original Version"` refers to the collection of Font Software components as
43 | distributed by the Copyright Holder(s).
44 |
45 | `"Modified Version"` refers to any derivative made by adding to, deleting,
46 | or substituting -- in part or in whole -- any of the components of the
47 | Original Version, by changing formats or by porting the Font Software to a
48 | new environment.
49 |
50 | `"Author"` refers to any designer, engineer, programmer, technical
51 | writer or other person who contributed to the Font Software.
52 |
53 | Permission & Conditions
54 | ------------------------
55 |
56 | Permission is hereby granted, free of charge, to any person obtaining
57 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
58 | redistribute, and sell modified and unmodified copies of the Font
59 | Software, subject to the following conditions:
60 |
61 | 1. Neither the Font Software nor any of its individual components,
62 | in Original or Modified Versions, may be sold by itself.
63 |
64 | 2. Original or Modified Versions of the Font Software may be bundled,
65 | redistributed and/or sold with any software, provided that each copy
66 | contains the above copyright notice and this license. These can be
67 | included either as stand-alone text files, human-readable headers or
68 | in the appropriate machine-readable metadata fields within text or
69 | binary files as long as those fields can be easily viewed by the user.
70 |
71 | 3. No Modified Version of the Font Software may use the Reserved Font
72 | Name(s) unless explicit written permission is granted by the corresponding
73 | Copyright Holder. This restriction only applies to the primary font name as
74 | presented to the users.
75 |
76 | 4. The name(s) of the Copyright Holder(s) or the Author(s) of the Font
77 | Software shall not be used to promote, endorse or advertise any
78 | Modified Version, except to acknowledge the contribution(s) of the
79 | Copyright Holder(s) and the Author(s) or with their explicit written
80 | permission.
81 |
82 | 5. The Font Software, modified or unmodified, in part or in whole,
83 | must be distributed entirely under this license, and must not be
84 | distributed under any other license. The requirement for fonts to
85 | remain under this license does not apply to any document created
86 | using the Font Software.
87 |
88 | Termination
89 | -----------
90 |
91 | This license becomes null and void if any of the above conditions are
92 | not met.
93 |
94 |
95 | DISCLAIMER
96 |
97 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
98 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
99 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
100 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
101 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
102 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
103 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
104 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
105 | OTHER DEALINGS IN THE FONT SOFTWARE.
106 |
--------------------------------------------------------------------------------
/2013-05/IPython/_static/leaguegothic/stylesheet.css:
--------------------------------------------------------------------------------
1 | /* Generated by Font Squirrel (http://www.fontsquirrel.com) on May 5, 2013 12:09:23 AM America/New_York */
2 |
3 |
4 |
5 | @font-face {
6 | font-family: 'LeagueGothicRegular';
7 | src: url('LeagueGothic-Regular-webfont.eot');
8 | src: url('LeagueGothic-Regular-webfont.eot?#iefix') format('embedded-opentype'),
9 | url('LeagueGothic-Regular-webfont.woff') format('woff'),
10 | url('LeagueGothic-Regular-webfont.ttf') format('truetype'),
11 | url('LeagueGothic-Regular-webfont.svg#LeagueGothicRegular') format('svg');
12 | font-weight: normal;
13 | font-style: normal;
14 |
15 | }
16 |
17 | @font-face {
18 | font-family: 'LeagueGothicItalic';
19 | src: url('LeagueGothic-Italic-webfont.eot');
20 | src: url('LeagueGothic-Italic-webfont.eot?#iefix') format('embedded-opentype'),
21 | url('LeagueGothic-Italic-webfont.woff') format('woff'),
22 | url('LeagueGothic-Italic-webfont.ttf') format('truetype'),
23 | url('LeagueGothic-Italic-webfont.svg#LeagueGothicItalic') format('svg');
24 | font-weight: normal;
25 | font-style: normal;
26 |
27 | }
28 |
29 | @font-face {
30 | font-family: 'LeagueGothicCondensedRegular';
31 | src: url('LeagueGothic-CondensedRegular-webfont.eot');
32 | src: url('LeagueGothic-CondensedRegular-webfont.eot?#iefix') format('embedded-opentype'),
33 | url('LeagueGothic-CondensedRegular-webfont.woff') format('woff'),
34 | url('LeagueGothic-CondensedRegular-webfont.ttf') format('truetype'),
35 | url('LeagueGothic-CondensedRegular-webfont.svg#LeagueGothicCondensedRegular') format('svg');
36 | font-weight: normal;
37 | font-style: normal;
38 |
39 | }
40 |
41 | @font-face {
42 | font-family: 'LeagueGothicCondensedItalic';
43 | src: url('LeagueGothic-CondensedItalic-webfont.eot');
44 | src: url('LeagueGothic-CondensedItalic-webfont.eot?#iefix') format('embedded-opentype'),
45 | url('LeagueGothic-CondensedItalic-webfont.woff') format('woff'),
46 | url('LeagueGothic-CondensedItalic-webfont.ttf') format('truetype'),
47 | url('LeagueGothic-CondensedItalic-webfont.svg#LeagueGothicCondensedItalic') format('svg');
48 | font-weight: normal;
49 | font-style: normal;
50 |
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/2013-05/IPython/_static/minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/minus.png
--------------------------------------------------------------------------------
/2013-05/IPython/_static/module_path.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/module_path.png
--------------------------------------------------------------------------------
/2013-05/IPython/_static/module_source.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/module_source.png
--------------------------------------------------------------------------------
/2013-05/IPython/_static/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/plus.png
--------------------------------------------------------------------------------
/2013-05/IPython/_static/prompt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/prompt.png
--------------------------------------------------------------------------------
/2013-05/IPython/_static/pygments.css:
--------------------------------------------------------------------------------
1 | .highlight .hll { background-color: #ffffcc }
2 | .highlight { background: #eeffcc; }
3 | .highlight .c { color: #408090; font-style: italic } /* Comment */
4 | .highlight .err { border: 1px solid #FF0000 } /* Error */
5 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */
6 | .highlight .o { color: #666666 } /* Operator */
7 | .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
8 | .highlight .cp { color: #007020 } /* Comment.Preproc */
9 | .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
10 | .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
11 | .highlight .gd { color: #A00000 } /* Generic.Deleted */
12 | .highlight .ge { font-style: italic } /* Generic.Emph */
13 | .highlight .gr { color: #FF0000 } /* Generic.Error */
14 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
15 | .highlight .gi { color: #00A000 } /* Generic.Inserted */
16 | .highlight .go { color: #333333 } /* Generic.Output */
17 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
18 | .highlight .gs { font-weight: bold } /* Generic.Strong */
19 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
20 | .highlight .gt { color: #0044DD } /* Generic.Traceback */
21 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
22 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
23 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
24 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */
25 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
26 | .highlight .kt { color: #902000 } /* Keyword.Type */
27 | .highlight .m { color: #208050 } /* Literal.Number */
28 | .highlight .s { color: #4070a0 } /* Literal.String */
29 | .highlight .na { color: #4070a0 } /* Name.Attribute */
30 | .highlight .nb { color: #007020 } /* Name.Builtin */
31 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
32 | .highlight .no { color: #60add5 } /* Name.Constant */
33 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
34 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
35 | .highlight .ne { color: #007020 } /* Name.Exception */
36 | .highlight .nf { color: #06287e } /* Name.Function */
37 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
38 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
39 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
40 | .highlight .nv { color: #bb60d5 } /* Name.Variable */
41 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
42 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */
43 | .highlight .mf { color: #208050 } /* Literal.Number.Float */
44 | .highlight .mh { color: #208050 } /* Literal.Number.Hex */
45 | .highlight .mi { color: #208050 } /* Literal.Number.Integer */
46 | .highlight .mo { color: #208050 } /* Literal.Number.Oct */
47 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
48 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */
49 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
50 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */
51 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
52 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
53 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
54 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */
55 | .highlight .sr { color: #235388 } /* Literal.String.Regex */
56 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */
57 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */
58 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
59 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
60 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
61 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
62 | .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
--------------------------------------------------------------------------------
/2013-05/IPython/_static/slides.css:
--------------------------------------------------------------------------------
1 | img.fill {
2 | position: absolute;
3 | left: 0;
4 | top: 0;
5 | min-width: 100%;
6 | min-height: 100%;
7 |
8 | border-radius: 10px;
9 | -o-border-radius: 10px;
10 | -moz-border-radius: 10px;
11 | -webkit-border-radius: 10px;
12 |
13 | z-index: -1;
14 | }
15 |
16 | a.headerlink {
17 | visibility: hidden;
18 | }
19 |
20 | h1:hover > a.headerlink,
21 | h2:hover > a.headerlink,
22 | h3:hover > a.headerlink,
23 | h4:hover > a.headerlink,
24 | h5:hover > a.headerlink,
25 | h6:hover > a.headerlink,
26 | dt:hover > a.headerlink {
27 | visibility: visible;
28 | }
29 |
30 | div.figure p.caption {
31 | position: absolute;
32 | left: 0;
33 | bottom: 0;
34 | font-size: 0.5em;
35 | }
36 |
37 | .slide-no {
38 | position: absolute;
39 | bottom: 1ex;
40 | right: 1em;
41 | font-size: 66%;
42 | }
--------------------------------------------------------------------------------
/2013-05/IPython/_static/sync.js:
--------------------------------------------------------------------------------
1 | var SlideSync = (
2 | function() {
3 |
4 | var
5 | slides,
6 | slide_listeners = [],
7 |
8 | showConsole = function(e) {
9 | slide_console = window.open(
10 | DOCUMENTATION_OPTIONS.URL_ROOT + 'console.html',
11 | 'console',
12 | "menubar=no,location=no,resizable=yes,scrollbars=yes,status=yes");
13 | },
14 |
15 | nextSlide = function() {
16 | slides.nextSlide();
17 |
18 | sendCommand('nextSlide');
19 | sendCurSlide();
20 | },
21 |
22 | prevSlide = function() {
23 | slides.prevSlide();
24 |
25 | sendCommand('prevSlide');
26 | sendCurSlide();
27 | },
28 |
29 | sendCurSlide = function() {
30 |
31 | var curSlide = slides.curSlide();
32 |
33 | notifyListeners(
34 | {command: 'cur_slide',
35 | content: curSlide,
36 | prev_slide: curSlide > 0 ? slides.getSlideEl(curSlide - 1).outerHTML : '',
37 | slide: slides.getSlideEl(curSlide).outerHTML,
38 | next_slide: curSlide < slides.length() - 1 ? slides.getSlideEl(curSlide + 1).outerHTML : ''
39 | }
40 | );
41 |
42 | },
43 |
44 | notifyListeners = function (message) {
45 |
46 | for (var i = 0; i < slide_listeners.length; i++) {
47 | slide_listeners[i].postMessage(message, '*');
48 | }
49 |
50 | },
51 |
52 | sendCommand = function(command) {
53 | return sendMessage({'command':command});
54 | },
55 |
56 | sendMessage = function(message) {
57 | notifyListeners(message);
58 | },
59 |
60 | handleMessage = function(message, source) {
61 |
62 | console.log(message);
63 |
64 | switch (message.command) {
65 |
66 | case 'register':
67 | slide_listeners.push(source);
68 | sendMessage(
69 | {command: 'num_slides',
70 | content: slideEls.length
71 | }
72 | );
73 | break;
74 |
75 | case 'nextSlide':
76 | slides.nextSlide();
77 | break;
78 |
79 | case 'prevSlide':
80 | slides.prevSlide();
81 | break;
82 |
83 | };
84 |
85 | sendCurSlide();
86 |
87 | },
88 |
89 | onKeyDown = function (event) {
90 |
91 | switch (event.keyCode) {
92 |
93 | case 84: // t
94 | slides.toggleView && slides.toggleView();
95 | break;
96 |
97 | case 67: // c
98 | showConsole();
99 | break;
100 | }
101 | },
102 |
103 | init = function(slidedeck) {
104 | slides = slidedeck;
105 |
106 | // attach event handlers
107 | document.addEventListener('keydown', onKeyDown, false);
108 | window.addEventListener(
109 | 'message',
110 | function(e) {
111 | return handleMessage(e.data, e.source);
112 | }, false);
113 |
114 | };
115 |
116 |
117 | return {
118 | init: init,
119 | showConsole: showConsole,
120 |
121 | nextSlide: nextSlide,
122 | prevSlide: prevSlide,
123 |
124 | handleMessage: handleMessage,
125 | sendMessage: sendMessage,
126 | sendCommand: sendCommand
127 | };
128 |
129 | }());
--------------------------------------------------------------------------------
/2013-05/IPython/_static/theme.css:
--------------------------------------------------------------------------------
1 | a.headerlink {
2 | display: none;
3 | }
--------------------------------------------------------------------------------
/2013-05/IPython/_static/up-pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/up-pressed.png
--------------------------------------------------------------------------------
/2013-05/IPython/_static/up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-05/IPython/_static/up.png
--------------------------------------------------------------------------------
/2013-05/threading/README.md:
--------------------------------------------------------------------------------
1 | Threading Patterns in Python
2 | ============================
3 | JR Rickerson
4 |
5 | Why Threading?
6 | --------------
7 | Sometimes, it makes sense to break a program down such that we can do little
8 | pieces of it at a time, and some of those pieces can be done in parallel. It's
9 | not a guarentee, but sometimes this can save us time overall, providing faster
10 | processing of large amounts of information or faster user response time.
11 |
12 | In this talk, we'll specifically be looking at threading. However, many of
13 | the same concepts apply to multi-process applications, or even applications
14 | distributed across many machine in a cluster, or across the world.
15 |
16 | Why Threading Patterns?
17 | -----------------------
18 | When we introduct threading or any kind of parallelism to an application, it
19 | can help us solve a certain set of problems - however, it can introduce a whole
20 | new set of problems as well. When different threads of execution are sharing
21 | the same resources - be it actual memory (variables, data structures),
22 | communication channels (pipes, sockets), or stored information (files,
23 | databases), unless we have a plan in place for coordinating access to these
24 | resources, unintended behavior can occur.
25 |
26 | Remember - the interpreter doesn't know what you intended, and the OS doesn't
27 | have any concept of what order to execute statements in your threads in -
28 | UNLESS you tell it.
29 |
30 | Most threading libraries, including Python's, provide what are called
31 | "synchronization" objects. Using these, in conjuction with well-established
32 | patterns for parallel process, can help us avoid or at least minimize many of
33 | the issues we could run into in the multi-threaded world.
34 |
35 | Most of these patterns have been established because they continually crop up
36 | as good solutions to common problems where multi-threading is useful, and
37 | through refinement of techniques by programmers writing multi-threaded code
38 | for years.
39 |
40 | References
41 | ----------
42 | * Python threading module: http://docs.python.org/2/library/threading.html
43 | * PMOTW threading: http://pymotw.com/2/threading/
44 | * Queue module: http://docs.python.org/2/library/queue.html
45 |
46 |
--------------------------------------------------------------------------------
/2013-05/threading/barrier.py:
--------------------------------------------------------------------------------
1 | # Threading Patterns in Python
2 | #
3 | # The "Barrier" pattern.
4 | # This pattern is used when you need to have multiple threads doing work,
5 | # and additional work needs to be completed, but only AFTER the other threads
6 | # have first completed their work. You can think of it like a dependency tree,
7 | # like so:
8 | #
9 | #
10 | # --> Task A -->
11 | # Start --> --> Task B --> --> Task D --> Complete
12 | # --> Task C -->
13 |
14 | import time
15 | from threading import Thread, Event
16 |
17 | A = Event()
18 | B = Event()
19 | C = Event()
20 | D = Event()
21 |
22 | def taskA():
23 | print 'Task A is doing some work'
24 | time.sleep(4)
25 | A.set()
26 | D.wait()
27 | print 'Task A is exiting'
28 |
29 | def taskB():
30 | print 'Task B is doing some work'
31 | time.sleep(1)
32 | B.set()
33 | D.wait()
34 | print 'Task B is exiting'
35 |
36 | def taskC():
37 | print 'Task C is doing some work'
38 | time.sleep(3)
39 | C.set()
40 | D.wait()
41 | print 'Task C is exiting'
42 |
43 | def taskD():
44 | print 'Task D is waiting on other tasks'
45 | A.wait()
46 | B.wait()
47 | C.wait()
48 | print 'Task D is doing some work'
49 | time.sleep(1)
50 | D.set()
51 | print 'Task D is exiting'
52 |
53 |
54 | def main():
55 |
56 | # Create our threads
57 | tasks = [
58 | Thread(target=taskA),
59 | Thread(target=taskB),
60 | Thread(target=taskC),
61 | Thread(target=taskD),
62 | ]
63 |
64 | print '"Main" is starting threads'
65 | # Start all the threads running
66 | for task in tasks:
67 | task.start()
68 |
69 | print '"Main" is waiting for threads to finish'
70 | for task in tasks:
71 | task.join()
72 |
73 |
74 | if __name__ == '__main__':
75 | main()
76 |
77 |
--------------------------------------------------------------------------------
/2013-05/threading/callback.py:
--------------------------------------------------------------------------------
1 | # Threading Patterns in Python
2 | #
3 | # The "Callback" pattern.
4 | # This pattern is not strictly a parallel / threading pattern, but often
5 | # comes up in asychronous development or multi-threading scenarios.
6 | # This is also common in scenarios when using a third party library that
7 | # you may have little to no control over.
8 | # Some thread typically runs as an "engine" or main thread, doing various
9 | # types of processing. Other threads under your control are able to register
10 | # callback functions which are called when certain events occur during the main
11 | # threading processing.
12 | #
13 | #
14 | # Start --> Engine (loops) --> Complete
15 | # |
16 | # ---> Callback function
17 | #
18 |
19 | import time
20 | from threading import Thread
21 |
22 |
23 | def engine(fizz_callback, buzz_callback):
24 | for i in xrange(100):
25 | # Engine does some work
26 | time.sleep(1)
27 | if i % 3 == 0:
28 | fizz_callback(i)
29 | if i % 5 == 0:
30 | callback_thread = Thread(target=buzz_callback, args=(i,))
31 | callback_thread.start()
32 |
33 | def fizz_handler(num):
34 | print 'Value {0} is FIZZ'.format(num)
35 |
36 | def buzz_handler(num):
37 | print 'Value {0} is BUZZ'.format(num)
38 |
39 | def main():
40 | engine_thread = Thread(target=engine, args=(fizz_handler, buzz_handler))
41 |
42 | engine_thread.start()
43 | engine_thread.join()
44 |
45 |
46 | if __name__ == '__main__':
47 | main()
48 |
--------------------------------------------------------------------------------
/2013-05/threading/producer_consumer.py:
--------------------------------------------------------------------------------
1 | # Threading Patterns in Python
2 | #
3 | # The Producer-Consumer Pattern
4 | # This is a very common pattern in multi-threading scenarios. In this pattern, one or
5 | # more threads are doing some pre-processing and "producing" units of work, while another
6 | # set of "consumer" or "worker" threads are actually doing the processing on these units
7 | # of work. Often, a queue system is used to communicate between threads and provide
8 | # synchronization. These queue-linked producers and consumers can be chained together
9 | # to form a type of pipeline. The queue can also set a maximum size to limit how much
10 | # work is done at once.
11 |
12 | import time
13 | from threading import Thread, Event
14 | from Queue import Queue, Empty
15 |
16 | producers_complete = Event()
17 | consumers_complete = Event()
18 |
19 | source_queue = Queue()
20 | work_queue = Queue()
21 |
22 |
23 | def consumer(consumers_complete):
24 | print 'Consumer started.'
25 | while not consumers_complete.is_set():
26 | try:
27 | item = work_queue.get(True, 1)
28 | print 'Consumer is working on {0}'.format(item)
29 | time.sleep(1)
30 | work_queue.task_done()
31 | except Empty:
32 | print 'Consumer Work Queue was empty, no work to do.'
33 |
34 | print 'Consumer exited.'
35 |
36 | def producer(producers_complete):
37 | print 'Producer started.'
38 | while not producers_complete.is_set():
39 | try:
40 | number = source_queue.get(True, 1)
41 | print 'Producer is generating work for item #{0}'.format(number)
42 | work_queue.put('Work Item #{0}'.format(number))
43 | source_queue.task_done()
44 | except Empty:
45 | print 'Producer Source Queue was empty, no work to do.'
46 | print 'Producer exited.'
47 |
48 |
49 | def main():
50 | # Set up initial signal conditions
51 |
52 | # Create 5 consumers
53 | consumers = [Thread(target=consumer, args=(consumers_complete,)) for i in range(5)]
54 | # Create 3 producers
55 | producers = [Thread(target=producer, args=(producers_complete,)) for i in range(3)]
56 |
57 | # Provide some original source of work
58 | for i in xrange(100):
59 | source_queue.put(i + 1)
60 |
61 | # Start consumers and producers
62 | for c in consumers:
63 | c.start()
64 | for p in producers:
65 | p.start()
66 |
67 | # Wait until all the work has been picked up
68 | source_queue.join()
69 | # Signal all our producers threads to exit
70 | producers_complete.set()
71 |
72 | # Wait on all the work to be completed
73 | work_queue.join()
74 | consumers_complete.set()
75 |
76 | # Now wait on all the threads to exit
77 | for p in producers:
78 | p.join()
79 | for c in consumers:
80 | c.join()
81 |
82 |
83 | if __name__ == '__main__':
84 | main()
85 |
--------------------------------------------------------------------------------
/2013-06/fizzbuzz/01_fizz_or_buzz.py:
--------------------------------------------------------------------------------
1 | 'Fizz' if not n % 3
2 | 'Buzz' if not n % 5
3 |
--------------------------------------------------------------------------------
/2013-06/fizzbuzz/02_fizz_and_buzz.py:
--------------------------------------------------------------------------------
1 | (''.join(
2 | ['Fizz' if not n % 3 else '',
3 | 'Buzz' if not n % 5 else ''])
4 | )
5 |
--------------------------------------------------------------------------------
/2013-06/fizzbuzz/03_number.py:
--------------------------------------------------------------------------------
1 | (
2 | ''.join(
3 | ['Fizz' if not n % 3 else '',
4 | 'Buzz' if not n % 5 else ''])
5 |
6 | or str(n))
7 | )
8 |
--------------------------------------------------------------------------------
/2013-06/fizzbuzz/boring.py:
--------------------------------------------------------------------------------
1 | for i in xrange(101):
2 | if (not i % 3) and (not i % 5):
3 | print 'FizzBuzz'
4 | elif not i % 3:
5 | print 'Fizz'
6 | elif not i % 5:
7 | print 'Buzz'
8 | else:
9 | print i
10 |
--------------------------------------------------------------------------------
/2013-06/fizzbuzz/clever.py:
--------------------------------------------------------------------------------
1 | for i in xrange(101):
2 | out = []
3 | if not i % 3:
4 | out.append('Fizz')
5 | if not i % 5:
6 | out.append('Buzz')
7 | if not out:
8 | out.append(str(i))
9 | print ''.join(out)
10 |
--------------------------------------------------------------------------------
/2013-06/fizzbuzz/fizzbuzz.py:
--------------------------------------------------------------------------------
1 | print '\n'.join(
2 | (''.join(
3 | ['Fizz' if not n % 3 else '',
4 | 'Buzz' if not n % 5 else ''])
5 | or str(n))
6 | for n in range(1, 101)
7 | )
8 |
--------------------------------------------------------------------------------
/2013-06/fizzbuzz/fizzbuzz_tweet.py:
--------------------------------------------------------------------------------
1 | print '\n'.join((''.join(['Fizz' if not n % 3 else '', 'Buzz' if not n % 5 else '']) or str(n)) for n in range(1, 101))
2 |
--------------------------------------------------------------------------------
/2013-06/fizzbuzz/one-liner.sh:
--------------------------------------------------------------------------------
1 | # via http://www.commandlinefu.com/commands/view/9454/fizzbuzz-one-liner-in-python
2 |
3 | python -c 'for i in range(1,101): print"FizzBuzz"[i*i%3*4:8--i**4%5]or i'
4 |
5 |
--------------------------------------------------------------------------------
/2013-07/virtualenv/requirements.txt:
--------------------------------------------------------------------------------
1 | Jinja2==2.7
2 | MarkupSafe==0.18
3 | Pygments==1.6
4 | Sphinx==1.2b1
5 | docutils==0.10
6 | hieroglyph==0.5.5
7 |
--------------------------------------------------------------------------------
/2013-07/virtualenv/source/_static/.placeholder:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-07/virtualenv/source/_static/.placeholder
--------------------------------------------------------------------------------
/2013-07/virtualenv/source/_static/custom.css:
--------------------------------------------------------------------------------
1 | .slides > article {
2 | /* background-color: lightblue; */
3 | color: #222222;
4 | }
5 |
6 | h2 {
7 | bottom: 50px;
8 | }
9 |
10 | /* Use when the pre tag contents do not fit on the screen otherwise. */
11 | .small {
12 | font-size: 70%;
13 | }
14 |
--------------------------------------------------------------------------------
/2013-07/virtualenv/source/_templates/.placeholder:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-07/virtualenv/source/_templates/.placeholder
--------------------------------------------------------------------------------
/2013-07/virtualenv/source/virtualenv_output.txt:
--------------------------------------------------------------------------------
1 | $ virtualenv -v foo
2 | Creating foo/lib/python2.7
3 | Symlinking Python bootstrap modules
4 | Symlinking foo/lib/python2.7/config
5 | Symlinking foo/lib/python2.7/lib-dynload
6 | Symlinking foo/lib/python2.7/os.py
7 | Ignoring built-in bootstrap module: posix
8 | Symlinking foo/lib/python2.7/posixpath.py
9 | Cannot import bootstrap module: nt
10 | Symlinking foo/lib/python2.7/ntpath.py
11 | Symlinking foo/lib/python2.7/genericpath.py
12 | Symlinking foo/lib/python2.7/fnmatch.py
13 | Symlinking foo/lib/python2.7/locale.py
14 | Symlinking foo/lib/python2.7/encodings
15 | Symlinking foo/lib/python2.7/codecs.py
16 | Symlinking foo/lib/python2.7/stat.py
17 | Symlinking foo/lib/python2.7/UserDict.py
18 | Symlinking foo/lib/python2.7/copy_reg.py
19 | Symlinking foo/lib/python2.7/types.py
20 | Symlinking foo/lib/python2.7/re.py
21 | Symlinking foo/lib/python2.7/sre.py
22 | Symlinking foo/lib/python2.7/sre_parse.py
23 | Symlinking foo/lib/python2.7/sre_constants.py
24 | Symlinking foo/lib/python2.7/sre_compile.py
25 | Symlinking foo/lib/python2.7/warnings.py
26 | Symlinking foo/lib/python2.7/linecache.py
27 | Symlinking foo/lib/python2.7/_abcoll.py
28 | Symlinking foo/lib/python2.7/abc.py
29 | Symlinking foo/lib/python2.7/_weakrefset.py
30 | Creating foo/lib/python2.7/site-packages
31 | Writing foo/lib/python2.7/site.py
32 | Writing foo/lib/python2.7/orig-prefix.txt
33 | Writing foo/lib/python2.7/no-global-site-packages.txt
34 | Creating parent directories for foo/include
35 | Symlinking foo/include/python2.7
36 | Creating foo/bin
37 | New python executable in foo/bin/python
38 | Changed mode of foo/bin/python to 0755
39 | Symlinking foo/.Python
40 | Testing executable with foo/bin/python -c "import sys;out=sys.stdout;getattr(out, "buffer", out).write(sys.prefix.encode("utf-8"))"
41 | Got sys.prefix result: u'/Users/dhellmann/Documents/2013/Presentations/virtualenv/foo'
42 | Creating foo/lib/python2.7/distutils
43 | Writing foo/lib/python2.7/distutils/__init__.py
44 | Writing foo/lib/python2.7/distutils/distutils.cfg
45 | Using existing setuptools egg: /Users/dhellmann/Library/Python/2.7/lib/python/site-packages/virtualenv_support/setuptools-0.6c11-py2.7.egg
46 | Installing setuptools..........
47 | Processing dependencies for setuptools==0.6c11
48 | Finished processing dependencies for setuptools==0.6c11
49 | ...Installing setuptools...done.
50 | Installing existing pip-1.3.1.tar.gz distribution: /Users/dhellmann/Library/Python/2.7/lib/python/site-packages/virtualenv_support/pip-1.3.1.tar.gz
51 | Installing pip...
52 | Processing pip-1.3.1.tar.gz
53 | Running pip-1.3.1/setup.py -q bdist_egg --dist-dir /var/folders/5q/8gk0wq888xlggz008k8dr7180000hg/T/easy_install-Jsz3Pu/pip-1.3.1/egg-dist-tmp-3vXRNj
54 | warning: no files found matching '*.html' under directory 'docs'
55 | warning: no previously-included files matching '*.txt' found under directory 'docs/_build'
56 | no previously-included directories found matching 'docs/_build/_sources'
57 | Adding pip 1.3.1 to easy-install.pth file
58 | Processing dependencies for pip==1.3.1
59 | Finished processing dependencies for pip==1.3.1
60 | ...Installing pip...done.
61 | Writing foo/bin/activate
62 | Writing foo/bin/activate.fish
63 | Writing foo/bin/activate_this.py
64 | Writing foo/bin/activate.csh
65 |
--------------------------------------------------------------------------------
/2013-09/operator-overloading/source/_static/custom.css:
--------------------------------------------------------------------------------
1 | .slides > article {
2 | /* background-color: lightblue; */
3 | color: #222222;
4 | }
5 |
6 | h2 {
7 | bottom: 50px;
8 | }
9 |
10 | /* Use when the pre tag contents do not fit on the screen otherwise. */
11 | .small {
12 | font-size: 70%;
13 | }
14 |
--------------------------------------------------------------------------------
/2013-09/operator-overloading/source/index.rst:
--------------------------------------------------------------------------------
1 | ===================================================
2 | Operator Overloading and Python's Special Methods
3 | ===================================================
4 |
5 | | PyATL
6 | | September, 2013
7 | | Doug.Hellmann@gmail.com
8 | | @doughellmann
9 | | http://doughellmann.com
10 |
11 | .. note::
12 |
13 | Going to talk about:
14 |
15 | 1. What special methods are.
16 | 2. Some example special methods.
17 | 3. Look at how the comparison operators use special methods.
18 |
19 | What are "Special Methods"?
20 | ===========================
21 |
22 | *Special Methods* are a naming convention to bind methods of your
23 | class to operators or built-ins in the language.
24 |
25 | Also known as "Dunder" methods ("double underscore").
26 |
27 | .. note::
28 |
29 | Special methods tie your class in to Python by using well-defined
30 | names that the interpreter looks for.
31 |
32 | __init__
33 | ========
34 |
35 | ::
36 |
37 | my_inst = MyClass()
38 |
39 | When a Class type needs to initialize a new instance, it calls the
40 | __init__ method.
41 |
42 | __del__
43 | =======
44 |
45 | ::
46 |
47 | del my_inst
48 |
49 | Clean up resources owned by an object in __del__.
50 |
51 | __str__ and __unicode__
52 | =======================
53 |
54 | ::
55 |
56 | str(my_inst)
57 | unicode(my_inst)
58 |
59 | Replacing the string representation via __str__ or __unicode__ makes
60 | it easier to debug with custom classes.
61 |
62 | __repr__
63 | ========
64 |
65 | ::
66 |
67 | repr(my_inst)
68 | print my_inst
69 |
70 | The print statement uses the repr() of an object by default.
71 |
72 | __iter__
73 | ========
74 |
75 | ::
76 |
77 | for i in my_inst:
78 | ...
79 |
80 | The __iter__ method returns an iterator for an iterable object.
81 |
82 | __call__
83 | ========
84 |
85 | ::
86 |
87 | my_inst(arg1, arg2)
88 |
89 | Adding a __call__ method means you can use the "invoke function"
90 | operator of two parens.
91 |
92 |
93 | __getattr__, __setattr__, __delattr__
94 | =====================================
95 |
96 | ::
97 |
98 | print my_inst.foo
99 | my_inst.foo = 'value'
100 | del my_inst.foo
101 |
102 | Attribute access using the dot operator can be overridden, too.
103 |
104 | __enter__ and __exit__
105 | ======================
106 |
107 | ::
108 |
109 | with my_inst as context:
110 | do_something(context)
111 |
112 | Adding __enter__ and __exit__ makes your class work as a context
113 | manager, so you can use it with the "with" statement.
114 |
115 | __len__
116 | =======
117 |
118 | ::
119 |
120 | len(my_inst)
121 |
122 | The len() built-in invokes the __len__ method
123 |
124 | __hash__
125 | ========
126 |
127 | ::
128 |
129 | hash(my_inst)
130 |
131 | d = {my_inst: 'value'}
132 |
133 | s = {my_inst}
134 |
135 | To control the way dictionary keys and set membership is computed,
136 | override the __hash__ method.
137 |
138 | __nonzero__
139 | ===========
140 |
141 | ::
142 |
143 | if my_inst:
144 | do_something()
145 |
146 | __nonzero__ is called to convert an object to a boolean
147 | representation
148 |
149 | __contains__
150 | ============
151 |
152 | ::
153 |
154 | if 'foo' in my_inst:
155 | do_something()
156 |
157 | if 'bar' not in my_inst:
158 | do_something_else()
159 |
160 | Python will fall back to scanning data structures, but using ``in`` to
161 | test membership can make it more efficient.
162 |
163 | Old-Style Comparison
164 | ====================
165 |
166 | ``__cmp__()`` returns a number representing the relationship.
167 |
168 | :-1: The object is less than the argument.
169 | :0: The object is equal to the argument.
170 | :1: The object is greater than the argument.
171 |
172 | **Warning**: This comparison style is deprecated.
173 |
174 | Rich Comparison Methods
175 | =======================
176 |
177 | ======== ==========
178 | Method Operator
179 | ======== ==========
180 | __lt__ ``<``
181 | __le__ ``<=``
182 | __eq__ ``==``
183 | __ne__ ``!=``
184 | __gt__ ``>``
185 | __ge__ ``>=``
186 | ======== ==========
187 |
188 | ``functools.total_ordering``
189 |
190 | Default Sorting
191 | ===============
192 |
193 | .. literalinclude:: unsorted.py
194 | :lines: 4-11
195 |
196 | Default Sorting
197 | ===============
198 |
199 | .. literalinclude:: unsorted.py
200 | :lines: 14-22
201 |
202 | *What will the output be?*
203 |
204 | Default Sorting
205 | ===============
206 |
207 | ::
208 |
209 | $ python unsorted.py
210 |
211 | Jetson, George
212 | Jetson, Jane
213 | Jetson, Elroy
214 | Jetson, Judy
215 |
216 | *Why?*
217 |
218 | Custom Sorting
219 | ==============
220 |
221 | .. literalinclude:: sortable.py
222 | :lines: 6-24
223 | :emphasize-lines: 1,10-24
224 |
225 | .. note::
226 |
227 | ``total_ordering`` adds the missing comparison operations based on
228 | the 2 given.
229 |
230 | Custom Sorting
231 | ==============
232 |
233 | ::
234 |
235 | $ python sortable.py
236 |
237 | Jetson, Elroy
238 | Jetson, George
239 | Jetson, Jane
240 | Jetson, Judy
241 |
242 | Caveats
243 | =======
244 |
245 | - ``total_ordering`` requires two rich comparison methods.
246 | - Easy to get carried away and abuse operator overloading.
247 | - Python does not do any type checking for you.
248 | - Special method names are reserved for internal use, so don't name
249 | arbitrary methods using the dunder scheme.
250 |
251 | References
252 | ==========
253 |
254 | - "Special Method Names"
255 | http://docs.python.org/2/reference/datamodel.html#special-method-names
256 |
--------------------------------------------------------------------------------
/2013-09/operator-overloading/source/sortable.py:
--------------------------------------------------------------------------------
1 | #!/bin/env python
2 |
3 | import functools
4 |
5 |
6 | @functools.total_ordering
7 | class Person(object):
8 |
9 | def __init__(self, first, last):
10 | self.first = first
11 | self.last = last
12 |
13 | def __repr__(self):
14 | return ', '.join([self.last, self.first])
15 |
16 | def __eq__(self, other):
17 | if not isinstance(other, Person):
18 | return NotImplemented
19 | return (self.last, self.first) == (other.last, other.first)
20 |
21 | def __lt__(self, other):
22 | if not isinstance(other, Person):
23 | return NotImplemented
24 | return (self.last, self.first) < (other.last, other.first)
25 |
26 |
27 | data = [
28 | Person('George', 'Jetson'),
29 | Person('Jane', 'Jetson'),
30 | Person('Elroy', 'Jetson'),
31 | Person('Judy', 'Jetson'),
32 | ]
33 |
34 | for p in sorted(data):
35 | print p
36 |
--------------------------------------------------------------------------------
/2013-09/operator-overloading/source/unsorted.py:
--------------------------------------------------------------------------------
1 | #!/bin/env python
2 |
3 |
4 | class Person(object):
5 |
6 | def __init__(self, first, last):
7 | self.first = first
8 | self.last = last
9 |
10 | def __repr__(self):
11 | return ', '.join([self.last, self.first])
12 |
13 |
14 | data = [
15 | Person('George', 'Jetson'),
16 | Person('Jane', 'Jetson'),
17 | Person('Elroy', 'Jetson'),
18 | Person('Judy', 'Jetson'),
19 | ]
20 |
21 | for p in sorted(data):
22 | print p
23 |
--------------------------------------------------------------------------------
/2013-09/zmq/README.rst:
--------------------------------------------------------------------------------
1 | ============
2 | ØMQ Examples
3 | ============
4 |
5 | :author: Daniel J. Rocco, @drocco007
6 | :date: September 2013
7 |
8 | Example code for my September 2013 PyAtl talk *Let's Talk*.
9 |
10 | `Talk slides `_; note that the
11 | background looks pretty good at projector resolution but a little weird on a
12 | full resolution display. :/
13 |
14 |
15 | hello
16 | =====
17 |
18 | Illustrates a basic request-response communication mechanism. Pretty much a
19 | straight copy from the guide example: http://zguide.zeromq.org/py:hwclient
20 |
21 | Run with::
22 |
23 | python hwserver.py
24 |
25 | and in a separate window
26 |
27 | ::
28 |
29 | python hwclient.py
30 |
31 |
32 | fizzbuzz (*)
33 | ============
34 |
35 | Very contrived publish-subscribe example.
36 |
37 | ::
38 |
39 | python ventilator.py
40 |
41 | starts the publisher, which publishes the numbers 1 to 100 forever. Yes. Time
42 | it if you don't believe me.
43 |
44 | Start the clients with something like
45 |
46 | ::
47 |
48 | python fizzer.py & python buzzer.py &
49 |
50 | Although this example is highly goofy, it does illustrate the basic principles
51 | of publish-subscribe in ØMQ. Remember:
52 |
53 | 1. Publishers do not wait. If you want synchronization, you need to add it.
54 |
55 | 2. Subscribers *must* set a subscription, even if it's ``''`` (everything). If
56 | you forget this, your listeners will be surprisingly deaf (like my kids).
57 |
58 | (*) not a real FIZZBUZZ
59 |
60 |
61 | image_farm
62 | ==========
63 |
64 | ``image_farm`` illustrates work distribution and processing, in this case
65 | resizing images in batch. The workers (``farmer.py``) receive source images and
66 | generate three size of thumbnails for each image they receive. Each worker
67 | sends a message to a listening process (``sink.py``) when finished.
68 |
69 | To try it out, first fire up some workers::
70 |
71 | python farmer.py # want >1 of these
72 | python farmer.py
73 | python farmer.py
74 |
75 | and a sink
76 |
77 | ::
78 |
79 | python sink.py
80 |
81 | Then, queue up some images::
82 |
83 | python cli_enqueue_images.py image1.png image2.jpg ...
84 |
85 | You probably want to give it quite a few images: modern hardware is quite fast.
86 | You'll need PIL installed for this to work; I suggest installing the Pillow
87 | fork unless you enjoy debugging build problems from an archaic package::
88 |
89 | pip install Pillow
90 |
--------------------------------------------------------------------------------
/2013-09/zmq/fizzbuzz/buzzer.py:
--------------------------------------------------------------------------------
1 | from fb import fizzerbuzzer
2 |
3 | fizzerbuzzer(5, 'Buzz')
4 |
--------------------------------------------------------------------------------
/2013-09/zmq/fizzbuzz/fb.py:
--------------------------------------------------------------------------------
1 | import zmq
2 |
3 | # Awkward factory for setting up listener processes. sentinel is the "divisible
4 | # by" value we're looking for and message is the message we print out. Usually
5 | # called with 3, 'FIZZ' and 5, 'BUZZ'.
6 |
7 | def fizzerbuzzer(sentinel, message):
8 | # Socket to talk to message publisher
9 | context = zmq.Context()
10 | socket = context.socket(zmq.SUB)
11 | socket.connect("tcp://localhost:5555")
12 |
13 | socket.setsockopt(zmq.SUBSCRIBE, '')
14 |
15 | # Synchronization: we'll most likely connect in the middle of the
16 | # publisher's message cycle, so wait till we see '100' before starting.
17 | while True:
18 | if socket.recv() == '100':
19 | break
20 |
21 | # Process 100 updates
22 | for index in range(100):
23 | value = socket.recv()
24 | value = int(value)
25 |
26 | if not value % sentinel:
27 | print message
28 | else:
29 | print value
30 |
--------------------------------------------------------------------------------
/2013-09/zmq/fizzbuzz/fizzer.py:
--------------------------------------------------------------------------------
1 | from fb import fizzerbuzzer
2 |
3 | fizzerbuzzer(3, 'Fizz')
4 |
--------------------------------------------------------------------------------
/2013-09/zmq/fizzbuzz/ventilator.py:
--------------------------------------------------------------------------------
1 | from itertools import cycle
2 | import time
3 |
4 | import zmq
5 |
6 | context = zmq.Context()
7 | socket = context.socket(zmq.PUB)
8 | socket.bind("tcp://*:5555")
9 |
10 | for index in cycle(range(1, 101)):
11 | socket.send(str(index))
12 | time.sleep(0.05)
13 |
--------------------------------------------------------------------------------
/2013-09/zmq/hello/hwclient.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | #
3 | # Hello World client in Python
4 | # Connects REQ socket to tcp://localhost:5555
5 | # Sends "Hello" to server, expects "World" back
6 | #
7 | import zmq
8 |
9 | context = zmq.Context()
10 |
11 | # Socket to talk to server
12 | print "Connecting to hello world server…"
13 | socket = context.socket(zmq.REQ)
14 | socket.connect ("tcp://localhost:5555")
15 |
16 | # Do 10 requests, waiting each time for a response
17 | for request in range (10):
18 | print "Sending request ", request,"…"
19 | socket.send ("Hello")
20 |
21 | # Get the reply.
22 | message = socket.recv()
23 | print "Received reply ", request, "[", message, "]"
24 |
--------------------------------------------------------------------------------
/2013-09/zmq/hello/hwserver.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | #
3 | # Hello World server in Python
4 | # Connects REP socket to tcp://localhost:5555
5 | # Receives "Hello" from client, sends "World" back
6 |
7 | from time import time
8 | import zmq
9 |
10 | context = zmq.Context()
11 | socket = context.socket(zmq.REP)
12 | socket.bind("tcp://*:5555")
13 |
14 | while True:
15 | message = socket.recv()
16 | print "[{}] Received {}".format(time(), message)
17 | socket.send("World")
18 |
--------------------------------------------------------------------------------
/2013-09/zmq/image_farm/cli_enqueue_images.py:
--------------------------------------------------------------------------------
1 | # Task ventilator
2 | # Binds PUSH socket to tcp://localhost:5557
3 | # Sends batch of tasks to workers via that socket
4 |
5 | import sys
6 | from time import sleep
7 |
8 | import zmq
9 |
10 | context = zmq.Context()
11 |
12 | # Socket to send messages on
13 | sender = context.socket(zmq.PUSH)
14 | sender.bind("tcp://*:5557")
15 |
16 | for filename in sys.argv[1:]:
17 | with open(filename, 'rb') as f:
18 | payload = filename, f.read()
19 |
20 | # Why, yes: Python *is* awesome!
21 | sender.send_pyobj(payload)
22 |
23 | sleep(0.25)
24 |
--------------------------------------------------------------------------------
/2013-09/zmq/image_farm/farmer.py:
--------------------------------------------------------------------------------
1 | # Task worker
2 | # Connects PULL socket to tcp://localhost:5557
3 | # Collects workloads from ventilator via that socket
4 | # Connects PUSH socket to tcp://localhost:5558
5 | # Sends results to sink via that socket
6 | #
7 | # Based on an example by Lev Givon
8 |
9 | import sys
10 | import time
11 |
12 | import zmq
13 |
14 | from resize_image import format_output_filename, resize_image
15 |
16 | context = zmq.Context()
17 |
18 | # Socket to receive messages on
19 | receiver = context.socket(zmq.PULL)
20 | receiver.connect("tcp://localhost:5557")
21 |
22 | # Socket to send messages to
23 | sender = context.socket(zmq.PUSH)
24 | sender.connect("tcp://localhost:5558")
25 |
26 | # Process tasks forever
27 | while True:
28 | image_name, image_data = receiver.recv_pyobj()
29 |
30 | # Simple progress indicator for the viewer
31 | sys.stdout.write('.')
32 | sys.stdout.flush()
33 |
34 | # Do the work
35 | for size in (64, 128, 256):
36 | output_filename = format_output_filename(image_name, size)
37 | resize_image(image_data, size, output_filename)
38 |
39 | # Send results to sink
40 | sender.send(output_filename)
41 |
--------------------------------------------------------------------------------
/2013-09/zmq/image_farm/resize_image.py:
--------------------------------------------------------------------------------
1 | import os
2 | from StringIO import StringIO
3 |
4 | from PIL import Image
5 |
6 |
7 | def format_output_filename(input_filename, max_height):
8 | base, extension = os.path.splitext(input_filename)
9 | output_filename = ''.join([base, '_thumbnail', str(max_height), extension])
10 |
11 | return output_filename
12 |
13 |
14 | def resize_image(image_data, max_height, output_filename):
15 | size = max_height, max_height
16 |
17 | image = Image.open(StringIO(image_data))
18 | image.thumbnail(size, Image.ANTIALIAS)
19 |
20 | image.save(output_filename)
21 |
22 | return image
23 |
24 |
25 | # test code that can be run standalone from the command line
26 |
27 | if __name__ == '__main__':
28 | import sys
29 |
30 | max_height = 128
31 | input_filename = sys.argv[1]
32 |
33 | output_filename = format_output_filename(input_filename, max_height)
34 |
35 | with open(input_filename, 'rb') as f:
36 | image_data = f.read()
37 |
38 | image = resize_image(image_data, max_height, output_filename)
39 |
40 | print 'Resized {} ({} {} {})'.format(
41 | input_filename, image.format, image.size, image.mode)
42 |
--------------------------------------------------------------------------------
/2013-09/zmq/image_farm/sink.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from time import time
3 |
4 | import zmq
5 |
6 | context = zmq.Context()
7 |
8 | # Socket to receive messages on
9 | receiver = context.socket(zmq.PULL)
10 | receiver.bind("tcp://*:5558")
11 |
12 | while True:
13 | image_name = receiver.recv()
14 | print '[{}] {} generated'.format(time(), image_name)
15 |
--------------------------------------------------------------------------------
/2013-10/flake8/README.rst:
--------------------------------------------------------------------------------
1 | To build the slides, run "make".
2 |
3 | The output will be written to the "build" directory.
4 |
5 | Output
6 | ======
7 |
8 | The output lines are formatted to make it possible (easy?) to
9 | integrate the output with an IDE or editor that knows how to jump to
10 | compiler errors.
11 |
12 | * filename
13 | * line number
14 | * column
15 | * error message
16 |
17 |
--------------------------------------------------------------------------------
/2013-10/flake8/source/_static/custom.css:
--------------------------------------------------------------------------------
1 | .slides > article {
2 | /* background-color: lightblue; */
3 | color: #222222;
4 | }
5 |
6 | h2 {
7 | bottom: 50px;
8 | }
9 |
10 | /* Use when the pre tag contents do not fit on the screen otherwise. */
11 | .small {
12 | font-size: 70%;
13 | }
14 |
15 | /* Center block quotes vertically and horizontally. Based on
16 | http://css-tricks.com/vertically-center-multi-lined-text/
17 | */
18 |
19 | blockquote {
20 | font-size: 130%;
21 | display: table;
22 | vertical-align: middle;
23 | text-align: center;
24 | height: 80%;
25 | width: 80%;
26 | }
27 |
28 | blockquote div {
29 | display: table-cell;
30 | vertical-align: middle;
31 | text-align: center;
32 | }
--------------------------------------------------------------------------------
/2013-10/flake8/source/clean.py:
--------------------------------------------------------------------------------
1 | MAPPING = {
2 | 'a': 'A',
3 | }
4 |
5 | LIST = [
6 | 'a',
7 | 'b',
8 | ]
9 |
10 | # This comment is a very long line, which causes problems for people
11 | # who program Python on punch cards.
12 |
13 | parser_errors = [
14 | (__name__, 1, 1, 'message'),
15 | ]
16 |
17 | errors = [
18 | 'Parse error at %s:%s "%s" (%s)' %
19 | (filename, num, line, err)
20 | for filename, num, line, err in parser_errors
21 | ]
22 |
23 |
24 | # This is something you might do in an __init__.py
25 | from .submodule import public_function # noqa
26 |
27 |
28 | def f(*args):
29 | print(args)
30 |
31 | f(1, 2, 3,
32 | 4, 5, 6)
33 |
--------------------------------------------------------------------------------
/2013-10/flake8/source/commits-per-month.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-10/flake8/source/commits-per-month.png
--------------------------------------------------------------------------------
/2013-10/flake8/source/contributors-per-month.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-10/flake8/source/contributors-per-month.png
--------------------------------------------------------------------------------
/2013-10/flake8/source/lines-of-code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2013-10/flake8/source/lines-of-code.png
--------------------------------------------------------------------------------
/2013-10/flake8/source/messy.py:
--------------------------------------------------------------------------------
1 | MAPPING = {
2 | 'a':'A',
3 | }
4 |
5 | LIST = [
6 | 'a',
7 | 'b',
8 | ]
9 |
10 | # This comment is a very long line, which causes problems for people who program Python on punch cards.
11 |
12 | parser_errors = [
13 | (__name__, 1, 1, 'message'),
14 | ]
15 |
16 | errors = ['Parse error at %s:%s "%s" (%s)' % (filename, num, line, err) for filename, num, line, err in parser_errors]
17 |
18 |
19 | # This is something you might do in an __init__.py
20 | from .submodule import public_function
21 |
22 | def f(*args):
23 | print(args)
24 |
25 | f(1, 2, 3,
26 | 4, 5, 6)
27 |
--------------------------------------------------------------------------------
/2013-10/objects/15-puzzle_old_version.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 |
3 | """15-puzzle
4 |
5 | Simple 15 puzzle game.
6 | """
7 |
8 | import random
9 |
10 |
11 | class Puzzle(object):
12 | """Represents a "15-puzzle"
13 |
14 | ``size`` is the width and height of the puzzle, supporting puzzles
15 | with dimensions other than 4x4
16 |
17 | >>> print(Puzzle())
18 | 1 2 3 4
19 | 5 6 7 8
20 | 9 10 11 12
21 | 13 14 15 _
22 |
23 | >>> print(Puzzle(2))
24 | 1 2
25 | 3 _
26 | """
27 | def __init__(self, size=4):
28 | self._size = size
29 |
30 | self._puzzle = []
31 | for row in range(self._size):
32 | row_start = row * self._size
33 | self._puzzle.append(map(str, range(row_start + 1,
34 | row_start + 1 + self._size)))
35 |
36 | self._puzzle[-1][-1] = "_"
37 |
38 | def __str__(self):
39 | return "\n".join(["\t".join(row) for row in self._puzzle])
40 |
41 | def move(self, row, column):
42 | """Move by sliding from the given square toward the empty space.
43 |
44 | >>> print(Puzzle(2).move(1,0))
45 | 1 2
46 | _ 3
47 |
48 | >>> print(Puzzle(2).move(0,1))
49 | 1 _
50 | 3 2
51 |
52 | >>> print(Puzzle(2).move(0,1).move(0,0).move(1,0))
53 | 3 1
54 | _ 2
55 |
56 | >>> print(Puzzle(2).move(0,0))
57 | Traceback (most recent call last):
58 | ...
59 | ValueError: locked square at (0, 0)
60 | """
61 | if "_" in self._puzzle[row]:
62 | return self._move_on_row(row, column)
63 |
64 | # transpose rows and columns
65 | puzzle = map(list, zip(*self._puzzle))
66 |
67 | if "_" in puzzle[column]:
68 | self._puzzle = puzzle
69 | self._move_on_row(column, row)
70 | self._puzzle = map(list, zip(*self._puzzle))
71 | else:
72 | raise ValueError("locked square at " + str( (row, column) ))
73 |
74 | return self
75 |
76 | def _move_on_row(self, row, column):
77 | """Move row-wise by sliding the given square toward the empty space.
78 |
79 | >>> print(Puzzle(2)._move_on_row(1,0))
80 | 1 2
81 | _ 3
82 |
83 | >>> print(Puzzle(3)._move_on_row(2,0)._move_on_row(2,1))
84 | 1 2 3
85 | 4 5 6
86 | 7 _ 8
87 |
88 | >>> print(Puzzle(2)._move_on_row(0,0))
89 | Traceback (most recent call last):
90 | …
91 | ValueError: list.remove(x): x not in list
92 | """
93 | self._puzzle[row].remove("_")
94 | self._puzzle[row].insert(column, "_")
95 |
96 | return self
97 |
98 | def valid_moves(self):
99 | """List the currently valid moves.
100 |
101 | >>> sorted(Puzzle(2).valid_moves()) == [(0, 1), (1, 0)]
102 | True
103 |
104 | >>> sorted(Puzzle(3).valid_moves()) == [(0, 2), (1, 2), \
105 | (2, 0), (2, 1)]
106 | True
107 |
108 | >>> sorted(Puzzle(3).move(1,2).move(1,1).valid_moves()) == \
109 | [(0, 1), (1, 0), \
110 | (1, 2), (2, 1)]
111 | True
112 | """
113 | for index, row in enumerate(self._puzzle):
114 | if "_" in row:
115 | _column_index = row.index("_")
116 | _row_index = index
117 | break
118 |
119 | row_moves = [(_row_index, column)
120 | for column in range(self._size)
121 | if self._puzzle[_row_index][column] != "_"]
122 |
123 | column_moves = [(row, _column_index)
124 | for row in range(self._size)
125 | if row != _row_index]
126 |
127 | return row_moves + column_moves
128 |
129 | def shuffle(self, iterations=100):
130 | """Shuffle the puzzle"""
131 |
132 | for iteration in xrange(iterations):
133 | move = random.choice(self.valid_moves())
134 | self.move(*move)
135 |
136 | return self
137 |
138 | def is_solved(self):
139 | """Is the puzzle solved?
140 |
141 | >>> Puzzle().is_solved()
142 | True
143 |
144 | >>> Puzzle().shuffle(1).is_solved()
145 | False
146 |
147 | >>> Puzzle(5).is_solved()
148 | True
149 |
150 | >>> Puzzle(3).move(0,2).is_solved()
151 | False
152 |
153 | """
154 |
155 | return self._puzzle == Puzzle(self._size)._puzzle
156 |
157 | # ====================================================================
158 | # doctest test harness
159 |
160 | def _test(_verbose=False):
161 | import doctest
162 | doctest.testmod(verbose=_verbose, optionflags=(doctest.ELLIPSIS |
163 | #doctest.REPORT_NDIFF |
164 | doctest.NORMALIZE_WHITESPACE))
165 |
166 | # ====================================================================
167 | # test stub: run doctests if this file is run directly
168 |
169 | if __name__ == "__main__":
170 | _test()
171 |
172 | for size in [2, 3, 3, 4, 5, 10]:
173 | puzzle = Puzzle(size)
174 | puzzle.shuffle(1000 * size)
175 | print(puzzle)
176 | print("")
177 |
--------------------------------------------------------------------------------
/2013-10/objects/README.rst:
--------------------------------------------------------------------------------
1 | Musing about Objects
2 | ====================
3 |
4 | Support code for my `Musing about Objects`_ October PyAtl talk.
5 |
6 | ``15-puzzle_old_version.py`` is the version I wrote as an assignment in 2009.
7 | It uses ``doctest`` as the testing framework; running the file will invoke the
8 | tests.
9 |
10 | The ``fifteen_puzzle`` package contains the newer implementation; its test
11 | suite is in ``tests``. You'll need ``pytest`` to run them::
12 |
13 | py.test tests
14 |
15 | ``NetworkX_sandbox.ipynb`` is an IPython notebook of my explorations of
16 | `NetworkX`_, which provided the graph data structure for the newer version.
17 |
18 | .. _Musing about Objects: http://pyatl.github.io/talks/2013-10_objects/
19 | .. _NetworkX: http://networkx.github.io/
20 |
--------------------------------------------------------------------------------
/2013-10/objects/fifteen_puzzle/__init__.py:
--------------------------------------------------------------------------------
1 | import networkx as nx
2 |
3 |
4 | class Puzzle(object):
5 | """Represents a 15-puzzle
6 |
7 | ``size`` is the width and height of the puzzle, supporting puzzles with
8 | dimensions other than 4x4.
9 |
10 | """
11 |
12 | def __init__(self, size=4):
13 | self.size = size
14 | self._puzzle = nx.grid_2d_graph(size, size)
15 |
16 | # Label each node with its tile value, e.g. (0, 0) is tile '1' in the
17 | # upper left. add_node is a NetworkX graph method to update an
18 | # existing node, in this case by setting its 'value'
19 | for value, coordinates in enumerate(sorted(self._puzzle), 1):
20 | self._puzzle.add_node(coordinates, value=str(value))
21 |
22 | # Label the empty tile
23 | self._puzzle.add_node((size-1, size-1), value='_')
24 |
25 | @property
26 | def is_solved(self):
27 | """Indicate whether the puzzle is in a solved state"""
28 |
29 | # TODO: implementation left as an exercise
30 | return True
31 |
32 | def coordinates_for(self, value):
33 | """Determine the coordinates for the specified number value
34 |
35 | Returns a 2-tuple representing the coordinates for the given value,
36 | with (0, 0) representing the top left corner of the puzzle.
37 |
38 | """
39 |
40 | for node in self._puzzle:
41 | if self._puzzle.node[node]['value'] == str(value):
42 | return node
43 |
44 | def move(self, value):
45 | """Move a tile by sliding it to the empty square.
46 |
47 | Raises ValueError if the requested tile is locked in place.
48 |
49 | """
50 |
51 | empty = self.coordinates_for('_')
52 | origin = self.coordinates_for(value)
53 |
54 | if empty not in self._puzzle.neighbors(origin):
55 | raise ValueError('locked square at ' + str(origin))
56 |
57 | # "move" the tile by swapping its value with the empty tiles
58 | self._puzzle.add_node(empty, value=str(value))
59 | self._puzzle.add_node(origin, value='_')
60 |
61 | @property
62 | def valid_moves(self):
63 | """List of currently valid moves, returned as tile labels, e.g.
64 |
65 | ['15', '12']
66 |
67 | """
68 |
69 | empty = self.coordinates_for('_')
70 |
71 | return [self._puzzle.node[node]['value']
72 | for node in self._puzzle.neighbors(empty)]
73 |
74 | # TODO: __str__ and shuffle left as an exercise
75 |
--------------------------------------------------------------------------------
/2013-10/objects/setup.cfg:
--------------------------------------------------------------------------------
1 | [egg_info]
2 | tag_build = dev
3 | tag_svn_revision = true
4 |
--------------------------------------------------------------------------------
/2013-10/objects/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup, find_packages
2 | import sys, os
3 |
4 | version = '0.0'
5 |
6 | setup(name='fifteen_puzzle',
7 | version=version,
8 | description="",
9 | long_description="""\
10 | """,
11 | classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
12 | keywords='',
13 | author='',
14 | author_email='',
15 | url='',
16 | license='',
17 | packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
18 | include_package_data=True,
19 | zip_safe=False,
20 | install_requires=[
21 | # -*- Extra requirements: -*-
22 | ],
23 | entry_points="""
24 | # -*- Entry points: -*-
25 | """,
26 | )
27 |
--------------------------------------------------------------------------------
/2013-10/objects/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/2013-10/objects/tests/conftest.py:
--------------------------------------------------------------------------------
1 | from fifteen_puzzle import Puzzle
2 |
3 | import pytest
4 |
5 |
6 | @pytest.fixture
7 | def puzzle():
8 | """Fixture providing a new Puzzle of the default size (4x4)"""
9 |
10 | return Puzzle()
11 |
--------------------------------------------------------------------------------
/2013-10/objects/tests/test_when_calculating_valid_moves.py:
--------------------------------------------------------------------------------
1 | def test_initial_valid_moves_should_be_twelve_and_fifteen(puzzle):
2 | assert ['12', '15'] == sorted(puzzle.valid_moves, key=int)
3 |
4 |
5 | def test_valid_after_horizontal_move(puzzle):
6 | puzzle.move(15)
7 |
8 | assert ['11', '14', '15'] == sorted(puzzle.valid_moves, key=int)
9 |
10 |
11 | def test_valid_after_vertical_move(puzzle):
12 | puzzle.move(12)
13 |
14 | assert ['8', '11', '12'] == sorted(puzzle.valid_moves, key=int)
15 |
16 |
17 | def test_valid_after_move_sequence(puzzle):
18 | puzzle.move(12)
19 | puzzle.move(11)
20 | puzzle.move(10)
21 | puzzle.move(6)
22 |
23 | assert ['2', '5', '6', '7'] == sorted(puzzle.valid_moves, key=int)
24 |
--------------------------------------------------------------------------------
/2013-10/objects/tests/test_when_create_new_puzzle.py:
--------------------------------------------------------------------------------
1 | from fifteen_puzzle import Puzzle
2 |
3 | import pytest
4 |
5 |
6 | def test_should_succeed():
7 | Puzzle()
8 |
9 |
10 | def test_default_size_should_be_4(puzzle):
11 | assert 4 == puzzle.size
12 |
13 |
14 | @pytest.mark.parametrize('size', (2, 3, 5))
15 | def test_can_set_puzzle_size(size):
16 | assert size == Puzzle(size).size
17 |
18 |
19 | def test_new_puzzle_should_be_solved(puzzle):
20 | assert puzzle.is_solved
21 |
22 |
23 | @pytest.mark.parametrize(
24 | ('location', 'value'),
25 | [
26 | ((0, 0), '1'),
27 | ((0, 1), '2'),
28 | ((0, 2), '3'),
29 | ((0, 3), '4'),
30 | ((1, 0), '5'),
31 | ((1, 1), '6'),
32 | ((1, 2), '7'),
33 | ((1, 3), '8'),
34 | ((2, 0), '9'),
35 | ((2, 1), '10'),
36 | ((2, 2), '11'),
37 | ((2, 3), '12'),
38 | ((3, 0), '13'),
39 | ((3, 1), '14'),
40 | ((3, 2), '15'),
41 | ]
42 | )
43 | def test_new_puzzle_should_be_in_order(puzzle, location, value):
44 | assert location == puzzle.coordinates_for(value)
45 |
46 |
47 | def test_new_puzzle_empty_should_be_bottom_right(puzzle):
48 | assert (3, 3) == puzzle.coordinates_for('_')
49 |
--------------------------------------------------------------------------------
/2013-10/objects/tests/test_when_moving.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 |
4 | def test_valid_horizontal_move_should_succeed(puzzle):
5 | puzzle.move(15)
6 |
7 |
8 | def test_valid_horizontal_move_should_update_tile_coordinates(puzzle):
9 | old_empty = puzzle.coordinates_for('_')
10 | puzzle.move(15)
11 |
12 | assert old_empty == puzzle.coordinates_for(15)
13 |
14 |
15 | def test_valid_horizontal_move_should_update_empty_tile_coordinates(puzzle):
16 | origin = puzzle.coordinates_for(15)
17 | puzzle.move(15)
18 |
19 | assert origin == puzzle.coordinates_for('_')
20 |
21 |
22 | def test_valid_vertical_move_should_succeed(puzzle):
23 | puzzle.move(12)
24 |
25 |
26 | def test_valid_vertical_move_should_update_tile_coordinates(puzzle):
27 | old_empty = puzzle.coordinates_for('_')
28 | puzzle.move(12)
29 |
30 | assert old_empty == puzzle.coordinates_for(12)
31 |
32 |
33 | def test_valid_vertical_move_should_update_empty_tile_coordinates(puzzle):
34 | origin = puzzle.coordinates_for(12)
35 | puzzle.move(12)
36 |
37 | assert origin == puzzle.coordinates_for('_')
38 |
39 |
40 | @pytest.mark.parametrize('invalid', (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14))
41 | def test_invalid_move_should_raise(puzzle, invalid):
42 | with pytest.raises(ValueError):
43 | puzzle.move(invalid)
44 |
45 |
46 | @pytest.mark.parametrize(
47 | ('first', 'second'),
48 | [
49 | (15, 15),
50 | (15, 14),
51 | (15, 11),
52 | (12, 12),
53 | (12, 11),
54 | (12, 8),
55 | ]
56 | )
57 | def test_move_sequence_should_succeed(puzzle, first, second):
58 | puzzle.move(first)
59 | puzzle.move(second)
60 |
61 |
62 | @pytest.mark.parametrize(
63 | ('first', 'invalid'),
64 | [
65 | (15, 13),
66 | (15, 10),
67 | (15, 12),
68 | (12, 15),
69 | (12, 10),
70 | (12, 4),
71 | ]
72 | )
73 | def test_move_sequence_with_second_invalid_should_fail(puzzle, first, invalid):
74 | puzzle.move(first)
75 |
76 | with pytest.raises(ValueError):
77 | puzzle.move(invalid)
78 |
--------------------------------------------------------------------------------
/2014-08/micropython/README.md:
--------------------------------------------------------------------------------
1 | Introduction to MicroPython
2 | ============================
3 | JR Rickerson
4 |
5 | Overview
6 | --------
7 | MicroPython is a reimplementation of the Python 3 language for micrcontrollers.
8 | The Kickstarter project provided a copy of the MicroPython code embedded on a
9 | a small microcontroller board called the "pyboard," and a Python module to
10 | provide access to the components on the board.
11 |
12 | Slides
13 | ------
14 | Slides are available via Google Docs:
15 | https://docs.google.com/presentation/d/1Y3Wslr_so9h0rhLIcHzoOU1z7XNXuJMO1-rfwCNNMuM/edit?usp=sharing
16 |
17 | Code
18 | ----
19 | Demo scripts presented during the talk can be found on Github:
20 | https://github.com/pyatl/talks/tree/master/2014-08/micropython/demo
21 |
22 | Resources
23 | ---------
24 | Resources for learning more:
25 | - MicroPython website (info, docs, diagrams, etc): http://www.micropython.org
26 | - AdaFruit (electronics kits, books, parts): http://www.adafruit.com
27 | - SparkFun (electronics kits, books, parts, projects): http://www.sparkfun.com
28 | - Microcenter (local electronics store with hobby section): http://www.microcenter.com
29 |
30 |
--------------------------------------------------------------------------------
/2014-08/micropython/demo/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2014-08/micropython/demo/__init__.py
--------------------------------------------------------------------------------
/2014-08/micropython/demo/accelerometer.py:
--------------------------------------------------------------------------------
1 | """ Interact with the accelerometer. Light up different leds
2 | when different axes are not level, within a tolerance. """
3 | import pyb
4 |
5 | ledx = pyb.LED(1)
6 | ledy = pyb.LED(2)
7 | ledz = pyb.LED(3)
8 | accel = pyb.Accel()
9 | SENSITIVITY = 5
10 |
11 | def run():
12 | while True:
13 | x = accel.x()
14 | y = accel.y()
15 | z = accel.z()
16 | if abs(x) > SENSITIVITY:
17 | ledx.on()
18 | else:
19 | ledx.off()
20 | if abs(y) > SENSITIVITY:
21 | ledy.on()
22 | else:
23 | ledy.off()
24 | if abs(z) > SENSITIVITY:
25 | ledz.on()
26 | else:
27 | ledz.off()
28 | pyb.delay(200)
29 |
30 |
--------------------------------------------------------------------------------
/2014-08/micropython/demo/hello.py:
--------------------------------------------------------------------------------
1 | """ Hello World on the pyboard. Just turn on the blue LED """
2 | import pyb
3 |
4 | led_blue = pyb.LED(4)
5 | led_blue.on()
6 |
--------------------------------------------------------------------------------
/2014-08/micropython/demo/leds.py:
--------------------------------------------------------------------------------
1 | """ Make your pyboard into a disco! Alternate leds in a cycle """
2 | import pyb
3 |
4 | led_list = [pyb.LED(i) for i in range(1, 5)]
5 |
6 | def run():
7 | i = 0
8 | while True:
9 | led_list[i].off()
10 | i += 1
11 | if i >= len(led_list):
12 | i = 0
13 | led_list[i].on()
14 | pyb.delay(200)
15 |
16 |
--------------------------------------------------------------------------------
/2014-08/micropython/demo/loop.py:
--------------------------------------------------------------------------------
1 | """ Looping your program - Make the red LED blink on and off every 500 ms """
2 | import pyb
3 |
4 | led_red = pyb.LED(1)
5 |
6 | def run():
7 | while True:
8 | led_red.toggle()
9 | pyb.delay(500)
10 |
11 |
--------------------------------------------------------------------------------
/2014-08/micropython/demo/switch.py:
--------------------------------------------------------------------------------
1 | """ Use the USR switch on the pyboard to toggle the blue led on and off """
2 | import pyb
3 |
4 | led = pyb.LED(4)
5 |
6 | def run():
7 | switch = pyb.Switch()
8 | switch.callback(lambda: led.toggle())
9 |
--------------------------------------------------------------------------------
/2014-09/roman/README.rst:
--------------------------------------------------------------------------------
1 | =====================
2 | Party Like it's 500BC
3 | =====================
4 |
5 | This talk from the September 2014 meeting of PyAtl examined the thought
6 | process developers use to solve problems, including
7 |
8 | - decomposition of a problem specification
9 | - considering tradeoffs among design choices
10 | - iterative refinement to build a solution
11 |
12 | We also looked at the specific details of implementing a solution in
13 | Python.
14 |
15 | Slides: http://pyatl.github.io/talks/2014-09_roman/500BC.html
16 |
17 |
18 | doctest
19 | =======
20 |
21 | The slides include a full ``doctest`` suite. To run it, download the
22 | `source for the slides`_, then run::
23 |
24 | python -m doctest -v 500BC.rst
25 |
26 | Try playing around with the source: start by breaking something to see
27 | the tests fail, then tackle the challenge problem!
28 |
29 |
30 | .. _`source for the slides`: https://raw.githubusercontent.com/pyatl/talks/master/2014-09/roman/500BC.rst
31 |
--------------------------------------------------------------------------------
/2014-09/stdlib-tour/requirements.txt:
--------------------------------------------------------------------------------
1 | Sphinx
2 | hieroglyph
3 | flake8
--------------------------------------------------------------------------------
/2014-09/stdlib-tour/source/_static/custom.css:
--------------------------------------------------------------------------------
1 | .slides > article {
2 | /* background-color: lightblue; */
3 | color: #222222;
4 | }
5 |
6 | h2 {
7 | bottom: 50px;
8 | }
9 |
10 | /* Use when the pre tag contents do not fit on the screen otherwise. */
11 | .small {
12 | font-size: 70%;
13 | }
14 |
15 | /* Center block quotes vertically and horizontally. Based on
16 | http://css-tricks.com/vertically-center-multi-lined-text/
17 | */
18 |
19 | blockquote {
20 | font-size: 130%;
21 | display: table;
22 | vertical-align: middle;
23 | text-align: center;
24 | height: 80%;
25 | width: 80%;
26 | }
27 |
28 | blockquote div {
29 | display: table-cell;
30 | vertical-align: middle;
31 | text-align: center;
32 | }
33 |
34 | table.highlighttable td {
35 | border: 0;
36 | padding: 0;
37 | }
--------------------------------------------------------------------------------
/2014-09/stdlib-tour/source/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # build configuration file, created by sphinx-quickstart
4 | # on 2013-09-08 # 11:34:00 dhellmann
5 | #
6 | # This file is execfile()d with the current directory set to its
7 | # containing dir.
8 | #
9 | # Note that not all possible configuration values are present in this
10 | # autogenerated file.
11 | #
12 | # All configuration values have a default; values that are commented out
13 | # serve to show the default.
14 |
15 | import datetime
16 | # import sys
17 | # import os
18 |
19 | # If extensions (or modules to document with autodoc) are in another directory,
20 | # add these directories to sys.path here. If the directory is relative to the
21 | # documentation root, use os.path.abspath to make it absolute, like shown here.
22 | #sys.path.insert(0, os.path.abspath('.'))
23 |
24 | # -- General configuration ---------------------------------------------------
25 |
26 | # If your documentation needs a minimal Sphinx version, state it here.
27 | #needs_sphinx = '1.0'
28 |
29 | # Add any Sphinx extension module names here, as strings. They can be
30 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
31 | # ones.
32 | extensions = [
33 | 'sphinx.ext.doctest',
34 | 'hieroglyph',
35 | ]
36 |
37 | slide_theme_options = {
38 | 'custom_css': 'custom.css',
39 | }
40 |
41 | slide_numbers = True
42 |
43 | # Add any paths that contain templates here, relative to this directory.
44 | templates_path = ['_templates']
45 |
46 | # The suffix of source filenames.
47 | source_suffix = '.rst'
48 |
49 | # The encoding of source files.
50 | #source_encoding = 'utf-8-sig'
51 |
52 | # The master toctree document.
53 | master_doc = 'index'
54 |
55 | # General information about the project.
56 | project = u'talk'
57 | today = datetime.datetime.today()
58 | copyright = u'%s, Doug Hellmann' % today.year
59 |
60 | # The version info for the project you're documenting, acts as replacement for
61 | # |version| and |release|, also used in various other places throughout the
62 | # built documents.
63 | #
64 | # The short X.Y version.
65 | version = '1.0'
66 | # The full version, including alpha/beta/rc tags.
67 | release = version
68 |
69 | # The language for content autogenerated by Sphinx. Refer to documentation
70 | # for a list of supported languages.
71 | #language = None
72 |
73 | # There are two options for replacing |today|: either, you set today to some
74 | # non-false value, then it is used:
75 | #today = ''
76 | # Else, today_fmt is used as the format for a strftime call.
77 | #today_fmt = '%B %d, %Y'
78 |
79 | # List of patterns, relative to source directory, that match files and
80 | # directories to ignore when looking for source files.
81 | exclude_patterns = []
82 |
83 | # The reST default role (used for this markup: `text`) to use for all
84 | # documents.
85 | #default_role = None
86 |
87 | # If true, '()' will be appended to :func: etc. cross-reference text.
88 | #add_function_parentheses = True
89 |
90 | # If true, the current module name will be prepended to all description
91 | # unit titles (such as .. function::).
92 | #add_module_names = True
93 |
94 | # If true, sectionauthor and moduleauthor directives will be shown in the
95 | # output. They are ignored by default.
96 | #show_authors = False
97 |
98 | # The name of the Pygments (syntax highlighting) style to use.
99 | pygments_style = 'sphinx'
100 |
101 | # A list of ignored prefixes for module index sorting.
102 | #modindex_common_prefix = []
103 |
104 | # If true, keep warnings as "system message" paragraphs in the built documents.
105 | #keep_warnings = False
106 |
107 |
108 | # -- Options for HTML output -------------------------------------------------
109 |
110 | # The theme to use for HTML and HTML Help pages. See the documentation for
111 | # a list of builtin themes.
112 | html_theme = 'default'
113 |
114 | # Theme options are theme-specific and customize the look and feel of a theme
115 | # further. For a list of options available for each theme, see the
116 | # documentation.
117 | #html_theme_options = {}
118 |
119 | # Add any paths that contain custom themes here, relative to this directory.
120 | #html_theme_path = []
121 |
122 | # The name for this set of Sphinx documents. If None, it defaults to
123 | # " v documentation".
124 | #html_title = None
125 |
126 | # A shorter title for the navigation bar. Default is the same as html_title.
127 | #html_short_title = None
128 |
129 | # The name of an image file (relative to this directory) to place at the top
130 | # of the sidebar.
131 | #html_logo = None
132 |
133 | # The name of an image file (within the static path) to use as favicon of the
134 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
135 | # pixels large.
136 | #html_favicon = None
137 |
138 | # Add any paths that contain custom static files (such as style sheets) here,
139 | # relative to this directory. They are copied after the builtin static files,
140 | # so a file named "default.css" will overwrite the builtin "default.css".
141 | html_static_path = ['_static']
142 |
143 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
144 | # using the given strftime format.
145 | #html_last_updated_fmt = '%b %d, %Y'
146 |
147 | # If true, SmartyPants will be used to convert quotes and dashes to
148 | # typographically correct entities.
149 | #html_use_smartypants = True
150 |
151 | # Custom sidebar templates, maps document names to template names.
152 | #html_sidebars = {}
153 |
154 | # Additional templates that should be rendered to pages, maps page names to
155 | # template names.
156 | #html_additional_pages = {}
157 |
158 | # If false, no module index is generated.
159 | #html_domain_indices = True
160 |
161 | # If false, no index is generated.
162 | #html_use_index = True
163 |
164 | # If true, the index is split into individual pages for each letter.
165 | #html_split_index = False
166 |
167 | # If true, links to the reST sources are added to the pages.
168 | #html_show_sourcelink = True
169 |
170 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
171 | #html_show_sphinx = True
172 |
173 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
174 | #html_show_copyright = True
175 |
176 | # If true, an OpenSearch description file will be output, and all pages will
177 | # contain a tag referring to it. The value of this option must be the
178 | # base URL from which the finished HTML is served.
179 | #html_use_opensearch = ''
180 |
181 | # This is the file name suffix for HTML files (e.g. ".xhtml").
182 | #html_file_suffix = None
--------------------------------------------------------------------------------
/2014-09/stdlib-tour/source/dis_simple.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # encoding: utf-8
3 |
4 | my_dict = { 'a':1 }
5 |
--------------------------------------------------------------------------------
/2014-09/stdlib-tour/source/index.rst:
--------------------------------------------------------------------------------
1 | ==========================================
2 | A Whirlwind Tour of the Standard Library
3 | ==========================================
4 |
5 | | Doug Hellmann
6 | | doug@doughellmann.com
7 | | @doughellmann
8 | | PyATL
9 | | 2014-09
10 |
11 | ``string``: Simple Templates
12 | ============================
13 |
14 | .. literalinclude:: string_template.py
15 |
16 | ::
17 |
18 | TEMPLATE:
19 | foo
20 | $
21 | fooiable
22 |
23 | .. note::
24 |
25 | Also includes ASCII constants.
26 |
27 | ``textwrap``: Formatting
28 | ========================
29 |
30 | * fill / wrap / justify
31 | * indent
32 | * dedent
33 | * hanging indent
34 |
35 |
36 |
37 | ``re``: Pattern Matching
38 | ========================
39 |
40 | * regular expressions
41 | * search
42 | * replace
43 |
44 | Numeric and Mathematical
45 | ========================
46 |
47 | * decimal – fixed decimal arithmetic
48 | * fractions – rational numbers
49 | * math – specialized mathematical functions
50 | * random – pseudo-random number generators
51 |
52 | ``time`` and ``datetime``
53 | =========================
54 |
55 | .. literalinclude:: time_info.py
56 |
57 | ::
58 |
59 | TIME: 1410107908.56
60 | TODAY: 2014-09-07 12:38:28.574200
61 |
62 | ``collections``: Data Structures
63 | ================================
64 |
65 | * namedtuple
66 | * deque
67 | * Counter
68 | * OrderedDict
69 | * defaultdict
70 |
71 | Data Formats
72 | ============
73 |
74 | * json – JavaScript Object Notation
75 | * base64 – ASCII encoding of binary data
76 | * csv – Comma Separated Value
77 | * pickle – Python-specific serialization format
78 |
79 | Archive formats
80 | ===============
81 |
82 | * tarfile
83 | * zipfile
84 |
85 | Compression
86 | ===========
87 |
88 | * zlib
89 | * gzip
90 | * bz2
91 |
92 | .. note::
93 |
94 | These can be combined with the tarfile module, but they can also be
95 | applied to other files and even sockets or other data streams that
96 | are not files.
97 |
98 | Databases
99 | =========
100 |
101 | * Key/Value stores
102 |
103 | * anydbm
104 | * shelve
105 |
106 | * Relational Database
107 |
108 | * sqlite3
109 |
110 | Operating System Tools
111 | ======================
112 |
113 | * os – interface to the operating system
114 | * os.path – work with filenames
115 | * sys – interface to the running system
116 |
117 | Application Building Tools
118 | ==========================
119 |
120 | * argparse – command line arguments
121 | * logging – files, remote services, etc.
122 | * getpass – ask for data securely
123 | * readline – interactive prompting
124 | * cmd – interactive command shell framework
125 | * gettext – internationalization and translation
126 | * fileinput – UNIX pipeline tool framework
127 |
128 | Concurrency
129 | ===========
130 |
131 | * threading – single-process concurrent execution
132 | * Queue – FIFO data structure
133 | * multiprocessing – manage multiple processes as threads
134 |
135 | Internet Tools
136 | ==============
137 |
138 | * urllib/urllib2 – retrieve data
139 | * urlparse – work with URLs
140 | * SimpleHTTPServer – static content server
141 | * xmlrpclib – remote function execution over HTTP
142 | * SimpleXMLRPCServer – serve functions over HTTP
143 |
144 | Testing Tools
145 | =============
146 |
147 | * unittest – test framework
148 | * doctest – tests in documentation
149 | * pdb – debugger
150 | * profile – performance analysis
151 | * trace – watch statements being executed
152 |
153 | ``trace``
154 | =========
155 |
156 | .. literalinclude:: trace_main.py
157 |
158 | .. literalinclude:: trace_recurse.py
159 |
160 | ``trace``
161 | =========
162 |
163 | ::
164 |
165 | $ python trace_main.py
166 | This is the main program.
167 | recurse(2)
168 | recurse(1)
169 | recurse(0)
170 |
171 | ``trace``
172 | =========
173 |
174 | .. rst-class:: small
175 |
176 | ::
177 |
178 | $ python -m trace --trace trace_main.py
179 | --- modulename: trace_main, funcname:
180 | trace_main.py(2): from trace_recurse import recurse
181 | --- modulename: trace_recurse, funcname:
182 | trace_recurse.py(4): def recurse(level):
183 | trace_recurse.py(11): def not_called():
184 | trace_main.py(5): def main():
185 | trace_main.py(10): if __name__ == '__main__':
186 | trace_main.py(11): main()
187 | --- modulename: trace_main, funcname: main
188 | trace_main.py(6): print 'This is the main program.'
189 | This is the main program.
190 | trace_main.py(7): recurse(2)
191 | --- modulename: trace_recurse, funcname: recurse
192 | trace_recurse.py(5): print 'recurse(%s)' % level
193 | recurse(2)
194 | trace_recurse.py(6): if level:
195 | trace_recurse.py(7): recurse(level-1)
196 | --- modulename: trace_recurse, funcname: recurse
197 | trace_recurse.py(5): print 'recurse(%s)' % level
198 | recurse(1)
199 | trace_recurse.py(6): if level:
200 | trace_recurse.py(7): recurse(level-1)
201 |
202 | ...
203 |
204 |
205 | Language Tools
206 | ==============
207 |
208 | * gc – garbage collector
209 | * inspect – ask questions about code objects at runtime
210 | * imp – module import system
211 | * dis - show the byte-code for source
212 |
213 | ``dis``
214 | =======
215 |
216 | .. literalinclude:: dis_simple.py
217 | :linenos:
218 |
219 | (line num, instruction, opcode, arguments)
220 |
221 | ::
222 |
223 | $ python -m dis dis_simple.py
224 | 4 0 BUILD_MAP 1
225 | 3 LOAD_CONST 0 (1)
226 | 6 LOAD_CONST 1 ('a')
227 | 9 STORE_MAP
228 | 10 STORE_NAME 0 (my_dict)
229 | 13 LOAD_CONST 2 (None)
230 | 16 RETURN_VALUE
231 |
232 | References
233 | ==========
234 |
235 | Internet
236 |
237 | * https://docs.python.org/2.7/library/index.html
238 | * http://pymotw.com
239 |
240 | Books
241 |
242 | * *Python Essential Reference* – Beasley
243 | * *The Python Standard Library by Example* – Hellmann
244 |
--------------------------------------------------------------------------------
/2014-09/stdlib-tour/source/string_template.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import string
4 |
5 | values = {'var': 'foo'}
6 |
7 | t = string.Template("""
8 | $var
9 | $$
10 | ${var}iable
11 | """)
12 |
13 | print 'TEMPLATE:', t.substitute(values)
14 |
--------------------------------------------------------------------------------
/2014-09/stdlib-tour/source/time_info.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import time
4 | import datetime
5 |
6 |
7 | print 'TIME:', time.time()
8 | print 'TODAY:', datetime.datetime.today()
9 |
--------------------------------------------------------------------------------
/2014-09/stdlib-tour/source/trace_main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from trace_recurse import recurse
3 |
4 |
5 | def main():
6 | print 'This is the main program.'
7 | recurse(2)
8 | return
9 |
10 | if __name__ == '__main__':
11 | main()
12 |
--------------------------------------------------------------------------------
/2014-09/stdlib-tour/source/trace_recurse.py:
--------------------------------------------------------------------------------
1 | def recurse(level):
2 | print 'recurse(%s)' % level
3 | if level:
4 | recurse(level-1)
5 | return
6 |
--------------------------------------------------------------------------------
/2015-03/redacted-tweets/README.md:
--------------------------------------------------------------------------------
1 | # Redacted Tweets
2 | A presentation about a twitter bot that redacts tweets (and makes mad libs!)
3 |
4 | Links:
5 | https://twitter.com/redactedtweet
6 | https://twitter.com/MadTweetLib
7 |
8 | Source:
9 | https://github.com/nloadholtes/Redacted-Tweets
10 |
11 | Presenter:
12 | Nick Loadholtes
13 | https://twitter.com/nloadholtes
14 | https://github.com/nloadholtes
15 |
--------------------------------------------------------------------------------
/2015-03/redacted-tweets/redacted_twitter_nick_loadholtes.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2015-03/redacted-tweets/redacted_twitter_nick_loadholtes.pdf
--------------------------------------------------------------------------------
/2015-06/effective_python/README.md:
--------------------------------------------------------------------------------
1 | # Book review: Effective Python
2 | _____
3 | A review of the book "Effective Python" by Brett Slatkin
4 |
5 | Book website:
6 |
7 | Code examples:
8 |
9 | Presenter: Nick Loadholtes
10 |
--------------------------------------------------------------------------------
/2015-06/effective_python/effective_python_presentation.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2015-06/effective_python/effective_python_presentation.pdf
--------------------------------------------------------------------------------
/2015-09/help-on-irc/README.md:
--------------------------------------------------------------------------------
1 | This Man Needed Help, So He Went on IRC
2 | =======================================
3 |
4 | You Won't Believe What Happened Next!
5 | -------------------------------------
6 |
7 | A presentation about using IRC to find help with Python problems.
8 |
9 | Presenter:
10 | Hank Gay
11 |
--------------------------------------------------------------------------------
/2015-09/help-on-irc/help-on-irc.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2015-09/help-on-irc/help-on-irc.pdf
--------------------------------------------------------------------------------
/2017-02/tcp-socket-file-sharing/client:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | nc localhost 8080 > output.jpg
4 |
--------------------------------------------------------------------------------
/2017-02/tcp-socket-file-sharing/helpme.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2017-02/tcp-socket-file-sharing/helpme.jpg
--------------------------------------------------------------------------------
/2017-02/tcp-socket-file-sharing/serve.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python3
2 | import socket
3 |
4 | image = open('helpme.jpg', 'rb')
5 |
6 | sock = socket.socket()
7 | # When you set a socket option, you set its name and level
8 | # The level argument (SOL_SOCKET) specifies the protocol level at which the
9 | # option (SO_REUSEADDR) resides
10 | #
11 | # SO_REUSEADDR tells the kernel that even if this port is busy (in
12 | # the TIME_WAIT state), go ahead and reuse it anyway
13 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
14 | sock.bind(('0.0.0.0', 8080))
15 | print('Listening on 0.0.0.0:8080')
16 |
17 | sock.listen(1) # number of queued connections
18 |
19 | client, addr = sock.accept()
20 | print('Got connection from', addr)
21 | client.sendfile(image)
22 | for x in [client, sock, image]:
23 | x.close()
24 |
--------------------------------------------------------------------------------
/2017-03-09/python-packaging/README.md:
--------------------------------------------------------------------------------
1 | Included are the raw Jupyter Notebook slides and the built slides.
2 |
3 | To build the slides, first install jupyter:
4 |
5 | pip install --user jupyter
6 |
7 | Remember, don't run with escalated privileges (admin, sudo, etc)
8 |
9 | Then run:
10 |
11 | jupyter nbconvert --to slides --post serve python_packaging.ipynb
12 |
--------------------------------------------------------------------------------
/2017-10-12/python-profiling/1.filesize.py:
--------------------------------------------------------------------------------
1 | # python 1.filesize.py
2 |
3 | import cStringIO
4 | from collections import OrderedDict
5 | import pexpect
6 |
7 | PROMPTS = OrderedDict({
8 | pexpect.EOF: None,
9 | })
10 |
11 | child = pexpect.spawn('du', ['-h', __file__])
12 | child.logfile_read = cStringIO.StringIO()
13 | while child.isalive():
14 | index = child.expect(PROMPTS.keys())
15 | answer = PROMPTS.values()[index]
16 | if answer is not None:
17 | child.sendline(answer)
18 |
19 | print child.logfile_read.getvalue()
20 |
--------------------------------------------------------------------------------
/2017-10-12/python-profiling/2.filesize.py:
--------------------------------------------------------------------------------
1 | # python 2.filesize.py
2 |
3 | import cStringIO
4 | from collections import OrderedDict
5 | import pexpect
6 | import re
7 |
8 | PROMPTS = OrderedDict({
9 | pexpect.EOF: None,
10 | re.compile(r'Enter passphrase for .*:\s*?$', re.M): 'some-ssh-passphrase'
11 | })
12 |
13 | child = pexpect.spawn('du', ['-h', __file__])
14 | child.logfile_read = cStringIO.StringIO()
15 | while child.isalive():
16 | index = child.expect(PROMPTS.keys())
17 | answer = PROMPTS.values()[index]
18 | if answer is not None:
19 | child.sendline(answer)
20 |
21 | print child.logfile_read.getvalue()
22 |
--------------------------------------------------------------------------------
/2017-10-12/python-profiling/3.display_file.py:
--------------------------------------------------------------------------------
1 | # python -m cProfile -s cumulative 3.display_file.py | less
2 |
3 | import cStringIO
4 | from collections import OrderedDict
5 | import pexpect
6 |
7 | PROMPTS = OrderedDict({
8 | pexpect.EOF: None,
9 | })
10 |
11 | child = pexpect.spawn('cat', ['large'])
12 | child.logfile_read = cStringIO.StringIO()
13 | while child.isalive():
14 | index = child.expect(PROMPTS.keys())
15 | answer = PROMPTS.values()[index]
16 | if answer is not None:
17 | child.sendline(answer)
18 |
--------------------------------------------------------------------------------
/2017-10-12/python-profiling/4.pstats.py:
--------------------------------------------------------------------------------
1 | # python 4.pstats.py
2 | # pip install gprof2dot
3 | # brew/yum/apt install graphviz
4 | # gprof2dot -f pstats output.pstats | dot -Tpng -o output.png
5 |
6 | from profiler import profile
7 |
8 | import cStringIO
9 | from collections import OrderedDict
10 | import pexpect
11 |
12 | PROMPTS = OrderedDict({
13 | pexpect.EOF: None,
14 | })
15 |
16 | with profile():
17 | child = pexpect.spawn('cat', ['large'])
18 | child.logfile_read = cStringIO.StringIO()
19 | while child.isalive():
20 | index = child.expect(PROMPTS.keys())
21 | answer = PROMPTS.values()[index]
22 | if answer is not None:
23 | child.sendline(answer)
24 |
--------------------------------------------------------------------------------
/2017-10-12/python-profiling/5.snakeviz.py:
--------------------------------------------------------------------------------
1 | # python 4.pstats.py
2 | # pip install snakeviz
3 | # snakeviz output.pstats
4 |
--------------------------------------------------------------------------------
/2017-10-12/python-profiling/6.line_profiling.py:
--------------------------------------------------------------------------------
1 | # pprofile 3.display_file.py | less
2 |
--------------------------------------------------------------------------------
/2017-10-12/python-profiling/profiler.py:
--------------------------------------------------------------------------------
1 | import cProfile
2 | import pstats
3 | from contextlib import contextmanager
4 |
5 | @contextmanager
6 | def profile():
7 | prof = cProfile.Profile()
8 | prof.enable()
9 | yield
10 | prof.disable()
11 | with open('output.pstats', 'w') as f:
12 | pstats.Stats(prof).dump_stats(f.name)
13 |
--------------------------------------------------------------------------------
/2019-05-09/python_in_security/CandidPythonAtlanta20190509-Final.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyatl/talks/f709dfe4bbfa25a5bd646cdf57003349cbc97f91/2019-05-09/python_in_security/CandidPythonAtlanta20190509-Final.pptx
--------------------------------------------------------------------------------
/2019-05-09/python_in_security/README.md:
--------------------------------------------------------------------------------
1 | # Python in Security
2 | ## Jonathan Glass, Candid Partners
3 |
--------------------------------------------------------------------------------
/2019-05-09/responder-tour/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 JR Rickerson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/2019-05-09/responder-tour/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | url = "https://pypi.org/simple"
3 | verify_ssl = true
4 | name = "pypi"
5 |
6 | [packages]
7 | responder = "*"
8 | requests = "*"
9 |
10 | [dev-packages]
11 |
12 | [requires]
13 | python_version = "3.7"
14 |
--------------------------------------------------------------------------------
/2019-05-09/responder-tour/README.md:
--------------------------------------------------------------------------------
1 | # Quick Tour of Responder
2 | ## JR Rickerson
3 |
4 | Github repository: https://github.com/jrrickerson/responder-tour
5 |
--------------------------------------------------------------------------------
/2019-05-09/responder-tour/client.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | data = {'stuff': 'things'}
4 | r = requests.post('http://127.0.0.1:5042/incoming', data=data)
5 |
6 | print(r.text)
7 |
8 |
--------------------------------------------------------------------------------
/2019-05-09/responder-tour/features.py:
--------------------------------------------------------------------------------
1 | import time
2 | import responder
3 |
4 | api = responder.API()
5 |
6 |
7 | # Returning JSON? Just return a dict!
8 | @api.route("/hello/{who}/json")
9 | def hello_to(req, resp, *, who):
10 | resp.media = {"hello": who}
11 |
12 |
13 | @api.route("/hello/{who}/html")
14 | def hello_html(req, resp, *, who):
15 | resp.html = api.template('template.html', who=who)
16 |
17 |
18 | @api.route("/teapot")
19 | def teapot(req, resp):
20 | resp.status_code = api.status_codes.HTTP_416 # ...or 416
21 |
22 |
23 | @api.route("/pizza")
24 | def pizza_pizza(req, resp):
25 | resp.headers['X-Pizza'] = '42'
26 |
27 |
28 | @api.route("/incoming")
29 | async def receive_incoming(req, resp):
30 |
31 | @api.background.task
32 | def process_data(data):
33 | """Just sleeps for three seconds, as a demo."""
34 | print('Doing background stuff')
35 | time.sleep(1)
36 | print('Doing more background stuff...')
37 | time.sleep(1)
38 | print('Almost done...')
39 | time.sleep(1)
40 | print('Done!')
41 |
42 | # Parse the incoming data as form-encoded.
43 | # Note: 'json' and 'yaml' formats are also automatically supported.
44 | data = await req.media()
45 |
46 | # Process the data (in the background).
47 | process_data(data)
48 |
49 | # Immediately respond that upload was successful.
50 | resp.media = {'success': True}
51 |
52 |
53 | if __name__ == '__main__':
54 | api.run()
55 |
--------------------------------------------------------------------------------
/2019-05-09/responder-tour/greeting.py:
--------------------------------------------------------------------------------
1 | import responder
2 |
3 | api = responder.API()
4 |
5 |
6 | @api.route("/{greeting}")
7 | async def greet_world(req, resp, *, greeting):
8 | resp.text = f"{greeting}, world!"
9 |
10 | if __name__ == '__main__':
11 | api.run()
12 |
--------------------------------------------------------------------------------
/2019-05-09/responder-tour/templates/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Look, {{who}}, it's a template!
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/README-hieroglyph.rst:
--------------------------------------------------------------------------------
1 | ========================================
2 | Creating Presentations with Hieroglyph
3 | ========================================
4 |
5 | Hieroglyph (https://pypi.python.org/pypi/hieroglyph) is a Sphinx
6 | (https://pypi.python.org/pypi/Sphinx) builder for converting
7 | reStructuredText files to HTML slide presentations. It lets you write
8 | simple text files with headings, lists, and embedded code samples and
9 | then turns them into slide presentations for you.
10 |
11 | Example
12 | =======
13 |
14 | First, you need a copy of cookiecutter
15 | (https://pypi.python.org/pypi/cookiecutter) installed. Cookiecutter
16 | uses templates to populate a directory with the files needed for a
17 | project. You can use the template for hieroglyph at
18 | https://github.com/dhellmann/cookiecutter-hieroglyph to create a basic
19 | presentation, which you can then modify with your own content.
20 |
21 | ::
22 |
23 | $ pip install cookiecutter
24 |
25 | Next, create a directory to contain the inputs for the
26 | presentation::
27 |
28 | $ mkdir mypres
29 | $ cd mypres
30 |
31 | Now run cookiecutter to create the basic presentation files::
32 |
33 | $ cookiecutter https://github.com/dhellmann/cookiecutter-hieroglyph
34 | config_path is /Users/dhellmann/.cookiecutterrc
35 | Cloning into 'cookiecutter-hieroglyph'...
36 | remote: Counting objects: 19, done.
37 | remote: Compressing objects: 100% (5/5), done.
38 | remote: Total 19 (delta 0), reused 0 (delta 0)
39 | Unpacking objects: 100% (19/19), done.
40 | Checking connectivity... done.
41 | full_name (default is "Doug Hellmann")?
42 | email (default is "doug@doughellmann.com")?
43 | twitter (default is "doughellmann")?
44 | repo_name (default is "talk")?
45 | meeting_date (default is "Date of meeting")? 2014-09
46 | title (default is "Title of your presentation")? A Whirlwind Tour of the Standard Library
47 |
48 | This creates a few files::
49 |
50 | $ tree .
51 | .
52 | ├── Makefile
53 | ├── requirements.txt
54 | └── source
55 | ├── _static
56 | │ └── custom.css
57 | ├── conf.py
58 | └── index.rst
59 |
60 | 2 directories, 5 files
61 |
62 | Put your content in ``source/index.rst``, using some of the other
63 | hieroglyph-based presentations in this repository as examples.
64 |
65 | To build your slides, just run ``make``. It will use virtualenv
66 | (https://pypi.python.org/pypi/virtualenv) to install the tools it
67 | needs and then use those tools to convert your input file to HTML.
68 |
69 | ::
70 |
71 | $ make
72 | virtualenv .venv
73 | New python executable in .venv/bin/python
74 | Installing setuptools, pip...done.
75 | .venv/bin/pip install -r requirements.txt
76 | Downloading/unpacking Sphinx (from -r requirements.txt (line 1))
77 |
78 | ... lots more download and installation output elided ...
79 |
80 | Successfully installed Sphinx hieroglyph flake8 Jinja2 Pygments docutils
81 | six pyflakes mccabe pep8 markupsafe
82 | Cleaning up...
83 | ./.venv/bin/sphinx-build -b slides -d build/doctrees source build/slides
84 | Making output directory...
85 | Running Sphinx v1.2.3
86 | loading pickled environment... not yet created
87 | building [slides]: targets for 1 source files that are out of date
88 | updating environment: 1 added, 0 changed, 0 removed
89 | reading sources... [100%] index
90 | looking for now-outdated files... none found
91 | pickling environment... done
92 | checking consistency... done
93 | preparing documents... done
94 | writing output... [100%] index
95 | writing additional files... genindex search
96 | copying static files... done
97 | copying extra files... done
98 | dumping search index... done
99 | dumping object inventory... done
100 | build succeeded, 1 warning.
101 |
102 | Build finished. The slides are in build/slides.
103 |
104 | The output presentation is in ``./build/slides/index.html``. All of
105 | the required files should be present under ``build/slides``, allowing
106 | you to give your presentation even without internet access.
107 |
--------------------------------------------------------------------------------
/bin/dates.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Print a list of the dates for the 2nd Thursday of every month for a year.
3 | """
4 |
5 | from __future__ import print_function
6 |
7 | import argparse
8 | import calendar
9 | import datetime
10 |
11 |
12 | ap = argparse.ArgumentParser()
13 | ap.add_argument(
14 | 'year',
15 | type=int,
16 | nargs='?',
17 | default=datetime.date.today().year,
18 | help='the year',
19 | )
20 | args = ap.parse_args()
21 |
22 |
23 | # Show every month
24 | for month in range(1, 13):
25 |
26 | # Compute the dates for each week that overlaps the month
27 | c = calendar.monthcalendar(args.year, month)
28 | first_week = c[0]
29 | second_week = c[1]
30 | third_week = c[2]
31 |
32 | # If there is a Thursday in the first week, the second Thursday
33 | # is in the second week. Otherwise, the second Thursday must
34 | # be in the third week.
35 | if first_week[calendar.THURSDAY]:
36 | meeting_date = second_week[calendar.THURSDAY]
37 | else:
38 | meeting_date = third_week[calendar.THURSDAY]
39 |
40 | print('%s %s' % (calendar.month_name[month], meeting_date))
41 |
--------------------------------------------------------------------------------