Category Archives: JavaScript

Becoming the Maintainer of an Abandoned Open Source Project

Lots of ink will probably be spilled documenting the stories of what people did during the summer of 2020. With COVID-19 spreading throughout the world and many places going into lock-down, it was an uncertain and strange time. Many people took the opportunity to catch up on old TV shows, learn about investing, or create a side hustle. Me? Well, somehow I found myself becoming the maintainer of one of my favorite open source projects.

Part 1: The Big Rewrite

Almost 4 years ago I was gearing up to rewrite a rather huge AngularJS app. I had been a bit disillusioned with Google’s decision to kill off AngularJS (don’t get me started with Angular 2), and I was looking to build an app that wouldn’t be tied to the whims of Google, since they have a tendency to shut things down. After surveying the landscape, a solution involving the open source libraries React, Redux, and Material UI seemed like a good fit. All that was left was finding a good datatable component…

mui-datatables looked clean and worked smoothly. It made my app look beautiful, and I was excited. To add to this, the official github repo seemed to be buzzing with activity. My first feature request got 12 reactions and a bunch of comments. There was clear enthusiasm about this project, and it stood out amongst all of the Material UI based datatables I evaluated. I felt like I’d found the final piece to my puzzle.

For a while everything went smoothly. I was no rush and my work had me juggling several projects, so the rewrite took place in-between other tasks I was doing. It wasn’t until I was a few months in that I realized I needed an ability that mui-datatables didn’t provide. “No worries” I thought, “I’ll just put in another feature request”, but when I checked the repo, I noticed Greg, the library’s creator, was no where to be seen. Instead, someone named Gabriel was now running the show.

At first this was fine, and I was glad to see someone had taken up the mantle and was moving the library forward, but I soon found myself increasingly frustrated. I was so close to having the library that I needed, yet many of my pull requests (PRs) were left to languish and some updates to the library made my life harder. To add to this, Gabriel wanted to rewrite the whole library, deeming its internals fundamentally flawed. He made a pinned issue announcing this big rewrite (“Version 3.0”), and said it would fix the table’s internals and possibility completely change its API. However, after this announcement he continued to work on features for version 2.x, and in updates months after this announcement he would state that he hadn’t started on version 3 and was still thinking about things.

I was concerned. Once again I looked at other datatables, but I was filled with dread when I concluded that mui-datatables was still the best fit for what I was doing. I either had to stick it out and convince Gabriel to take my PRs, or fork the library and be on my way… and well, I forked it. And that actually turned out to be a pretty freeing experience. But there are downsides to forking that cannot be ignored:

  • You don’t get updates from the community – you’re on your own.
  • When you eventually leave your position, you leave the next developer with learning the fork you made. I’ve been in this boat and it’s not a fun boat to be in, especially as the fork gets old and bugs are found.

After the app I had been working on launched, I thought a little more about these 2 points. One of the key reasons for the rewrite (but not the only reason) was to get off of the now archaic AngularJS framework so that future developers could easily jump into the project. But leaving someone with a forked library that was heavily modified seemed to clash with this idea.

I decided to once again check in with mui-datatables to see if there was some way we could reconcile. What I found was 60 PRs, 2 pages of unanswered issues, and someone @-ing Greg and Gabriel, asking if the project was dead. The last release was 3 months old, and it had a number of problems (a malfunctioning resizable column feature, the responsive design was broken, etc etc). After Greg and Gabriel, I was the 3rd biggest contributor to the project, and with all the updates I’d done in my fork, I realized I was probably the most qualified person to take over. To add to this, COVID-19 was spreading around the country and my work had recently closed down. I was at home with nothing to do for the foreseeable future. I needed something to take my mind off things.

I decided to reach out to Greg on Twitter to let him know the situation and ask if I could take over. I’d previously sought him out to ask why he’d left the project so I knew he’d be responsive on Twitter. A week later he handed me the keys. I then went to 2 of my oldest PRs, merged them in, and did a release. I was the new maintainer.

Part 2: mui-datatables 3.0

Gabriel briefly returned to wish me well. He told me his time had become scarce, and he simply didn’t have enough of it to spend on the project. Even though I’d felt a lot of frustration with some of his decisions, we’d been friendly and I appreciated the work he’d done. Had he not taken on the project, it most likely would have died. However, a year had passed since he’d made his announcement about the next version of the library. Was a version 3 still on the table? I’d done a lot of work on my fork and there were a lot of PRs. Maybe there was enough new stuff to justify a big release.

For the next two weeks I poured through the PRs and open issues. It was oddly fun and proved to be an eye opening experience. Some of the stuff people submit is completely nonsensical while other things are highly complex and clearly had a huge amount of work put into them. For example, one person had rewritten the whole library in TypeScript, and while this was a neat idea, it was completely impractical and would have made it almost impossible to merge the other updates in (plus, I’m not completely sold on TypeScript – but that’s another story). On the opposite end, there were some requests that were small with little explanation. Often times they didn’t work at all and/or caused the tests to fail. It was like people submitted their work without checking it.

