Keeping your enemies closer
The Social Network
If you haven’t been asleep for the past 5 years, you’ve probably noticed the rise of the “Social Networking” website. These oddly popular networks have achieved an impressive amount of influence across the web.
Do you ever just find yourself lamenting that there are 24 hours in the day? It gets even worse when you start counting seconds; we did.. there are 86,400 of them! How are you going to spend all of that time avoiding personal responsibilities and meaningful personal introspection? Luckily, social networks are here! You can wile away the hours online with people just like you, and avoid the difficulty of talking to anyone face to face.
Of course the true value these sites offer is letting everyone know just how popular you are. Social networks let you collect and display friends who don’t have to know you, like you, or have even met you! Don’t have any friends? Don’t worry… go through the effort of gaining a few through traditional means (or create fake accounts for people) and add them as your friends. Like a beggar who seeds his styrofoam cup with a few coins to say to all the passersby, “Look at these coins, others didn’t find me offensive!”
The crazy thing is, social networking sites seem to be astronomically valued in the marketplace. I mean over-valued like reality television or Enron stock. One particular social networking site, which shall remain nameless, has recently been pegged at 15 billion dollars! With roughly 70 million users, that puts a value of about $200 per user. WTF?!
Even though social networks appear to have saturated the market, we’ve found a demographic area that they’ve completely neglected: anti-social people. We’re not referring to people who spend their days being productive and interacting in the real world, we’re referring to people who genuinely don’t like each other and want to express it. In our experience, it’s easy to keep track of people we genuinely like, but hard to keep track of everyone we don’t like. Not to mention that it seems our list of enemies seems to grow much faster than our list of friends. So we’ve come up with a solution:
farcebook
Features
Messaging
While most people will consider messaging to be email by just a different name, we can’t help but point out that you can’t check your email from our website.
Profiles
Want to be followed by some online-admirers offline? Leave your full name, telephone number, address, daily schedule, and list of your greatest fears in your profile.
Innovation
farcebook isn’t only about copying other features though. We’ve taken existing ideas and tweaked them just enough to call them innovative.
Foes
When you lose track of your friends, it’s no big deal… they don’t send you a christmas card. If you lose track of an enemy, they send you a christmas card, but it’s got anthrax in it. That’s why you need a “foe” list.
Foes are people who you consider enemies. Farcebook lets you keep a running list of the people that you don’t like, which can often get long in this day and age. The big innovation here is that the other person doesn’t have to accept you as their foe. This is an intentional feature to farcebook - we figure that while friendships are usually mutual, hatreds can be entirely unidirectional. For example, there are people in the world right now that hate me because I’m an American. They can hate me in real life without my permission and now they can hate me on farcebook.
Stabs

Do you ever want to get your foe’s attention? Just to let them know that you’re thinking about them? We have too! For this, we came up with the concept of stabs. Stabs remind your foes that you’re still out there, plotting revenge or counting the days until you’re off of probation. Of course, once you’ve been stabbed as a user, you can stab them back. It’s only fair.
High Score List
Social networks seem to ignore the idea of competitiveness amongst users. Of course we’re all trying to have the most number of foes! farcebook puts this list on a page for everyone to see. That way, when you reach the top, you’ll actually have a place to prove your bragging rights.
“Gifts”
The idea of gifts aren’t unique to farcebook, but the kind of gifts we let you give are like the back-handed compliments of gifts. Send someone a punch in the face, or a trojan horse. Go on, accept our gift. Let it inside your ring of trust. Let your kids and pets play with it. Nothing bad will happen. Will it?
Giving it back
At Code Irony, we’re all about doing. So rather than just speculate, we’ve gone ahead and built farcebook. You can visit it here. Also, you can download the source code here. Thanks for reading, and be sure “foe” us on farcebook.
6 commentsA More Satisfying Programming Experience
This week, we’re here to put the kibosh on a movement that’s destroying very core of our hitherto dysfunctional programming community. We’re out to stop the movement towards smaller, sanely-structured, compact, and readable code. It’s just too short and quick. More is more, people! Really… despite what anyone may tell you, it is the size of your program that matters.

