Showing iTunes track in XMPP presence

Now that you can connect third party clients to my.OnSIP you can take advantage of some of their powerful features. One of my favorites is the ability of Adium to display my currently playing song from iTunes. I get a lot of questions about how I'm doing that and it's quite simple, so here's how you can do it, too:

Requires

  • XMPP hosting
  • Adium

Steps

  1. Start Adium
  2. Connect to your XMPP account
  3. Open the Status menu
  4. Select ♫ iTunes
  5. As iTunes plays songs your status will now update automatically

Astrology doesn't work for me, either.

Grab the book nearest you. Right now. Turn to page 56. Find the fifth sentence. Post that sentence along with these instructions in your LiveJournal. Don't dig for your favorite book, the coolest, the most intellectual. Use the CLOSEST.

However, he couldn't.

Now Wait for Last Year, Philip K. Dick

erlc says TOO CLEVAR 4 YUOS!

The one time I wanted anonymous function syntax, so I could do pattern matching against the enclosing function:

find_option(Option, Default, Options) ->
    case lists:foldl(fun ({Option, Value}, Acc) -> [Value | Acc];
                         (_, Acc) -> Acc
                     end, [], Options) of
        [] -> Default;
        [Val] -> Val
    end.


In other words, I want the Option in the lambda for lists:fold/3 to match the Option passed into find_option/3. Woulda been nice, huh? Unfortunately:

./mod_jnctn.erl:30: Warning: variable 'Option' is unused
./mod_jnctn.erl:30: Warning: variable 'Option' shadowed in 'fun'

4 hours, 18 minutes.

I just saw the railroads on json.org and wondered how hard it'd be to put it in Erlang. Unfortunately they're no t exactly accurate, but that gave me a convenient excuse to avoid a lot of things, too. I was only going to the minimum spec (with few as few false positives as reasonable) according to those diagrams. White space doesn't get eaten properly, for instance, but I don't really care.

I was surprised at how little I still knew of Erlang, and found myself reaching for the documentation for really basic stuff. I obviously need to do this kind of thing more often. I had to abort an early attempt at using gen_fsm once i realized it was completely unsuitable for what I was trying to do.

-module(json).

-export([parse/1]).

parse(String) ->
    parse_value(String).

parse_value([34 | _] = Rest) -> % 34 = $", damn emacs
    parse_string(Rest);
parse_value([H | _] = String)
  when H == $-; H >= $0, H =< $9 ->
    parse_number(String);
parse_value([${ | Rest]) ->
    parse_object(Rest);
parse_value([$[ | Rest]) ->
    parse_array(Rest);
parse_value("true" ++ Rest) ->
    {true, Rest};
parse_value("false" ++ Rest) ->
    {false, Rest};
parse_value("null" ++ Rest) ->
    {null, Rest}.

parse_string([34 | Rest]) ->
    parse_string(Rest, []).

parse_string([34 | Rest], Acc) ->
    {lists:reverse(Acc), Rest};
parse_string([$\\, $b | Rest], Acc) ->
    parse_string(Rest, [$\b | Acc]);
parse_string([$\\, $f | Rest], Acc) ->
    parse_string(Rest, [$\f | Acc]);
parse_string([$\\, $n | Rest], Acc) ->
    parse_string(Rest, [$\n | Acc]);
parse_string([$\\, $r | Rest], Acc) ->
    parse_string(Rest, [$\r | Acc]);
parse_string([$\\, $t | Rest], Acc) ->
    parse_string(Rest, [$\t | Acc]);
parse_string([$\\, $u, H1, H2, H3, H4 | Rest], Acc)
   when ((H1 >= $0 andalso H1 =< $9)
         orelse (H1 >= $a andalso H1 =< $f)
         orelse (H1 >= $A andalso H1 =< $F))
andalso ((H2 >= $0 andalso H2 =< $9)
         orelse (H2 >= $a andalso H2 =< $f)
         orelse (H2 >= $A andalso H2 =< $F))
andalso ((H3 >= $0 andalso H3 =< $9)
         orelse (H3 >= $a andalso H3 =< $f)
         orelse (H3 >= $A andalso H3 =< $F))
andalso ((H4 >= $0 andalso H4 =< $9)
         orelse (H4 >= $a andalso H4 =< $f)
         orelse (H4 >= $A andalso H4 =< $F)) ->
    parse_string(Rest,
                 [hex_to_int(H4), hex_to_int(H3), hex_to_int(H2), hex_to_int(H1) | Acc]);
parse_string([$\\, Next | Rest], Acc) ->
    parse_string(Rest, [Next | Acc]);
parse_string([H | Rest], Acc) ->
    parse_string(Rest, [H | Acc]).

parse_number([Sign | Rest]) when Sign == $- ->
    {V, R} = parse_number(Rest),
    {-1 * V, R};
parse_number([H | _] = String) when H >= $0, H =< $9 ->
    parse_int(String, 0).

parse_int([], Acc) ->
    {Acc, []};
parse_int([Sep | _] = Rest, Acc) when Sep == $\ ; Sep == $,; Sep == $]; Sep == $} ->
    {Acc, Rest};
