create blog

go home go home
  1. about
  2. code
  3. wiki
  4. blog
December 29th, 2009 by Alex Iskander

For the Love of a Deity, Please Prove Me Wrong: IE Alpha

Please no. Just, no. I mean, honestly, how far can IE sink? I really hope I am wrong here, but…

If you check my test case, you may notice that it looks different in Internet Explorer than it does in sane browsers. What is the culprit?

Simple: filter:alpha.

Supposedly, making elements somewhat transparent is possible in everyone’s favorite browser. Well, it is, but you have to use Microsoft’s proprietary “filter” CSS property.

Okay, fine, at least it works. Except in one case, from what I can tell: it will not apply transparency to absolutely positioned child elements of the element with the “filter” property set.

Why is this an issue? Let’s take the simple example of a button control (specifically, SproutCore’s SC.Button, but it should apply to other button controls as well): you have a left part (with nice rounded corners), a center part (that can be stretched), and a right part (again with the rounded corners). One part—for instance, the right part—is either positioned relatively or is the parent element itself, and simply has a background-position:right. The left and center parts, however, are positioned absolutely; something like left: 10; right: 10 for the center part; right:0; width:10; for the right part (I just made these numbers up! They aren’t real!)

So, what happens if you try to fade the button out in Internet Explorer? Well, it looks really odd. In the above example, the right part fades out, but the left and center do not. They just stay as they were.

There is only one workaround that I know of: seting filter:alpha on every element. There are a few problems with this:

  • Performance. Each setting of “opacity” will have to recursively loop through all child elements.
  • Performance * Animation fps. Yep, animating opacity in IE is plain screwed.
  • Pure messiness.
  • Long-term issues: what about when (if) Microsoft fixes the issue?

Don’t you just love Internet Explorer?

I keep thinking I must be wrong, and there must be some nice little workaround, CSS hack, or even the simple explanation of me just being plain wrong (I actually hope I am).

Anyone know?

December 21st, 2009 by Alex Iskander

SproutCore Animation: SC.Animatable

In real life, things don’t just suddenly disappear from one place and appear in another. This isn’t Harry Potter1. We can’t apparate.

But chances are, you know that, and don’t need to be convinced of the wonder of animation. So, instead, I will tell you about the beginnings of SproutCore’s support for animation.

SproutCore’s animation support currently takes the form of a mixin for views: SC.Animatable. Here are some of the features:

  • Relatively fast. It can animate 1000 or so views with reasonable performance on a fast machine. Oddly, the biggest performance hurdle may now be the rendering engine (unless you are on IE—the slow script speed will kill you first).
  • Uses CSS transitions where possible. Oddly, CSS transitions do not appear to be significantly faster2 than JavaScript transitions (again, indicating the rendering engine could now be the bottleneck).
  • Support for Layout. This almost goes without saying, as what animation framework would be worth anything if it didn’t allow you to animate the position of views?
  • Support for Opacity. So you can fade things in and out.
  • Support for display:none. You can add transitions to the display property, and they will simply be ignored (display gets applied immediately) except in the special case of display:none, which will only apply after the specified duration. See display:none notes
  • Support for Timing Curves. You can specify curves to adjust the speed of the animation, and have them work in both JavaScript transitions and CSS transitions, or optionally, CSS transitions only.

Animating with SC.Animatable

It is quite simple. Here are the steps:

  • Add “sproutcore/animation” to the required frameworks array in your Buildfile (in quotes and all).
  • Mix in SC.Animatable to your view.
  • Add transitions.
  • Change layout, opacity, or display.

So, how about some code? First, let’s take a look at a Buildfile:

# The Contacts application Buildfile
config :contacts, :required => [:sproutcore, :"sproutcore/animation", :forms, :pomona]

Now, how about a view?

myView: SC.View.design(SC.Animatable, { // mix it in
  transitions: {
    // and add transitions
    left: .25,
    top: {duration: .25},
    width: { duration: .25, timing: SC.Animatable.TRANSITION_EASE_IN_OUT }, // with timing curve
    height: { duration: .5, timing: [0, 0, 0.58, 1.0] }, // with custom timing curve
    opacity: { duration: .5, timing: SC.Animatable.TRANSITION_CSS_EASE_IN_OUT }, // CSS-transition-only timing function (JavaScript gets linear)
    display: .75 // a bit longer than opacity 
  }
})

And finally, to animate!

myView.adjust("left", 250);
myView.set("layout", {left: 100, top: 300, width: 250, height: 340});
 
// style manipulation: a feature of SC.Animatable
myView.adjust("opacity", .5);
myView.set("style", {opacity: .7});
myView.adjust("display", "none"); // applies after .75 seconds
myView.adjust("display", "block"); // applies immediately
 