Don’t worry. Thousands of other programmers just like you are experiencing the disease behind this movement that our medical laboratories are calling:
Software Constructile Dysfunction (SCD)
Not sure whether you’re stricken with this problem? Here are some questions to ask yourself to tell if you have SCD:
- Is your average module list only about 5 or 6 modules long?
- Do you find yourself writing programs that run too quickly?
- Is your pair programming partner unsatisfied with your performance?
If you’ve answered “yes” to any of these questions, then this post could change your life!
But how did we rid the world of this terrible affliction? We knew that if we were ever going to crack this nut, we needed to get to the core of the problem. How do you even begin to write a long program that’s complex enough to satisfy without expending time or effort? Well… why not import a tall, thick stack of third-party modules?
Let’s see how this would work. Consider exhibit A:
Program 1:Unremarkable
import codecs import re import sgmllib import types |
Program 2:Impressive!
import codecs import cPickle import itertools import logging import os import math import re import sgmllib import StringIO import sys import syslog import types import urllib |
Now even in this simplest of examples, you already know which program is going to be better! Not only will the second program run with more substantial startup time, but it’s obvious that the second programmer is more experienced, richer, healthier, taller, drives a nicer car, and is more successful with the opposite sex.
Without further ado, we present:

Formulation
So what does it do? We cut right to the chase and increase your module import list length by generating an arbitrary number of “third-party” python modules for you, automatically! Some of your co-workers may not even be able to tell that the code doesn’t make any sense. Your management definitely won’t be able to tell. Only your confident swagger, or maybe your bigger raise, could give you away! But what does it all mean? It means that you’re now on the road to longer, more girthy programs. Hold your head up high–with Modulex!
Clinical Trials
You’re probably asking yourself, “how does it work?” Let’s run Modulex and ask it for 20 new modules and have it recommend 10 standard modules:
$ ./modulex.py 20 10
Poof… before you can begin to have second thoughts, you’ve got a enormous module list to import in your program. Let’s take a look at the output:
# Standard Modules import cPickle import codecs import datetime import decimal import fileinput import heapq import itertools import sha import stat import uu # Modulex Modules import beefy_frazzler import brawny_aggregator import brisk_swizzler import cautious_crasher import eensy_aggregator import energetic_mangler import fat_mapper import femto_crasher import forceful_mangler import lethargic_roast import mega_expander import myghty_frazzler import pico_indexer import quick_cracker import rotund_expander import slow_infinator import swift_infinator import tiny_mangler import turbo_mapper import uber_infinator
forceful_mangler? brawny_aggregator?! Wow!!! It’s things like this that keep the python community importing with a purpose! Let’s take a look inside one of these modules:
#—————————————————————————— # Filename: eensy_swizzler.py #—————————————————————————— def swizzle(*args, **kwargs): hurtless = 9114 rather_ = 9909 # again dingle cause hateful farmers sands for i in xrange(840): musters = 5881 whereof = min(musters, 12) theres = sin(whereof) offers = 7956 # thats again after whereof = musters # goneril changed discpassage monsters pinion servants though = 7430 # british ignorant cannot for i in xrange(447): groom = 8261 bring = though prolegomenon = 6826 vengeance = 1434 # patience ransom madam answer entreat # edmund doors wrongs henceforth beastly = max(12, 888) # argument remember remove there return 0
“# goneril changed discpassage monsters pinion servants”? Well at least we know, thanks to the comments that come standard with Modulex. This is real high-quality and syntactically correct python code. In a trivial amount of time, we were able to generate about 3500 lines of it! That’s productivity you can take to the bank.
Since this is the internet where everything is free, Code Irony is running a promotion for a free sample of Modulex without a prescription. To redeem your trial, download the code here: Modulex.
Modulex is not for everyone. Ask you doctor if you’re healthy enough for software development in a Modulex environment. Do not use Modulex if you are weak of heart or mind or if you are taking MAOI inhibitors as this could increase your risk of clot or stroke.
7 commentsblogggg! A blog engine for the ages.
In the past 3 years, blogs have popped up faster than Starbucks locations, and we want to be the first to say: “Me too!” Ok, maybe we’re not the first to be the second, but that’s not going to stop us from cramming the world’s already-full blog hole with yet another blog engine. We’re jumping onto the dog pile… er… “blog pile.”
You might ask, “why?” Because it’s easy; that’s why!! It’s so easy that it seems people just can’t help themselves. We’re no different. Here’s a history lesson:
In the beginning, there was static content. And it was good. But then there was a problem: it was fast and didn’t use enough bandwidth. What good are fat pipes if you’re not going to cram them full of bloat?

