LlamaWorld

Although there are no llamas in LlamaWorld, there is plenty of JavaScript.  In fact, almost the entire world is JavaScript.

At the moment, most of LlamaWorld‘s code is directly taken from an example on the Mozilla Developer Center.

If you beat the first (and currently the only) level, please take the survey when you are asked.  I’ll be posting the results on my blog later as soon as there are enough to be worthwhile.

VKitty

An online friend of mine has tried to make a virtual cat game several times and gave up each time.  But this time is different.  This time, she has the support of a programmer, and I won’t let her give up.

Sir Soybean... VKitty?

The new VKitty is all ajaxified, so there is only one full pageload for each time you visit your virtual cat, and everything else is handled by XMLHttpRequests.  Being admin on VKitty does have its advantages, as I am allowed to do things nobody else can do—adopt a llama and have over nine million cat cash, for example.

There are currently five different adoptable cat types.  None of them require any food or play yet, because VKitty is not quite done.  But at a rate of one update or more per day, it’s getting closer and closer to being finished.

Already, stats refresh twice a minute directly from the server, dates update twice a second using the JSON-encoded responses the server gives, there’s a fully searchable memberlist, and much more.

Unfortunately, each adoption costs five thousand cat cash, and when you join VKitty, you are only supplied with 250.  If anyone needs help adopting, until the “free kitten for joining” offer is in place, I’ll be glad to help.  Just send me an email at nigh@vkitty.co.cc

If you have any suggestions for VKitty, you can suggest them here, and view the development here.

Without further ado, please join VKitty!

Unpacking /packer/

Ever since I started working on the mostly Ajax app “VKitty“, I’ve been looking into JavaScript compression, and trying to figure out how it works.  Most compressors have very simple ways to compress JavaScript, by simply removing whitespace, but Dean Edwards’s /packer/ defies the simplicity of most compressors by making an unreadable function that acts the same as the JavaScript you feed it, also known as obfusication.

I’ve decided to find out how it works, and I’m starting with something very simple.  “alert(‘STUFF GOES HERE’)“.

First, I packed it in /packer/.  I got back the code “eval(function(p,a,c,k,e,r){e=String;if(!”.replace(/^/,String)){while(c–)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return’\\w+’};c=1};while(c–)if(k[c])p=p.replace(new RegExp(‘\\b’+e(c)+’\\b’,’g’),k[c]);return p}(‘0(\’1 2 3\’)’,4,4,’alert|STUFF|GOES|HERE’.split(‘|’),0,{}))“, which is really unreadable.

Let’s unpack the /packer/.

I did a bit of formatting on the function returned by /packer/: (it’s an image because I couldn’t get syntax highlighting to work on my blog)

/packer/: Unpacked

/packer/: Unpacked (Click for a bigger view)

If you can’t already see what’s happening, I’ll walk you through it.  It basically creates a function, calls itself, and evaluates the result as JavaScript.  Here it is, line by line:

Line 1: eval(
Evaluates the code that is created by the function.

Line 2: function (p, a, c, k, e, r) {
Starts the declaration of a function, via shameless plug.

Line 3: e=String;
Makes the variable e into a function that returns whatever it is given as a string.

Line 4: if (!”.replace(/^/, String)) {
This seems pointless to me, because evaluating the code inside the if statement would always return true.  I even removed the code, and it kept working!  The code is probably for compliance with less-up-to-date JavaScript implementations.

Line 5: while(c–) r[c] = k[c] || c;
While the c variable is above zero, reducing c by 1 every time, the r variable (an empty object) gets a new variable inside it: one of the words contained in k, or ‘alert|STUFF|GOES|HERE’, split at the |‘s.  If the variable doesn’t exist (which shouldn’t happen), it puts the key into the array so it will replace with itself.

Line 6: k = [function (e) {
The variable k is turned into an array with a function inside it.

Line 7: return r[e]
Return the xth word in r. (x is the variable e)

Line 8: }];
Closing the function-in-an-array statement.

Line 9: e = function () {
The variable e is now another function, not the String function, let’s see what it does:

Line 10: return ‘\\w+’
In regex, this means “find as many alphanumeric characters as possible”.

Line 11: };
Closing a function.

Line 12: c=1
We are no  longer looking for words 4 (in this case) times, but 1.  This is only possible because of the stuff inside the if statement.

Line 13: };
Ending an if statement.  Note the unnecessary semicolon.

Line 14: while (c–)
While the variable c is nonzero, reducing it by 1 after we test for nonzero-ness.

Line 15: if (k[c])
Make sure k has c as one of its keys.

Line 16: p = p.replace(new RegExp(‘\\b’+e(c)+’\\b’,’g’), k[c]);
Replace the p variable with the k[c] variable instead of the c variable’s value.

Line 17: return p
Return the final value.

Line 18: } (‘0(\’1 2 3\’)’, 4, 4, ‘alert|STUFF|GOES|HERE’.split(‘|’), 0, {})
Set the p, a, c, k, e, r variables.

Line 19: )
Close the eval statement.

