Filtered by JavaScript, Python

Page 34

Reset

Title - a javascript snippet to control the document title

August 22, 2011
0 comments JavaScript

This is a piece of Javascript code I use on "Kwissle" to make the document title change temporarily. Other people might find it useful too.

Code looks like this:


var Title = (function() {
 var current_title = document.title
   , timer;

 return {
    showTemporarily: function (msg, msec) {
      msec = typeof(msec) !== 'undefined' ? msec : 3000;
      if (msec < 100) msec *= 1000;
      if (timer) {
        clearTimeout(timer);
      }
      document.title = msg;
      timer = setTimeout(function() {
        document.title = current_title;
      }, msec);
    }
 }
})();

Demo here

Comparing Google Closure with UglifyJS

July 10, 2011
17 comments JavaScript

On Kwissle I'm using Google Closure Compiler to minify all Javascript files. It's fine but because it's java and because I'm running this on a struggling EC2 micro instance the CPU goes up to 99% for about 10 seconds when it does the closure compilation. Sucks!

So, I threw UglifyJS into the mix and instead of replacing the Closure compiler I added it so it runs alongside but I obviously only keep one of the outputs.

Here is the log output when I run it on my MacbookPro:


MAKING ./static/js/account.js
UglifyJS took 0.0866 seconds to compress 3066 bytes into 1304 (42.5%)
Closure took 1.2365 seconds to compress 3066 bytes into 1225 (40.0%)
MAKING ./static/js/ext/jquery.cookie.js
UglifyJS took 0.0843 seconds to compress 3655 bytes into 3009 (82.3%)
Closure took 1.3472 seconds to compress 3655 bytes into 4086 (111.8%)
MAKING ./static/js/ext/jquery.tipsy.js
UglifyJS took 0.1029 seconds to compress 7527 bytes into 3581 (47.6%)
Closure took 1.3062 seconds to compress 7527 bytes into 3425 (45.5%)
MAKING ./static/js/maxlength_countdown.js
UglifyJS took 0.082 seconds to compress 1502 bytes into 1033 (68.8%)
Closure took 1.2159 seconds to compress 1502 bytes into 853 (56.8%)
MAKING ./static/js/ext/socket.io-0.6.3.js
UglifyJS took 0.299 seconds to compress 76870 bytes into 30787 (40.1%)
Closure took 2.4817 seconds to compress 76870 bytes into 30628 (39.8%)
MAKING ./static/js/scoreboard.js
UglifyJS took 0.084 seconds to compress 2768 bytes into 1239 (44.8%)
Closure took 1.2512 seconds to compress 2768 bytes into 1167 (42.2%)
MAKING ./static/js/rumbler.js
UglifyJS took 0.0872 seconds to compress 3087 bytes into 1384 (44.8%)
Closure took 1.2587 seconds to compress 3087 bytes into 1235 (40.0%)
MAKING ./static/js/ext/shortcut.js
UglifyJS took 0.0987 seconds to compress 5796 bytes into 2537 (43.8%)
Closure took 1.3231 seconds to compress 5796 bytes into 2410 (41.6%)
MAKING ./static/js/play.js
UglifyJS took 0.1483 seconds to compress 18473 bytes into 10592 (57.3%)
Closure took 1.4497 seconds to compress 18473 bytes into 10703 (57.9%)
MAKING ./static/js/playsound.js
UglifyJS took 0.0824 seconds to compress 1205 bytes into 869 (72.1%)
Closure took 1.2335 seconds to compress 1205 bytes into 873 (72.4%)  

(Note here that for the file ./static/js/ext/jquery.cookie.js Closure failed and when it fails it leaves the code as is and prepends it with a copy about the error from the stdout. that's why it's greater than 100% on that file)

Here are the averages of those numbers:


AVERAGE TIME: (lower is better)
  * UglifyJS: 0.11554 seconds
  * Closure: 1.41037 seconds

AVERAGE REDUCTION: (higher is better)
  * UglifyJS: 45.6% 
  * Closure: 51.5%