parse_int([H | String], Acc) when H == $. ->
    parse_frac(String, Acc);
parse_int([H | String], Acc) when H == $e; H == $E ->
    parse_exponent(String, Acc);
parse_int([H | String], Acc) when H >= $0, H =< $9 ->
    parse_int(String, Acc * 10 + H - $0).

parse_frac(String, OldAcc) ->
    parse_frac(String, OldAcc, 0).

parse_frac([], Int, Acc) ->
    {Int / math:pow(10, Acc), []};
parse_frac([Sep | _] = Rest, Int, Acc) when Sep == $\ ; Sep == $,; Sep == $]; Sep == $} ->
    {Int / math:pow(10, Acc), Rest};
parse_frac([H | String], Int, Acc) when H == $e; H == $E ->
    {V, _} = parse_frac([], Int, Acc),
    parse_exponent(String, V);
parse_frac([H | String], Int, Acc) when H >= $0; H =< $9 ->
    parse_frac(String, Int * 10 + H - $0, Acc + 1).

parse_exponent([Sign | String], K) when Sign == $- ->
    parse_exponent_digits(String, K * -1);
parse_exponent([Sign | String], K) when Sign == $+ ->
    parse_exponent_digits(String, K);
parse_exponent(String, K) ->
    parse_exponent_digits(String, K).

parse_exponent_digits(String, K) ->
    parse_exponent_digits(String, K, 0).

parse_exponent_digits([], K, Acc) ->
    {K * math:pow(10, Acc), []};
parse_exponent_digits([Sep | _] = Rest, K, Acc) when Sep == $\ ; Sep == $,; Sep == $]; Sep == $} ->
    {K * math:pow(10, Acc), Rest};
parse_exponent_digits([H | Rest], K, Acc) when H >= $0; H =< $9 ->
    parse_exponent_digits(Rest, K, Acc * 10 + H - $0).

parse_object(Rest) ->
    parse_object(Rest, dict:new()).

parse_object(String, Acc) ->
    {Key, R1} = parse_string(String),
    [$: | R2] = R1,
    {Val, R3} = parse_value(R2),
    case R3 of
        [$} | R4] ->
            {dict:append(Key, Val, Acc), R4};
        [$, | R4] ->
            parse_object(R4, dict:append(Key, Val, Acc));
        _ -> {error, syntax_error, parse_object, String, Acc}
    end.
    
parse_array(Rest) ->
    parse_array(Rest, []).

parse_array(String, Acc) ->
    {Val, R1} = parse_value(String),
    case R1 of
        [$] | R2] ->
            {lists:reverse(Acc), R2};
        [$, | R2] ->
            parse_array(R2, [Val | Acc]);
        _ -> {error, syntax_error, parse_array, String, Acc}
    end.
    
hex_to_int(C) when C >= $0 andalso C =< $9 ->
    C - $0;
hex_to_int(C) when C >= $a andalso C =< $f ->
    C - $a + 10;
hex_to_int(C) when C >= $A andalso C =< $F ->
    C - $A + 10.

ABCs for My Daughter

A is for Atom
B is for Binary
C is for Choice
D is for Diameter
E is for Entropy
F is for Fraenkel
G is for Gravity
H is for Heisenberg
I is for Impedence
J is for Joules
K is for Konstant
L is for Logic
M is for Mass
N is for Neutron
O is for Oscillate
P is for Particle
Q is for Quark
R is for Resistance
S is for Seconds
T is for Time
U is for Universal
V is for Vector
W is for WIMP
X is for Xeon
Y is for Yttrium
Z is for Zermelo

Attaching Behavior in JS

There are plenty of libraries out there for attaching scripted behavior to HTML elements. Unfortunately, we're using Prototype, which lacks support for this. While we could integrate one of these libraries, in theory, I believe it's not worth the side-effects: possible destabilization due to conflicts, learning a new library, and additional download time for our clients.

Instead, I wrote one up myself. It doesn't have to do very much: scan the DOM when the page loads and monitor the DOM for dynamic updates. I've chosen to do strict class-based behavior. To enable behavior on an element, you must do three things:

  1. On the JavaScript side, you code up the actual behavior (for instance, submitting an Ajax request for a link, instead of following it normally).
  2. On the HTML side of things, you have to add a class to your element so our DOM watcher can know where to attach it. For instance, you would specify a class of "async_link" on the A tags where you want an Ajax request submitted.
  3. Finally, you have to inform your DOM watcher that a given CSS class has a given JS behavior. With the module I've written, this is as simple as:
    DOMWatcher.EventHandlers.async_link = AsyncLink.Watcher;

Well, that's the theory anyway. On to the code.

First, let's create a module to contain all this code, along with the public API methods:

var DOMWatcher = function () {
  return {
    EventHandlers: {},

    scanDocument: function () {
      attachBehavior();
    },

    addWatcher: function (klass, watcher) {
      DOMWatcher.EventHandlers[klass] = watcher;
      if (document.body) {
        attachBehavior();
      }
    },

    removeWatcher: function (klass, watcher) {
      delete DOMWatcher.EventHandlers[klass];
    }
  };
}();

