November 16, 2009

Comment of the day

Starting a new series guys!!! :-)

This one came from Debashish (my team mate at work) when India lost 4 significant early wickets but Rahul Dravid was still playing his one of the best innings:

"All the pillars are gone, but the wall doesn't need pillars to stand on the field"

November 07, 2009

On demand CSS and JS minimization (Java/PHP)

In web development CSS and JS play a very important role but at the same time, if you don't give proper attention, you may make your pages load really slow. I'm a yahoo fan for the standards and open technologies they have come up for the web. If you are a web developer, i strongly recommend these Exception Performance Blog and High performance websites.

Recently in my current work i'd to deal with a requirement where we had a couple of common JS libraries and some common CSS files along with some custom JS and CSS per user too. If you read the above two links, you must be thinking about JS and CSS compression for each of these files. There is an issue though, you will be hitting your server multiple times for each of these files. Since its common for a sufficiently large project to have multiple JS and CSS files, you've to make a choice between combining all the code into very few files vs keeping individual application logic separate. Well i decided to keep them separate :) This may sound absurd, but here is the learning from Y! days that helped me, i decided to not only load them in one go, but as well compress them. Thanks to YUICompressor (it was easy to adapt since its java based). As far as compression performance is concerned, once you compress it, you can always keep it cached for future transmissions. Some data on the performance:

JS - fairly complex (extjs based OO JS) - 1.4 MB - 532 msec - compression achieved 56%
CSS - fairly complex - 1.1 MB - 328 msec - compression achieved 52%

Now depending on the complexity of these source files, the compression might differ, but i'm confident it should not vary way too much from what i've mentioned above.

In our case, we had strict performance requirements to serve most of the requests in sub msecs, so we decided to go the caching way, otherwise i don't think on the fly compression of JS/CSS using YUICompressor is any bad (looking at the numbers above). Below is the code for the portion that does compression (again, its not mine, credit goes to the creators of YUICompressor, i just stripped this piece for my purpose)

JavaScriptCompressor compressor = new JavaScriptCompressor(
    new FileReader("original.js"), new ErrorHandler());
  StringWriter out = new StringWriter("new.js");
  int linebreakpos = 80;
  boolean munge = true, verbose = false, preserveAllSemiColons = false, disableOptimizations = false;
  compressor.compress(out, linebreakpos, munge, verbose,
    preserveAllSemiColons, disableOptimizations);
class ErrorHandler implements ErrorReporter {

  public void warning(String message, String sourceName, int line,
    String lineSource, int lineOffset) {
   if (line < 0) {
    System.err.println("\n[WARNING] " + message);
   } else {
    System.err.println("\n[WARNING] " + line + ':' + lineOffset
      + ':' + message);
   }
  }

  public void error(String message, String sourceName, int line,
    String lineSource, int lineOffset) {
   if (line < 0) {
    System.err.println("\n[ERROR] " + message);
   } else {
    System.err.println("\n[ERROR] " + line + ':' + lineOffset + ':'
      + message);
   }
  }

  public EvaluatorException runtimeError(String message,
    String sourceName, int line, String lineSource, int lineOffset) {
   error(message, sourceName, line, lineSource, lineOffset);
   return new EvaluatorException(message);
  }
 }
CssCompressor compressor = new CssCompressor(new FileReader("original.css"));
  StringWriter out = new StringWriter("new.css");
  int linebreakpos = 80;
  compressor.compress(out, linebreakpos);
One could very well pass a "null" instead of the ErrorHandler instance but make sure that verbose is set to false, else you will get a NPE. So this is just the compression part, what about reducing the number of requests?? Well so i created a servlet that basically takes all the required parameters for loading these static resources and serves them from cache or classpath (well some intelligence required here to avoid serving unwanted stuff but thats pretty straight forward. If you want to know what i did for this, post in comments and i will see if i should post that as well). And just FYI, Y! does similar thing for distributing such files through CDN. Just go to any of the pages on yahoo.com and you would see script urls of the kind
  • http://yui.yahooapis.com/combo?2.8.0r4/build/animation/animation-min.js&2.8.0r4/build/connection/connection-min.js&2.8.0r4/build/container/container-min.js
Now i'm not sure what is done in the backend, but i got this idea looking at their urls. And if you are wondering what if you want to use PHP, there is a similar project called Minify on google code which uses similar concepts borrowed from Y!'s guidelines. That's it for now... more to come!! :-)

