tim.clifford.io

The blog of an aspiring technologist.

I'm a web developer.

I'm the lead developer behind The Gleaners Interface.

I got my start in web development making fast Wordpress Spinups for non-profits.

I run an irc server and spend time asking and answering questions in the popular #django and #python channels on freenode.

I live in Vermont, and love to travel.

My Github Repos

A Solution A Day

May 13, 2014, 7:07 a.m.

I'm a big fan of the new Problem Of the Day website, despite some of the problems bringing out my bull headed side.

Yesterday's problem was pretty straightforward, to take a string and list the frequency each character appeared in it, and then bonus points to visualize the data afterwards. The problem can be found here.

Despite the use of single-character variables, I thought my code ended up being rather elegant, as it is two functions, the second of which makes good use of both the lambda function and reversed.

def counter(input_string):
    dictionary = {}
    for l in input_string:
        if l != " ":
            dictionary[l] = dictionary.get(l, 0) + 1
    return dictionary

def graph(input_string):
    data = counter(input_string)
    tdata = data.items()
    tdata.sort(key=lambda tup: tup[1])
    for tup in reversed(tdata):
        print tup[0], "."*tup[1]

By way of forinstance re:bull-headedness, this problem asks the viewer to create a simple encryption and decryption system for the Vigenere cypher. This isn't a particularly tough problem, but then as an afterthought it asks for code designed to break an encrypted phrase, given that the key is 5 characters or less.

This is where the bull headedness comes in. The vigenere cypher isn't used to encrypt web traffic for a number of reasons, one of which is that it is a relatively weak encryption standard. How and why, I don't know, and I'm sure I could look it up and make this problem easier to solve for myself.

But would it be that hard to brute force?

5 characters isn't that many, and it would have the added bonus of having thought of a correct, working solution at the outset. Let's start with the initial solution, a cipher and decipher.

from string import ascii_lowercase, lower


def cipher(key, message):
    key = lower(key)
    message = lower(message)
    key_index = 0
    output = ""
    for letter in message:
        letter_number = ascii_lowercase.find(letter)
        key_number = ascii_lowercase.find(key[key_index])
        cipher_number = (letter_number + key_number) % 26
        output += ascii_lowercase[cipher_number]
        key_index = (key_index + 1) % len(key)
    return output

#cipher("reddit", "todayismybirthday")
##'ksgdgbjqbeqkklgdg'


def decipher(key, message):
    message = lower(message)
    key_index = 0
    key = lower(key)
    output = ""
    for cipher in message:
        cipher_number = ascii_lowercase.find(cipher)
        key_number = ascii_lowercase.find(key[key_index])
        letter_number = (cipher_number-key_number) % 26
        output += ascii_lowercase[letter_number]
        key_index = (key_index + 1) % len(key)
    return output

I wrote that code a few months ago, I think comparing it against the solution I wrote yesterday is a good example of professional growth. Next up, a simple key generation method. As 5^5 isn't really that many, I decided it was better to use literally every possible character solution rather than simply dictionary words, as proper nouns (like "REDDIT" in the linked example) would be overlooked.

import itertools


def any_letters(max_length=2):
    for i in range(1, max_length+1):
        for j in itertools.permutations(ascii_lowercase, i):
            yield "".join(j)

Ok, that seems to be working as expected. Now looking at my old code, I apparently gave up after finding a bunch of false positives based on how I tested the resulting potential plaintext. Come to think of it, proper nouns (as well as abbreviations and nonsense words) throw a pretty big wrench into the problem.

But I'll leave that for the next post.

Read More »

Flag Variables

Jan. 13, 2014, 11:03 a.m.
Quick python post: turns out those flag variables that I've always begrudged making have a convenient and clean workaround already built into python's code.
If you're using a for loop to find something, you can break out of a loop early if you found something you wanted. But if you're looking for the exclusion of something, the obvious solution is to use a flag variable:
alphabet_soup = ["n", "e", "fly", "b", "a", "f", "w"]

good_to_eat = True
for item in example_list:
    if item == "fly":
        print "There's a fly in my soup!"
        good_to_eat = False
        break
if good_to_eat:
    print "Good enough to eat"
    ## meaningful soup eating code
The Python devs thought there was a better way to do this, so they included an implicit if statement, which fails on a break. Because there's a hidden if statement in your for loop, else will fire if nothing broke it:
soup_with_fly = ["n", "e", "fly", "b", "a", "f", "w"]
alphabet_soup = ["n", "e", "c", "b", "a", "f", "w"]