Simple enough. A method to scan the document and attach behavior, and a couple of accessors to add and remove behavior after the document has been loaded.

To define the element behaviors themselves, I've gone with a simple map of CSS classes to behavior objects, which is stored in DOMWatcher.EventHandlers. The format of this object is straightforward: a behavior object may contain a setup method, which is called with a single argument of the element to be initialized, and methods starting with 'on' which specify the event on this element to attach behavior.

Here's a simple example:

var AlertLink = {
  setup: function () {
    this._alert = 'Hello World!';
  },

  onclick: function (event) {
    alert(this._alert);
  }
};
DOMWatcher.EventHandlers.alert_link = AlertLink;

During execution of behavior methods, I want the this object to be set to the element for which the behavior applies. It's not terribly important - we could just pass it in, but I like this way better.

So now that we know what we want the code to look like, lets have a go at the attachBehavior function which makes all this possible:

var DOMWatcher = function () {
  var ATTRIBUTE_BOUND = '_DOMWatcher_bound';

  function attachBehavior(target) {
    var elements, elt, klass, i, length, handler, method;

    target = target || document.body;
    elements = target.getElementsByTagName('*');

    for (i = 0, length = elements.length; i < length; i++) {
      elt = $(elements[i]);
      for (klass in DOMWatcher.EventHandlers) {
        if (DOMWatcher.EventHandlers.hasOwnProperty(klass) &&
            !elt[ATTRIBUTE_BOUND] && elt.hasClassName(klass)) {
          elt[ATTRIBUTE_BOUND] = true;

          handler = DOMWatcher.EventHandlers[klass];
          if (handler.setup) {
            handler.setup.call(elt);
          }

          for (method in handler) {
            if (method.substring(0, 2) == 'on') {
              Event.observe(elt, method.substring(2, method.length),
                            handler[method].bindAsEventListener(elt));
            }
          }
        }
      }
    }
  }

  ...

}();

Let's break that down: first we grab the node from which to begin scanning, defaulting to document.body, if it wasn't passed in, and grab all its children:

target = target || document.body;
elements = target.getElementsByTagName('*');
  

Once we have all the child elements, we can iterate over them, looking for classes with behavior defined:

for (i = 0, length = elements.length; i < length; i++) {
  elt = $(elements[i]);
  for (klass in DOMWatcher.EventHandlers) {
    if (DOMWatcher.EventHandlers.hasOwnProperty(klass) &&
        !elt[ATTRIBUTE_BOUND] && elt.hasClassName(klass)) {
      elt[ATTRIBUTE_BOUND] = true;

      ...
    }
  }
}
  
Note that we're using elt[ATTRIBUTE_BOUND] in order to store whether or not we've already attached behavior to this element, as an optimization to prevent reattaching behavior.

With the element stored in our temporary elt variable and a behavior class in klass, we can now run the setup routine and attach event handlers from DOMWatcher.EventHandlers:

...

handler = DOMWatcher.EventHandlers[klass];
if (handler.setup) {
  handler.setup.call(elt);
}

for (method in handler) {
  if (method.substring(0, 2) == 'on') {
    Event.observe(elt, method.substring(2, method.length),
                  handler[method].bindAsEventListener(elt));
  }
}

...
  

Now let's set up the scan to happen when the document is finished loading, so our behavior will get attached when the page is ready:

Event.observe(window, 'load', DOMWatcher.scanDocument);
  

And we're almost done. We also need to handle the case of Ajax updates to the DOM. Unfortunately, there's no good cross-browser way to do this, as only a few support DOMNodeInserted. Notably, IE does not, and has no equivalent that we could use in its stead. Also, Prototype has no facilities to support this, and in fact makes it quite painful to try and do it cleanly.

Luckily, JavaScript is incredibly dynamic, and has no real security model, so what we can do instead of events is scan the document when certain Prototype functions are called. Since we use Prototype exclusively, this is only a matter of figuring out which calls update the DOM, and wrapping them to add a call to DOMWatcher.scanDocument:

(function () {
  var oldReplace = Element.Methods.replace;
  var oldUpdate = Element.Methods.update;
  var oldInsertion = Abstract.Insertion.prototype.initialize;

  Element.Methods.replace = function (element, html) {
    oldReplace(element, html);
    DOMWatcher.scanDocument();
  };
  Element.replace = Element.Methods.replace;

  Element.Methods.update = function (element, html) {
    oldUpdate(element, html);
    DOMWatcher.scanDocument();
  };
  Element.update = Element.Methods.update;

  Abstract.Insertion.prototype.initialize = function (element, content) {
    oldInsertion.call(this, element, content);
    DOMWatcher.scanDocument();
  };
})();
  

It's worth noting that I used three temporary variables, because IE had issues when I tried to use a single variable inside an iterative function. Oh well. People would probably find this version easier to read anyway.

And that's all there is to it. Really. With this foundation in place, we now have the ability to add behaviors to elements fairly cleanly, which encourages a nice separation of code from HTML and from other code by use of the module pattern.

Coming up: using DOMWatcher to automatically enable and disable links and forms.