I tried to be nice. After all, each PR represented someone spending their own free time to better this library. At the very least they deserved someone trying out and reviewing the changes that they made – even if they had to wait a year. And to my delight, people were pretty cool. I either got a positive response thanking me for looking at their PR, or no response at all.

Of the 60, I ended up accepting 23. The vast majority of these were bug fixes and minor updates. The only submission that really fell into the “cool new feature” category was one that added an injectable component feature. During this period I also ported over most of the updates from my fork, which in the end, accounted for all but 5 of the new features/API updates. A thorough review of the code base was also done which cleaned up a hand full of anomalies. For example, most of the deprecation warnings had accidentally been disabled in version 2.14.0, and starting in version 2.13.1, a large 5MB file was accidentally being included in the npm package. No one seemed to have noticed these things though.

I also updated the library from using version 3 of Material UI to version 4. In the year that had passed, most of the Material UI community had moved on to version 4. Not updating the library to correctly work with version 4 had probably hurt adoption. When I had parted ways the previous year, mui-datatables had 15k downloads per week on npm and it’s closest competitor, the feature heavy material-table, had 7k a week. Now the tables had turned. Material-table was crushing it at 80k downloads a week to mui-datatable’s 25k. The version issue most definitely wasn’t the only reason mui-datatable had lost ground, but I have to imagine it was a significant factor in people’s decisions.

In the end, version 3 would be no great revelation, but it would be a step forward and hopefully a step in the right direction.

Part 3: The Rise and Fall of a Maintainer

After it was released a few people chimed in to say thanks and report bugs, but there was no big celebration that the library was back to getting updates. I got the impression that many people using the table had built their apps around it a year ago. It didn’t seem like it was attracting a ton of new users. From github stars, I could tell that on average, 1.35 new people were starring the library a day, which seemed a bit lower than it had been in the past.

To get things going again I decided to start work on two features I felt were essential:

  • A cell rendering method that would significantly boost performance.
  • Draggable columns.

I had a soft spot for draggable columns. It had been discussed with feverish enthusiasm when I was originally looking at the table, and I felt like it would be poetic as the first big feature of the 3.x era. I wanted something that was nice though, I didn’t want something cheap looking. So I got to work and created what I felt was a slick draggable column feature:

click to play or pause

Most people will say they don’t care about small little effects like this – that all they really want is the functionality, but over time I’ve found this to be false. Little touches like this add up, and overall lead to users liking a product more. 

As I prepped a new release, I began to talk about new features with the few of the people still hanging around. Maybe a grouping feature should be next? Editable columns? I was excited. I was going to get this table back on track and soon it would have features that rivaled material-table. But in addition to the lack of activity in the repo, something else bothered me: Surely I couldn’t be the only one who felt datatables for Material UI were lacking? Hell, when I was doing AngularJS there were several great community options. What was going on?

I went digging, and found my answer on the material-ui github repo. In a thread lambasting material-table, several people stated that they weren’t happy with the community options. The co-creator of Material UI, Olivier Tassinari, satiated the criticism by ensuring them that they were hard at work on an official datatable component. It would be ready for preview in September – basically at the end of the summer.

I had been out of the loop, and though it seemed obvious, apparently the community was displeased with both mui-datatables and material-table. The creators of Material UI realized they needed an official solution, so in October of 2019 they’d announced plans to create one. That explained why no other table had come forth, and it made me feel like mui-datatables and material-table were both lame ducks. A good solution was on the way, and there was no point in a community project if an official table was going to be supported. (however, I would later learn that certain parts of this official table were for paid users only – so material-table and mui-datatables would still have a place in the future)

I was a little distraught, but decided to continue work, albeit at a slower pace. Then, after 10 weeks of being at home, I got the call to come back to work. I reintegrated mui-datatables into work my project and showed off some of the new features. My team lead seemed impressed and was thankful we were no longer using a forked project. With work on mui-datatables now restricted to evenings and weekends, my contributions to it slowed even more. Then, one day in late September, I handed in my resignation at work.

Wait, what?? Oh yeah, probably forgot to mention that during my time off I was kind of stressed about my future. My work had been extremely generous in paying us to stay home and do nothing, but there were rumors about leave without pay in the Fall. With no telework option available and no assurances made about what might happen once the leaves started turning, I had decided it was best to hedge my bets and look for another position.

In a twist of fate my new job would involve working on another AngularJS 1.x project (it never ends!) and possibly porting it to React (though as of now that hasn’t happened – my guess is we’ll still be dealing with AngularJS 1.x apps 10 years from now, though that’s a topic for another time). Now I had even less motivation to continue work on mui-datatables. I didn’t want the project to fall back into disarray, so I felt like the only reasonable thing to do was to find a successor. Thankfully during my time as maintainer another developer, Woo Dohyeong, had joined me in my quest to better the library. He was the obvious choice to take over and with Greg’s blessing, I passed the torch. After Woo made his first release I stepped back.