// disable animation temporarily to change something directly
myView.disableAnimation();
myView.adjust("opacity", 0).updateStyle(); // makes invisible and applies immediately.
myView.enableAnimation();
myView.adjust("opacity", 1); // fades in to visibility (applying lazily).

Pretty simple!

display:none notes

When animating the display: none property, you should add a bit of extra time to its transition.

If everything was animated using JavaScript, there would be no issue. However, because SC.Animatable takes advantage of CSS transitions where possible, and CSS transitions don’t necessarily begin immediately, if you don’t add extra time to display’s transition it could set display:none before the other transitions end (in effect, cutting them short). In the most usual case—an opacity transition—the view will start to fade out and then suddenly disappear. Again, the easiest way to fix this is by simply adding a bit of time to the transition for the display property.

The Problem with Callbacks

Currently, SC.Animatable does not have callbacks for animation completion. In fact, unless the view is being animated using JavaScript (non-WebKit browsers and Firefox earlier than 3.6, I believe), it is even impossible to tell if a view is animating.

For JavaScript-based transitions, this should not be a terribly difficult feature to add in general; there is a question of, since animations are started and stopped automatically instead of explicitly by the developer, how those callbacks would be set: should it be one per property? One per the whole view?

For CSS transitions, however, this is trickier. There is an event fired in WebKit’s implementation, but I am unable to find any documentation on Mozilla’s support for it (or, for that matter, lack thereof).

Even if support was present, it may or may not be tricky to reconcile that with the actual animation library: what if one transition ends, but a new one starts immediately after? Will the event fire after the new one begins, tricking others into thinking it has already fired? It may be more reliable to “guesstimate,” and just set a timer for a callback to go off somewhere shortly after the target time (much like the way the “display” transition is implemented).

Demo

It is not “officially” released by any means—it still needs fixes, including at least one animation-related one—but a fancy demo of the animation (used in FormView, another project I am working on) can be found here.

The code is all online too at GitHub. I am slowly making it into a full sample app for SproutCore that demonstrates animation, FormView, and Comet—and hopefully multiple back-ends (I’m working on a wacky Python one right now, and I’d like to make a node.js-based one eventually, too).


  1. I had to slip in some HP reference.3 

  2. It is tricky to tell, because I cannot measure the FPS of transitions objectively. Actually, the JavaScript transitions looked faster than the CSS transitions. 

  3. I love footnotes too much. In some papers, I have filled almost half the page with footnotes. The thing about footnotes is that they allow you to add extra information (sometimes a lot of extra information) while not badly interrupting the flow of the original piece. 

December 15th, 2009 by Alex Iskander

Making SproutCore Objects Show in Chromium’s Heap Profiler

It’s a hack. If Chromium+v8 would just support displayName, it could all be nice and clean and part of SproutCore (please go tell the Chromium folks how helpful this would be).

As it is, this hack could have some SEVERE side-effects, but chances are, if you are trying to debug a memory leak, you won’t care about these side-effects because everything else will be driving you MAD (and, you’ll probably be able to find these side-effects much more easily than the leak itself).

It is very simple; here is how to do it for ListItemView:

SC.mixin(SC.ListItemView, { create: function() { return new SC._ListItemView(this, arguments); } });
 
SC._ListItemView = function(base_type, args){
  base_type.call(this, args);
};
 
// for extra safety (should get around most potential side-effects):
SC.mixin(SC._ListItemView, SC.ListItemView);
 
SC._ListItemView.prototype = SC.ListItemView.prototype;

Now, ListItemViews will show up as SC._ListItemView in the heap profile. Hooray!

P.S. This revealed for me that the objects leaking were not SC.ListItemViews. I still have no idea what is leaking, and am giving up for now—but at least I’ll have better tools when I come back to it. :)

December 11th, 2009 by Alex Iskander

SproutCore, Todos, Django, and Comet in < 100 Lines of Code

This is a continuation of the Django Todos Back-End Tutorial that adds Comet using Roots.

Warning: This is not tested by anyone other than me at the moment, and might prove somewhat bumpy. Feedback is very welcome!

Here is a high-level introduction of how Roots works is available here.

Very little needs to be done to add Comet. There are three main steps on the server side:

  1. Get Roots and Cornelius.
  2. Add views to allow clients to subscribe/connect to events.
  3. Trigger events.

On the client side, there are also three major steps:

  1. Get+set up Pomona.
  2. Subscribe to events.
  3. Receive events.

First Step

You will need at least three terminal windows—one for each server. You might as well open them first.

