coveter of classifications
06.16.2008 @ 1:44 AM CST
I've spent the last few months digging deep into ActionScript, the programming language for Adobe Flash Player. The result: I now have the power to create unspeakably irritating advertisement banners, surprisingly fun 2D physics-based games, and various charts of dubious usefulness. In the spirit of sharing, I now give you one of the latter: a smattering of ActionScript benchmarks in colorful, bubbly chart form.
This little project was originally inspired by a JavaScript benchmarking page I stumbled across, wherein the author quips "no one should care about JavaScript performance. But if you do, this page will help you get a feel for which operations are fast and which are slow." Pretty much the same rationale applies here - unless you're building a complex, cpu-intensive Flash game (like myself, hence my own interest), you don't need to worry too much about outer static variable access taking a few microseconds longer than inner static variable access.
Usage: click 'Test Iterations' to perform each benchmarking action the specified number of times. Unless you're on a very slow computer, even 150,000 should fly by fairly quick. On some pages, you can also click the 'Auto Test' button, which will incrementally test more iterations until it has a total duration of at least 100 ms, which should give you a decently accurate average duration (note that the number of iterations may be different for each benchmark). You can also hover over the individual bars to see more detailed statistics and the code performed in the iterations (typically without the loop code itself, with the exception of linked list iteration.) Also, feel free to right-click and select "View Source" to look at and/or grab the source code. As usual, the code is licensed under the Creative Commons Attribution-Share Alike 3.0 United States License.
Caveats: I'm still trying to build a better AxisRenderer so the benchmark groupings look more, er, grouped. The Flex BarChart can group ("cluster") by default, but I haven't found a native way to omit empty bars for unequal group sizes or display titles for all group members. Hopefully I'll get that figured out soon, along with a staggered benchmarking engine so that you don't have to wait for all the benchmarks to complete before the chart updates.
And naturally, I'll be adding some more benchmark variations in the near future. Function calls *are* positively thrilling, after all...
This little project was originally inspired by a JavaScript benchmarking page I stumbled across, wherein the author quips "no one should care about JavaScript performance. But if you do, this page will help you get a feel for which operations are fast and which are slow." Pretty much the same rationale applies here - unless you're building a complex, cpu-intensive Flash game (like myself, hence my own interest), you don't need to worry too much about outer static variable access taking a few microseconds longer than inner static variable access.
Usage: click 'Test Iterations' to perform each benchmarking action the specified number of times. Unless you're on a very slow computer, even 150,000 should fly by fairly quick. On some pages, you can also click the 'Auto Test' button, which will incrementally test more iterations until it has a total duration of at least 100 ms, which should give you a decently accurate average duration (note that the number of iterations may be different for each benchmark). You can also hover over the individual bars to see more detailed statistics and the code performed in the iterations (typically without the loop code itself, with the exception of linked list iteration.) Also, feel free to right-click and select "View Source" to look at and/or grab the source code. As usual, the code is licensed under the Creative Commons Attribution-Share Alike 3.0 United States License.
Caveats: I'm still trying to build a better AxisRenderer so the benchmark groupings look more, er, grouped. The Flex BarChart can group ("cluster") by default, but I haven't found a native way to omit empty bars for unequal group sizes or display titles for all group members. Hopefully I'll get that figured out soon, along with a staggered benchmarking engine so that you don't have to wait for all the benchmarks to complete before the chart updates.
And naturally, I'll be adding some more benchmark variations in the near future. Function calls *are* positively thrilling, after all...
04.09.2008 @ 12:37 AM CST
One of my favorite little elegances in Ruby on Rails is ActiveRecord's dynamic finder magic. It lets you perform simple model queries with as much readability as is conceivable in a method call:
Fortunately, a little experimentation, a covert glance at the ActiveRecord code, and a timely discovery of the wonders of inject led me to a successful implementation:
Much like ActiveRecord's dynamic finders, this bit of code accepts find_by and find_all_by methods with any variety of attribute names (as long as they're delimited by _and_, e.g. find_by_name_and_age). And while it doesn't accept an options hash for miscellaneous conditioning (yet?), it does have a few extras: you can query for the indices of matching elements instead of the elements themselves (e.g., find_index_by_name or find_indices_by_name), and it will match hash key/values in addition to methods.
Some example usage:
# Normal ActiveRecord call - tasty, but still a bit bland. Sandwich.find(:all, :conditions => ['meat = ? and tastiness = ?', 'turkey', 'medium']) # Dynamic finder - unequivocally delicious. Try it with chocolate! Sandwich.find_all_by_meat_and_tastiness('bacon', 'very')Lost in the wonders of such syntactic saltiness (er, sugariness), I frequently found myself using these kinds of commands on arrays of model objects I had already retrieved from the database. Naturally enough, all I encountered was a variety of colorful exceptions, but I continued to dream of a world where dynamic finders worked for arrays, too.
Fortunately, a little experimentation, a covert glance at the ActiveRecord code, and a timely discovery of the wonders of inject led me to a successful implementation:
class Array # Dynamic finder for Array class def method_missing(method, *args) # Get method match info; proceed only if a dynamic finder call super unless match = method.to_s.match( /^find_(by|all_by|index_by|indices_by)_([_a-zA-Z]\w*)/) # Determine finder type & attribute names/symbols based on method name finder = match.captures.first.to_sym finder_is_all = (finder == :all_by or finder == :indices_by) attr_names = match.captures.last.split('_and_') attr_symbols = attr_names.collect { |i| i.to_sym } attr_indices = (0..attr_names.size - 1) # Iterate through array elements, storing matches as we go (via 'inject') return (0..size-1).inject([]) do |matches, idx| el = self[idx] # Iterate through attribute names and match against hash values (if a hash, # attempting both string and symbol keys, since we can't distinguish them # from the dynamic method) or method names (using __send__) if el and attr_indices.all? { |attr_idx| (el.is_a?(Hash) and el[attr_symbols[attr_idx]] == args[attr_idx] || el[attr_names[attr_idx]] == args[attr_idx]) or (el.respond_to?(attr_symbols[attr_idx]) and el.__send__(attr_symbols[attr_idx]) == args[attr_idx]) } # Return first match (or index) unless this is a 'find all' command return (finder == :index_by ? idx : el) if !finder_is_all # If 'find all', add element to match array; otherwise, add index matches.push(finder == :all_by ? el : idx) else finder_is_all ? matches : nil # Return state of matches array for 'inject' purposes end end end endI'm sure there is some ridiculous way to rubyify this into three lines of code, but in the spirit of what this code does (making code prettier), I figured I'd avoid the obvious potential for irony.
Much like ActiveRecord's dynamic finders, this bit of code accepts find_by and find_all_by methods with any variety of attribute names (as long as they're delimited by _and_, e.g. find_by_name_and_age). And while it doesn't accept an options hash for miscellaneous conditioning (yet?), it does have a few extras: you can query for the indices of matching elements instead of the elements themselves (e.g., find_index_by_name or find_indices_by_name), and it will match hash key/values in addition to methods.
Some example usage:
# Define an array of hashes (with name, birth year, and state entries) hash_citizens = [{:name => 'Mike', :birth_year => 1982, :state => :illinois}, {:name => 'Barack', :birth_year => 1961, :state => :illinois} # Define an array of Citizen model objects (with attributes matching entries defined in hashes above) model_citizens = [Citizen.new(:name => 'Mike', :birth_year => 1982, :state => :illinois), Citizen.new(:name => 'Barack', :birth_year => 1961, :state => :illinois)] # Hash key/values will be matched against names supplied in method - :name (or 'name') for find_by_name, etc. # Any other objects will be matched using messages (method calls) hash_citizens.find_by_name('Mike') model_citizens.find_by_name('Mike') # Multiple matches will only be returned if 'all' is present in method name model_citizens.find_by_state(:illinois) # Returns the first match only model_citizens.find_all_by_state(:illinois) # Returns all matches in array, in order # Indexes are returned similarly model_citizens.find_index_by_name('Barack') # Returns 1, the position of 'Barack' in the array model_citizens.find_indices_by_state(:illinois) # Returns [0,1] # If no matches are found, returns nil (singular calls) or empty array ('all' calls) model_citizens.find_by_other_stuff # Returns nil model_citizens.find_all_by_other_stuff # Returns empty arrayI've written 40 or so tests for these routines, so they should work properly enough, but do let me know if you spot any issues. And as always, any other comments or suggestions would also be greatly appreciated!
04.03.2008 @ 6:21 PM CST
JavaScript has come a long way in the last few years. Once merely the domain of primitive drop-down menus, image rollovers, and other assorted gimmicks, it now powers countless trendy Web 2.0 destinations, providing ever-popular AJAX queries and, um, even more gimmicks. More than you ever thought possible.
Lately I've been exploring both the gimmicky and functional sides of JS, both at my job and in my many assorted Rails projects. I've worked extensively with a commercial drag-and-drop tree library and hunted down countless other data browsing tools, but I've always turned up short of exactly what I needed - essentially, a lightweight tool that could peruse the kids of deep object relationships you get by performing good database normalization. Trees are useful, but they almost always focus on IDs and generally require you to conform to some irritating XML schema for data delivery.
As I continued to develop on my (relatively) new Mac, I found myself using the column view in finder almost exclusively - and suddenly it dawned on me that such a view could do equal justice to arbitrary data sets as it could to my file system. Thus, I began work on what I dubbed the Multi Viewer Trary; originally just a proof of concept, I've now decided that it could be quite useful, thus prompting its evolution into an Official Project.
There is still a laundry list of improvements to make before it's truly distribution-ready, but you're welcome to check it out, look at the code, and offer suggestions. I know what *I* want it to do, but I bet there are a whole bunch of similarly tree-hating (er, tree-view-adverse) fellows out there who are clamoring for some Mac-inspired interface goodness in their web applications.
02.18.2008 @ 12:00 PM CST
Paper bank statements accumulate in piles around my room faster than a backpedaling politician. So you can imagine my surprise and wonder when I received the following missive from Capital One:
What a deal! How do banks even make money any more?Simplify your account management even more by stopping your paper statements and just getting them online - for FREE!
01.12.2008 @ 5:16 PM CST
Nearly everyone has a collection of photos, scribblings, crafts, and innocent/incoherent writings that form a sort of quirky, historical self-portrait. More often than not, parents are the gatekeepers of these items, hoarding them at their parent-ish domiciles - which is fine in my book (do you really want your colleagues to see naked little you in a bathtub?)
But thanks to the Interweb, these self-portraits are merging into the online world. Today's social-networking-hungry teens, what with their obsessive personal blogging and drunken Facebook photography, are the most obvious benefactors, but you might be surprised at what dirt you can dig up on the 9600 baud geek crowd - like me, for instance.
Because when you're thirteen years old and building up your fluency in QBasic, you might just want to make a game about... surfing. And jumping. And doing stunts. And sharks. I give you "Stunt Surfer":

