Screen Savers for the Mac using Flash

This is an evening project that turned out to be really cool. Let’s say that you’re a Macromedia Flash designer, and your clients ask you to bundle your nice Flash movie as a screen saver. What to do? For Windows there are free utilities to convert a SWF into a screen saver, but not for the Mac – and the first commercial one costs around USD 200!

I propose here a simple solution for this problem:

  1. Using Xcode, you can create screen savers (basically, Cocoa apps).
  2. Cocoa applications can host a WebKit component (basically, Safari).
  3. Safari can show local HTML pages (basically, “file:///” stuff).
  4. And HTML pages can show Flash movies (basically, <OBJECT> and <EMBED>)

The idea, then, is to bundle your own page, with your own movie, inside the screen saver bundle, and show the Flash movie this way. Easy said, easy done.

It all goes nice until… you try this solution :) The problem is, Flash movies loaded from “file:///” URLs are blocked by the built-in security mechanisms of Adobe… and you have to find a workaround for that. Mine was to follow the instructions on how to bypass the Flash security mechanism, and then create an installer package that will do what’s needed for you to enjoy the screen saver.

You can get both the project and the installer package in my projects section. I’ve tested the installer in three different machines, and it worked, so I hope it’ll work for you too :) Enjoy! As always, try this at your own risk. Murphy says that things can go wrong, so watch out.

REST + HTTP (Basic + Digest) Authentication support for Django’s test Client class

Django has a nice support for unit and functional testing; however, its django.test.client.Client class does not support PUT and DELETE requests, which might be useful if, like me, you’re doing some kind of REST implementation using that framework. There’s an open ticket about it, but for the time being, here’s my wrapper that supports those methods as well as GET and POST:

[source:python] from cStringIO import StringIO from django.test.client import Client as DjangoClient, encode_multipart from django.utils.http import urlencode import base64 import md5

class Client(DjangoClient): “”" Wrapper and drop-in replacement around Django’s own test “Client” class, providing PUT, DELETE and OPTIONS support, as well as HTTP Basic + Digest Authentication support. NOTE: the django.test.client.Client does not directly support PUT, DELETE or OPTIONS requests so we’re using the “request()” method directly… there’s an open ticket about it: http://code.djangoproject.com/ticket/5888 “”"

auth = { }
def http_basic_login(self, username, password):
    base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
    self.auth = { "HTTP_AUTHORIZATION": "Basic %s" % base64string }
def http_digest_login(self, method, url, params, response, username, password):
    (authmeth, auth) = response['WWW-Authenticate'].split(" ", 1)
    if authmeth.lower() != 'digest':
        return
    amap = {}
    for itm in auth.split(", "):
        (k, v) = [s.strip() for s in itm.split("=", 1)]
        amap[k] = v.replace('"', '')
    try:
        realm    = amap['realm']
        qop      = amap.get('qop', '')
        nonce    = amap['nonce']
        opaque   = amap['opaque']
    except:
        return
    cnonce = "01b6730aae57c007"
    nc = "00000001"
    query_string = "&".join(["=".join(item) for item in zip(params.keys(), params.values())])
    uri = url + "?" + query_string
    ha1 = md5.md5('%s:%s:%s' % (username, realm, password)).hexdigest()
    ha2 = md5.md5('%s:%s' % (method, uri)).hexdigest()
    if qop:
        chk = "%s:%s:%s:%s:%s:%s" % (ha1, nonce, nc, cnonce, qop, ha2)
    else:
        chk = "%s:%s:%s" % (ha1, nonce, ha2)
    response = md5.md5(chk).hexdigest()
    self.auth = {
        "HTTP_AUTHORIZATION": 'Digest username="%s", realm="%s", nonce="%s", uri="%s", response="%s", opaque="%s", qop=auth, nc=%s, cnonce="%s"' % (username, realm, nonce, uri, response, opaque, nc, cnonce),
    }
def http_logout(self):
    self.auth = {}
def pre_request(self, url, data):
    r = {
        'CONTENT_LENGTH':  None,
        'CONTENT_TYPE':    'text/html; charset=utf-8',
        "HTTP_USER_AGENT": "Django Unit Test HTTP Client",
        'PATH_INFO':       url,
        'QUERY_STRING':    urlencode(data, doseq=True),
    }
    r.update(self.auth)
    return r