You will have three directories to work out of:

  • Roots (or Dobby)—not much to do here :)
  • SproutCore Project
  • Django Project

Tip: if you want to be able to open only one TextMate window (or whatever IDE you use), you can place the Django project (and, even, Roots) in a subdirectory of your SproutCore project.

Server-Side

Getting Roots and Cornelius

First, let’s get Roots. In the Roots terminal, navigate to the folder you’d like to keep it, and:

$ git clone git://github.com/ialexi/dobby.git

And now, you can start it (assuming you have the prerequisites):

$ cd dobby
$ python dobby.py
Instating Dolores High Inquisitor of Hogwarts

There may be some deprecation warnings due to issues with Twisted, but they don’t cause problems. (Roots should be ported to node.js soon, and node.js doesn’t have these issues).

Now, get Cornelius. In the Django terminal, navigate to your Django project directory. Then run:

$ git clone git://github.com/ialexi/cornelius.git

Next, you need to add Cornelius to your Django project as an application (making it really easy to import). To do this, edit settings.py and add “cornelius” in the INSTALLED_APPS setting:

	'django.contrib.auth',
	'django.contrib.contenttypes',
	'django.contrib.sessions',
	'django.contrib.sites',
	'todos',
	'cornelius' # <- SEE! :D

Making Views to Make Connections

We can’t trust the client. As such, we do not allow the client to connect itself to any path it wants. Instead, it has to go through our Django web app. Ironically, since we’re just doing a simple application, we are in fact, going to allow the client to connect to whatever it wants (I’ll show how to change this, though).

First, you need an updated urls.py:

from django.conf.urls.defaults import *
 
urlpatterns = patterns('',
	# You don't have to do it this way, but in this example, we match
	# optional ending slashes.
	(r'^tasks/?$', "todos.views.tasks"),
	(r'^task/(?P<taskid>[0-9]+)$', "todos.views.task"),
 
	# See here:
	(r'^tasks/connect/(?P<uid>[^\s]+)$', "todos.views.connect"),
	(r'^tasks/disconnect/(?P<uid>[^\s]+)$', "todos.views.disconnect")
)

This makes tasks/connect/(CLIENT_ID) call our “connect” view, and tasks/disconnect/(CLIENT_ID) call our “disconnect” view.

Now, for the views themselves:

# Import cornelius's Dudley
from cornelius import dudley
 
# Connect
def connect(request, uid):
	paths = json.loads(request.raw_post_data)  # Pomona sends the list of paths to connect to in a JSON array.
	# note: paths is just a plain list of strings; you can loop through them and filter for security.
	dudley.connect(uid, paths)  # Dudley takes a client id and a list of paths. That's it.
 
def disconnect(request, uid):
	paths = json.loads(request.raw_post_data)
	# note: ditto regarding paths being a list of strings.
	dudley.connect(uid, paths)

Triggering Events

Django has nice post-save and post-delete events we can use to trigger events (“updates” in Roots-speak).

Here’s how we use them:

# Comet alerters
from django.db.models.signals import post_save, post_delete
def task_saved(sender, **kwargs):
	try:
		instance = kwargs["instance"]
		dudley.update("tasks", json.dumps(task_to_raw(instance)))
	except:
		pass
 
def task_destroyed(sender, **kwargs):
	try:
		instance = kwargs["instance"]
		data = task_to_raw(instance)
		data["DELETE"] = True
		dudley.update("tasks", json.dumps(data))
	except:
		pass
post_save.connect(task_saved, sender=Task)
post_delete.connect(task_destroyed, sender=Task)

Note how we once again use task_to_raw.

And now, the server-side is done!

Of course, start it with:

$ python manage.py runserver

Client Side

Getting and Setting Up Pomona

In your SproutCore terminal, navigate to your SproutCore project. Then, get Pomona and put it in the “frameworks” folder:

$ git clone git://github.com/ialexi/pomona.git frameworks/pomona

Next, just like you add the project in Django, you need to add the framework to your SproutCore project. To accomplish this, you edit the “config” line of “Buildfile” to look like this:

config :all, :required => [:sproutcore, :pomona]

You changed it from the solitary :sproutcore, to the array [:sproutcore, :pomona].

Next, you need to proxy Roots’ long-polling server. Just add this line at the end of Buildfile after the other two proxy lines:

proxy "/comet/", :to => "localhost:8008", :url=>"/"

Subscribing to Events

There are two things that have to happen to subscribe to events: create and configure an instance of the long-poller, and call connect().