It was bittersweet. Part of me knew I didn’t have enough time to be a maintainer forever. It’s a job that gobbles up the extra minutes of your day and its mostly thankless. I didn’t talk too much about it above, but there were a few days where I would handle half a dozen questions, and the majority of people wouldn’t say thanks or respond, some people would even be rude. However, reviving the table and improving upon what so many others had built was rewarding. There was a sadness in stepping back, but it was for the best.

Final Thoughts

Well, I didn’t expect this to be so long, but the story (even trimmed down) turned out to be much longer than I thought it would be. I needed a place to write it down though, and if you read it, thank you for reading my story. The summer of 2020 was a crazy time, and even this bloated blog post barely scratches its surface. Hell, I didn’t even write about my bike rides through empty streets or obsession with Hollow Knight (and Animal Crossing, and Cuphead), not that those things are in any way relevant to mui-datatables, but they filled the gaps between development. Anyway, hopefully you found this entertaining or enlightening. Next time you use a piece of open source, be sure to show appreciation to the maintainer, and don’t be afraid to contribute yourself. If you have the time it can be a fun little adventure. Also, don’t get too caught up in the endless cycle of front-end rewrites. There’s a certain madness to it.

figlet and grunt-figlet npm packages

Last month I discovered Grunt, which is described as a “JavaScript task runner” by its creators. What’s that mean? Well, it allows you to automate mundane tasks like JS-linting, JavaScript/CSS minifying, compiling LESS into CSS, watching files for updates, and other development tasks. I had personally been using makefiles for these types of tasks, but after coming across a Grunt plugin for inlining AngularJS templates, I ended up going down the Grunt rabbit hole and converting over my makefiles to gruntfiles.

Once I had everything working with Grunt, I thought it might be fun to try and write my own plugin. Since Grunt is node.js based, I decided it might be neat to use the figlet.js library I wrote a while back to auto-generate ASCII banners for source code files. figlet.js was originally written to be browser-side only, so I had to do a little reworking to get it to work with node. However, after I had created an npm package for it, I wrote a simple grunt plugin around it called grunt-figlet. You can the result of a test run of the plugin below.

/**
 * _________            .___      
 * \_   ___ \  ____   __| _/____  
 * /    \  \/ /  _ \ / __ |/ __ \ 
 * \     \___(  <_> ) /_/ \  ___/ 
 *  \______  /\____/\____ |\___  >
 *         \/            \/    \/ 
 * This is a message for the comment body.
 * More random text...
 */
function abc(a,b,c){console.log(a+b+c);}var a=1,b=2,c=3;abc(a,b,c);

My office mate pointed out that it sort of defeats the purpose of minifying, but I still think its cool. The Text to ASCII Art Geneartor has a similar code comment feature, though it supports more languages. I’ll probably add support for other commenting styles into the grunt plugin later on, though right now I’m not sure if Grunt is used for any non-web development type projects.

After posting the project up someone submitted a change to allow the figlet library to work at the command line. However, I decided to break it out into its own package, so someone could use the library without it interfering with an existing installation of figlet. Ultimately I think it would be cool if this command line app mirrored the behavior of the c-based app. I mentioned the idea on the figlet mailing list, and Ian (the I in FIGlet) seemed to like idea. However, unless there’s suddenly a bunch of interest, right now that’s low on my list of things to do (though if you’re up for the task, feel free to submit changes to it).

Keyboard Layout Analyzer 3.0 Beta Release

I’m not completely done, there are still a hand full of new features I want to add, but I have a feeling that if I put off the update any longer, it’s never going to get posted up. So today I’m releasing the newest version of my Keyboard Layout Analyzer (KLA), which I’m dubbing version 3.0, since it’s the 3rd overhaul of the layout.

kla

New features:

  • Analysis results can be shared.
  • Charts are interactive / contain hover effects.
  • There are more “Display” options in the various results sections.
  • You can turn on/off certain keyboard data in the individual results sections.
  • The heatmap uses a more realistic heatmap visualization, has a table of key stats, and I’ve re-added in the mouse over effect (the biggest complaint in my previous version was that I took this out).
  • Miscellaneous section has charts for each piece of data.
  • Layouts you create can be submitted.

The biggest change though is the UI. The main reason I created this version was because I thought it would be a fun project to get better familiar with AngularJS. MV* JavaScript libraries like Angular have taken off recently because they make maintaining, updating and reusing front-end code easier. I felt the code I wrote for version 2.0 of KLA got a little spaghetti-ish at points, so this really appealed to me.

