Use your keyboard to play hangman, and view recent activity in the Feed section. Speak & Spell is live as my homepage.
Category: website
Speak & Spell!
Those of you who remember the Speak & Spell will probably love my first attempt at a website redesign based around it.
So far, you can type letters using the keys, and it has sounds I recorded from my actual Speak & Spell. The text is much bigger than the real thing, so it can be read, but it is limited to 8 characters like the real thing. The sounds are somewhat delayed on Firefox, and the text is in the wrong place in IE… but you can see the potential!
The image is from a patent application made by Texas Instruments. Hopefully they don’t mind if I use it!
Edit: it’s now my home page
Javascript Mergesort
A while ago, I couldn’t find any Javascript mergesort implementations, so I wrote one. The nice thing about mergesort is that it is “stable”, id est it retains the previous order of elements with equal value. Therefore it is great for sorting rows in a table on different columns sequentially. Also, the merge() function is handy for merging two sorted arrays into one big sorted array.
Check out Wikipedia for more info on mergesort and other sorting algorithms.
Here it is:
var MergeSorter = function(comparator) { var merge = function(a, b) { var aLen = a.length; var bLen = b.length; if(aLen == 0) return b; if(bLen == 0) return a; var i, j, k; i = j = k = 0; var result = Array(); while(i < aLen && j < bLen) { if(comparator.compare(b[j], a[i])) result.push(a[i++]); else result.push(b[j++]); } while(i < aLen) result.push(a[i++]); while(j < bLen) result.push(b[j++]); return result; }; return { sort: function(a) { var aLen = a.length; if(aLen <= 1) { return a; } else { var middle = Math.round(aLen / 2); var left = a.slice(0, middle); var right = a.slice(middle); left = this.sort(left); right = this.sort(right); var result = merge(left, right); return result; } } } }; var normalComparator = { compare: function(n1, n2) { return n1 >= n2; } };
Here is sample code that makes use of the MergeSorter and does some sanity checks. It could easily be turned into a set of unit tests.
var mockComparator = { calls: 0, compare: function(n1, n2) { this.calls++; return n1.num >= n2.num; } }; function writeError(str) { document.write('<span style="color: red;">' + str + '</span><br>'); } var size = 100000; var ary = new Array(size); for(var i = 0; i < size; i++) { var num = Math.round(Math.random() * size); ary[i] = {num: num, id: i}; } document.write('<br>'); var start = new Date().getTime(); var myMergeSorter = new MergeSorter(mockComparator); ary = myMergeSorter.sort(ary); var stop = new Date().getTime(); var executionTime = stop - start; document.write('Merge sorting an array with ' + ary.length + ' random integers in it...<br>'); document.write('Execution time: ' + executionTime / 1000 + 's<br>'); document.write('Result length: ' + ary.length + '<br>'); document.write('Comparisons: ' + mockComparator.calls + '<br>'); var ceilLgN = Math.ceil(Math.log(size) / Math.log(2)); var maxExpectedCompares = (size * ceilLgN - Math.pow(2, ceilLgN) + 1); document.write('Worst case (for this size): ' + maxExpectedCompares + '<br>'); document.write('Theoretical average (for this size): ' + (maxExpectedCompares - 0.2645 * size) + '<br>'); if(ary.length != size) { writeError('Result is not the right size: ' + ary.length); } for(var i = 0; i < ary.length; i++) { if(ary[i + 1]) { if(ary[i].num > ary[i + 1].num) { writeError('Sorting error at index ' + i + '! ' + ary[i].num + ' greater than ' + ary[i + 1].num); break; } if(ary[i].num == ary[i + 1].num && ary[i].id > ary[i + 1].id) { writeError('Stability error at index ' + i + '! ' + ary[i].id + ' greater than ' + ary[i + 1].id); break; } } } if(mockComparator.calls > maxExpectedCompares) { writeError('Too many comparisons executed!'); }
Edit on December 1, 2010: I modernized the code a bit by making use of object literals, closures, etc. The comparator no longer has to be passed down the recursion. In order to do that with merge() and sort() as top-level functions, the comparator would have to be assigned to a global variable. Also, I added a more thorough example of the usage, with sanity checks.
It is worthwhile to mention that some Javascript implementations, array.sort() is already stable. See, for example, the documentation on sort at the MDC. Since native implementations of sort() have the potential to be much faster, it may be worthwhile to check whether this is the case and if so implement user agent testing to determine whether to use Javascript’s sort, or your own implementation.
braindump – html 5
As pointed out on slashdot, the first public material on HTML 5 is now available from the W3C. http://www.w3.org/TR/2008/WD-html5-diff-20080122/
It’s a major victory that frames have been completely removed from the language. They have always been horrible for the UI, security, bookmarkability, etc.
However, I take major issue with their choice to standardize innerHTML into the DOM. The only reason I’ve ever used innerHTML is because sometimes it’s impossible to get IE to behave any other way. IE’s poor lack of support for DOM is no reason to standardize a workaround though! Not only does innerHTML promote bad programming practices, it can all-too-easily lead to injection attacks.
What’s Up / StatSVN
So, what are you up to, you ask? Well, my biggest project right now is adding SvnKit support to StatSVN. Instead of calling the svn command-line client executable many times while building statistics, SvnKit will allow StatSVN to make calls in native Java to the SVN API, meaning that it should be much faster. Hopefully, that will be the case. If so I’m also hoping my code will make it into StatSVN. The biggest challenge about this is adding this new functionality in while leaving the svn bin as a fallback option. The SvnKit calls will need to be multithreaded in a different way than the svn bin calls, which are using Runtime.getRuntime().exec() which has no requirement to “execute asynchronously or concurrently with respect to the Java process that owns the Process object.” Instead of using static methods to call Runtime.getRuntime.exec() multiple times from several threads, I’d prefer to use non-static methods. It’s an ongoing process.
In addition, I am trying to figure out what to do with my website here. I wrote the layout you see on the home page, but I’m not sure whether I want to continue using it. I’d like to have a site that’s somewhat integrated with a blog, but to which I can easily add any kind of advanced content or features. WordPress is nice, but I don’t yet know how easily extensible it is especially in regards to creating additional databases. I’ve been messing around with an installation of CakePHP. So far it’s kind of nifty, but I have a lot of learning to do. I already know the Fusebox framework very well, but I’d rather learn something new. I also need to get RoR set up. My friend Roy and I are working on a project, and I’ll need to know RoR for it anyway.
In other news, I woke up today and watched a baby squirrel running around like nuts on the tree outside my window. Very amusing.