Blog

August 28, 2008 19:41 +0000  |  Programming 1

Found via The Blomsa Code, Margaret sent me this little gem. I should mention that the embed code the thing gave me appears to only include <embed> data and not Exploder's <ojbect> tags so I can't be sure it'll work in their browser.

August 12, 2008 19:06 +0000  |  PHP Programming Work [at] Play 1

I've been assigned to a junior-level programmer here at the office to teach her how to write code for the server I've been labouring on over the past six months. The system is my brainchild, my baby and it's with a mix of relief and aprehension that I'm taking on this new apprentice for this project.

And then I saw this at the top of her first class file:

<?php



	/**
	*
	*   Author: Coworker's Name (coworker@donatgroup.com)
	*  Licence: GPL-3 "Information wants to be free"

Granted, she forgot to capitalise "Free" but it's a pretty good start ;-)

August 06, 2008 10:55 +0000  |  Geek Stuff Programming Python 2

Yeah, I know it's late, but I got obsessed and couldn't turn away. Now I have a really slick python script that pulls down the latest Questionable Content strip and adds it to my collection to read later:

#!/usr/bin/env python

import os, sys, re
import pycurl, urllib2

destination = "/path/to/qc/repository"

class QC:

  def __init__(self):

    self.contents = ''
    self.baseurl  = 'http://questionablecontent.net/'


  def callback(self,buf):

    self.contents = self.contents + buf


  def end(self):

    c = pycurl.Curl()
    c.setopt(c.URL, self.baseurl)
    c.setopt(c.WRITEFUNCTION, self.callback)
    c.perform()
    c.close()

    try:
      return int(re.search('.*\/comics\/(\d+)\.png', self.contents).group(1))
    except:
      print ""
      print "  The regular expression no longer works."
      print "  You might want to check into that."
      print ""
      exit()


  def fetch(self,n):

    strip = urllib2.build_opener().open(self.baseurl + 'comics/' + str(n) + ".png").read()

    f = "%s%s%04d%s" % (destination, "/", n, ".png")

    fout = open(f, "wb")
    fout.write(strip)
    fout.close()


# Main -----------------------------------------------------------------------

qc = QC()

for i in range(1, qc.end() + 1):
  f = "%s%s%04d%s" % (destination, "/", i, ".png")
  if not os.path.exists(f):
    print "Fetching strip #" + str(i)
    qc.fetch(i)

May 02, 2008 03:30 +0000  |  Geek Stuff PHP Programming Work [at] Play 0

I just wrote this nifty wrapper for Simpletest, a unit testing suite for PHP and thought that I'd share it here.

Basically, the text output for Simpletest is ugly. And it's kinda lacking in output for those of us who are visually gratified. I like to see my tests pass and I like to see something green when everything is ok. Mock me if you like, I dig the pretty :-)

To use this, just put the following block into a file and call it something like TextReporterWithPasses.php and then, where your test suite script looks something like this:

  $test = new GroupTest('MTV API Layer');
  // Some $test->addTestFile() stuff
  $test->run();

Do this instead:

  require 'TextReporterWithPasses.php';
  $test = new GroupTest('MTV API Layer');
  // Some $test->addTestFile() stuff
  $test->run(new TextReporterWithPasses());

And behold the pretty ;-) Here's the code:

<?



  /**
  *
  *   Author: Daniel Quinn (daniel.quinn@donatgroup.com)
  *  License: GPL-3 "Information wants to be Free"
  * Function: Prettifies Simpletest's text output
  *
  */


  class TextReporterWithPasses extends TextReporter
  {

    private $_colours;
    private $_testCount;
    private $_errors;

    public function __construct()
    {
      parent::__construct();

      $this->_testCount = 0;
      $this->_errors = array();
      
      $this->_setColours();
    }


    public function paintPass($message)
    {
      $this->_passes++;
      print ($this->_testCount == 0) ? '  .' : '.';
      $this->_manageWrapping();
    }


    public function paintFail($message)
    {
      $this->_fails++;
      $error = new stdClass();
      $error->message = $message;
      $error->breadcrumb = "\tin ". implode("\n\tin ", array_reverse($this->getTestList()));

      $this->_errors[] = $error;

      print $this->_colours['red-light'];
      print ($this->_testCount == 0) ? '  x' : 'x';
      print $this->_colours['grey'];

      $this->_manageWrapping();

    }


    public function paintHeader($name)
    {
      if (!SimpleReporter::inCli())
      {
        header('Content-type: text/plain');
      }

      print "\n  ". $this->_colours['white'] . $name . $this->_colours['grey'] . "\n  ----------------------------------------------------------------------------\n";

      flush();

    }


    public function paintFooter()
    {

      if ($this->getFailCount() + $this->getExceptionCount() == 0)
      {
        print "\n\n  ". $this->_colours['white'] .'[ '. $this->_colours['green-light'] .'w00t!'. $this->_colours['white'] ." ]\n";
      }
      else
      {
        print "\n\n". $this->_colours['red-light'] ."  The result was less awesome than you might have hoped :-(\n\n". $this->_colours['red'];
        foreach ($this->_errors as $e)
        {
          print "  $e->message";
        }
        print "\n";
      }

      $status = array(
        'run' => $this->getTestCaseProgress() ."/". $this->getTestCaseCount(),
        'passes' => $this->getPassCount(),
        'failures' => $this->getFailCount(),
        'exceptions' => $this->getExceptionCount()
      );

      print $this->_colours['white'];

      print "\n  Test cases run: $status[run], Passes: $status[passes], Failures: $status[failures], Exceptions: $status[exceptions]\n\n";

      print $this->_colours['none'];

    }


    // Private methods -------------------------------------------

    private function _setColours()
    {
      $this->_colours = array(
        'black'       => "\033[0;30m",
        'blue'        => "\033[0;34m",
        'blue-light'  => "\033[1;34m",
        'green'       => "\033[0;32m",
        'green-light' => "\033[1;32m",
        'cyan'        => "\033[0;36m",
        'cyan-light'  => "\033[1;36m",
        'red'         => "\033[0;31m",
        'red-light'   => "\033[1;31m",
        'purple'      => "\033[0;35m",
        'brown'       => "\033[0;33m",
        'grey'        => "\033[1;30m",
        'grey-light'  => "\033[0;37m",
        'pink'        => "\033[1;35m",
        'yellow'      => "\033[1;33m",
        'white'       => "\033[1;37m",
        'none'        => "\033[0m"
      );
    }


    private function _manageWrapping()
    {
      // Poor man's wrapping
      if (++$this->_testCount == 76)
      {
        print "\n";
        $this->_testCount = 0;
      }
    }


  }