(I'm skipping the file that Closure failed to minify)

So, what does that mean in bytes? These are the source Javascript files for two pages but the total is 123949.0 bytes. With Closure that saves me 63833.7 bytes (62 kbytes) whereas UglifyJS only saves me 57760.2 bytes (56 kbytes) of bandwidth.

Discussion...

The fact that Closure fails on one file is a real bummer. I'm not even using the advanced options here.

UglifyJS doesn't save as many bytes as Closure does. This is potentially important because after all, minification process happens only once per revision of the original file but might be served hundreds or millions of times.

Because I run my minifications on-the-fly it does matter to me that UglifyJS is 1220% faster.

It's rare but I have observed twice that the minified Javascript from Closure has actually broken my code. I default to suspect that's my fault for not making the code "minifyable" enough (e.g. too many global variables).

I've just noticed that I'm relying on files that almost never change (e.g. jquery.tipsy.js). I might as well create a ...min.js versions of them and add them to the repository.

In conclusion...

Because of the convenience of UglifyJS being so much faster and that it doesn't choke on that jquery.cookie.js file I'm going switch to UglifyJS for the moment. The remaining bytes that I don't save become insignificant if you add the gzip effect and compared to images the bandwidth total is quite insignificant.

UPDATE (JAN 2016)

I wrote a follow-up post comparing UglifyJS2 with Closure Compiler with the advanced option.

Slides about Kwissle from yesterdays London Python Dojo

July 8, 2011
0 comments Python

Since this was published, I've abandoned the kwissle.com domain name. So no link no more.

Here are the slides from yesterday's London Python Dojo event.

I presented and demo'ed "Kwissle" to my fellow Python London friends and focused a lot on the technology but also tried to plug the game a bit.

Having seen that there's a lot of interest in "socket" related web applications about I thought this was a good chance to say that you don't need NodeJS and that tornadio is a great framework for that.

Optimization story involving something silly I call "dict+"

June 13, 2011
0 comments Python, MongoDB

Here's a little interesting story about using MongoKit to quickly draw items from a MongoDB

So I had a piece of code that was doing a big batch update. It was slow. It took about 0.5 seconds per user and I sometimes had a lot of users to run it for.

The code looked something like this:


 for play in db.PlayedQuestion.find({'user.$id': user._id}):
    if play.winner == user:
         bla()
    elif play.draw:
         ble()
    else:
         blu()

Because the model PlayedQuestion contains DBRefs MongoKit will automatically look them up for every iteration in the main loop. Individually very fast (thank you indexes) but because of the number of operations very slow in total. Here's how to make it much faster:


   for play in db.PlayedQuestion.collection.find({'user.$id': user._id}):

The problem with this is that you get dict instances for each which is more awkward to work with. I.e. instead of `play.winner` you have use `play['winner'].id`. Here's my solution that makes this a lot easier:


class dict_plus(dict):

  def __init__(self, *args, **kwargs):
       if 'collection' in kwargs:  # excess we don't need
           kwargs.pop('collection')
       dict.__init__(self, *args, **kwargs)
       self._wrap_internal_dicts()

   def _wrap_internal_dicts(self):
       for key, value in self.items():
           if isinstance(value, dict):
               self[key] = dict_plus(value)

   def __getattr__(self, key):
       if key.startswith('__'):
           raise AttributeError(key)
       return self[key]

  ...

 for play in db.PlayedQuestion.collection.find({'user.$id': user._id}):
    play = dict_plus(play)
    if play.winner.id == user._id:
         bla()
    elif play.draw:
         ble()
    else:
         blu()

Now, the whole thing takes 0.01 seconds instead of 0.5. 50 times faster!!

A script tag's type in HTML5

May 10, 2011
4 comments JavaScript

If you look at html5boilerplate.com they never use any type on their <script> tags. Hmm... but is there more to it?

If you don't specify a type, the default becomes "text/javascript" but according to RFC4329 the "text/javascript" MIME type is obsolete in favor of "application/javascript".

If the default MIME type for a <script> tag thus becomes either "text/javascript" or "application/javascript" is there any sensible browser on this green earth that would not translate a piece of inline Javascript code as, exactly that; Javascript? Probably not.

What about <script> tags with a src attribute? Does the type matter?

I read the spec a couple of times and it feels like reading legalese but it ultimately says: the value of the type tag must be that of the body of the script tag.

So, what happens if you embed a javascript file with a mismatching type? Let's see:

Truncated! Read the rest by clicking the link below.

maxlength_countdown() - a useful jQuery plugin for showing characters left

May 1, 2011
6 comments JavaScript

If people find this useful I might turn it into a proper jQuery plugin and publish it.

Without further ado; here's the demo

What it does is that for all input fields that have a maxlength="nnn" it shows a counter to the right that increases in opacity as it reaches the maximum. You can generally start it like this:


$('input[maxlength]').maxlength_countdown();

Since the plugin "hard codes" the count down expression in English you can override it easily like this:


$('input[name="message"]').maxlength_countdown(function (count, max) {
   return count + " (max: " + max + ")";
});

What do you think? Is it useful? Does it make sense?

Mocking DBRefs in Mongoose and nodeunit

April 14, 2011
0 comments JavaScript, MongoDB

Because this took me a long time to figure out I thought I'd share it with people in case other people get stuck on the same problem.

The problem is that Mongoose doesn't support DBRefs. A DBRef is just a little sub structure with a two keys: $ref and $id where $id is an ObjectId instance. Here's what it might look like on the mongodb shell:


> db.questions.findOne();
{
       "_id" : ObjectId("4d64322a6da68156b8000001"),
       "author" : {
               "$ref" : "users",
               "$id" : ObjectId("4d584fb86da681668b000000")
       },
       "text" : "Foo?",
       ...
       "answer" : "Bar"
       "genre" : {
               "$ref" : "question_genres",
               "$id" : ObjectId("4d64322a6da68156b8000000")
       }
}

DBRefs are very convenient because various wrappers on drivers can do automatic cross-fetching based on this. For example, with MongoKit I can do this:


for question in db.Question.find():
   print question.author.first_name

If we didn't have DBRefs you'd have to do this:


for question in db.Question.find():
   author = db.Authors.findOne({'_id': question.author})
   print author.first_name

Truncated! Read the rest by clicking the link below.

TornadoGists.org - launched and ready!

April 6, 2011
1 comment Python, Tornado

Today Felinx Lee and I launched TornadoGists.org which is a site for discussing gists related to Tornado (python web framework open sourced by Facebook).

Everyone in the Tornado community seems to solve similar problems in different ways. Oftentimes, these solutions are just a couple of lines or so and not something you can really turn into a full package with setup.py and everything.

Sharing a snippet of code is a great way to a) help other people and b) to get feedback on your solutions.