def get(self, url, data, **extra):
    r = {}
    r.update(extra)
    r.update(self.auth)
    return DjangoClient.get(self, url, data, **r)
def post(self, url, data, **extra):
    r = {}
    r.update(extra)
    r.update(self.auth)
    return DjangoClient.post(self, url, data, **r)
def delete(self, url, data):
    r = self.pre_request(url, data)
    r["REQUEST_METHOD"] = "DELETE"
    return self.request(**r)
def options(self, url, data):
    r = self.pre_request(url, data)
    r["REQUEST_METHOD"] = "OPTIONS"
    return self.request(**r)
def put(self, url, data, form):
    BOUNDARY = 'BoUnDaRyStRiNg'
    MULTIPART_CONTENT = 'multipart/form-data; boundary=%s' % BOUNDARY
    encoded = encode_multipart(BOUNDARY, form)
    r = self.pre_request(url, data)
    r.update({
        'CONTENT_LENGTH': len(encoded),
        'CONTENT_TYPE':   MULTIPART_CONTENT,
        'REQUEST_METHOD': 'PUT',
        'wsgi.input':     StringIO(encoded),
    })
    return self.request(**r)
def hello(self, url, data, **extra):
    """Sends a fake 'HELLO' request which returns a 405 answer :)"""
    r = self.pre_request(url, data)
    r["REQUEST_METHOD"] = "HELLO"
    r.update(extra)
    return self.request(**r)

[/source]

Hope it helps! Of course you could extend this to support OPTIONS, HEAD or other HTTP methods you could find in the specification.

Update, 2008-03-05: Following Yoan’s comment below, I’ve DRYed the code a bit. Neat.

Update, 2008-03-11: I’ve added HTTP Basic Authentication support to the class (and changed the post title accordingly).

Update, 2008-03-13: Another modification: now the client supports HTTP Digest Authentication (Yay! To use it, make a first call to your server and then pass the response as a parameter to the http_digest_login method), plus support for the OPTIONS verb, plus another method which sends a method with a “HELLO” verb, which of course does not exist… and which will (normally) return a 405 response!

How to count words in LaTeX files?

I am a big LaTeX fan, mostly thanks to my friend Cedric who introduced me to it ;) And I don’t regret it at all; there is simply no better way to create long, beautiful PDF documents, particularly during these times of dissertation writing! I’m in my last step towards the Master’s degree I’ve been working on for the last two years, and creating documents is an important part of that.

LaTeX works for me, because:

  1. It’s cross-platform (and I need that for my project!);
  2. It’s text based (I can edit the files with any decent editor; personally I use and TexShop and sometimes TextMate);
  3. I can generate PDF, plain text, RTF, and much more from the same source;
  4. I can split my documents in several others and work separately in each;
  5. I can generate meaningful diffs using Subversion (to see what I’ve changed in every revision);
  6. I can manage the bibliography for my papers easily (using the awesome BibDesk tool);
  7. I don’t have to cope with a buggy text editor that crashes every so often!
  8. I can generate gorgeous, absolutely beautiful documents. Easily.

For my last document, the dissertation, I have a numeric limit in the number of words (~ 10K to 15K words) and I need to count the number of words in the documents I generate. Since I’m not using Word, nor KOffice nor OpenOffice, this simple requirement becomes more complex to fulfill. But working in a Unix environment has its benefits; first I found this solution:

$ detex file.tex | wc -w

This command provides a first approach to the problem; however, it just strips off the LaTeX commands, even those that generate content in the final document. For example, if you have a macro that puts in bold the name of your project, those words will not appear in the final calculation even if they do appear in the final document. Clearly not acceptable. Googling a bit more, I found what I was looking for:

$ ps2ascii file.pdf | wc -w

In this case we’re working on the final PDF document, and of course the final result is much, much more interesting.

Happy typesetting!

Install MySQL_python in Leopard

I wanted to make my Django blog engine work on Leopard using MySQL as a database engine. I had a hard time making it work, partially because of my lack of knowledge of Python, partially because I am using MAMP instead of a “/usr/local/mysql”-like MySQL installation, partially because of Leopard itself.

The problem is, basically, that if you try to do the “easy_install MySQL_python” thing, it won’t work in Leopard (the compilation of the native code fails). Here’s how I made it work, following the instructions in this post in the MySQL forums, and doing some tweaking manually. Continue reading

Starting with Django in Leopard