The easiest place to do this is in an init function in our data source. Just place this code in the DataSource definition (preferably at the top).

  init: function(){
    // DataSource has no init right now, but what if it adds one?
    // so, call super function first.
    sc_super(); 
 
    // needs proxy /comet/ to dobby
    this.firenze = Pomona.Firenze.create({    // Firenze is the name of the long-poll system.
      connectUrl: "/tasks/connect/%@",        // %@ is replaced with the client id
      disconnectUrl: "/tasks/disconnect/%@"
    });
 
    // tell it to call this.taskReceived when a message is received on path "tasks"
    this.firenze.connect("tasks", this, "taskReceived");
  },

The connectUrl/disconnectUrl parameters tell Pomona what URLs to send connect and disconnect requests to. All it does is send a JSON array of path (event) names in a JSON array). It will automatically re-send these messages if the connection with the long-polling server is interrupted and a new connection (with a new id) is created.

All that’s left now is to receive messages!

Receiving Messages

Receiving messages is simple: we just implement the “taskReceived” function we told it about earlier.

  taskReceived: function(path, message) {
    if (message.trim() === "") return;  // the first time, we receive "" to confirm connection
    var data = JSON.parse(message);   // we sent a JSON-encoded message from Python
 
    if (data.DELETE) {
      // We set DELETE if the record needed deleting
      Todos.store.pushDestroy(Todos.Task, data.guid);
    } else {
      // otherwise, we should just re-load that record.
      Todos.store.loadRecords(Todos.Task, [data]);
    } 
  },

That’s All!

Start sc-server, open two browsers, both pointing at http://localhost:4020/todos, and hopefully, you’ll have Comet.

There may be some bumps—if anyone is willing to test and offer feedback, please do so!

Good luck!

December 10th, 2009 by Alex Iskander

SproutCore Animation Mixin Timing Curves (and BUG FIXES!!!)

First, the comparatively boring but very good news: several bugs which made CSS transitions not always work too well have been fixed! There were a lot of little errors—including a really odd one in Safari that caused transitions to be ignored if they were initiated too soon after a style.display change—that were causing some rather annoying issues, and they have now been resolved.

Now, the comparatively exciting: The SproutCore Animation mixin now supports timing curves!

There are two ways to set the timing curve to use: globally and locally. The global timing curve (null by default) is used if there is no local timing curve—in essence, the global timing curve is the default timing curve (in fact, it is named defaultTimingFunction).

aView: SC.LabelView.design(Animate.Animatable, {
    transitions: {
        left: .25,
        top: {duration: .25},
        width: { duration: .25, timing: Animate.TIMING_EASE_IN_OUT }, // with timing curve
        height: { duration: .5, timing: [0, 0, 0.58, 1.0] } // with custom timing curve
    }
})

Timing curves are cubic beziér curves, as used in CSS Transitions. They can be used as CSS-only, or, if you are willing to take a bit of a JavaScript performance hit, in both CSS and JavaScript. In fact, the JavaScript variety’s code is based on WebKit’s actual code for handling cubic beziér curves.

The pre-defined timing curves are identical to the CSS timing functions:

// CSS-only
TRANSITION_NONE: "linear",
TRANSITION_CSS_EASE: "ease",
TRANSITION_CSS_EASE_IN: "ease-in",
TRANSITION_CSS_EASE_OUT: "ease-out",
TRANSITION_CSS_EASE_OUT: "ease-in-out",
 
// JavaScript-enabled
TRANSITION_EASE: [0.25, 0.1, 0.25, 1.0],
TRANSITION_LINEAR: [0.0, 0.0, 1.0, 1.0],
TRANSITION_EASE_IN: [0.42, 0.0, 1.0, 1.0],
TRANSITION_EASE_OUT: [0, 0, 0.58, 1.0],
TRANSITION_EASE_IN_OUT: [0.42, 0, 0.58, 1.0]

The implementation is somewhat simple; if the timing function is a string, it is set directly into the transition-timing-function CSS property—and JavaScript animations ignore it (and thus work linearly). Otherwise, a cubic-bezier() is inserted into the CSS, and the JavaScript implementation is set up.

The calculations for the cubic beziér curves involve loops, and must be calculated every frame—they have a significant potential to slow things down (it may be wise to have a pre-calculated option as well at some point to help alleviate this). As such, you may not want to use the JavaScript variety unless you are animating relatively few elements.

I don’t know if anyone is using the Animate mixin (aside from me) but if anyone is, I hope they enjoy this new feature!

December 7th, 2009 by Alex Iskander

Roots Deliver Nutrients

Push is complex. I tried to figure it out with ActiveMQ, Orbited, and friends awhile back, but it just seemed too complicated. It made me feel like I was not very smart—obviously, some people understand this thing, but I don’t. I am a bit too prideful, and do not like feeling unintelligent.