To keep things short, I’ll go ahead and just cut to the chase: Angular lived up to its hype. It was great at giving structure to the app. The new KLA code base feels a lot more sane and the HTML is easy to follow. If you do front-end development, I’d highly recommend you try Angular out. If you need a starting point, egghead.io has some great tutorial videos and Dan Wahlin has a really nice AngularJS Fundamentals video. And as a side note, even though Angular’s official documentation is good, I wouldn’t start there. I found it to be somewhat cryptic when I first started out. It’s a good reference point after you’ve gotten your feet wet though.

The only negative I came across with Angular was that it had a steep learning curve. I ended up having to back track a few times and re-do sections of the app because I didn’t do them the “Angular way”. Angular forces you re-think how to do certain actions and it uses some strange terminology, but once you get past all of that, it’s a pretty powerful tool.

Removing JK.js

My early days in JavaScript reminded me of an old puzzle game called The 7th Guest. In The 7th Guest, if you had trouble solving one of the puzzles, you could ask for a hint from the library. After getting 3 hints, the puzzle would be solved for you, but you’d miss the video that was shown after completing the puzzle, therefore missing a part of the game’s story. If you missed too many videos, you’d have no idea what was going on.

When I first started learning JavaScript, I kind of felt this way about third party libraries. I didn’t mind using ones that provided UI components, but I felt I’d be missing out on something if I used jQuery. So I wrote my own jQuery-like utility library called JK.js, which I used in my personal projects. However, I no longer feel like I’d be missing out on anything by implementing low level utility functions. What I really care about is writing an app, not a library. So as I’ve been refactoring my projects, I’ve been removing JK.js and replacing it with jQuery.

Flatly

Bootstrap makes it easy to create nice looking web pages. I decided to use an awesome Bootstrap theme someone created called Flatly, though I tweaked the colors a little bit. I also used an image from subtlepatterns.com as the background to make it feel a little livelier. However, while Flat is cool looking, I worry the result may be a little too flat, so at some point I may backtrack.

jqPlot

The charts in my previous KLA versions used a modified version of PlotKit. PlotKit was a good library, but it hasn’t been maintained in years. On top of that, my modifications to it used my own JS library JK.js, which I wanted to weed out, so I knew I needed a new chart library if I was to redesign this app. I decided upon jqPlot since it was jQuery-based and had a lot of great functionality. So far I’m pretty happy with it.

Heatmaps

I came across a neat visualization library for heatmaps, so I decided to use that over the simple key-color heat maps I was creating before. Interestingly, the author of this library also has his own keyboard heatmap app. When I saw this I felt a little weird about using the library – but since the heatmap library was its own separate component, I figured it wouldn’t be too weird if I used it too.

Future Updates

I still a have more features I want to add, ones that will be more stat based, so hopefully there’ll be another update in the next 2 weeks or so. I also may update my Typing Speed Test to use this same type of layout (it’s in dire need of an update). If you have any feature requests let me know. Special thanks go out to Wayne D. for submitting a bunch of awesome ideas and feed back!

Crafty Tricks for Avoiding XSSI

While looking at the response data from certain AJAX requests in GMail, I noticed that they were prepending their response JSON with either a number, “while(1);”, or “)]}'”. They do this to avoid cross-site inclusion attacks (XSSI), where a malicious site includes a file from another site in order to steal its data. Example:

<-- Code on evil site -->
<script src="http://gmail.google.com/user_email.json"></script>

Even if the data in the JSON object isn’t wrapped in a function or set to anything, it can still possibly be stolen by overriding the Array constructor or defining a setter property on the Object prototype. Most of these holes were plugged up after being discovered, but they still exist in some older browsers, which is why GMail is putting these safe guards in place. Two of the techniques of the mentioned, “while(1);” and “)]}'”, are pretty straight forward. “while(1);” will cause an infinite loop, keeping an attacking site from reaching its payload, and “)]}'” will cause a syntax error, stopping the rest of the script from executing. But the number trick is not so straight forward, and it had me scratching my head. The response data looked something like this:

123
["Email message", 123, "?", 0];

Was this to cause a syntax error? I decided run the code – nope, no syntax error. In fact, it turns out that the above code is valid JavaScript. However, instead of returning the last line, the array, it returns undefined. Wait a second, how could that possibly evaluate to undefined?

To experiment more, I decided to try executing:

123
456;

Which evaluates to 456. And then:

123
"test";

Which evaluates to “test”.

So when the second item is an array, it evaluates to undefined, but when it’s a number or string, it evaluates to the second parameter? WTF JavaScript? After showing the issue to a few co-workers, none of us were able to figure out what was going on, so I took the question to StackOverflow.

Within a few minutes, freakish had the answer. It turns out that JavaScript’s automatic semi-colon insertion was to blame. In the second and third cases, JavaScript realized that “123 456” and “123 ‘test'” weren’t valid statements, so it inserted a semi-colon at the line breaks. However:

123 ["Email message", 123, "?", 0]

IS a valid statement. What’s happening is that the []’s cause JavaScript to look for a property value on the number object. The comma statement returns its last parameter, 0, so JavaScript looks for a property named 0 in the number’s prototype chain. When it finds nothing, it returns undefined. This can be tested with the following code:

Number.prototype["0"] = "test";
123["Email message", 123, "?", 0]

Which evaluates to “test”.

Wow. That is so completely ridiculous. However, it’s also pretty clever on Google’s part. It allows them to have another XSSI-busting technique, and I’m assuming they use a variety of methods in case a hack is discovered which gets around one of the other techniques. Anyway, I found the number trick to be especially interesting, so I figured I’d share it here. And again, freakish deserves the credit for figuring out what was going on.

Book Review: “JavaScript: The Definitive Guide”

I felt a little nerdy asking for this for Christmas, but it was worth while read

The web apps I write for this site are written in JavaScript, and after landing a web developer job two years ago, I’ve focused more on getting better at everything web related – through reading blogs, writing apps, and reading books.

As far as books were concerned, there had been one which had consistently caught my eye, but which I’d kept resisting due to its size. I have a short attention span and I was worried I wouldn’t finish it. I also tried to foolishly convince myself that I probably already knew most of what it covered – after finishing JavaScript: The Good Parts and a couple other short books, I felt I had a pretty good handle on the language. What else could there really be to know? But temptation got the best of me, and I’m glad it did, because it’s a great book and I learned a ton.

JavaScript: The Definitive Guide, by David Flanagan, is 1078 pages* of densely packed information on the JavaScript programming language. It’s not filled with fluff and it covers an amazing amount of ground. In truth, it’s really 3 books in one: a book on the core JavaScript language, a book on client-side JavaScript development, and a reference book for client-side and core development. It’s written for people familiar with programming who want to gain an in-depth understanding of everything they can do with JavaScript.

An experiment in retaining information

I didn’t want to read this book and then 6 months later not remember anything I’d read. I had a friend who’d read it and not gotten much out of it, but I believed that may have been because of information overload. Leisurely reading technical books can be fun, but the information isn’t going to stick unless you use it or discuss it. So I decided to try an experiment – after each chapter, I was going to write up a set of notes on what I found interesting in that chapter. That would force me to go back over the information and help me document what I may want to go back to later on.

I did this on the wordpress blog Reading the Rhino JS Book. It’s really just a collection of notes, but it’s a great way for me to go back and go “oh yeah, this is what I found interesting in this chapter”. In the beginning I was really excited and felt it was a great way to read a technical book – if you’re going to invest the time in reading a large book, you might as well invest the time to try and retain the information. However, I’d be lying if I didn’t say I got tired of writing up notes on each chapter. So my feelings are mixed. I do believe it helped in organizing what I learned and found interesting, but it was also a bit of a pain towards the end. I haven’t yet decided if I’ll take notes on each chapter of the next programming book I read, but I can say it was useful to do so in this case.

Who should read this Book?

I would not recommend this book for people who are new to JavaScript. It does contain almost everything you need to know, but it’s not really written for the newbie. When you’re new you want to get up and running quickly, and you want a brief introduction to the tool set you have at hand. For that, JavaScript: The Good Parts is probably the better choice.

If you do front-end web development professionally, or you just really like writing web apps, this book is worth picking up. It’s written to be readable and thoroughly covers the current set of web technologies you have at your finger tips with JavaScript. Even if you feel like you have a good handle on things, this book does a good job at filling in the gaps. As an example, I knew JavaScript did automatic semicolon insertion if you forgot to include semicolons**, but I wasn’t sure how this worked. It turns out that the ECMAScript spec has a clearly defined algorithm for this, and knowing how it works gives some insight into using the language.

Final Thoughts

This is probably now my favorite book on JavaScript. A couple weeks ago I was openly pondering where I wanted to go web development wise, and I think, for now, I’m going to focus on client-side development. This doesn’t mean I’m going to ignore back-end stuff, I do a lot of PHP at work and there’s other back-end technologies like Ruby, Python, and Node which look interesting, but the client-side looks like it has the most utility for app developers. It’s nice to be able to quickly write a single page app, upload it, and have anyone be able to use it.

* 716 pages if you don’t include the reference sections.
** Technically the interpreter doesn’t insert semicolons, it just treats a line break as the end of a statement in certain situations. Thus it’s sort of simulating semicolon insertion.

Tone Playing Experiment with HTML5’s Web Audio API

tl;dr: Tone Player (works in Google Chrome and Safari 6+ only)

One of my favorite parts of the QBasic class I had in high school was discovering how to play sounds. It introduced a whole new layer on which to experiment with.