?>

Isn't it cool that I work for a company that supports the Free distribution of code?

March 12, 2008 21:25 +0000  |  Drupal Programming 1

I'm finally understanding what it's like to write code for Drupal. Essentially, you have to imagine the least efficient way of doing something, then look for how to do that... 'cause that's exactly what Drupal does.

I mean, why would anyone want to create additional columns to a user table when they could just put a bunch of serialised data into a string in the user table? It's just so easy! Why didn't I think of that?

Oh, right, 'cause I'm not insane.

March 06, 2008 18:11 +0000  |  Activism Programming 0

I know that I've been falling behind on the blogging lately. In fact, I think this is the longest dry spell I've ever had here. I'm going to chalk it up to adapting to the dramatic changes in my social, professional, and activist life resulting from my move out West. In an effort to deal with all of it though, I've made a conscious decision to prioritise the latter two to the detriment of the first. There's a considerable learning curve at work both technically and in terms of leadership, and my role with the VPSN is getting more exciting, so a strategy like this only seems appropriate.

The rest of this post is pretty technical, so if you don't read geek, you might just wanna skip it.

Donat currently has me working on a really cool project, for which I'm writing the most interesting part. We have multiple sites with the need to share user information between them, so for example, if you log into site A, change your profile to include a new favourite book, people looking at sites B, C, and D should be able to see that new book on your profile page there. Eventually it'll also track user relationships, group assignments etc., and it's all managed through my nifty API layer.