The ultimate site redirect

Add the following lines to your .htaccess file:

RewriteCond %{HTTP_HOST} !^example\.com$ [NC]
RewriteRule ^(.*)$ http://example.com/$1 [L,R=301]

of course, you would change example.com to your domain name, and example\.com to your domain name with backslashes before the dots.

Add the following JavaScript to a file that is common to your whole website.

try {
    if (window.top.location.href != document.location.href) {
        window.top.location = document.location;
    }
} catch (ex) {
    var alllinks = document.getElementsByTagName("a");
    for (var i=0; i<alllinks.length; i++) {
        alllinks[i].setAttribute("target", "_top");
    }
}

Here’s how it works:

The .htaccess file tells your server to redirect all domains except your domain that are pointed at your files to change to your domain.

The JavaScript tells browsers to redirect out of frames, and if that is not possible, to change all links so they will do so.  This prevents users of browsers like FireFox 3 from not going directly to your website.

Browser Warz-Part 3: Things just got interesting.

In all of the previous Browser Warz competitions, there were only 4 competitors.  Now, there are 26.  Now, I hope you’re thinking “26 browsers on one computer? This guy must be crazy!”, because I am.

However, unlike the other Browser Warz competitions, the browsers in this competition will be facing other versions of their own kind before going on to face the winners of each individual competition.

There are 4 things that the browsers will be scored on in this leg of the competition:

  • CSS errors (Is the purple header there?  Does the body of the page match up with the header?  Is the footer matching?  Are the horizontal rules hidden?)
  • JavaScript errors (Are there any?  How bad are they?)
  • Speed of the 3 tests (How fast were each of the three tests?  How long did it take 5 repeats of each test to occur?)
  • Total time taken on the tests (How many seconds did it take?)

The 26 browsers are split up into 5 categories:

  • Internet Explorer icon for Browser Warz Internet Explorer (7 browsers, page 2)
  • Firefox icon for Browser Warz Firefox (4 browsers, page 3)
  • Opera icon for Browser Warz Opera (6 browsers, page 4)
  • Netscape icon for Browser Warz Netscape (7 browsers, page 5)
  • “Other” icon for Browser WarzOther (2 browsers, page 6)

This competition, because it is so long, is divided into pages to reduce loading time.

Browser Warz-Part 2: Safari wins

The test:

To pass test 2, the browser has to:

  1. Correctly render the page from last time, except not gzipped.
  2. Read base64 encoded data and parse it as JavaScript.
  3. Do 10 million empty loops, 5 million Math.random() calls, and 500 thousand empty eval() calls as soon as the page loads.
  4. Respond to a double click event.
  5. Ask for permission to do memory-intensive scripts.
  6. Do 250 million empty loops, 125 million Math.random() calls, and 12.5 million empty eval() calls in under 10 minutes.
  7. Not crash during the time that it does step 3, although not responding for up to 5 minutes at a time is ok.

The results:

Safari went the fastest:  256.564 seconds (4.276 minutes)
Safari-Browser Warz test 2

Next in speed was Opera, with a time of 275.92 seconds (4.599 minutes)
Opera-Browser Warz test 2

And then comes Firefox, with a time of 371.446 seconds (6.191 minutes)
Firefox-Browser Warz test 2

Internet Explorer was disqualified because it did not render the page, nor did it respond to the double click event when I gave it a .html copy of the test.  I was curious, however, so I used the javascript: protocol and tested it.  It came in faster than opera!
IE-Browser Warz test 2

As always, you can download the test.  Here it is: Browser Warz test 2