The goal is to make it a very open and active project with lots of contributors. I'll be accepting and reviewing all forks but hopefully control will be opened up to all Tornado developers. Also, since the code is quite generic to any open source project Felinx and I might one day port this to rubygists.org or lispgists.org or something like that. After all, Github does all the heavy lifting and we just wrap it up nicely.

QUnit testing my jQuery Mobile site in full swing

March 17, 2011
1 comment JavaScript

QUnit testing my jQuery Mobile site in full swing Yay! I've figured out how to properly unit tests my jQuery Mobile app that I'm working on. This app uses localStorage, localSession, lots of AJAX and works both offline and online. Through various hacks and tricks I've managed to mock things so that I can easily test the otherwise asynchronous AJAX calls and I can also test the little quirks of jQuery Mobile such as re-rendering <ul> tags after having changed the DOM tree.

I'm using the QUnit testing framework and I like it. The app isn't launched yet and the code is currently protected but once I get it nailed a bit more I'll blog about it more fully so other people can jump in unit testing their Javascript heavy jQuery Mobile sites too. For now I'm up to 75 tests and it's growing steadily.

Here's a little taster for how I mock the $.mobile, AJAX and the localStorage stuff:


module("Storage and AJAX", {
  setup: function() {
     localStorage.clear();
  },
  teardown: function() {
     localStorage.clear();
  }
});

var MockMobile = function() {
  this.current_page;
};
MockMobile.prototype.changePage = function(location) {
  this.current_page = location;
};

test("test Auth", function() {
  $.mobile = new MockMobile();
  var _last_alert;
  alert = function(msg) {
     _last_alert = msg;
  };
  $.ajax = function(options) {
     switch (options.url) {
      case '/smartphone/checkguid/':
        options.success({ok:true});
        break;
      case '/smartphone/auth/login/':
        if (options.data.password == 'secret')
          options.success({guid:'10001'});
        else
          options.success({error:"Wrong credentials"});
        break;
      default:
        console.log(options.url);
        throw new Error("Mock not prepared (" + options.url + ")");
     }
  };
  var result = Auth.is_logged_in(false);
  equals(result, false);

  Auth.ajax_login('peterbe@example.com', 'other junk');
  ok(_last_alert);
  ...

(Note: this is copied slightly out of context but hopefully it reveals some of the hacks and tricks I use)

More productive than Lisp? Really??!

March 10, 2011
0 comments Python

Erann Gat reveals why he lost his mojo with Lisp

What caught my attention (for busy people who don't want to read the whole email):

"So I can't really go into many specifics about what happened at Google because of confidentiality, but the upshot was this: I saw, pretty much for the first time in my life, people being as productive and more in other languages as I was in Lisp. What's more, once I got knocked off my high horse (they had to knock me more than once -- if anyone from Google is reading this, I'm sorry) and actually bothered to really study some of these other languges I found myself suddenly becoming more productive in other languages than I was in Lisp. For example, my language of choice for doing Web development now is Python."

I'm currently studying Lisp myself and it's hard. Really hard. I blame it on being spoiled with a programming language that I can work in without having to read the manual. With python's brilliant introspection I can use the interpreter to find out how a library works just by using help() and dir() without even having to read the source code. (not always true of course)

As we're entering the 21st century, the new contender "Usability" is becoming more and more important. Considering that I've now done Python for more than a decade I remind myself one of the reasons I liked it so much; yes, exactly that: Usability.