But I need messaging.

I don’t care about queuing or persistence. For web applications (what I work on) messages should be delivered as quickly as possible. Any “queues” can be in-memory, and any message should not remain in a queue for more than a minute—if the client was disconnected for any duration, it would likely be better off re-downloading that receiving incremental updates.

So, whatever these systems do, they seem too complicated (I could be wrong—as I said, I have trouble understanding them).

My requirements:

  • Normal Authentication. Clients should go through the “normal” web app to subscribe to events.
  • Easy. It should be very simple and easy to understand.
  • Quick. I should be able to add Comet to an app in ten to fifteen minutes, maximum.

I found out that it is not only possible to write messaging servers on one’s own—it is relatively easy. So I wrote one.

I’ll stop the backstory here, though there is plenty more—tell me if you want any of the boring details about Dolores and the rest.

Roots

Roots—codenamed Dobby after the Harry Potter character—is a messaging server that has a built-in long-polling server (among several other things).

Roots is made up of many small message-passing pieces. They plug together, just like Lego pieces. Each piece is simple, and the connection between the pieces are even simpler: a single function, called “update.”

If you are interested, I’ll go over that more thoroughly in “Implementation.”

How Roots is Used

Above All, Roots is Easy.

It takes me about fifteen minutes to use Roots to add push to a SproutCore application (starting with a fresh clone of Roots—which, by the way, does not need any configuration for testing). It should only take me five minutes, but I am often a bit slow of a coder.

There is a brief semi-tutorial on GitHub. The following is based on that tutorial, but has some extra background information.

So, a bird’s-eye view: unless you implement the server-side in Roots itself, you will have three components in any application: back-end (Rails, Django, etc.), front-end (SproutCore), and Roots.

  • Client—such as Pomona, the SproutCore framework for Roots) connects to a Roots server.
  • Roots sends the client (Pomona) an id.
  • The client calls predefined URL to connect to events.
    • The URLs are part of the back-end (Django, etc.)
    • The ID is sent with these requests.
    • Clients (Pomona) usually will keep track of what server-side events you are listening to and can reconnect automatically if the Dobby connection is interrupted—you just provide the client with the URLs and the events to listen to.
  • Back-end tells Roots to connect client to events—and can perform any authorization it wishes.
  • Back-end sends updates to Roots.
  • Client receives notifications—everyone’s Happy!!!

What You Do (for SproutCore)

You don’t have to do much:

  1. Add Pomona to your SproutCore project.
  2. Add a Roots connector to your server-side project:
    • Cornelius for Python
    • Others as I add them (I plan Ruby and PHP)
    • Implement your own (the Python version of the better protocol—Dudley—is 45 lines counting whitespace and comments).
  3. “Update” Roots (call update(path, message) from your back-end—Django has handy model post-save signals you can use).
  4. Add some URLs to your back-end that connect clients.
    • URLs accept client ID in them (/my/connect/AN_ID_HERE or /my/connect.src?id=AN_ID_HERE)
    • URLs should accept POST of a simple JSON array of path/event names.
    • For each path/event/whatever you want to call it, call connect(id, path) on your Roots connector.
    • Initialize Pomona and connect to Roots in your SproutCore Data Source.
    • Accept incoming data!

A more detailed tutorial is here on GitHub with the rest of Dobby (Roots).

Open Question: Would anyone like a tutorial on setting up a Django back-end for the SproutCore Todos tutorial, with an extra step of adding Comet at the end? Done!

Implementation

Roots/Dobby is currently written in Python. I am working on a rewrite in node.js, because node.js is super cool—and, secondarily, it means that some of the same code used in the server (for instance, the message dispatch code) could be used on the client.

Roots has many small parts that hook together in a very simple way. At Roots’s core is Thestral, a simple interface that requires implementors to do two things: have an id and implement a single method: update(sender, path, message)—where sender is an originator, path is an event name, and message is some data to send.

Here are some of the components:

  • Dolores: This is the main controller. It assigns IDs to all Thestral instances. It itself is a Thestral instance, and sends its updates to “delegates”.
  • Pig: An “Owl,” or, really, a dispatcher; it knows who receives what message. It is often one of Dolores’s delegates. Specially-formed messages, tell it to connect certain Thestral ids with certain events—for instance, the event “::connect” with message “12345->my/data” would connect Thestral “12345″ to “my/data”.
  • Imperio. A somewhat pathetic text-based protocol, with accompanying receiver server (a bit like Dudley, which should be used instead). In addition to reading from a server, Imperio supports writing to anything with a write() method, and as such, is used for logging as a delegate of Dolores.
  • Dudley. Dudley is not a delegate of Dolores. Rather, Dolores can be its “delegate” (or, in this case, “receiver”). Dudley is an HTTP server, and receives messages over HTTP and funnels them to a receivers (Thestral implementation), and Dolores is its default receiver.
  • Firenze. Firenze, like Dudley, is an HTTP server; but instead of being a receiving server, it is a long-polling push server. It is not usually Dolores’s delegate—you don’t want every client to get every message. Instead, Firenze merely registers itself with Dolores to get an ID, and lets others register it (for instance, a client could send Dudley a message, which, through Dolores, would be received by Pig to make the connection).