Until recently, adding custom sounds to a web application has not been a simple task. Thankfully, the W3C is working on a new high level audio specification called the Web Audio API that allows you to easily create and play sounds. Webkit based browsers have pushed out an implementation of this spec (Chrome and Safari 6+), and hopefully other browsers will follow suit soon. Previously, Mozilla had been working on a more lower level audio API called the Audio Data API, but it is now deprecated.

After seeing a few fancy demos of the Web Audio API, I decided to do some digging to see what all it could do. Sadly, there aren’t a lot of great up-to-date tutorials on how to use it. A couple of exceptions I found to this were the getting started tutorial at creativejs.com and a hand full of nice blog posts by Stuart Memo. However, I was also surprised to find that the Web Audio WC3 specification is actually very readable.

So with this fancy new API, how hard is it to create and play a simple tone? It’s pretty easy actually. The below code gives one example.

var context = new webkitAudioContext(),//webkit browsers only
    oscillator = context.createOscillator();

oscillator.type = 0; // sine wave
oscillator.frequency.value = 2000;
oscillator.connect(context.destination);
oscillator.noteOn && oscillator.noteOn(0);

You can also play more than one frequency at once. However, I found that playing too many tones together can crash the browser, so this is something you have to be careful about, and there may be a better way to do this.

var context = new webkitAudioContext(),
    oscillators = [], num = 5, ii;

for (ii = 0; ii < num; ii++) {
    oscillators[ii] = context.createOscillator();
    oscillators[ii].type = 0;
    oscillators[ii].frequency.value = 2000 + ii * 200;
}

var connectIt = function(ii) {
    oscillators[ii].connect(context.destination);
    oscillators[ii].noteOn && oscillators[ii].noteOn(0);
    ii++;
    if (ii < num) {
        setTimeout(function() {connectIt(ii);}, 1000);
    } else {
        setTimeout(function() {
            for (var jj = 0; jj < num; jj++) {
                oscillators[jj].disconnect();
            }
        }, 1000);
    }
}

connectIt(0);

Oh, and you'll notice I check for the noteOn property before trying to use it. The spec says you need to use it, while Chrome tells me it doesn't exist. This appears to be a possible bug in Chrome's implementation.

With the basics down, I decided to create a simple Tone Player. It doesn't add much to what I've already showed you, but it has a few extra features. And in all honestly, it was actually made more to serve as a hearing test for myself. A couple years ago I had a hearing test done which indicated I had hearing issues, especially in my left ear. Since then I've been trying to take care of my hearing as best as possible. This tone generator is fascinating for me because I actually found that I can't hear certain frequencies (near 12000Hz), unless I really jack up the volume, but I can hear others fine all the way up to the 20k's. Hrm, probably time to schedule another appointment.

Anyway, enough about my hearing issues. Even though the API currently only works in a couple of browsers, it's a lot of fun, and I've hardly even dared to scratch the surface with this entry. I recommend checking it out if you have a few moments. If you're looking for a less experimental, more cross-browser way to play sound, I'd recommend checking out one of the many JavaScript libraries that have popped up to play audio. I'll link a few below for those who are interested.

Finding and fixing JavaScript errors that no one tells you about

Earlier this month I saw an interesting article on logging client side JavaScript errors, and then another one that showed how to do it using Google Analytics. The idea was clever and easy to implement, so I decided to try out the Google Analytics version when I posted up my new Keyboard Layout Analyzer last week. When an error occurred, I’d log the file it happened in, the line number it happened on, the browser’s user agent string, and the error message itself. Below you can see a screen shot of the error log after 1 week.

Google Analytics Panel

I’m unsure what errors 2-5 are. There’s no associated file, and the error message is simply “Script error”. The Analyzer gets an average of 90 visitors a day, so these account for a small percentage of users, though it is a little peculiar. Error 1 is definitely a real error though. I had been checking the stats every day, so when it popped up I actually got a little excited.

Usually when I discover an error, it stings. Users don’t often tell you about errors, unless they really like the app or are feeling unusually nice. Often times they may not even know something’s wrong. If the app wont work correctly, they just move on to another page without another thought.

This time, I caught it right after it happened, so I was actually a little happy. The error was pretty easy to pinpoint. Luckily it only occurred if AltGr keys were used, which doesn’t effect users unless they decide to add customizations for foreign layouts, which is why it didn’t show up until later in the week. I should have caught this while testing, but over sights are made sometimes.

So far I’m happy with this little experiment, and am thinking about possibly adding client side error logging to my other apps. For now the only draw backs I see are that this method of discovering errors can be a hassle if your scripts are minified and concatenated, and that users could abuse this if they knew you were doing it (though then again, they could abuse any kind of data saving request you were doing).

Plotting and Analyzing US Baby Naming Data

Photo By mahalie

I’ve created a new tool that allows you to query US baby naming data from the past 130 years and play around with it on an interactive chart. I got the idea after stumbling upon the data at the US Social Security website.

