Put your message here! Contact me for more information
 
 







 

If you do “gem install capistrano”, the gem package manager will go fetch the latest gem version of capistrano, currently 2.3.0 and installed in the gem repository. In case you want to have multiple version s of capistrano running, here’s how to do it.

To install older gem version of Capistrano
gem install –version 1.4.2 capistrano
(1.4.2 is the latest one in the 1.x branch before the release of 2.0)

To run specifically the 1.4.2 version, use
cap _1.4.2_ *your_tasks_here*

Shortcut
To reduce the typing, you can make an alias in your .bash_profile on Linux to run the 1.4.2 version as cap1 (cap 2.x.x is still running as cap) using

# add this line to .bash_profile
alias cap1=”cap _1.4.2_”

Afterwards, reload the profile with

$ source .bash_profile


Since I am on Windows, what I did was creating a batch file called “cap1.bat” and saved it within my system’s PATH environment. For simplicity’s sake, I save the cap1.bat file inside my C:\Windows\System32 folder

@echo off
cap _1.4.2_ %*

The special wildcard %* will be replaced with your command-line arguments, saving you the typing.

To read more about the Capistrano 1.4.2 version, check out Jamis’s post here.

view comments
 

I’m in the process of installing Ruby on Rails on a VPS running CentOS 5.1 and run into an issue with gem complaining for the missing zlib library. What happened was that I first used “sudo yum install ruby” to install the ruby runtime. However, the pre-packaged ruby in the Yum repository was older, 1.8.5. I only found out about this when I tried to run the mongrel_cluster to set up the mongrel instances. Mongrel was complaining about the older version of Ruby and the need for the fcgi fix. I decided to uninstall the yum ruby package and compile the newer version of Ruby from the source.

I compiled and installed Ruby 1.8.6 from the tar ball source first (./configure, make, make install), then I removed the pre-installed package using “sudo yum remove ruby” and removed all the dependencies with it. Next I installed gem 1.1.1 from the source (ruby setup.rb). I proceeded to install rails 2.0.2 again (”sudo gem install rails -y”). Bam, gem started to complain:

/usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in
`gem_original_require': no such file to load -- zlib (LoadError)

Not good!

I did some research and it turned out that my CentOS 5.1 VPS is a barebone box, it did have the extra development libraries installed. Hence when I compiled Ruby from source, make did not compile the zlib extension because I did not have the zlib-devel package installed.

After installing zlib-devel package through yum (”sudo yum install zlib-devel”), I cd’ed into my Ruby source folder and into the ext/zlib folder (in my case, ruby-1.8.6-p114/ext/zlib/). Then I proceeded to install the zlib library (”ruby extconf.rb”, “make”, “make install”). Afterwards, gem was working fine again! Yay!

view comments
 

I’ve been working extensively with JavaScript for the past few weeks, developing an all-Javascript application (the code base is exceeding 2000 lines of JavaScript already). Since the application needs to scale well with a large amount of dynamically generated elements, I have discovered, learend, and used quite a few shortcuts to boost the speed, minimize memory usage with mem-leak checks, and reduce file-size in general while still maintain the readability of the code.

This article is mainly about the nuggets that I extract out from my experience. I learned a few things from reading the source of PrototypeJS and Scriptaculous, while I learned other things (ideas, concepts) from different languages such as Ruby (famous for one-liners). I have to admit, nothing beats reading other people’s source code. Prototype is extremely well-written and there are tons of programming gems that one can learn from.

A few tricks are possible only in JavaScript because it is NOT Java, or C#, or C, and it is extremely powerful and flexible. With the Prototype cool-aid, Object-Oriented JavaScript is not only possible, but easy, standardized, and straight-forward to implement

Tip 0: Use a JavaScript framework
Pick a framework and use it. Any framework is *much* better than no framework at all. Different browser behaves differently and the framework will help smooth out those wrinkles. You are simply insane if you are not using one.

Our menu comes with several choices: so it’s a matter of personal preference. The learning curve will a bit steep as you will have to Google alot for the API’s, but once you are familiar and comfortable, you will become a much better scripter.

  • Prototype: Easy to use. One of the first that popularized the idea of frameworks. Lowest learning curve with virtually NO dependencies (1 file, ~ 130Kb)
  • jQuery: almost feel like writing javascript short-hand notation. Will take sometime to get used to the syntax. Core library is very small (~30Kb)
  • YUI: there’s a lot being offered in this framework. Get quite large (ZIP file: ~10MB!). I just don’t like everything being stuffed inside the YUI namespace, even when I register my own namespace.

Tip 1: Format your code well.
Nothing is worse than writing a large ( or any) application with poor code readability. As the application gets more complex, as it did in my case, having the ability to scan through the code and pin-point the hot-spot to fix is extremely helpful. Simply by consistently indent the code with NO EXCEPTION and keep yourself to a high coding-standard, your code will look pretty, work well, and have less bugs. The key is to do this as you code, not after everything has been done. You think you won’t ever look at your code again once it’s done, well, YOU ARE WRONG!

Once you are in the habit of formatting the code yourself, you become more aware of the “beauty” of your code. You’ll start seeing cool things, similar to the guys in Matrix see our world. You’ll become Neil and fly through your code and feel its force-field.


Tip 2: Having a high coding standard.
The reason why you have to keep your code in order and of high standard with no exception is that I believe in the Broken-window theory (wikipedia). Once there is a sub-standard spot in your code and you ACCEPT that it is there, you’ll more likely to repeat it and produce more sub-standard code. Nobody vandalizes your code better than you are. Soon, it will become an unmanageable, unreadable mess. Imagine debug these kinds of code? I’ll be cursing all day long.

I highly recommend the Code Complete book. It is thick enough to use as a pillow, but it is a mandatory read if you are serious about programming.


Tip 3: Explicitly write out your coding style and standard.
This is essential when you are working in a team with other people. Also, once you have established a coding style guideline, you will spend less time on thinking about the formatting, how to name variables, how to organize your code. I fondly remember DHH’s word: constraint is liberation. Yup, having a certain constraints will allow you to be more freely to do other productive programming.


Tip 4. Namespacing your code
If you are develop something more complicated than an alert box, put your code inside namespaces to avoid cluttering up the global scope, reducing potential conflicts with accidental over-written from other scripts, and organizing your code much better.

Repeat after me: Namespace your code, it’s easy. Do it.

Example:
Our application is a JavaScript drawing program called JsPaint. We can separate the code into different namespaces as follow:

/* Include in your first included JS file */
var JsPaint = {
  Data: {}
  ,UI: {}
  ,Util: {}
};

To add more methods or classes to JsPaint.UI:

JsPaint.UI = {
  Menu: {}
  ,MenuItem: {}
  ,Canvas: {}
  ,getCanvas:  function() { /* return reference to the canvas here */ }
};

To add a Renderer sub-namespace later on to the JsPaint.UI:

JsPaint.UI.Renderer = {
  Simple: function() {} /* class */
  ,Fancy:  function() {} /* class */
};

/* define shortcut to Renderer */
var jsr = JsPaint.UI.Renderer;
var simpleRenderer = new jsr.Simple();

Namespace is awesome to organize your code. However, if you have lots of level within your namespace, you can, and should, use aliases for the different namespaces. By aliasing, you also reduce the amount of “dot” operations to query the object, thus helping the properties lookup faster.


Tip 5: Putting comma-separator at the begining of the line.
I ran into this post on Thomas Fuchs’s blog a couple days ago. Thomas is the guy behind Scriptaculous. I couldn’t help but smile.

Internet Explorer is every picky about JSON format (I think this is good in a way, as it forces you to pay attention to the code). If you leave an extra trailing comma, IE will silently crash, while good old FireFox still works just fine.

Example:

var ieWontLikeThis = {
  isIEBadForYou:  true
  ,hoursWastedOnDebuggingIE:  function() { throw "Number Out Of Range";}
  ,noticeTheTrailingCommaBelow: true
  ,
}

The extra comma will cause IE to be so confused and throw up.

My solution is to always put comma right before your properties, so that you won’t end up forgetting about the extra comma. The code may look ugly and weird a little bit at first, but you’ll save yourself lots of pain and aggravation down the road. Moreover, you can comment out a properties without further re-formatting of the code. If I don’t want the hoursWastedOnDebuggingIE() method, I only need to comment it out. If you put the comma trailing the previous line, you will have to remember to remove it too. Not fun.

Bonus:
This coding style with the comma or the separator as the prefix is also useful for other languages as well, especially for SQL statements. It helps with 1) List of Columns to be SELECT’ed, 2) WHERE conditions, 3) Different temp variables in Common Table Expression (SQL Server 2005). (Besides that, I also force myself to indent the code in a consistent way, indentation matters!).

SELECT
  p.title
  ,p.description
  ,p.is_published
--  ,p.category_id   /* don't need this column*/
  ,a.user
  ,a.author_id
  ,p.created_at
FROM posts p
INNER JOIN author a
  ON p.author_id = a.author_id
WHERE a.user = 'alexle'
  AND p.type = 'post'
  AND p.is_published = true
--  AND p.category_id = 1   /* this line can be commented out without affecting the previous code */
ORDER BY p.created_at DESC
--   AND p.category_id  /* this line also can be commented out without affecting the code */

Another example with writing and debugging Common Table Expressions. This comes directly from my experience with writing a humongous CTE in SQL Server 2005

WITH firstCTE AS (

)
-- SELECT * FROM firstCTE  /* uncomment this line to debug the first CTE */
, secondCTE AS (

)
-- SELECT * FROM firstCTE  /* uncomment this line to debug the second CTE */
, thirdCTE AS ( 

)
-- SELECT * FROM firstCTE  /* uncomment this line to debug the third CTE */

SELECT *
FROM firstCTE
INNER JOIN secondCTE
  ON ...
INNER JOIN thirdCTE
  ON ...

Tip: 6 Having fun with Function Arguments
If you have to write functions with lots of arguments, well, you don’t have to. Instead, pass an array (or hash to be exact) of parameters as the argument and have your code handled it intelligently. You have more flexibility as the parameters list can be changed anytime. This technique is used extensively through out Prototype, Scriptaculous, and other frameworks such as jQuery, or ExtJs.

JsPaint.UI.Canvas = function( options ) {
  var defaultOptions = {
    canvasId:     'canvas_container'
    ,width:       100
    ,height:      200
    ,menuItems:   [ "File", "Edit", "View", "Help" ]
  };  

  /* merging default options with the passed in options  */
  this.canvasId   = options ? ( options.canvasId || defaultOptions.canvasId ) : defaultOptions.canvasId;
  this.width      = options ? ( options.width || defaultOptions.width ): defaultOptions.width;
  this.height     = options ? ( options.height || defaultOptions.height ): defaultOptions.height;
  this.menuItems  = options ? ( options.menuItems || defaultOptions.menuItems ) : defaultOptions.menuItems;
};

I use a shortcut with the ternary operator ? : and the “or” operator || to quickly merge the options with the defaultOptions.


Tip 7: Using or operator || for Coalescing nullable values
If you need to choose the first not-null value from a list, you can use the || (’or’) operator. Besides its usage as a logical boolean operator, || can be used as a fall-through-if-null operator, return the first non-null value.

var width = options.width || defaultOptions.width || 100;

It will check for the options.width, if null, defaultOptions.width will be used, then finally 100 if both the previous variables are null.

In SQL Server and MySQL, you can use the function COALESCE( csv_list_of_variables ) to do the same, e.g. getting the first non-null value;


Tip 8: Using ternary operator to reduce the amount of if-else in your code
I love the ternary operator. It may look cryptic, but after a while, your code will be shortened quite a bit while still remains readable with proper formatting. Nested ternary operations can be hard to read so it’s a matter of balancing between coding shorthand and code readability.


Tip 9: Function Arguments, enhanced with Prototype
Do you see how ugly our previous code to get the values from the arguments? If you are using Prototype, you can shorten all the ugly manual merging with a one liner

var JsPaint.UI.Canvas = function( options ) {
  var defaultOptions = {
    canvasId:     'canvas_container'
    ,width:       100
    ,height:      200
    ,menuItems:   [ "File", "Edit", "View", "Help" ]
  };  

  /* merge defaultOptions with options */
  options = Object.extend( defaultOptions, options );
  this.canvasId   = options.canvasId;
  this.width      = options.width;
  this.height     = options.height;
  this.menuItems  = options.menuItems;
};

Done! Object.extend() merges all the options together so you can have fun writing other productive code.


Tip 10: Optimize Loops
If you need to iterate through a large array, you should squeeze every bit of speed by caching the length. There’s always a trade-off between speed and storage, and if you want speed, you must trade RAM for it. The Prototype’s API page for Array has an excellent example:

// Custom loop with cached length property: maximum full-loop performance on very large arrays!
for (var index = 0, len = myArray.length; index < len; ++index) {
  var item = myArray[index];
  // Your code working on item here...
}

Tip 11: Object Inheritance made easy with Prototype
Since Prototype version 1.6, you now have full support for inheritance for your Object-Oriented JavaScript application. JavaScript has the support for inheritance, albeit not built-in, but it has never been easy to work with. Before, I had to write hacks and came up with something monstrous, ugly, and kludgy in the end. With Prototype, you get full support for inheritance for virtually free using Object.extend() and Class.create().

To ready more about inheritance, consult the Prototype’s Tutorial page on Inheritance


Tip 12: Leveraging Prototype’s Internal Methods
I highly recommend you to read through Prototype’s source code. The file contains more than 4000 lines of high-quality JavaScript code and you will learn a lot from doing so. An example is Event.KEY_* attributes (~ line 3700), containing the numerical code for various keys so you don’t have to look them up or re-define them again. Another example is the Prototype.emptyFunction attribute, which is an empty function. I often use emptyFunction in my base classes to make it clear that these methods are virtual methods, to be overridden by the sub-classes.

Example:

JsPaint.Shape.ShapeBase = Class.create( {
  initialize: function() {}

  /* only the object knows how to draw itself */
  ,draw: Prototype.emptyFunction

  /* only the object knows how to refresh the screen */
  ,refresh: Prototype.emptyFunction

} );

JsPaint.Shape.Rectangle = Class.create( JsPaint.Shape.ShapeBase, {
  initialize: function( $super, width, height, x, y ) {
    /* calling parent's constructor */
    $super();
  }

  ,draw: function( $super ) {
    /* drawing logic here */
  }

  ,refresh: function( $super ) {
    /* refresh logic here */
  }
} );

JsPaint.Shape.Square = Class.create( JsPaint.Shape.Rectangle, {
  initialize: function( $super, side, x, y ) {
    /* calling Rectangle's constructor */
    $super( side, side, x, y);
  }
  /* draw() and refresh() stay the same */
} );

Tip 13: Implementing Enumerable methods for your custom collections
For my application, I need to implement a generic sorted list that must behaves similar to a regular array while being optimized for speed. I set out to write a hybrid data structure that uses binary sorting to keep the array always in-ordered. I’ll publish the code in a separate post, but the interesting idea I want to share is the implementation of methods from the Enumerable interface, which helps working with the custom sorted list a lot more enjoyable.

From Prototype’s API page for Enumerable, the methods are

  • all
  • any
  • collect
  • detect
  • each
  • eachSlice
  • entries
  • find
  • findAll
  • grep
  • inGroupsOf
  • include
  • inject
  • invoke
  • map
  • max
  • member
  • min
  • partition
  • pluck
  • reject
  • select
  • size
  • sortBy
  • toArray
  • zip

I did not implement many these methods for my collection (I didn’t need them all), but my favorite ones are each(), first(), last() (these 2 are not listed, but they are still my favorites). Enumerable is a great time saver, implement it if you can.


Tip 14: A better Enumerable#each() implementation
The current implementation for Enumberable#each() in Prototype is not as nice and it’s cumbersome to break out from the loop. I’m greedy and I want everything a native for-loop can offer: item, its index, ability to break and continue, plus the piece of mind of not worrying about the index-out-of-range issue.

Here is my so-called better each() implementation:

  each: function( iterator ) {
		for( var i = 0, len = this.collection.length; i < len; ++i ) {
			if( typeof( temp = iterator( this.collection[i], i ) ) != 'undefined' && !temp )
				break;
		}
	}

The trick is to only break when the iterator explicitly returns false.

Example Usage:

var list = new SortedList ();
/* populate the list here */

/* iterating ... */
list.each( function( item, index ) {
  /* process here */
  item.process();

  /* skipping ...*/
  if( continueConditionIsTrue )
    return; /* this will returned 'undefined' back to the iterator */

  /* break out early */
  if( breakOutConditionIsTrue )
    return false;

} );

Tip 15: Passing function reference: The Strategy Pattern
Once you realize how flexible JavaScript is, you begin to have fun with it. Passing function reference is a neat trick that can be very useful. If you look at the each()’s implementation above, you see that the iterator function is being passed in as an argument variable. The iterator is than invoked directly via that argument variable just as you would normally execute a function. Neato!

I used this trick in my SortedList implementation and love it. Since the items stored in the list are custom objects that do not implement IComparable interface (that you can’t do item.compareTo( otherItem) ), however, to sort them, I need to be able to compare 2 object together directly. I implemented a comparator that contains (or encapsulate) the business logic for the object comparison. Basically the SortedList doesn’t care on how the objects are constructed, as long as the comparator can give the correct comparison results, the list is guaranteed to work

Here is the constructor for my SortedList. I used Prototype Class.create() to create a new class and the initialize() method is the constructor.

/* I use Prototype */
var SortedList = Class.create( {
  initialize: function( options ) {
    this.collection = [];

    var defaultOptions = {
      comparator: function(a,b) { return ( a < b ) ? -1 : ( a == b ) ? 0 : 1; }
      ,jsonifier: function(a) { return a.toJSON() }
    };

    this.comparator = options ? options.comparator || defaultOptions.comparator : defaultOptions.comparator;
    this.jsonifier  = options ? options.jsonifier || defaultOptions.jsonifier : defaultOptions.jsonifier;
  }
} );

I have a default comparator which can be used for basic data types (int, float, double, etc.), or I can pass in a custom comparator in the options argument to override the default one. The strategy for the comparison can be swapped out anytime and still the rest of the implementation remains unchanged.

The indexOf(item) function can be then implemented as follow:

indexOf: function( item ) {
  if( this.comparator( this.collection[ 0 ], item ) == 0 )
    return 0;
  else if( this.comparator( this.collection[ this.collection.length - 1 ], item ) == 0 )
    return this.collection.length - 1;

  for( var i = 0, len = this.collection.length; i < len; ++i )
  {
    if( this.comparator( this.collection[ i ], item ) == 0 )
      return i;
  }

  return -1; // not found;
}

Tip 16: Closure
Closure is powerful. Without this feature, JavaScript won’t be as flexible and robust as it is now. There are lots of good tutorials on closure so I won’t be cover it again in depth. I’ll provide a code sample instead. Yup, show, don’t just tell. The simplest example is to access the “this” keyword in a setTimeout or setInterval context.

Let’s have a StopWatch class that keeps track of its internal run time and update its display accordingly. Here is a very simple implementation that I cooked up in 5 minutes

var StopWatch = Class.create({
  initialize: function() {
    /* init these varialbe */
    this.runTime        = 0;
    this.tickDuration   = 100;  /* tick every 100 ms */
    this.timer          = null;
  }

  ,start: function() {
    /* exit if the stop watch already running */
    if( this.timer ) return; 

    var me = this;
    this.timer = setInterval( function() { me.tick() }, this.tickDuration );
  }

  ,tick: function() {
    this.runTime += this.tickDuration;
    this.updateDisplay();
  }

  ,stop: function() {
    clearInterval( this.timer );
  }

  ,updateDisplay: function() {
    /* update the time display here */;
  }

});

/* Now run the stop watches */
var exeriseStopWatch = new StopWatch();
exeriseStopWatch.start(); /* you'll see the time ticking here */

var cookingStopWatch = new StopWatch();
cookingStopWatch.start(); /* you'll see the time ticking here */

exeriseStopWatch.stop();
cookingStopWatch.stop();

In the start() method, we declare a “me” variable to hold the reference to the current object and if you remember, we can pass function references as variables within JavaScript. Since the function defined within setInterval is still in the local scope of the start() method, we have access to the “me” variable — which again point back to “this” StopWatch.


Tip 17: Closure with Prototype Cool-aid
If you use Prototype, you can have a much nicer syntax for closure and accessing the “this” scope. Let’s rewrite the start() function of our WtopWatch class.

  ,start: function() {
    /* exit if the stop watch already running */
    if( this.timer ) return;
    this.timer = setInterval( this.tick.bind( this ), this.tickDuration );
  }

Prototype extends the native Function object within JavaScript with some neat wrappers, bind() is one of them. The explanation for function.bind() :

Wraps the function in another, locking its execution scope to an object specified by thisObj.

Your code suddenly becomes much clearer and it states the intention of what it does! Prototype’s developers get the principle from the Ruby language: optimizing the programmer’s fun and productivity. These utility methods such as bind() and bindAsEventListener() just make writing JavaScript a lot more enjoyable and straightforward.


Final Words
This is by far the longest post I have ever written in a single day. I am excited to learn more about JavaScript, and I am more than glad to share my experience with everyone. I hope you can get out a few good things from this post and apply in your everyday work.

Let me know if you find any bugs and typo. Disclaimer: the code samples in this post have not been tested so point it out if you can.

view comments
 

Based on an article on detection connection speed using JavaScript, I implemented a more completed speed detection solution which you can drop into your project with minimal fuss. An example would be to detect the user’s connection speed to show either high or low bandwidth version of the website. All the ingredients you need are an image, a small JavaScript snippet, and some imagination. There is no dependency and no other 3rd party library needed.

The main idea is that we load an image programmatically and measure the time it takes the browser to load such an file. Once an image is done loading, the browser will fire the onLoad event and we can capture the end time. I included two different versions of the code. The first one is quite simple with the image being loaded only once. The second one is more sophisticated, loading the image multiple times and taking the average loading time to arrive at a more accurate answer.

The key technique being used here are closure and passing functions as arguments. These two techniques are very commonly used in modern JavaScript frameworks such as Prototype, Scriptaculous, jQuery, Ext, YUI, etc.

In order for this technique to work, we need to have an image with an average size. Too small of an image won’t give us a very good result while too big of an image will cause more lags and affect the user’s experience. For your convenience, I included the a JPG image around 58.5KB in size as our testing image. We will need the exact size of the image in Bytes in order to calculate the bitrates or byte-rates.

Simple Javascript Speed Detection
Insert this code snippet into the page where you want to conduct the speed test

var SpeedTest = function() {
  /*
  From:  http://techallica.com/kilo-bytes-per-second-vs-kilo-bits-per-second-kbps-vs-kbps/
  256 kbps            31.3 KBps
  384 kbps            46.9 KBps
  512 kbps            62.5 KBps
  768 kbps            93.8 KBps
  1 mbps ~ 1000kbps   122.1 KBps
  */
};
SpeedTest.prototype = {
  imgUrl: "speedtest.jpg"    // Where the image is located at
  ,size: 59917                // bytes
  ,run: function( options ) {

    if( options && options.onStart )
      options.onStart();

    var imgUrl = this.imgUrl + "?r=" + Math.random();
    this.startTime = (new Date()).getTime() ;

    var testImage = new Image();
    var me = this;
    testImage.onload = function() {
      me.endTime = (new Date()).getTime();
      me.runTime = me.endTime - me.startTime;

      if( options && options.onEnd )
        options.onEnd( me.getResults() );
    };
    testImage.src = imgUrl;
  }

  ,getResults: function() {
    if( !this.runTime )
      return null;

    return {
      runTime: this.runTime
      ,Kbps: ( this.size * 8 / 1024 / ( this.runTime / 1000 ) )
      ,KBps: ( this.size / 1024 / ( this.runTime / 1000 ) )
    };
  }
}

First, we need to specify where we would load the image from (in this case, the relative path to the page) and the exact size of that image in Kilobytes. Since we don’t want the browser to cache the image, which short-circuits our test, we append a random number to the original image’s url (line 19). Before we run the test, we check to see if we need to run the onStart() functions being passed in. The idea is that you can show on the page with some messages or pop-up to notify about the test is about to run, simply by passing in an inline function.

The crux of the detection is from line 23 to line 30. If you are new to JavaScript or you are not comfortable with Closure, you should investigate a bit more since Closure is a critical and extremely powerful part of Object-Oriented JavaScript. In its simplest form of explanation, Closure means an anonymous function from a different execution context can gain access to another function’s internal properties.

In this case, after downloading the image, the browser fires the image’s onLoad event at a later time in a different execution context (the context of the current browser) other than context of our SpeedTest object. Without a closure reference via the variable “me” (line 23), which holds the reference to the SpeedTest object, we can no longer access to the startTime and endTime properties of the current SpeedTest object.

Now to run the test and obtain the results, all you have to do is to initialize a new SpeedTest object, execute the run() method, and pass in your custom actions. Currently 2 custom events onStart() and onEnd() are supported:

var st = new SpeedTest();
st.run({
  onStart: function() {
    alert('Before Running Speed Test');
  }

  ,onEnd: function(speed) {
    alert( 'Speed test complete:  ' + speed.Kbps + ' Kbps');
    // put your logic here
    if( speed.Kbps < 200 )
    {
      alert('Your connection is too slow');
    }
  }
});

The Multi-trial speed test

As with any kind of measurements, one single measure is subjected to certain errors and inaccuracy. In our case, the degree of inaccuracy is much higher since connection speed fluctuates constantly. Other factors would affect the single-pass test is the initial DNS look-up speed and overhead, temporal network latency, slow browser, etc. Hence we can further improve our answers by taking multiple tests and average the results to get a more accurate number.

Below is a more sophisticated speed-detection code, which we can specify how many times the test is run. Typically 3 runs is good enough and it will not impact on the user’s experience.

var SpeedTest = function() {
  /*
  From:  http://techallica.com/kilo-bytes-per-second-vs-kilo-bits-per-second-kbps-vs-kbps/
  256 kbps            31.3 KBps
  384 kbps            46.9 KBps
  512 kbps            62.5 KBps
  768 kbps            93.8 KBps
  1 mbps ~ 1000kbps   122.1 KBps
  */
};
SpeedTest.prototype = {
  runCount: 3                 // how many times we want to run the test for
  ,imgUrl: "speedtest.jpg"    // Where the image is located at
  ,size: 59917                // bytes
  ,run: function( options ) {
    this.results = []; // reset the results
    this.callback = ( options && options.onEnd ) ? options.onEnd : null;
    this.runTrial(0, options);
  }

  ,runTrial: function(i, options ) {
    var imgUrl = this.imgUrl + "?r=" + Math.random();
    var me = this;
    var testImage = new Image();
    testImage.onload = function() {
      me.results[i].endTime = ( new Date() ).getTime();
      me.results[i].runTime = me.results[i].endTime - me.results[i].startTime;

      if ( i < me.runCount - 1 )
        me.runTrial( i + 1 ); // run the next trial
      else
      {
        // Execute the callback
        if( me.callback )
          me.callback( me.getResults() );
      }
    };
    this.results[i] = { startTime: ( new Date() ).getTime() };
    testImage.src = imgUrl;
  }

  ,getResults: function() {
    var totalRunTime = 0;
    for( var i = 0; i < this.runCount; i++ )
    {
      if( !this.results || !this.results[i].endTime )
        return null; // exit if we found no endTime.  --> test’s not done yet
      else
        totalRunTime += this.results[i].runTime;
    }

    var avgRunTime = totalRunTime / this.runCount;

    return {
      avgRunTime: avgRunTime
      ,Kbps: ( this.size * 8 / 1024 / ( avgRunTime / 1000 ) )
      ,KBps: ( this.size / 1024 / ( avgRunTime / 1000 ) )
    };
  }
}

Even though our test method has changed, you can still use the same exact code as above to run the speed-test. The answer will be much more accurate this time. Basically we run multiple trials back-to-back, each time measuring the runtime and store it into an array, then average and get the final result.

Another small difference is that we have to store the reference to the user’s custom onEnd() method as a property of the SpeedTest object so that at the end of the test, we can execute it and return the answer to the user.

Final words

I hope you enjoy this article and make good use of the code. I packaged the 2 versions and the image into a zip file so just go ahead and have some fun. Go speed-racer!

Download

view comments
 

This year, Startup School 2008 again had some excellent speakers. I enjoyed it as much as I did for last year. I came in late for about an hour but I hope I did not miss much. I also bumped to a few old faces from last year as well.

Paul Graham is charismatic and funny with his advices as always. He gave a revised speech (a bit different from the one from last year) about the usual topic: “how to start a start up”. A good analogy for his advices is the relationship between the founders and the investors (VC) is similar to a relationship between girls and boys. If you show that you can live without money (or love) and generally be okay on your own financially (or emotionally) then more people would be interested in you (either fund you the money, or trying to get a date with you). A strong start-up with an action plan and a profitable potential will more likely to spark more interests from the VC than one needs the cash infusion to struggle along.

Paul paused, then brought up the next slide:

“A startup needs to be like a roach”

This clicked me. Personally I’m not afraid of any insects or reptiles, but I disgust roaches. Can’t stand them and just imagine how they would crawl up my legs makes me want to find a shotgun and smoke their tiny brown ass. Nonetheless, a startup should have a roach as a hero to look up to for its survivability, adaptation, and persistence. For millions of years, the cockroaches still survive just fine while the almighty dinosaurs went belly up, fossilized, and became the crude oil we got addicted to more than cracks. A startup needs to change when the weather changes, needs to survive from the fierce competitions or the VC’s liquidation, and be persevered to keep going when the odds are all against you.

In his book, “How to get Rich“, Felix Dennis (SOLE owner of Maxim and tons of other magazine) wrote about the idea of acting small and think big (not the other way around). A startup must keep coming even when facing failures is not even an option but a reality and knows how to act small and determined to come back to take a piece of that pie and steal more of the market-share. Personally, after watching a roach running for its life so many times, fleeing away from my smoking shotgun, I should know better how a roach would zig when I’m about to zag it. It would predict my next blow, running as fast as it could on all its got (6 tiny legs and a pair of paper-wings). No matter how much I tried to kill them, they still get away, and come back with more roach-warriors the next day. Acting like a cockroach will definitely help in dire situations when one is starting a startup. We usually learn the best lesson and experience from Mother Nature. Well-done, Paul, and it is hilarious too.

Another old speaker from last year, Greg McAdoo from Sequoia talked about the VC industry and how Sequoia love to work with Startups. Since I am not much interested in getting funded from VC (more of this later), I only listened to him with half the attention. Nonetheless, he is a really good speaker with lots of advices. His observation: the successful entrepreneur needs to have the skills to identify the trend and ride it to where it is heading to. Don’t fight the trend but leverage it to supercharge ahead. Isn’t that what people call “chances” and “luck”? Greg ended his speech with an impressive video, showing this one guy rode the biggest wave I have ever seen:

As much as Greg McAdoo pushes how the VCs are interested in working with little startups, my most favorite speaker of the entire program, (drum rolls…) David Heinemeier Hansson (DHH) dissed the whole general startup mentality, i.e. build something, raise VC’s money , go big, and hope for an exit (or just die in flames). DHH is truely a business man in how he approaches the subject of startup. He knows his goal (making ENOUGH money to enjoy life) and hits the bullseye with his skills (RoR is just amazing - I’m so thankful for his release of RoR to the open-source community and how he has helped me get to my dream).

DHH:

  • Focus on the customers
  • Build something good that you can have the customers hand over their card numbers
  • Going through VC is NOT the only way to make a profit for startups
  • Everybody is a winner in the market if they can grab the customers. The internet is HUGE
  • Instead of technology makes the business profitable, it is the well executed business with the correct technology which will be the cash-cow.
  • Work less hours: 12 hours of work is not necessarily as productive as a good solid 3 or 4 hours of focused, zoned-in development.
  • Shift the mentality of building a tech startup to building a self-sustainable and profitable business
  • Customers can either consumers (harder to get money from) to the Fortune:5,000,000 (easier to get money from, provided that the application is solving a business problem)

As I just wrote, the idea of raising money for my startup never stuck in my mind for long. I’m in this game to build businesses that MAKE money. What DHH said did truly touch me. I want my business card to say “Alex Le - Owner”, not just “Alex Le - so and so of this business”. I want to trade my sweat equity for ownership. With RoR and a little imagination, the road to success has never been as accessible. The real question is that do I really have the guts and perseverance walk down that path. in the future, I may change my mind about raising money from the VC, but it’s only when I know that I can use this money to rocket the business, and only when I am financially independent through my own businesses. More specifically, when I don’t need VC’s money then that is when I want to raise more from them. Why? I can run the business my way if I have the choice to say NO anytime I want to.

I can’t help but post this photo:

Yup, DHH and me. I got a chance to talk to him when the lunch break started. A group of other people gathered around DHH and asked him questions about running an online business. DHH really shines as a extremely smart guy (he is!) and business-savvy. I took a video with my camera for almost of the DHH-group interview but the file is rather big (1.04GB!) so I’ll post it on YouTube later. You’ll probably get a lot of kicks and nuggets of wisdoms from the side-walk talk with DHH. The end result: no more pizza when I came out and I was starving for the rest of the day. But between pizza and the opportunity to talk to DHH? You tell me.

DHH is simply awesome and to see him shot down what Greg McAdoo had just said is equally interesting. DHH has the most credibility and right to say what he said because he has singlehandedly changed the startup/IT industry and happens to get rich along the way. The most important thing is: he is totally right.

However, I am a bit disappointed with Paul Buchheit’s speech this year. He delivered an un-energetic, monotonous talk with a somewhat sparse slide. The big theme for his presentation was to listen to people’s needs, build what they want, but don’t “obey” (the hello-kitty slide was rather cute) all their requests. The talk was stretched into 15 minutes and occasionally got some laughs from the audience. Probably the people already know Paul so they laughed to show him some support. Maybe I set my bar too high after hearing DHH’s speech, but seriously, Paul’s last year speech was a lot more inspirational and energetic than this.

Don’t get me wrong, I enjoyed the contents and message of his talk, but have criticism over the way he delivered it. Don’t shoot the messenger, that’s what people say. However, in this case I think the messenger a bit sloppy in the preparation. Probably Paul had been up late working on FriendFeed the night before.

After the lunch break was Jeff Bezos, CEO of Amazon. From his talk and the way he responded to the questions from the audience, I believe that he is genuinely a nice and humble person. From his vision and actions, he is a man of conviction and strong beliefs in what he does. Amazon Web Service reflects that and I did write a post praising him back in 2006, even before Amazon ’s stock rallied up when people realized the true potentials of the company.

Jeff was promoting and evangelizing AWS, EC2 in particular. He did so rightly because he is more than happy to see more startups using AWS as the underlining infrastructure. As I mentioned in my 2006 post,

Amazon is building the new web economy and they are collecting tax already.

I totally agree with Jeff’s response to a question regarding the competition about Google Engine: the market is huge and everybody wins, i.e. it is not a zero-sum game but everybody benefits as the adoption grows and more and more values are being created everyday.

For the technical questions, Jeff handed to an engineer from Amazon (just wished the engineer was given a microphone so the poor guy did not have to scream his heart out in a 600+ person hall). Nonetheless, I’m so glad to see Mr. Bezos took the time to give a speech at Startup School this year. And I can’t help but to post this …

Hey … he’s the man, I don’t think I can allow myself to miss the chance to take a picture with him. Are you kidding me?

Next was Marc Andreessen. It was a QA session with the host lady and was informative. Marc is a passionate person and I could really see his passion for the web when he talked. I will definitely check out his blog more often.

Last but not least, Peter Norvig, the Director of Research from Google, a guy with intimidating white hair that makes me feel so young, little, and reckless, gave his speech on some data mining techniques. He showed some interesting clustering results from algorithms that Google is employing to enhance the Image Search quality. The example he used was a search for Mona Lisa (with safe search on, he stressed). To come back with good and relevant results, Google look at the contexts of the images (surrounding words, image tags, DOM structures, etc.), then from this result set, they establish the common features of the pictures (main structures, shapes, etc.) and establish clusters of “connected” images by comparing each photos with one another. The end results are clusters of images, with the center images being the most relevant to the search query and the outer ones are still related but with a much lesser degree. Another interesting example was a search for Abraham Lincoln: the algorithms generated 3 clusters for the results: 2 for the indoor statue, and one for the outside building. Seeing the Director of Research from Google giving a presentation on his work is pretty inspiring, considering that Google is spending only(!) $2.1bn in 2007.

A guy , self-proclaimed as the “evangelist” for semantic web (now that was arrogant), asked about Google’s interest in pushing for semantic web. Norvig responded (indirectly) that with the vast amount of text data from the web (50% more spam than ham?), it is already possible to run data mining techniques and algorithms to achieve good results. I think this is true. Analyzing the DOM trees, structures, and other aspects of the vast number of websites out there, one can establish a good working knowledge for relationship between the words and can potentially solve interesting problems already. Semantic web will be helpful, but it won’t be a make-or-break feature of the web, as Norvig answered wittily “Semantic Web is the future of the web, and always will be.”

This is my mini-coverage for the 2008 Startup School. I think I’ll wrap up some other stuff before heading to bed (Note to self: It’s been a long but awesome day already and I’m flying back to Chicago tomorrow afternoon so getting some rest now would be useful :).

A quick photo of me taken with Justin (from Justin TV), Trip (CEO of Scribd), and Wu (I bumped into her at last year Startup School while finding my way to the Kresge Hall)

Other web-coverages:

view comments