The layer uses a framework I wrote from scratch, but based loosely on the one used on this site, which in turn looks a little like Fusebox. The magic of the whole thing is that not only is everything built according to a strict MVC model, but because of this model, the View layer is able to output data in any format you like. Currently the framework supports standard XHTML, XML, JSON, TEXT, XMLRPC and SOAP, but it's infinitely extensible with limited overhead. On top of that, everything is managed through mod_rewrite so that the URLs are stupid-easy to reference:

  site.com/xml/user/add
  site.com/soap/user/get/someUserName
  site.com/json/user/getFriends/someUserName

I've been talking to the brass here at Donat about making the code available on my site to help other geeks shave time off research for something like this since it's a pretty common task in large-scale projects and there's no reason people should have to reinvent the wheel (like I had to), and they've been receptive. We'll see how it goes.

The VPSN has me working on a really exciting mapping project that plugs into GoogleMaps. It's based on a similar (but slightly improved) framework to the above, but I've dropped the XMLRPC and SOAP stuff in favour of a simpler REST-based setup. So what's this site going to do? Imagine pulling up an interactive map of Vancouver and being able to see any or all of the following:

  • All the bike lockers
  • Bike lanes
    • Rated by difficulty
  • CCTV cameras
    • Their range and model
  • Community gardens
  • Public parks
  • Green roofs

The list is long and growing and we'll be doing it all with a volunteer army and a few GPS units. A lot of the above data is already collected and I'm writing a CSV importer that'll geocode the addresses and map the data to a coordinate class. The data will then be pulled dynamically through an AJAX interface, redrawing the map for each element you request. This also means that if other people want to use or contribute to our data, it'll be available through simple REST URL. It's really exciting and it's been consuming pretty much every night these past few weeks.

The code for the VPSN will be GPL, but frankly, it's nothing novel. It was the SOAP & XMLRPC integration that made things nifty, so I do hope the brass at Donat come out in favour of me sharing that code.

Alright, that's it. I've got too much work to do and I've already burnt a considerable amount on this post.

January 16, 2008 01:27 +0000  |  Geek Stuff Javascript Programming 0

A Graph

Reinvent has decided to start playing with Flot, an Open graphing library that uses the <canvas> tag. It dynamically creates graphs like the one you see above using only JQuery and this flot plugin. It's absolutely amazing.

Geeks might be interested in checking out the samples on flot's site.

January 23, 2007 22:39 +0000  |  Programming Riptown 0

One of my coworkers helped me out of a jam by writing some amazing math-foo the other day and I wanted to share:

public static function getDefinitionFromSerials($in) {

	$out = array();
	if ($in) {

		sort($in);

		$n = $in[0];
		for ($i = 1; $i < count($in); $i++) {
			$z = $n;
			if ($in[$i] != $in[$i-1] + 1) {
				if ($z == $in[$i-1]) {
					$out[] = $z;
				} elseif ($z + 1 == $in[$i-1]) {
					$out[] = $z;
					$out[] = $in[$i-1];
				} else {
					$out[] = $z .'-'. $in[$i-1];
				}
				$n = $in[$i];
			}
		}
		if (count($in) == 1 || $z != $n) {
			$out[] = $n;
		} elseif ($z+1 == $in[count($in)-1]) {
			$out[] = $n;
			$out[] = $in[count($in)-1];
		} else {
			$out[] = $z .'-'. $in[count($in)-1];
		}

	}

	return implode(',', $out);

}

The above is an algorithm that transforms an array of numbers (1,2,3,7,9,10,11) into a human readable range or fieldset such as "1-3,7,9-11". I spent hours online googling for the solution and found nothing so I thought I'd share it here in the hopes that someone else might find it useful.