def inspect_soup(example_list):
    for item in example_list:
        if item == "fly":
            print "there's a fly in my soup!"
            break
    else:
        print "Apparently I didn't find any flies this time"
        ## consume soup

inspect_soup(soup_with_fly)
>>> "there's a fly in my soup!"
inspect_soup(alphabet_soup)
>>> "Apparently I didn't find any flies this time"

Neat, right? For some reason this struck me as particularly clever, and if you wanted to see more you can go straight to source, a Python Dev going over how to write beautiful and idiomatic python.

Read More »

Conservation of Mass

Dec. 8, 2013, 8:45 p.m.

Recently moved to a nice town in Massachusetts, and I'm figuring out how to balance work-life again.

With local resources, I've been happy to find it easier to discuss problems with fellow programmers (I still have WPI friends in Worcester, if you ever wanted to meet a programmers who are also tough as nails), and I'm going to have to do a lot more peacocking to get my work seen and appreciated.

I've updated the site to use Django 1.6 which mirrors the work I'm doing for a client, and added a slew of new features just for fun. I'd like to experiment more with some out there plugins to somehow interact with all the pi's around my house, but in the mean time I'll settle for a snazzy code highlighter that took entirely too long to work.

Syntax Highlighter (written by Alex Gorbachev)

This is a javascript plugin that allows you to put code into html <pre /> tags and it'll prettify it for you, assuming you properly escape your angle brackets. As a test, see if you can see the issue that took my hungover mind all of an hour to track down, in this snippet of code:

    <link rel="stylesheet" src="/static/css/shCore.css">
    <link rel="stylesheet" src="/static/css/shThemeDefault.css">

Can you spot why these stylesheets weren't working?

Makes me wonder what I did with that comment system I implemented...

Read More »

Djangocon!

Sept. 6, 2013, 5:51 p.m.

What a conference!

It's been a damn long week, and it ended with a pull request to Django's source code! Here's a quick rundown of tips that I'll be thinking of next time I go to a conference:

  • Talks are teasers, they act as great introductions but no substitute for spending real time with a topic
  • All the pay-extra fluff is worth it, the TDD tutorial was amazing and I wish I went to more lke it
  • Have your marketing materials ready and handy, I felt awful for having a mediocre-at-best portfolio site, and I talked to devs who felt worse for not having their business cards with them
  • Like any good project you undertake, make a reasonable estimate for how much it's going to cost, and then quote for double
  • As always, prioritize your own energy

There are a lot of takeaways, but I'd like to really elaborate on that last one. One of the ringleaders of the event made a joke about the 3-2-1 rule, in that every day at a conference you should get three hours of sleep, two square meals, and one shower. And if you have to skip something, don't skip the shower.

::rimshot::

That said, there's a lot of rules we all abide by when we're in our normal lives that need to get a little extra emphasis at a conference. For short two day stretches, it's easy to run yourself thin and sleep when you get home, but a week long event like Djangocon, I found myself battling with sleep deprivation, not moderating my coffee consumption, and basically the mindset of sprint til you get home couldn't hold out that long.

Maybe I'm just getting older, but I'm glad that Wednesday night I decided to just eat the lost productivity and go to sleep at 9 like a sane person. It made the last day of the conference that much more enjoyable and remember why I put such a high priority on maintaining my energy through my non-conference-going life.

Thanks again Djangocon, I hope to see everyone who attended at PyCon Montreal!

Read More »

Coded on a Plane

Sept. 1, 2013, 2:51 p.m.

By the way, this site was coded on the way here. It's still a work in progress, because with all the work I've been doing, I haven't actually had the time to write up a basic portfolio site.

So after getting through airport security two hours early for my flight, (Burlington International doesn't quite bruise the ego the way a big place like Logan does), I sat down and did all the fun stuff that developers often skip. You need a README file, that hopefully can act as a revision history, a git repository, the legwork to make a site actually run on Heroku (or you deployment platform of choice), and ran out of fluff to work on with time to spare.

When all that was left to do was actually writing the site, I had already boarded the plane and figured I'd try writing code from miles up. Long story short, there have been a few words said about coding on a plane, but I don't think they cover that sometimes software mostly writes itself.

The site is written in Django (and references its own source in the bottom right). If you're a fan of messing with websites, there's a brief window between now and the end of the week that you can post to this blog yourself if you're interested in looking through the code to see the open security hole (hint: I'm still deciding on an auth model).

That said, happy hacking!

Read More »