October 31, 2009

Interesting case study on innovations in Indian context

http://online.wsj.com/article/SB125598988906795035.html

Coke Studio Songs

Just thought to share this interesting musical fusion that was being aired on some pakistani channel. I loved most of the songs. Here is a link with downloadable mp3s

http://www.koolmuzone.com/2009/08/coke-studio-episode-5-download-audios-videos/

October 12, 2009

Thought of the day...

Stolen from Ghai's fb post, but it was worth it:

"We don’t get a chance to do that many things, and every one should be really excellent. Because this is our life. Life is brief, and then you die, you know? And we’ve all chosen to do this with our lives. So it better be damn good. It better be worth it." - Steve Jobs

Regex Pattern for Validating Email addresses

Interesting post here talks about how complex RFC 822 is, that defines a valid email address. But thankfully the guy found a simpler pattern from msdn and modified it to put more restriction on the regex; here it goes:-

"^([\w]+)(([-\.][\w]+)?)*@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"

However this pattern fails to approve email ids like "mygroup+subscribe@mygroups.com" which is a common pattern used by listserv email lists. There are few more cases when email bots send you emails containing reply to addresses like "mygroup+confirm-23EWEJEW233@mygroups.com" where you reply and using the session id "23EWEJEW233", your a/c is activated or something. Writely (now Google docs) uses a similar pattern allowing you to upload documents through emails; their email ids are of type "xyz+pqr-12345678901234567890-SDWEPO23@prod.writely.com"

To verify if a value is passing through this perl regex filter, i used the following command:
echo [candidate_value]|grep -P [pattern]
and then checking "echo $?", if its 0, the pattern matches, else it failed. Actually if the pattern matches, you will see the [candidate_value] printed as well.

Turns out adding support for '+' as additional symbol was the only thing required. The modified regex looks exactly the same, except one character "+" added in the sequence.

"^([\w]+)(([-\.\+][\w]+)?)*@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"
For ex:
  1. echo "abc.pp@fjdsf.sdsd.dsdsds.com"|grep -P "^([\w]+)(([-\.\+][\w]+)?)*@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"
    passes the regex
  2. echo   "abc.@fjdsf.sdsd.dsdsds.com"|grep -P "^([\w]+)(([-\.\+][\w]+)?)*@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"
    fails the regex
  3. echo "xyz+pqr-12345678901234567890-SDWEPO23@prod.writely.com"|grep -P "^([\w]+)(([-\.\+][\w]+)?)*@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"
    passes the regex

October 03, 2009

selecting from a combobox, populated using JsonStore in extjs

gotcha.. it took me quite sometime in figuring this out. I was populating the combobox from a JsonStore and then wanted to select one of the values by default.

The documentation for
setValue(String v) : Ext.form.Field 
says:
Sets the specified value into the field. If the value finds a match, 
the corresponding record text will be displayed in the field. If the 
value does not match the data value of an existing item, and the 
valueNotFoundText config option is defined, it will be displayed as 
the default field text. Otherwise the field will be blank (although 
the value will still be set).
Parameters:

    * value : String
      The value to match

However it doesn't say what does it mean by "value into the field". Atleast i got confused and was trying with all sorts of permutation/combination (this is what happens when you get stuck with something and don't know a way out). It did mean the value that you want to submit along with the form. So just in case some poor soul is stuck like me, here is the code on how to do it.
var jsonStore = new Ext.data.JsonStore({
        storeId: 'my-json-store',
        // store configs
        autoDestroy: true,
        autoLoad: true,
        proxy: new Ext.data.HttpProxy({
            url: /relative_backend_url, 
            method: 'GET'
        }),
        // reader configs
        root: 'response',
        idProperty: 'elemId',
        fields: [ 'name', 'elemId', 'description' ]
    });

jsonStore.on('load', function(store, data){
    Ext.each(data, function (elem){
            if(elem['name'] == some_value_to_compare) {
                var combo = Ext.getCmp('my-json-combo');
                combo.setValue(elem['elemId']);
            }
 });
     // or if you already know the value of elemId, lets call it xValue for which you 
     // want to show the element, go for combo.setValue(xValue)
});

JSON response from the backend looks something like this:
{
    "response": [{
        "description": "Some long description",
        "name": "Name of the element",
        "elemId": "af02a9d6-a11c-11de-bcd5-b2e876978f0a"
    }],
    "success": true
}