As I’ve written earlier, I’m playing with Django these days. It’s a refreshing change, I must say, even if I admit that I prefer Ruby’s syntax to Python’s. Of course that’s just a purely subjective impression (I’m writing this while I try to avoid the rotten tomatoes thrown by angry pythonistas reading this) that does nothing to do with the power of the Python language + framework, which is by all means absolutely impressive.

In any case, I had to install a working Django environment in my machine, and while following the excellent and free Django Book instructions, this is what I did in my Leopard installation to have it up and running (Leopard already comes bundled with Subversion 1.4.4, Python 2.5.1 and SQLite 3.4.0, so you don’t need to do anything about them): Continue reading

Django & Leopard & the UTF-8 error

If you use Django on Leopard, you might encounter a strange “Locale UTF-8 not found” error when running your application. This is due to a bug in Terminal.app, albeit an easy to fix one: just go to the Preferences pane / “Settings” page / “Advanced” tab and uncheck the “Set LANG environment variable on startup” checkbox. Reopen your Terminal session, load the Django application and voilĂ ! Your bug has disappeared. The screenshot below might help too:

solution.png

Hope this helps!

PS: yes, I’m doing Django and hence Python these days ;)

Updating RubyGems and Rails in Leopard

If you just installed Leopard and the developer tools, you’ll find out that Ruby on Rails is there, ready to be used. But of course, it’s Rails 1.2.3, which is fine, but it turns out that last Friday Rails went 2.0. Not only that, but RubyGems was updated to 0.9.5 lately too… and you’re dying to have everything up and running on your system.

So how to proceed? Follow these instructions:

  1. Open Terminal.app
  2. $ sudo gem update --system
  3. $ sudo gem install rails
  4. $ sudo gem update

If you just do “gem update”, then the current Rails installation will be broken. You must do ‘gem install rails” (which seems odd, because it was already installed, after all). The thing is that since you’ve updated RubyGems with the command 2) above, then you need to re-install Rails. I haven’t tried with other gems, but it could be the same situation for them.

Update, 2007-12-19: Here’s another solution for this problem!

git

If you haven’t tried git, you should. Git is a “distributed version control” system, that is, similar to Subversion with the big difference that… you do not need a server. There are only clients, any of them, and you can pull and push changes to and from other repositories from your project colleagues. The git Wikipedia entry does a much better job than me to introduce the subject :)

In Mac OS X, I’ve just downloaded the source code tarball with the latest snapshot of the code, and it compiled out of the box. Just the classical operations:

./configure
make
sudo make install

Then I went through the tutorial, and frankly, I loved it. The Everyday GIT Guide is excellent too to understand the idea of this beautiful piece of code.

It’s too cool, really. Lightweight, and damn fast. No wonder why everyone’s talking about it lately!

Installing Xubuntu 7.10 on a G3 iBook

Just a small post, pointing to the one and only solution to a known bug, that (incredibly) shipped with the public release of the PowerPC version of the latest Ubuntu distribution: 7.10 or “Gutsy Gibbon”. When installing that OS on a PowerPC G3 iBook (like mine), during the boot sequence the computer “freezes” (that is, the scrollbar stops running and the whole boot stops) and then you get a “BusyBox” screen, which is, needless to say, kind of a bummer.

The problem is that /dev/hda3 is not available (that is, your IDE internal hard disk) and of course, Xubuntu does not know what to do in that case. Kind of incredible, huh?

Well, the solution for that problem was in this answer of the Ubuntu Forums. Just follow the instructions there and you’ll succeed. Now I have a nice Xubuntu install in my good old and faithful G3 iBook (in double boot with Mac OS X “Jaguar”).

Building JUCE on Kubuntu 7.10

JUCE is a gorgeous thing:

JUCE (Jules’ Utility Class Extensions) is an all-encompassing C++ class library for developing cross-platform applications. It’s particularly good for creating highly-specialised user interfaces and for handling graphics and sound.

For Mac OS X (with the Developer Tools installed) and Windows (using Visual Studio 6, 2003 or 2005), the library builds out-of the box (well, almost: on Windows you need to have QuickTime and the ASIO SDK installed). However, for Linux there are a couple of external dependencies.

This is a small tutorial (and a reminder for myself, as usual) for those interested in building JUCE on Kubuntu 7.10 “Gutsy Gibbon” (these instructions should also be useful for other Linux distributions, but I cannot tell for sure). Continue reading