The graphics are clearly way ahead of their time - these days you'd need a next-gen 1024 MB nVidia just to keep up. And you wouldn't believe the gameplay, not to mention the veritable cornucopia of secret moves available for discovery. And check this out - you even get to choose the color of your surfer shorts:

Why on earth Midway didn't pick this up back in 1996 we'll never understand, but what we do know is that some people just can't see the sublime beauty in surfing/blackflip combos, decrying it as:
In any event, I guess this means that my digital self-portrait has neon purple swim trunks. Beat that.
PS: Yes, you can actually download the game from games.qbasic.com, and yes, I called myself "Michael Ziphrus" online back in those days, because the Internet was still a shady place. It's completely un-shady now, of course.
But thanks to the Interweb, these self-portraits are merging into the online world. Today's social-networking-hungry teens, what with their obsessive personal blogging and drunken Facebook photography, are the most obvious benefactors, but you might be surprised at what dirt you can dig up on the 9600 baud geek crowd - like me, for instance.
Because when you're thirteen years old and building up your fluency in QBasic, you might just want to make a game about... surfing. And jumping. And doing stunts. And sharks. I give you "Stunt Surfer":
The graphics are clearly way ahead of their time - these days you'd need a next-gen 1024 MB nVidia just to keep up. And you wouldn't believe the gameplay, not to mention the veritable cornucopia of secret moves available for discovery. And check this out - you even get to choose the color of your surfer shorts:
Why on earth Midway didn't pick this up back in 1996 we'll never understand, but what we do know is that some people just can't see the sublime beauty in surfing/blackflip combos, decrying it as:
Well, there you have it. Personally, I'd call the gameplay something like "dubious" or "convoluted" rather than ganging up on it with two such sinister, ugly adjectives, and I'd certainly place "well packed" before "rather poor" in the name of good paragraph design, but who am I? I'm just a man who used to be a boy who wanted to do some tricked-out backflips over some killer waves.A rather poor surfing game featuring minimalistic graphics and highly doubtful and awkward gameplay. It's a well packed game, featuring nice menus and very good documentation.
In any event, I guess this means that my digital self-portrait has neon purple swim trunks. Beat that.
PS: Yes, you can actually download the game from games.qbasic.com, and yes, I called myself "Michael Ziphrus" online back in those days, because the Internet was still a shady place. It's completely un-shady now, of course.
01.02.2008 @ 6:53 PM CST
Posts on this site will henceforth be available in a tasty RSS package for your consumption:
http://www.mikelaurence.com/posts/rss
Of course, right after I had finished coding my own RSS generator earlier tonight, I discovered that there is a Ruby RSS library in the public domain. However, Rails is efficient enough that my efforts took under 45 minutes, so I can't say I'm unhappy.
http://www.mikelaurence.com/posts/rss
Of course, right after I had finished coding my own RSS generator earlier tonight, I discovered that there is a Ruby RSS library in the public domain. However, Rails is efficient enough that my efforts took under 45 minutes, so I can't say I'm unhappy.
12.30.2007 @ 11:55 PM CST
About two years ago, I decided to write my own blogging software as an exercise in learning PHP / MySQL. But while I did acquire a decent working knowledge of those languages (along with a mostly-functioning blog), my ill-fated creation was doomed for other reasons - mainly, a lack of time to upload anything of interest. Various blog incarnations have surfaced at mikelaurence.com in the interim, but they've suffered from similar disinterest on my part. After all, who can keep up with MyLinkedFaceSpace anymore, not to mention their own private website?
Fortunately, I feel so very wonderfully witty (and alliterative) these days that I can't help but think I'll buck the trend this time. And the technology is more fun, too - MikeBlog 4.0 is written in 98% organic, MSG-free Ruby on Rails and plugs in nicely to everything else on my site (though admittedly "everything else" doesn't amount to much as of yet.) Plus, I've got some interesting little projects that are nearly ready for public consumption, so hopefully the past 22 1/2 or so hours of blog programming and design won't be lost as just "practice". Because honestly, who likes to practice? I could've been slamming some pogs (note clever tie-in to title.)
Fortunately, I feel so very wonderfully witty (and alliterative) these days that I can't help but think I'll buck the trend this time. And the technology is more fun, too - MikeBlog 4.0 is written in 98% organic, MSG-free Ruby on Rails and plugs in nicely to everything else on my site (though admittedly "everything else" doesn't amount to much as of yet.) Plus, I've got some interesting little projects that are nearly ready for public consumption, so hopefully the past 22 1/2 or so hours of blog programming and design won't be lost as just "practice". Because honestly, who likes to practice? I could've been slamming some pogs (note clever tie-in to title.)