Enter: “The blog”
What is it you ask? It’s static content, but served dynamically!!! This is the kind of thing we can get behind. Plus, it has the added bonus of being able to trivially produce eye-rot candy like tag clouds.
Blogggg!
To the point, we’ve written our own blog software: Blogggg! If you’re going to compete with all 100+ other blog engines out there, you need to have a catchy name. Our is super catchy because you say it like “blog” but you say it like you’re on meth. The exclamation point is absolutely mandatory as its emphatic qualities underscore our gratuitous use of the letter: “g”. It’s a recipe for success!!!
Design
We’re living in a database-driven world… no use in trying to change that now. Since SQL can be really hard (and you know how we hate solving hard problems), how will we overcome our debilitating laziness while simultaneously being a sheep in web 2.0 flock? Luckily, we aren’t the first programmers to try and avoid this mysterious and ancient SQL technology. We turn to Object Relational Mapping.
We here at Code Irony worship “The Python” no matter what it ends up costing us in our careers or hygiene. We need an ORM and we have The Snake… That can mean only one thing: sqlalchemy (not true… ORMs grow on trees). Sit back and watch the hits come in. Brilliant!!!!
The Code
There are two parts to blogggg! — submitting a blog post, and viewing it. When you submit the post, it is stored in a database backend using the code below. The first time you run the post code, you’ll need to feed it the command “create_db” — this will set up the magical database backend for you (don’t worry about understanding that part).
>python post.py create_db
Once this is set up, write your text to a file, and run the post command again, only with your post file as the input:
>python post.py mypost.html
Then, when you want to view your static content, you use the view code, as shown below. To get a simple server going, just run:
>python serve.py
And then navigate in your browser to http://localhost:8080/mypost.html. Look, there’s your post!
It’s so simple! And no SQL was necessary! We’re well on our way to serving this static content as fast as the Python interpreter can!

Deployment
Blogggg! will only work locally using the code above. Our blog software needs to be deployed for the real world — how else will thousands of people be able to view our witty static content?!?!?
First, we need to set up our code to run in a served environment. We’ll use Apache to get rid of that silly :8080 after the domain. Then, we’ll need to install mod_fastcgi on Apache. If you don’t know how to do that, use Google — it’ll practically compile itself! Just like that scene in Fantasia.
Then install flup… it’ll do convert the output from our application into something that Apache can use. You can use:
>easy_install flup
Then, at the top of the serve.py file, add this:
#!/usr/bin/python from flup.server.fcgi import WSGIServer
and at the bottom, add this:
app = cherrypy.tree.mount(MyBlog())
cherrypy.engine.start(blocking=False)
try:
WSGIServer(app).run()
finally:
cherrypy.engine.stop()
Then in httpd.conf, add these lines:
FastCgiIpcDir /tmp
FastCgiServer /path/to/serve.py -idle-timeout 120 -processes 4
and in your directory that you’re serving from, add a file named .htaccess with this inside:
AddHandler fastcgi-script .py
ScriptAliasMatch (.*$) /path/to/cherry.py$1
If you’ve been following, you can now go to your domain name, append “myentry.html” and you’ll see your text! It was so simple! If there’s an easier way to serve static content, be sure to let us know (but we’ll be skeptical for sure!)!
post.py
# Filename: post.py # Revision: 0.1 # # Copyright 2008 Christopher Myers and Justin Davis # # blogggg! poster # Load the content, and you’re almost done # # You have unlimited license to use this software however you want. There # is no warranty either expressed nor implied. Actually, we recommend not # using it. It just exists to prove a point. from sqlalchemy import * import datetime db = create_engine(’sqlite:////home/guido/blogg.db’) meta = MetaData(db) blog_entries = Table(‘entries’, meta, Column(‘entry’, String(), primary_key = True), Column(‘url’, String()), Column(‘date’, DateTime, default=datetime.datetime.now()) ) class Entry(object): def __init__(self, text, url): self.entry = text self.url = url orm.mapper(Entry, blog_entries) session = orm.create_session(bind=db) if __name__ == “__main__”: import sys if sys.argv[1] == “create_db”: blog_entries.create(bind=db) else: f = open(sys.argv[1]).read() entry = Entry(f, sys.argv[1]) session.save(entry) session.flush()
serve.py
# Filename: serve.py # Revision: 0.1 # # Copyright 2008 Christopher Myers and Justin Davis # # blogggg! server # Now, watch the hits come in! # # You have unlimited license to use this software however you want. There # is no warranty either expressed nor implied. Actually, we recommend not # using it. It just exists to prove a point. import postimport cherrypy class MyBlog: def default(self, url): my_query = post.session.query(post.Entry) my_entry = my_query.filter_by(url=url).first() return my_entry.entry default.exposed = True cherrypy.quickstart(MyBlog())9 comments
Fastest templating engine ever. Period.
Since web frameworks seem to be the only thing people are doing in Python these days, templating languages have become increasingly important. The problem that we at Code Irony keep running into is that they’re just not fast enough. How slow are they? We ran some profiling across one of our projects and this is what we’ve found:
<h1>Hello %(name)s</h1>
After many usability tests, we found that the %(variable)s syntax is the easiest for people to understand. Furthermore, we want to be sure to separate the logic from the presentation, so we only want to replace strings. Save this file to hello.html Then, in your web framework, just import our template engine and use the code like this:

from contemplate import ConTemplate
mytemplate = ConTemplate("hello.html")
name = "Guido"
print mytemplate.render()
> <h1>Hello Guido</h1>
Look! ConTemplate filled in your name and everything! Now, we all know that speed is the real factor in making a templating language. Check out how ConTemplate stacks up against some of the competition:
| Template | Processing Time |
|---|---|
| Genshi | .110s |
| Mako | .109s |
| ConTemplate | .107s |
Wow! On our first try, we beat the two fastest python templating languages! And Genshi lost by almost 3%! Imagine how fast it’ll be when version 2 comes out! You can get the benchmark test here and download the implementation here, or browse it below.
# Filename: contemplate.py # Revision: 0.1 # # Copyright 2008 Christopher Myers and Justin Davis # # “ConTemplate” # This is by far the fastest python templating language you’ve ever used. # # You have unlimited license to use this software however you want. There # is no warranty either expressed nor implied. Actually, we recommend not # using it. It just exists to prove a point. import inspect class ConTemplate(object): def __init__(self, filename): “”“Load the template”“” try: self.template = open(filename).read() except IOError: raise IOError, “No file at that location” def render(self, locs = None): “”“Render the template”“” if not locs: locs = globals() locs.update(inspect.currentframe(1).f_locals) return self.template % locs21 comments
A Rose By Any Other Name…
Sure, semantic HTML and pure CSS layout are all the rage, but we at Code Irony can’t help but notice that somewhere along the way, the table element became a persona non grata. We find that there are some occasions where using a table can mean a particular layout is well behaved across browsers, predictable, maintainable, and quick to implement. Think column layouts.
Ever notice how your “semantic” markup with divs and spans oddly enough ends up looking similar to how it would look using a table with trs and tds? It’s not really that semantic at all. Plus, you have to use “float,” which if you think about it means you’re really just pushing the dirt under the CSS rug. To top it all off, it just doesn’t work as well. If the user can’t tell, then what exactly are you trying to accomplish?
So we want to help eliminate the shame your colleagues and friends will heap on you for using the <table> so you can just move on with your life and stop fiddling with your markup and CSS. We figure the best way to do that is to introduce a new HTML element! This way, the purists can keep their pride and you can bask in pragmatic warmth.
It’s called: <layout>
I know… mind-blowing. We should write a book about it. It’s not without friends, too: <layout-row> and <layout-cell>.
Here’s an example of how to get a two-column layout using our new tags:
<layout>
<layout-row>
<layout-cell>Left Content</layout-cell>
<layout-cell>Right Content</layout-cell>
</layout-row>
</layout>
And since the browser won’t know what in the world you’re talking about, we’ve written a script that turns it back into valid HTML. You can download the Table Shame Eliminator here, or check out how it’s done below.
#—————————————————————————- # Filename: layout.py # Revision: 0.1 # # Copyright 2008 Christopher Myers and Justin Davis # # “Table Element Shame Eliminator” # The purpose of this script is to transform markup with our magical “layout” # element into valid HTML using the html table. # # You have unlimited license to use this software however you want. There # is no warranty either expressed nor implied. Actually, we recommend not # using it. It just exists to prove a point. #—————————————————————————- import os import sys from BeautifulSoup import BeautifulSoup def usage(): print “Usage: %s input-filename” % (sys.argv[0]) if not sys.argv[1:] or not os.path.exists(sys.argv[1]) or \ not os.path.isfile(sys.argv[1]): usage() sys.exit(1) # Soup the input infile = sys.argv[1] fhandle = open(infile, “r”) soup = BeautifulSoup(fhandle) fhandle.close() # Convert from our semantic elements to actual html elements layout_to_table_map = { “layout” : “table”, “layout-row” : “tr”, “layout-cell” : “td” } layout_elements = soup.findAll(layout_to_table_map.keys()) for layout_element in layout_elements: layout_element.name = layout_to_table_map[layout_element.name] print soup.prettify()13 comments
