Older blog entries for Ohayou (starting at number 12)

7 Mar 2005 (updated 7 Mar 2005 at 00:58 UTC) »
Javascript

I've seriously started digging into Venkman now, the Mozilla project's javascript debugger and profiler. I'm sure it's a great tool if it's your own baby or if you have someone initiated around to teach you its ways, but short of that, you need to find good webpages to help you get anywhere, such as figuring out how to set a simple breakpoint. It's a bit like learning to make good use of Emacs, though in a GUI application. Striking.

Anyway, once you acquire some basic working skills, it has a lot to offer. I fell in love with the profiling tools, not so much because I tend to write javascript code in need of optimisation, but for being beautifully done. (Once you are sitting with the profiling data and have left Venkman's GUI safely behind, anyway.)

As it happens, though, I read through Svend Tofte's good guide referred above, and ended up at the BrainJar JavaScript Crunchinator. "Hey, cool hack!" I thought to myself, and tried feeding it my present work project, an application weighing in at 32 kilobyte, and it sat there for a long time grinding on it. Minutes later, it spat out a big chunk of code that started much like my own code and ended in mid air, three kilobyte short of the end of the file. Weird.

So I inspected my own source code, and found that I had commented out a block with /*...*/ just before where the crunchinator had given up, and the block ended in a // comment, inside the block comment -- and lo, the mystery was solved.

As I was curious to see if the crunched code would actually work, once that issue was resolved, I peeked on the comment stripper, decided it was beyond fixing and decided to run my own instead. After trying a regexp cut and paste approach, I was again annoyed at Javascript RegExps, for some reason not eating entire input strings (why does (.*) not match the rest of my input data? M'kay, I suppose I will read find the answer myself in ECMA-262 next time I'm bit by this and sufficiently annoyed to learn from the specification).

On the other hand, a regexp cut-and-paste solution is by rule of thumb always the wrong solution, for one reason or another, and after having given the matter some thought and made a brief inventory of the search methods on offer in javascript (thank you so much for Javascript: the Definitive Guide, David Flanagan!), I found a much more aesthetic solution built from String.search, String.indexOf and Array.join:

function removeComments( s )
{
  var found, code = [], commentStart = /\x2f[\x2f\x2a]/, commentEnd;
  while( (found = s.search( commentStart )) >= 0 )
  {
    code.push( s.substring( 0, found ) );
    if( s[++found] == '*' )
      commentEnd = '*/';
    else
      commentEnd = '\n';
    if( (found = s.indexOf( commentEnd, found )) >= 0 )
      s = s.substring( found + commentEnd.length );
    else
      s = '';
  }
  s = code.join(' ') + s;
  return s.replace( /\n/g, ' ' );
}

I paste it back into the crunchinator, fire away, and in mere seconds, the result pops up this time, no truncation to be seen. Surprised, I test it again. Sure enough, a speedy weasel indeed. I apply my newfound Venkman knowledge, sleep through the original code's 154.34 seconds worth of heavy processing (81 of which were spent in the original removeComments function), run my own version and get a lean 4.70 seconds for running the entire script. That's some mean garbage collection gains. Just to be sure I'm not measuring something irrelevant, I run the tests again in the other order. No difference worth mentioning.

I sumbit my improvements to the original author, notice that my additions just feel into the GPL (you know where to find the license, folks) and figure it's been a decent hack. Maybe someone could even learn from it. For reference, here is the original source code (don't do this at home):