Above all, it is simple. The longest of these pieces is Firenze, at 280 lines of code (50 of which are intro comments I used to explain it to myself and spec it while planning).

That’s All!

I hope you find this helpful. I am excited about porting Roots to node.js; progress is somewhat slow, as I am quite busy (I am a student, and finals for all four classes tomorrow!)

What I am most looking forward to is how Pig (the dispatcher) could use the same code in both the client (Pomona) and the server—the routing is quite similar; in one case, you want to route to handlers/callbacks, in the other, to update functions on Thestral instances—pretty similar; even identical.

I am also looking forward to experimenting with two-way push, where all data is transferred through push—completely eradicating the expectation of a response to a request, and providing only a single receive/send code path on both client and server.

Anyway, I think this is all super cool. :)

Thanks to Endash for the nice title. :) Roots (called Dobby in development) is available on GitHub.

P.S. I like the name Dobby, but Roots is better P.R.

October 21st, 2009 by Alex Iskander

JavaScript Animation Benchmarks

I’ve been working on a mixin to add animation to SproutCore views.

The current version only works for layout properties, and does not yet work for centerX and centerY properties (they used to work, but some of the performance optimizations have made it slightly more tricky—I’ll be adding it back soon, though).

I decided to see how fast the code was in different browsers. The tests were done using a test application which generated a specified number of views, and then, once per second, updated a “frames per second” display. The measuring is somewhat subjective, as I have to deduce, based on consistency (or lack thereof) in the numbers, what the frame rate actually is. For the most part, they were pretty consistent, but the WebKit browsers at really low numbers of views (and really high frame rates) could be quite inconsistent at times.

I ran the tests on two separate machines:

  • Mac OS X Snow Leopard on MacBook Pro 15″ Core 2 Duo 2.33Gz w/2GB RAM. Lots of open programs, including iTunes. Not as scientific as would be optimal, but it is my work machine.
  • Windows XP on Pentium 4 3.20GHz w/2GB RAM. Only the browser was open.

Browsers tested (note that my Firefox was OLD):

  • Safari 4.0.3 for Mac
  • Firefox 3.5.3 for Mac
  • Chromium 4.0.223.3 (29380) for Mac
  • Internet Explorer 8
  • Firefox 3.0.1 for Windows (oops. Should have upgraded first. Remind me to update numbers on Friday)
  • Safari 4.0.3 for Windows
  • Chrome 3.0.195.27 for Windows

Here is the data:

Data collected during testing of the different browsers

Data collected during testing of the different browsers

That’s boring. Where are the pictures?

All Browsers

All Browsers

Even here, you can tell that Chrome and Chromium are the best performers for small numbers of views. However, for larger numbers of views, Safari on Mac was a very clear winner, running at 12 frames per second for 2000 LabelViews..

Predictably, Internet Explorer was slowest. I didn’t bother to run all the tests for it.

Windows Browsers

Windows Browsers

This chart shows only the Windows browsers. Again, you can tell IE is very slow. Chrome is very very fast. Safari is pretty good. My out-of-date Firefox is not always that much faster than IE; it will be interesting to see how Firefox 3.5 fares.

Notice the dip in performance for Safari at around 300? It briefly does worse than Firefox. It quickly levels off, though, and is second only to Chrome.

Mac Browsers

Mac Browsers

And, of course, the best for last. Note how we see the same dip in performance for Safari—though it does not dip below Firefox; it would have dipped below Chromium, were it not already below it. Again, though, it leveled out faster than Chromium.

I always wanted to do a performance chart, but now that I have… it’s a lot of work (about 57 or so data points there… each measured separately).

Question Is the difference between Safari and Chromium completely caused by Google’s V8 JavaScript engine, or are there a few other differences?

October 17th, 2009 by Alex Iskander

Sprouting—Automated Spriting for SproutCore

Well. Spriting. Do you know what it is? While I’ve included a very brief summary, you may want to just skip that part if you already know about it, or find a better description of the technique. Also, while this article is specifically aimed at SproutCore, the concepts (and the script download) can easily be applied elsewhere.

