Copy password button in Keychain.app

I don’t know if this is new or not, but I haven’t noticed it before. My normal workflow for Keychain.app and finding a forgotten password (ie, my Twitter one to put into a new app) is to open the password entry, and copy the value.

Today, I noticed a Copy button at the bottom of the window:

Keychain Access

This still requires you to enter your keychain password to authorise the copy, but saves a step or two.

Combining recurring events with approval

A while ago, I talked about the issues with taking a set of potentially recurring events and merging them into the least number of events that fully describe all of the occurrences. This was a bit of a challenge, but with a TDD process, I was able to get something that, as far as my testing tells me works. Thus, deleting one middle occurrence of a recurring event results in two events being left, and re-creating that occurrence results in the one event being created.

This goes even further, with occurrences that touch or overlap being merged into potentially a new event. This is a requirement of our problem domain, since these events are used to see if a person is available to perform a task, and two adjacent occurrences would otherwise make it hard to determine if the person is indeed available.

So, it turns out that this is only part of the problem. In addition, changes to availability may require approval by a manager. So, in addition to being able to merge objects, we also need to be able to merge pending objects with one another, and mark pending objects as superseding other objects. And, even more fun, if a pending object is created that matches a pending-deletion object, for instance, then that object is restored: the two pending events cancel one another out. Finally, a pending object can also be ‘psuedo-merged’ with an availability, where it then is the union of the two events, and supersedes the approved event!

This problem is even stickier than the previous part. Having said that, I have it working, although at this stage it is not possible to have recurring pending events. Things were made even more difficult by the way that I handle superseding events. This cannot be just references in the database, as events and occurrences may be deleted and created by saving another event, so a different method of keeping track of which events are superseded is required.

The good news is, this is coming along well. It did occur to me on the way home today that without ‘never ending’ events, this would possibly collapse the problem space down. Occurrences would no longer need to be recreated quite as often, and indeed they may be the sole storage representation: abstract events could then be created on the fly, purely for descriptive purposes. All I need is some way to represent events that don’t have an end date…

…or I could make it that never-ending events must end in 2050. Then, any event that ends that year will be represented to the user as never-ending. This seems like a slippery Y2K-style slope, but if I keep moving the goal-posts, then it might work. And simplify my code immensely. It turns out there are only ~2100 weeks until then, and my events at this stage only occur weekly (it makes the simplification simpler to only have to look for weekly patterns, and that is how people usually determine their schedule).

I’m glad we had this little chat.

Combining recurring events

On a project I am working on for work at the moment, we have a need to handle recurring events. These events need to be merged if they are the same and can be simplified in any way. As it turns out, this is quite a tricky problem.

There are really only two ways that events can be merged. If two events have the same frequency, and occur on the same day, or on consecutive days according to the period, and they have the same start and finish times, then they can be merged into one.

Similarly, if two events have the same period, occur on all of the same days, and overlap or touch in times, they can be merged into a single event.

From there, it starts to get complicated. Two events that partially overlap may be able to merge parts of themselves, possibly resulting in an extra event being created.

For instance, an event every Tuesday at 9am-12noon, that lasts for 10 weeks, and another event every Tuesday 11am-2pm that starts 5 weeks later, and also runs for 10 weeks, will result in 3 events: one that lasts 5 weeks 9-12, one that lasts 5 more weeks 9-2, and one that lasts a further 5 weeks 11-2.

This on its own is easy to deal with, but as soon as you consider events that have no end date, things get tricky quickly.

Typing the ° symbol on iPhone.

For future reference: press and hold 0, and the ° will appear.

View man pages in Preview

It’s not a new concept, but here is my take on it:

function man {
    # We can get the actual path to the man command here, so we can override
    # it with our function name.
    MAN=`which man`
    # Change these two if you are not on OS X.
    CACHE_DIR="${HOME}/Library/Caches/manpages"
    OPEN="open"
    
    # If we don't have any arguments, use the nice man error message
    if [ ! $1 ]; then
        $MAN
        return
    fi
    
    # If we have an argument that clashes with what we are wanting to be
    # able to do, pass the whole command through.
    for ARG in $*; do
        case $ARG in 
            -[dfkKwtWP])
                $MAN $*
                return;;
        esac
    done
    
    # Make sure our cache directory exists.
    mkdir -p $CACHE_DIR
    # Get the man page(s) that match our query.
    MAN_FILES=`$MAN -w $*`
    for MAN_FILE in $MAN_FILES; do
        # Get the name of the man file, and the section.
        MAN_PAGE=`basename "$MAN_FILE" | cut -d \. -f 1-2 | sed 's/\./(/' | sed 's/$/)/'`
        # Our PDF will be in this location
        PDF_FILE="${CACHE_DIR}/${MAN_PAGE}"
        
        # If we actually have a man file that matches
        if [ -n "$MAN_FILE" ]; then
            # See if the man file is newer than our cached PDF, and if it is,
            # then generate a new PDF. This works even if $PDF_FILE does not
            # exist.
            if [ $MAN_FILE -nt $PDF_FILE ]; then
                $MAN -t $* | pstopdf -i -o "$PDF_FILE"
            fi
            # Then display the file.
            $OPEN "$PDF_FILE"
        fi
    done
}

On UI sins

My sister likes to back up DVDs that her children use all of the time: they are old enough to change discs, but they tend to get scratched. So, I have been looking into backup solutions for her to use on her new MacBook.

I came across Aimersoft DVD Backup, and ran it. Not looking too bad to begin with.

The actual window, however, is appalling:

Aimersoft DVD Backup(Unregistered)

It is a little hard to see, but the window is not actually connected to the titlebar. You can actually see the objects that are in obscured windows in the gap between them!

Finally, the text from the close confirmation sheet just cracked me up:

Surely, they can tell if a copying task is in progress, and display a dialog then. If not, then just quit immediately!

On Django and Check Constraints

I’ve come to love Django, and now I seem to be spending not only my work time, but also my own time working on one django project or another. Today at work I came across the need to have check constraints in a database. For instance, this can be used to ensure that the start of an event is before the end of the event, or that a certain value has a particular range of values.

For the SQL savvy, it can look like:

CREATE TABLE event (
...more columns here...
start datetime,
finish datetime,
count integer CHECK (count >= 0),
CONSTRAINT event_starts_before_finish CHECK (start < finish)
);

There are two types of constraint here: the column-level constraint, which in this instance can be done with django, and the table-level constraint, which in many systems cannot be a part of a column definition. In PostgreSQL, my DBMS of choice, it is possible to define a constraint that affects more than one column as part of a column, but I prefer not to. Note also that I am using the syntax form that allows me to name the constraint. This means I can alter or drop it later.

As I mentioned, django can do the first type of constraint, as long as it is a > 0 constraint, using one of the field types that subclasses PositiveInteger. However, there is no functionality built into django to do the latter. And I would like to use them.

It is possible to just add the constraints to an already existing database: indeed, that is what I did for work. Having the constraints at the database level means that, since I have more than one interface to my datastore (don’t ask: one of them is for an old SOAP interface I need to keep around), I want to ensure that even if someone accesses it outside of django, they cannot put in data that breaks these constraints. Similarly, if I use an interface other than the admin interface, or heaven forbid, open up the database in raw form, I cannot accidentally put in data that breaks this validation.

But, pure database level constraints don’t give very nice feedback in django. It is nicer to have the pretty red boxes around my field than the traceback. So, I want the validation to occur on the field level as well. As long as I am using django’s forms (and my API for RESTful access will use them for validation), then I will have these errors nicely presented.

So, to that end, I have created some code that allows for the definition and enforcement of both of these types of constraint.

The column form allows for a new keyword argument to a field:

count = models.IntegerField(constraint=">= 0")

Notably, the string that can be passed in must conform to the pattern “cmp value”, where cmp is one of the comparison operators (<, >, <=, >=, =, !=), and value is a valid value for this column type. It will be passed to the to_python() method of this field when comparing. There must be a string between the two parts.

The other form is a new attribute on the Meta class of a model.

check_constraints = ('start < finish',)