function removeComments(s) {
  var lines, i, t;
  // Remove '/* ... */' comments.
  lines = s.split("*/");
  t = "";
  for (i = 0; i < lines.length; i++)
    t += lines[i].replace(/(.*)\x2f\x2a(.*)$/g, "$1 ");
  // Remove '//' comments from each line.
  lines = t.split("\n");

t = ""; for (i = 0; i < lines.length; i++) t += lines[i].replace(/([^\x2f]*)\x2f\x2f.*$/, "$1"); // Replace newline characters with spaces. t = t.replace(/(.*)\n(.*)/g, "$1 $2"); return t; }

"The results?" I hear you asking. Well, my original 32 kilobyte application weighed in at 19, a pleasing 59.8% of its original weight, without resorting to variable renaming and similar destructive modifications. It worked, after fixing only six slight misses, half of which were my own (missing end-of-line semicolons and a case of an operator on both sides of a newline). The other half were inside regexps -- two related to apostrophes and quotation marks, the last one being the regexp /  /, which had been optimised to // (...ow! -- and the rest of the line , or the rest of the script if you so prefer, was thus effectively cut off :-).

I suppose that means that another healthy exercise would be to rewrite the string literal parsing code too, but I would suspect that any improvements over the present would mean to parse by language grammar rather than crude string matching, and somehow it doesn't feel like very gratifying work. Not that I have peeked at the code, though.

3 Mar 2005 (updated 3 Mar 2005 at 17:44 UTC) »
Bookmarklet (and calendar rant)

I absolutely detest all numeric non-ISO date formats, M/D/Y probably most of all. So when I encountered the Kingdom of Loathing calendar some benevolent (albeit calendrally challenged) person had published, I did not track down said person to tell him how glad I was at finding what I was looking for and how I felt about the format in which it was published. The meld of feelings would just not make any sense, and after all, the information was both there and fairly easily deciphered. I just strongly feel that deciphering is best left to computers.

Enter today's bookmarklet (feel free to bookmark it). It will ask you which (numeric) date format to convert from, harvest all frames for dates on that format and reformat them to readable ISO YYYY-MM-DD dates. If you go with the default M/D/Y, it will find 3/2/5, being sillyspeak for yesterday, and turn it into 2005-03-02. Short dates in the future (such as 3 / 3 / 6) will be assumed to mean the corresponding date from last century. Run it a year from now you will see 2006-03-03, though. Unless your clock is off, by a lot.

Upon googling for date tables to try it out on, I found a hilarious hallmark of stupidity - an excel sheet featuring the column "Employee Start date", "m/d/y or y/m/d e.g. 5/17/2 or 2002/5/17". The web is a silly place. Let's not go there.

Javascript

Okay, the last procrastinational activity for today: a very (stone axe) crude kind of javascript indent tool built on GNU indent. So it doesn't really reindent Javascript code, but C. Silly me. But while it does trash the occasional RegExp literal, it's less of a hassle than doing all the work manually.

Besides, most C users wouldn't use web tools to indent their code. Not me, anyway. But if you would, feel free to use this one. The worst thing that could happen is that it might at some time in the future also work with keywords and literals you do not use in your C code, where they are not supported.

(I wish I had some tool that turns javascript input to an abstract syntax tree, which I could then just traverse to cook my own Function.prototype.toSource(). ...Okay, back to work now.)

Javascript

How does one intercept modal browser alerts about connection problems, file transfer failues and the like from javascript?

Most of all, I want to trap the "The operation timed out when attempting to contact www.kingdomofloathing.com" dialog, which pops up very frequently (typically at least once every session) when I load a new frame from my javascript code. Of course it has nothing to do with which method I employ to load it, but it's mostly when I initiate the transfers myself when I'm really interested in trapping the alert to handle it in a more constructive and less user-involving manner.

Even a solution requiring me to be a Mozilla plugin would be useful, though what I really want is something that could live in a scriptlet or web page and handle the call, ideally cross-browser. With browser Javascript not being nearly as wing-clipped today as it was back in the nineteen hundreds, I've come to expect to be able to solve issues like these. (Let's hope I'm not being overly optimistic.)

Hmm. I suppose due to the lack of talkback features here, I'd better leave a mail address -- feedback to oyasumi at gmail dot com would be very welcome indeed. I'll be sure to write some kind of article about the solution once I find or get pointed to it.

24 Feb 2005 (updated 24 Feb 2005 at 21:07 UTC) »

Mozilla

My signature-uncluttering phpBB Firefox extension seems to have been listed recently at Extension Room. And as proof of someone already using it, a few hits in the access log show that browsers are eagerly polling for updates -- and I received a second feature request, not counting my own. (With a bit of luck, I'll learn how to get a callback once just the HTML bits of a loading page have been fully loaded, so I can address my own issues with it. After all, it doesn't make any sense loading lots of graphics just to purge them a second later.)

Macromedia security team got back to me reporting that they have reproduced the problem and that it fortunately only feeds mouse events to the background flash application (not including data on which window should have seen the events). I hope the Macromedia and Mozilla people get to share intelligence on the subject; I'd be delighted if the former nailed their bug and the latter found a way of fixing the entire problem class from their side. Since IE for once seems unaffected, I have hope it's possible to somehow alter the plugin interface sandbox to catch this.

Net

Oops, I just encountered a solution Net doesn't consider valid. Minesweeper addicts beware: this game carries the same mind tying properties that your former brain virus did.

Ooo, shiny! Completed the master level of Net in 13:37 (pun not intended) m:s. What an extraordinarily geeky personal record. One probably ought to quit when encountering such divine hints that there are better ways of wasting time.

I could, for instance, finish that object oriented javascript+HTML set top box interface I have a deadline to complete before next Friday and get actual pay for doing, by the hour. That last somehow makes the code very pretty, easy to debug, extend, explain and reuse in a way my pet projects seldom seem to. Why isn't personal hobby hacking paid by the hour?

(Yeah, I know. It's amusing how some question make sense in feelings but come out inane traps of logic short circuit if spelled out in words. Life can be so much fun if you are as easily amused as I am at times.)

22 Feb 2005 (updated 22 Feb 2005 at 05:36 UTC) »

Hmm. My Firefox 1.0 lets through mouse clicks in my advogato tab to the flash game running in its own tab. When clicking places in my advogato tab where the game tab had a widget, I hear the characteristic clicking noise evoked by the game. I wonder if there's a bugzilla ticket on this yet.


...Well, now there is, anyway. (It also seems bug id:s have more than doubled in the almost three years that passed since my first and prior issue was registered.)


Upon closer inspection, that's hardly a mozilla issue at all, since XEmacs and Photoshop exhibit the same behaviour. Oh, well, now it's reported to the hopefully security minded engineers at Macromedia too.

And thank god for Google to helt bypass the many tightly woven webs of frustration on icky corporate websites to get to what you want to go. I tried to find that page unaidedly at first, and was very close to dying in the process. Never again.

21 Feb 2005 (updated 22 Feb 2005 at 02:01 UTC) »

Today's addictive game encounter (pointed out by Jesse Ruderman): Net by Pāvils Jurjāns. It's one of these really good basic, well designed mind games where you have a complete overview of the board, and set it straight in as few turns (and, I presume, as little time) as possible, to the set of logic rules dictated by the game. I'm not yet sure if it's as addictive as Minesweeper which, despite suffering from the misfeature of occasionally forcing the element of chance on your completion of a stage, through similarly basic rules, comes out a great time sink. Or, as might be argued, that may well be what makes Minesweeper so compelling to some.

Either way, I started out trying to find the rules, to soon be puzzled finding my optimal solutions were a few turns more than the reported minimum required amount of turns. As it turns out, the turn count was not how many times a tile had been rotated 90 degrees, but how many turns a tile had been rotated any angle you well please. (Okay, so let's not make necessary partial rotations until we know for sure just which rotation is the correct configuration of every tile.) Results crept down to suggested figures. Until I suddenly found myself having completed a minimum 44 turn stage in 43 turns. (Yay! :-) Wish I'd had a screenshot of it before I started, too, but I suppose I'll bug report it, either way. Not that it matters much to game play, but the author might want to know (assuming he isn't already aware of the issue).

Maybe this bug actually adds to the game more than had it not been there in the first place; it's very rewarding to not only complete a game, but to actually beat it. I'll feel much better leaving the game in a mental state of victory over leaving it after a lengthy session of having just played it successfully, beating my time scores for as many times as that remains interesting. In a free game, this might be a feature indeed, whereas it would probably be an economic set-back in a pay per play time arcade or internet game.

(Seems it can be off by more than one turn, too; I just completed a nine by nine board in 55 turns of 58. :-)

21 Feb 2005 (updated 21 Feb 2005 at 02:25 UTC) »
Javascript tip of the day:

For all the annoying cases where javascript gives you an object with numeric indices but which isn't a proper Array object, you can upgrade it to become one using Array.prototype.slice.apply(object) It's more cruft than had the language already provided us with true arrays (in cases like the arguments variable bound in functions, the window.frames list and the various arrayish return values of numerous DOM methods, to name a few), but it's one less needless javascript level loop to do the transition.

And why doesn't javascript come with your basic set of higher level methods like mapcar and friends? Sure we can cook our own, but it's as if the language tries to imitate a blunt stone age axe, when it's capable of being a real power tool, with just a few touches here and there to get a proper class library. (Is this some misguided attempt at making the language more graspable to a web developer in diapers?)

On Geek Nostalgia and Fatherhood

Sometimes I miss my more active days on the web, and wish I had a blog and spent more time doing random hacks for fun, and silently publishing them where someone sooner or later might drop by, catch on, embrace and adopt them for their own joy. I suppose most of the toys I played with at the time never did catch on and spread, but my first published scriptlets gained a happy crowd at the time and a few survived, sometimes just as ideas, but to some limited extent the code did not even rot with time.

The one thing I did in those days (late twentieth century), though, that still spuriosly returns to me like some magical boomerang through time, is the 404 page I made myself. It's a tribute to Doglas Adams (while he was still alive), where you get a page where a Marvin travesty sulkily types away at the visitor in a text field about how awfully sorry he is not being able to serve that particular file, and how generally sad it is to be a forgotten-about manic depressive web server yadda yadda yadda. You got the gist of it I'm sure. I put it there, and mostly forgot about it. At least until it started spreading to other poor web servers. They were catching that manic depression like the flue. And it was great fun to behold. (In a warmly kind of way, bless their poor souls.)

At first, I got a fan mail or two about it, but since I had not left any notice about crediting my work in the source code, or visibly for that matter, or indeed any reference to myself at all except for my webmaster contact link, the replicas were untraceable back to me and started a life in the free all on their own. I think I once contacted some website admin that had credited his 404 to himself, or maybe asked for feedback on it or something to that effect, curious about whether he received any, but decided to let my baby take on whatever niches he'd find himself without my fatherly eyes on him.

He still pops up here and there, but by now it's just a skeletal heritage -- few are the instances that stay with the original message (I'm quite sure mine was monospaced rather than using a proportional font), but on studying the code, it's always very obviously still my code. My type_text() method, the Javascript 1.0 safe code and all the rest, intact. Some change a few of the speed and delay variables I left behind, most add some message of their own, some make stylesheets to improve (or ruin) the teletype looks. Today a very tasteful example caught my eye, and again got that nostalgic feeling to find its way back to me, like so many times before.

I just did a google search for some of the code bits, and found about a hundred pages, some from tips and tricks sites offering tutorials on how to customize and use the code on your own pages, some explaining in German how to do it, with very nicely annotated source code, one substituting the textarea for a div tag, missing some polish to get newlines to work in the switch, one rather close to the original, but also pointing out that Douglas Adams has died.

I wonder if and how some note about me in the source would have changed how this play with words, code and web standards would have swept across the globe. Maybe I would have seen more mail traffic about it. Probably both in the form of the kind of joyful notes I did receive, and in the form of questions on how to adopt it and get it to run for some particular target environment. I suppose I would not have been much happier with than without that feedback, or perhaps felt bad about not responding to much of it. It is still a lot of fun to occasionally be reminded about it on random encounterns -- it's the kind of thing friends or net acquaintances occasionally tend to smile at, spread among themselves and end up broadcasting my way, too, unknowing of my relation to the code, and it is still about as fun as the first few times I saw it. It is the really simple ideas that tend to live long. The same thing applies to my scriptlets for comfy web navigation; they, too, show the same signs. In very rare cases, a complicated tool it takes hours to craft, will still be useful long afterwards, but mostly it's the small and simple ideas that live on.

If (or should I perhaps more likely say "when") I ever do a fun thing like this one again, I think I will make all the paramaters broken out of the code for easy customization. In the world of the web, the precious few who know programming are most frequently also the precious few who do original work. In a way, I think that gives us the responsibility of making our work easily reusable by the masses. I'm sure that is just as appreciated as the idea itself to all the smiling visitors out there. Of course, we can rigteously selfishly also ignore this Someone Else's Problem and do just as well, ourselves. But it's not really my style. If something should be worth doing, it should be worth doing right, and while I might be able to live up to that standard with my own work, when other players get in to the picture, I can only make it so much more or less likely that they also will. I think I prefer giving them an easy climb, if it doesn't cost me too much.

Oh! One more thing.

I'm so depressed.

3 older entries...

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!