To cut to the chase, below you can see some interesting effects of our culture on naming trends.

  • Star Wars – George Lucas created the names “Anakin” and “Padme”, and he had a big impact on the number of babies given the name “Han”, “Leia” and “Luke”. I didn’t include Luke on the chart because it dwarfed the others so much, but between 1880 and 1977, 18,027 babies were named Luke, between 1977 and now, 176,125 babies were given that name.
  • Hermione – Apparently Hermione is a real name, though the 478 babies given the name since 2000 were probably due to the recent popularity in the Harry Potter series.
  • US Presidents – My friend Ben found this one. Back in the early twentieth century, who got elected president had a big impact on what people named their babies.
  • Reagan and Kennedy – I don’t want to get too political, and I’m just talking out of my ass here, but I wonder if the idealizing of past political heroes (from different sides of the aisle) has led to the recent surge in these names.
  • Ninja Turtles – The Ninja Turtle craze of the late-80’s / early 90’s seems to have caused a small impact on naming trends in that time period.
  • Paris – Paris Hilton’s sex tape leaked onto the internet in 2003 and became a big news story. For some reason this inspired hundreds of people to name their kid after her.
  • Osama – The frequency of people naming their kid “Osama” actually increased after the 1998 embassy bombings, but I’m guessing after 9-11, people realized naming their kid after after the world’s most wanted terrorist was probably not a good idea.
  • Miley – In 2005, 26 babies were born with the name “Miley”. In March of 2006, Hannah Montana debuted with star Miley Cyrus on the Disney Channel. That year the name started to sky rocket in popularity, and peaked in popularity in 2008 when 2,643 babies were given the name.
  • Selena – In 1995, this name shot up in popularity by 400%, with 3,839 babies given the name “Selena”. This was most likely was caused by the 1995 death of latin super star “Selena Quintanilla-Pérez“. Interestingly, Selena Gomez has not had the effect on “Selena” that Miley Cyrus has had with “Miley”.
  • Carson – This name had been slowly increasing in popularity, but it started to skyrocket in 1998, which coincidentally was the year MTV debuted its mega hit TV show TRL, with host Carson Daily. The name has maintained its popularity, so its probably not all due to Daily, but since TRL was a young person’s show, and not many notable people are named Carson, he probably had some effect in getting the ball rolling.
  • Shirley – Shirley Temple shot to super stardom in 1934 with Bright Eyes, and so did the use of her name for new borns.
  • Britney – Britney Spears dropped “…Baby One More Time” in 1999 and had a big impact on the “Britney” (interestingly, the version spelled “Brittany” stayed in steep decline during this time period).

These were all found by just trying out different names and looking at the time period for when the names peaked or dropped in popularity.

Chart Library and Modifications

For those of you who are curious, I used Martin Kleppmann’s PlotKit repo as a starting place for the chart (that repo is a heavily modified version of Plotkit with lots of new features and fixes). I then modified it to add in some additional features and minor bug fixes, including the mouse interaction stuff. I’ll probably submit my changes back to him at some point, though right now I feel like I kind of hacked stuff into it, so I’ll probably wait until I polish it up and the changes are field tested more. If you have any trouble with the chart please let me know.

The mouse interaction stuff was done by creating a separate canvas element and having it overlay the chart. The dynamic dots you see are then drawn on this canvas. This is done because re-drawing the whole chart is time consuming. The one exception to this is IE7 (and possibly IE8), for which I couldn’t get the overlay to work. So for those browsers, the whole chart re-drawn when it changes. So you’ll notice if you use IE7 that mouse interaction isn’t smooth, while if you use Chrome, FireFox, or IE9, things should be pretty smooth.

CSS3 Card Flip Animation Trick

I’ve been playing around with some of CSS3’s new animation features. For an app I’m writing, my wife suggested I jazz things up a bit by having an image look like its flipping over, and I realized that with CSS3, I could actually do that. To demonstrate what I’m talking about, in the latest version of Chrome, click one of the playing card images below*.

The neat thing is that the effect is ridiculously simple. The one catch is that you can’t change the background-image property of a div during an animation. To get around this, you just need to use an image that contains all of the pictures you want to display. When the image is out of view (e.g., roated at 90 degrees or 270 degrees on the Y axis), you change the background-position. That way, when the image rotates back into view, it’s displaying a different picture.

It’s pretty simple, but kind of amusing. Below is some example code you can use for your own animations. The card image used in this example can be seen here, and the full set of cards can be obtained here.

CSS:

@-webkit-keyframes card1Flip {
    0% {-webkit-transform: rotateY(0deg);}
    24% {background-position-y:0px;}
    25% {background-position-y:204px;}
    50% { -webkit-transform: rotateY(180deg);}
    75% {background-position-y:204px;}
    76% {background-position-y:0px;}  
    100% {-webkit-transform: rotateY(360deg);}
}
.card1FlipProps {
    -webkit-animation-name: card1Flip;
    -webkit-animation-duration: 2000ms;
    -webkit-animation-timing-function: linear;
    -webkit-animation-iteration-count: 1;	
    -webkit-animation-direction: normal;
    -webkit-animation-delay: 0;
}
#card1 {
    background-image:url('/images/blog-2011/card_map.png');
    width:150px;
    height:204px;
}

JavaScript:

var elm;
elm = document.getElementById("card1");
elm.addEventListener("webkitAnimationEnd", function(){
    if (this.classList) {
        this.classList.remove('card1FlipProps');
    }
}, false);
elm.addEventListener("click", function() {
    if (this.classList) {
        this.classList.add('card1FlipProps');
    }
}, false);

HTML:

<div id="card1"></div>

* Important Notes: Unfortunately, the CSS3 animation module isn’t implemented in most browsers right now, so the above example will only work in the latest version of Chrome. Safari also uses Webkit as its layout engine, however, when I tested this example in the latest version of Safari (5.0.5), it didn’t work correctly. Some digging around showed that my version of Safari was using Webkit version 533.21.1, and my version of Chrome was using Webkit version 534.30.

Since the animation module is still being worked on right now, this technique, and animations in general, should probably be used cautiously and for effects that aren’t that important.

Extendible BBCode Parser in JavaScript

Photo By Dean Terry

I decided to try my hand at implementing a BBCode parser in JavaScript. You can play around with it online here, and download the source here.

I had looked around a little bit and noticed that the existing JavaScript BBCode parsers had at least a few of the following issues:

  • They didn’t report errors on misaligned tags (e.g., [b][u]test[/b][/u]).
  • They couldn’t handle tags of the same type that were nested within each other (e.g., [color=red]red[color=blue]blue[/color]red again[/color]). This happens because their regex will look for the first closing tag it can find.
  • They couldn’t handle BBCode’s list format (e.g., [list][*]item 1[*]item 2[/list]).
  • They didn’t report errors on incorrect parent-child relationships (e.g., [list][td]item 1?[/td][/list]).
  • They weren’t easily extendible.

I naively thought it’d be easy to quickly whip up a parser, and at first it was. Most BBCode tags can be implemented with a simple find and replace. However, I quickly ran into the issues of dealing with nested tags of the same type, the noparse tag, and the list tag’s annoying [*] tag (which doesn’t have a closing tag). Luckily, I came across a neat blog post on finding nested patterns in JavaScript, which came in handy for isolating tag pairs, from the inner-most on up. Taking the idea from that post, one can do something like this to process the inner tags first and avoid the nested tag problem:

var str = "[list][list]test[/list][/list]",
    re = /\[([^\]]*?)\](.*?)\[\/\1\]/gi;
while (str !== (str = str.replace(re, function(strMatch, subM1, subM2) {
    return "" + subM2 + "";
})));
// str = "test"

That idea works well, though you can’t implement a noparse tag if you process the inner-most tags first. So I decided to pre-process the BBCode with something similar to the idea above and add in nested-depth information to each open and close tag. Once all of the tags had that, I could parse the processed code with a regex that could easily match-up the correct open and close tags.

To get around the issue of the [*] tag having no closing tag, I wrote code that inserted [/*] tags where they were supposed to go during the pre-processing period. I wont go into the algorithm here, but you can dig into the code if you’re interested.

Also, I should note that the fact that JavaScript allows you to use a function as the second parameter to the replace method makes processing the tags really easy. Once you match a set of tags, you can recursively call the parse function on that tag’s contents from inside of the function you passed to replace.

Using the parser

To use the use the parser, you’d simply include xbbcode.js and xbbcode.css files somewhere on your page (which are contained in the zip file linked above), and then call the XBBCODE object from somewhere in your JavaScript:

var result = XBBCODE.process({
    text: "Some bbcode to process here",
    removeMisalignedTags: false,
    addInLineBreaks: false
});
console.log("Errors: " + result.error);
console.dir(result.errorQueue);
console.log(result.html);// the HTML form of your BBCode

Adding new tags

To add a new tag to your BBCode, add properties to the “tags” object inside of the XBBCODE object. For example, say you wanted to add a tag called [googleit] which would change its contents into a link of its google search results. You’d implement that by adding this to the tags object:

"googleit": {
    openTag: function(params,content) {
        var website = "\"http://www.google.com/#q=" + content + '"';
        return '<a href=' + website + '>';
    },
    closeTag: function(params,content) {
        return '</a>';
    }
}

Then you could have BBCode like this: “[googleit]ta-da![/googleit]” which would be transformed into this: “<a href=”http://www.google.com/#q=ta-da!”>ta-da!</a>”

If you have any suggestions or find any bugs let me know.