This must be a tuple of strings, where a string is of the form “column cmp column”. Again, there must be a space either side of cmp, and each column name must be a valid column. Not meeting these criteria will result in a validation error.

From these definitions, the database constraints will be applied, and validation of forms will also occur.

I have deliberately made the constraints simple (ie, not callable objects) so that they can easily be converted to database constraints. For instance, they can effectively be transferred straight through to the database (with the addition of the column name in the case of the column constraint).

I am going to create a ticket in the django trac, and submit a patch. Guessing I should write up some test cases, though!

Setup Django with Passenger Prefpane

I am loving Django for web development. I didn’t have it set up to serve my (development) projects automatically until just now.

I had installed the Passenger Prefpane, which greatly simplifies the management of VirtualHost-based serving of sites, at least for Rails and other ruby-based frameworks. With a little work, you can use the same setup to serve Django projects.

Rather than re-detail the setup, I’ll just point you to the mod_passenger setup, and the Passenger Prefpane setup pages.

Now, to set up a Django project: obviously you need a django project. Create one, and note where it is located. I stick all of mine in ~/Sites.

Add a file to the root of this project, called passenger_wsgi.py. It needs to contain the following data:

import os, sys
sys.path.append('/Users/matt/Sites') # Replace with your directory
os.environ['DJANGO_SETTINGS_MODULE'] = 'testing.settings' # replace with your projectname.
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

Now, add the site to the Passenger prefpane. My site is the testing.local site:

Now visit the address and ensure that it works. You should get the basic you need to set up django message.

To get the admin media served by the standard apache setup, I created a link inside the /Library/WebServer/Documents directory to /Library/Python/2.5/site-packages/django/contrib/admin/media. This can be done inside the Terminal:

sudo ln -s /Library/Python/2.5/site-packages/django/contrib/admin/media /Library/WebServer/Documents/admin-media/

Then, change the ADMIN_MEDIA setting in your django projects to http://localhost/admin-media/. This is probably the weakest point in the setup, as it will only work for pages served to your machine, not others on your network.

# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = 'http://localhost/admin-media/'

I had some issues with mod_passenger serving the data for localhost (and arne, my actual machine’s name) from the first installed VirtualHost. To overcome this, I put in a new file into /etc/apache2/other/localhost.conf, which looks like:

<VirtualHost *:80>
  DocumentRoot "/Library/WebServer/Documents"
  <directory "/Library/WebServer/Documents">
    Order allow,deny
    Allow from all
  </directory>
</VirtualHost>

This forces unnamed, or other sites to work as intended. Including the /User/*/Sites directories.

Prowl

Prowl is awesome. Growl notifications can be forwarded to your iPhone.

But you can get notifications from anywhere. A Perl script is included, but that didn’t work on my server. So I wrote one in Ruby:

#! /usr/bin/ruby

# A ruby class for sending notifications to Prowl.

require 'uri'
require 'net/http'
require 'net/https'

class String
  def urlencode
    gsub( /[^a-zA-Z0-9\-_\.!~*'()]/n ) {|x| sprintf('%%%02x', x[0]) }
  end
end

class Hash
  def urlencode
    collect { |k,v| "#{k.to_s.urlencode}=#{v.to_s.urlencode}" }.join('&')
  end
end

class Prowler
  def initialize user, pass
    @url = URI.parse('https://prowl.weks.net/api/add_notification.php')
    @username = user
    @password = pass
    
    @http = Net::HTTP.new(@url.host, @url.port)
    @http.use_ssl = true
  end

  def send_notification app, evt, desc
    

    options = {
      'application' => app,
      'event' => evt,
      'description' => desc
    }
    
    req = Net::HTTP::Get.new("#{@url.path}?#{options.urlencode}")
    req.basic_auth @username, @password
    @http.request(req)
  end

end

# How to use?
# p = Prowler.new('username', 'password')
# p.send_notification('App','Event','Desc')

Logos

Started up a new iPhone app today. The logo at the bottom of the screen looked a bit familiar:

Here is the logo from the Adelaide City Council (which has been in use for about 7 years):

Wonder which came first…

If I overlay one one the other, we see they are not identical:

]