Well, here are your options:

  1. Read the whole article. Could be amusing, if I’m having a bad writing day.
  2. Skip to the download and “how to use.” No, I’m not going to explain the code. Well, not here, at any rate. I’ll explain it in the code itself. Yes, of course there are comments.

What is Spriting?

Example Sprited Images

Example Sprited Images

Spriting is a technique which combines multiple small images into one large image. This can be very beneficial, because it means that, instead of downloading, say, 100 small images for all the commonly used icons in your web application, the web browser downloads one bigger image (or, perhaps, two or three, but you get the picture).

The goal of spriting is to reduce the effect of latency on your web app’s performance.

To your left is an example set of sprited images.

Using a Script

You may thing that combining several images into one larger image might be a bit time-consuming and, overall, a tad challenging, especially if you are often updating the individual images.

You are not alone. I feel the same way.

However, I do know a little about writing scripts—even if I’d like to know a lot more; I’m still only learning Python. So, there is a simple answer:

Write a darn script!

The Product

If you just want the script and how to use it, you’re in luck. Because there are, in fact, some comments in the script, I’ll leave the explanation of how the code works for there.

You can download the code from GitHub.

The script is written in Python. It requires: Either: Python 2.6+ or Python 2.5 with simplejson installed PIL (Python Imaging Library)

Very briefly, here is what it does:

  • Takes a “sets” folder, which should have sub-folder sets of icons to be sprited.
  • Takes an output folder, under which it will create new set folders containing CSS and image files.
  • Combines images under a maximum size (128×128 by default—see Configuration) into a sprites.png file in the output set folder.
  • Creates CSS referencing these images using a URL template (SproutCore oriented at first—see URL)

Sets

You often might have more than one set of icons. For instance, you could have a main set, and then an alternate set that you only want to load on demand. You still want that additional set to be sprited.

Or, perhaps, you may have images meant for repeating backgrounds, but that you still want to sprite.

To facilitate this, the spriting script takes, as its first argument, the location to a sets folder. You put your sets as subfolders into this folder. For instance, this could be your folder layout:

my-sets
	common
		delete-32.png
		delete-64.png
		refresh-32.png
		refresh-64.png
		refresh-512.png
	repeat-x
		config.js       — see Configuration
		toolbar.png
		footer.png
		header.png
	odd-feature
		some-icon.png
		other-icon.png

URLs

The CSS has to reference the images. Only problem: it doesn’t know where those images are.

Usually, you’d just be able to use paths relative to the StyleSheet. However, if you are using SproutCore, this won’t work because it moves around all the CSS and JavaScript.

With SproutCore, you need something more like:

static_url('images/set/sprites.png')

This is what the script does by default. Just like above. It uses a URL template of

static_url('images/{set}/{image}')

It is a string which will be passed through the Python format function, with set and image as arguments.

Configuration

There are a few things that are configurable. Configuration is done per-set.

Configuration files are JSON files, and are very simple. They are optional, and take at most four parameters:

  • max-size: Default: 128.
    The maximum size for sprited images. Images above this size will be put as separate images. Useful if you have some really high-res icons you don’t want to sprite, but want to keep with the set.

  • repeat: Default: “none”; can also be “x” or “y”.
    Determines the repeat mode. If repeat is “x,” the sprites will be laid out in rows; if “y,” the sprites will be laid out in columns. The generated CSS will include repeat-x or repeat-y, respectively.

Note that all images in a repeat-x set must be the same width, and all images in a repeat-y set must be the same height. The width or height of these images should be set using repeat-width and repeat height, which are discussed below.

  • repeat-width: Default: 32.
    If repeat=“x,” the width of the repeat images. If your repetition does not require a pattern, you could set this to 1.

  • repeat-height: See that lovely summary of repeat-width above? Well, this is the same, but for y/height.

The CSS

As you may know, SproutCore automatically includes any CSS files. So, since this generates CSS files (and, if you provide the right argument, puts them directly into a SproutCore-watched folder), the CSS is automatically added. So, how do you use it?

Very simply. The script generates CSS rules in this format:

.set-name .icon-name.icon, .set-name .icon-name.icon { /* CSS */ }

For example, to show “refresh-64″ icon in set “common”, you’d do something like this:

ImageView.design({
  layout: { left: 100, top: 100, width: 64, height: 64 },
  value: "common refresh-64 icon" // using SproutCore's built-in className support for spriting
}

Or, as you may have noticed from the rule above, you can accomplish some basic theming very easily by treating set names as themes:

View.design({
  layout: {left: 100, top:100, width:256, height: 256},
  classNames: ["common"], // the theme
  childViews: ["styledView"],
  styledView: ImageView.design({
    layout: { left: 100, top: 100, width: 64, height: 64 },
    value: "refresh-64 icon" // using SproutCore's built-in className support for spriting
  })
})

Nice and simple, eh?

August 4th, 2009 by Alex Iskander

Running Orbited (or other Twisted Services) as a Windows Service

It took me awhile to figure out how to run Orbited and Dolores as Windows Services. Unfortunately, while I love Mac, almost every other computer at my workplace is Windows, including the servers. When deploying my web application, I can’t really just leave instructions like: “When you restart the server, please run these two scripts.”

They need to be Windows Services.

Thankfully, it isn’t actually too hard. You just need a couple of Python packages (which I actually don’t remember installing, so they may have come with Twisted or Python), and then all you have to do is write a couple of very simple scripts. Here are mine:

Orbited Service

import OrbitedManager # a copy of orbited.start with some very minor modifications, which I'll include after the break
import time
 
# Service Utilities
import win32serviceutil
import win32service
import win32event
 
class WindowsService(win32serviceutil.ServiceFramework):
	_svc_name_ = "Orbited"
	_svc_display_name_ = "Orbited Server"
 
	def __init__(self, args):
		win32serviceutil.ServiceFramework.__init__(self, args)
		self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
 
	def SvcStop(self):
		self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
		win32event.SetEvent(self.hWaitStop)
 
	def SvcDoRun(self):
		import servicemanager
		OrbitedManager.start()
		while True:
			retval = win32event.WaitForSingleObject(self.hWaitStop, 10)
			if not retval == win32event.WAIT_TIMEOUT:
				OrbitedManager.stop()
				break
				time.sleep(5.0)
 
 
if __name__=='__main__':
	win32serviceutil.HandleCommandLine(WindowsService)

Dolores Service

import Dolores
import time
 
# Service Utilities
import win32serviceutil
import win32service
import win32event
 
class WindowsService(win32serviceutil.ServiceFramework):
	_svc_name_ = "Dolores"
	_svc_display_name_ = "Dolores Server"
 
	def __init__(self, args):
		win32serviceutil.ServiceFramework.__init__(self, args)
		self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
 
	def SvcStop(self):
		self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
		win32event.SetEvent(self.hWaitStop)
 
	def SvcDoRun(self):
		import servicemanager
		Dolores.start()
		while True:
			retval = win32event.WaitForSingleObject(self.hWaitStop, 10)
			if not retval == win32event.WAIT_TIMEOUT:
				Dolores.stop()
				break
				time.sleep(5.0)
 
 
if __name__=='__main__':
	win32serviceutil.HandleCommandLine(WindowsService)

That’s the basics, but as you may have noticed, I also changed Orbited’s start script. I did this because the original did not play nicely with threads.

Instead of changing it in its original location in the filesystem, I created a copy of it in the local directory (as you can see, I’m not importing Orbited.OrbitedManager).

Read the rest of this entry »

August 4th, 2009 by Alex Iskander

Dolores & Cornelius, Sitting in a Tree. Of Comet, Orbited and Python.

I’ll give you a moment to allow you to get that disturbing image out of your head.

I have been working on a web application. I’ll hopefully be able to post the application soon.

I needed the server to be able to send updates to the client via Comet. I’d never done any Comet before, so I wasn’t sure what to do.

A lot of articles had examples making use of message queues and who knows what else. They were a tad overwhelming. While a message queue of some sort may eventually be a good idea, for now, all I needed to do was push a non-vital progress indicator for a job (15%, 20%, 30%, and so on) to the client so the user could see what was happening. I wanted more than one job to be supported, and the overall system should eventually allow sending updates when elements in the user’s filesystem are updated.

So, I’d like to be able to send:

UPDATE process/at/my/process/path; {progress:.5}
UPDATE file/at/my/file/path.txt

In short, I’d like to send paths, along (sometimes) with little tiny messages.

Also, each instance of the web app should only receive updates to paths they are listening to, and they should only be allowed to listen to paths they actually have access to. Or, at least, that should be the case once I implement permission management in the app &emdash; right now, anything goes, which is fine for the moment because it is limited to test use on our local network.

So, I made a little script, called Dolores, which handles all of this, and another script, named Cornelius, which connects to it (incidentally, there are two Corneliuses: a Python one, and a JavaScript one).

I have posted it here in case anyone is interested. I used Orbited in JavaScript to connect to the server. In a separate post in just a few moments, I’ll write about something a tad more useful than the Dolores & Cornelius code I’m writing about here: how to run the Orbited (and, actually, Dolores) as a Windows service.

Read the rest of this entry »