Setting Nginx, PHP Fastcgi and XCache on a new Ubuntu

Recently, because of a mandatory VPS move I had an opportunity to migrate all my sites from apache to nginx. My old box was in a messy state and setting up a new box from scratch was always going to be fun. Here in this post, I will walk you through all the steps that helped me migrate seamlessly. Specially, how did I setup the new box ensuring zero downtime on the sites.

Ensuring zero downtime while migration:
By the time I will pin up various pieces on my new vps box, I didn’t want my site visitors to see an under-maintenance page. To ensure zero downtime, I usually follow these steps:

  • Setup the new vps with nginx, php-fastcgi, etc as described later in the post
  • To verify the setup on new vps, edit the local host file depending upon your operating system
    /private/etc/hosts (mac)
    /etc/hosts (ubuntu)
    C:WindowsSystem32driversetchosts (windows)
    

    Go ahead and add the following host entry:

    99.198.122.216 abhinavsingh.com

    where, 99.198.122.216 is my new vps ip address and abhinavsingh.com is a vhost configured to handle by nginx on my new vps

  • Now, whenever I visit http://abhinavsingh.com in my browser, my local machine will point it to my new vps box. However, all other visitors will still be served by apache on old vps.
  • After verifying the setup, I simply remove previously added host setting on my local box and update the DNS settings for my site at godaddy.

To start with, just add up the required host setting on your local system.

Installing Nginx and configuring vhosts:
Follow these steps to install nginx webserver:

  • Update and upgrade apt-get and install nginx
    sudo apt-get update
    sudo apt-get upgrade
    sudo apt-get install nginx
  • Configure vhost for nginx by creating a file /etc/nginx/sites-available/mysite.com as follows:
    server {
            listen   80;
            server_name  mysite.com;
            access_log  /var/log/nginx/mysite.access.log;
    
            root   /var/www/mysite;
            index  index.php index.html index.htm;
    
            location / {
            }
    }
  • Enable vhost by creating a symlink as follows:
    cd /etc/nginx/sites-enabled
    ln -s /etc/nginx/sites-available/mysite.com mysite.com
    sudo /etc/init.d/nginx restart
  • Assuming you have configured your local host file correctly, try visiting http://mysite.com and your browser will take it to the new vps

Setting up php-fastcgi and xcache:
Here are the steps to configure php-fastcgi and how to ensure php-fastcgi is up and running even after system reboot. We will also configure xcache for better performance.

  • sudo apt-get install php5-cgi php5-cli php5-xcache
  • Download php-fastcgi default config and place it at /etc/default/php-fastcgi
  • Download php-fastcgi init.d script and place it at /etc/init.d/php-fastcgi
  • Add php-fastcgi init.d as startup script
    update-rc.d -f php-fastcgi defaults
  • Update following fields inside /etc/php5/conf.d/xcache.ini:
    xcache.admin.user = "admin"
    xcache.admin.pass = "pass"
    xcache.size  =  128M
    xcache.count = 4

    xcache.count should ideally be equal to cat /proc/cpuinfo |grep -c processor

  • Setup xcache admin interface:
    cd /var/www
    ln -s /usr/share/xcache/admin xcache
  • Update /etc/php5/cgi/php.ini as per your requirements and start php-fastcgi process
    sudo /etc/init.d/php-fastcgi start
  • Visit xcache admin panel http://vps_ip_address/xcache

Stitching php-fastcgi and nginx vhosts:
Now lets enable php for vhosts configured with nginx:

  • Download nginx fastcgi param config file and place it at /etc/nginx/fastcgi.conf
  • Update /etc/nginx/sites-available/mysite.com with following config:
    location ~ .php$ {
                    fastcgi_pass    127.0.0.1:9000;
                    fastcgi_index   index.php;
                    fastcgi_param   SCRIPT_FILENAME /var/www/mysite$fastcgi_script_name;
                    include         /etc/nginx/fastcgi.conf;
            }
    
  • Restart nginx and we are done

Here we complete the vps setup and vhost configurations. Verify the new vps setup and once satisfied update site’s DNS settings. Another challenge involving migration from apache to nginx includes rewriting apache .htaccess rewrite rules for nginx. However, I will keep that for another post.

Making cross-sub-domain ajax (XHR) requests using mod_proxy and iframes

One of the restrictions imposed by all browser side programming languages is that one cannot make cross-domain ajax requests. This restriction comes because of the same origin policy and even sub-domain ajax calls are not allowed. In this blog post, I will demo two methods of making cross-sub-domain ajax requests. First demo will use mod_proxy module of Apache. While the second demo will use iframe and javascript tricks for making sub-domain ajax requests.

Using mod_proxy for cross-domain ajax requests
By enabling mod_proxy module of apache2, we can configure apache in reverse proxy mode. In reverse proxy mode, apache2 appears be like an ordinary web server to the browser. However depending upon the proxy rules defined, apache2 can make cross-domain request and serve data back to the browser.

Demo Link for Cross Domain Ajax using Apache mod_proxy

In this demo, I will make cross-domain request to http://gtalkbots.com/reverse-proxy-data.php. To make this cross-domain request successful, I have configured apache2 as shown below:

  1. Enable mod_proxy module.
    $ a2enmod proxy
    $ a2enmod proxy_http
    $ a2enmod proxy_connect
  2. Add the following lines to httpd.conf:
    $ cat /private/etc/apache2/httpd.conf | grep mod_proxy
    
    LoadModule proxy_module libexec/apache2/mod_proxy.so
    LoadModule proxy_connect_module libexec/apache2/mod_proxy_connect.so
    LoadModule proxy_http_module libexec/apache2/mod_proxy_http.so
  3. Create a file reverse-proxy.conf and add the following config:
    $ cat /private/etc/apache2/other/reverse-proxy.conf
    
    ProxyRequests Off
    
    <Proxy *>
    Order deny,allow
    Deny from all
    Allow from .abhinavsingh.com
    </Proxy>
    
    ProxyPass /webdemos/crossdomainajax/reverse-proxy-get.php http://gtalkbots.com/reverse-proxy-data.php
    ProxyPassReverse /webdemos/crossdomainajax/reverse-proxy-get.php http://gtalkbots.com/reverse-proxy-data.php

In brief, when Apache sees an incoming ajax request to /webdemos/crossdomainajax/reverse-proxy-get.php , it simply proxy pass it to http://gtalkbots.com/reverse-proxy-data.php and return back the response. The whole process is hidden from the users on the demo page.

Using iframes for cross-domain ajax requests
Another method of achieving sub-domain ajax requests is by using iframes. However, javascript does not allow communication between two frames if they don’t have same document.domain. The simplest of the hacks to make this communication possible is to set document.domain of the iframe same as that of the parent frame.

Demo Link for Sub-Domain Ajax using iFrames

In this demo, I will make a sub-domain request to http://img1.abhinavsingh.com/iframe-data.php. To make this possible, I load an iframe with src="http://img1.abhinavsingh.com/iframe-demo.php" and set document.domain="abhinavsingh.com"; for the iframe.

iframe-demo.php

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<script type="text/javascript">
	jQuery(function($) {
		function getTimestamp() {
			$.get(ajax_url,
				{},
				function(data) {
					$('#iframe_ajax_data', top.document).html('Server time received through iframe ajax: '+data);
				}
			);
		}

		document.domain = "abhinavsingh.com";
		$('#link', top.document).click(function() {
			getTimestamp();
		});
	});
</script>

In brief, iframe-demo.php sets an onclick event on $('#link' top.document) , which makes a sub-domain ajax request to http://img1.abhinavsingh.com/iframe-data.php

Enjoy!

Introducing jSlider: A Content Slider plugin for JQuery

jSlider is a light weight JQuery plugin for content sliding. By content we mean everything: HTML code, Images, Advertisements etc etc. jSlider allows to put our content in simple <div>‘s, and then it automatically generates a content slider for you, which one can customize using various options provided.

Screenshot
Below is a screen shot of a content slider using jSlider:

jSlider

Download and Demo
jSlider is hosted at google code. Use the following links for demo and downloads:

Using jslider.jquery.js
Below is a sample html code which will be processed by jslider:

Sample input to jslider

    <div id="jslider">
      <div>
        <input type="hidden" value="Title for Content 1"/>
        <div>
          HTML Content # 1
        </div>
      </div>
      <div>
        <input type="hidden" value="Title for Content 2"/>
        <div>
          HTML Content # 2
        </div>
      </div>
      <div>
        <input type="hidden" value="Title for Content 3"/>
        <div>
          HTML Content # 3
        </div>
      </div>
      <div>
        <input type="hidden" value="Title for Content 4"/>
        <div>
          HTML Content # 4
        </div>
      </div>
      <div>
        <input type="hidden" value="Title for Content 5"/>
        <div>
          HTML Content # 5
        </div>
      </div>
    </div>

One must preserve the div structure as given in the example above. The hidden input values will be taken as heading for that block of content. If you want to have no heading or a common heading, fill this hidden input field appropriately.

Sample output from jslider

  <div id="jslider">
    <div class="slider">
      <h2>Title for Content 1</h2>
      <ul>
        <li class="selected">1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
      </ul>
    </div>
    <div class="content">
      <div class="block">
        <input type="hidden" value="Title for Content 1"/>
        HTML Content # 1
      </div>
      <div class="block">
        <input type="hidden" value="Title for Content 2"/>
        HTML Content # 2
      </div>
      <div class="block">
        <input type="hidden" value="Title for Content 3"/>
        HTML Content # 3
      </div>
      <div class="block">
        <input type="hidden" value="Title for Content 4"/>
        HTML Content # 4
      </div>
      <div class="block">
        <input type="hidden" value="Title for Content 5"/>
        HTML Content # 5
      </div>
    </div>
  </div>

Customizing jslider.jquery.js
jSlider provides following options for customization:

  1. width: Width of jslider div above, defaults to ‘610px’
  2. height: Height of jslider div above, defaults to ‘225px’
  3. slider_height: Height of slider div above (navigation bar), defaults to ’24px’
  4. content_height: Height of content div above, defaults to ‘180px’
  5. block_width: Width of block div inside content div’s above, defaults to ‘590px’
  6. block_padding: Padding of block div inside content div’s above, defaults to ’10px’
  7. animation_time: Time taken by 1 slide of content, defaults to 300 msec
  8. animation_type: Animation type, defaults to ‘linear’. Other option is ‘swing’

Rest of the options like various padding etc can be controlled using the css properties. View demo for more implementation details. This is my first jquery plugin and I am only 2 weeks old in jquery. If you find any bug or need any enhancement, you are most welcome.

fixed.js – Solution to IE6 “position:fixed” Bug

IE6 has been a bane for all frontend developers for years. An element can be positioned relative to the browser window using the style position:fixed, it does not move when the page is scrolled. You can do nice layout things (e.g. facebook chat bar) with this in most modern browsers but not for IE6 in windows until you use fixed.js

Sample Code for Facebook Type Chat Bar

<html>
  <head>
    <style type="text/css">
      body {
        margin:0px;
        padding:0px;
        height:1600px;
        position:relative;
      }
      #shoutbox {
        position:fixed;
        background-color:#F2F2F2;
        border-top:1px solid #CCCCCC;
        bottom:0px;
        left:0px;
        width:100%;
        height:25px;
      }
    </style>
    <script type="text/javascript" src="fixed.js"></script>
  </head>
  <body>
    <div id="shoutbox">
      <!-- Our Shoutbox -->
    </div>
  </body>
</html>

The above code will show you a bar at the bottom of the page, which remains fixed at the bottom even if you scroll the page.

How does fixed.js help me?

  1. fixed.js is smart enough to invoke only if the browser is IE6 on Windows machine. This is achieved by these two lines of code in fixed.js.
    /*@cc_on
    @if (@_win32 && @_jscript_version>4)
  2. It specifically tells IE6 how to render elements with position:fixed attributes. Which are otherwise ignored by IE6.
  3. For remaining browsers, fixed.js go to sleep silently. Doesn’t do any processing.

Download fixed.js
fixed.js is developed and maintained at doxdesk.com. Click here to download fixed.js

Happy Coding!

Getting started with Autotools – GNU Build System on Debian

The_GNU_logo
If you eat and drink open source, chances are high that you might have downloaded an open source project code, only to see files like: aclocal.m4, configure.ac, Makefile.am, Makefile.in and what not. You might have also used commands like ./configure, make etc but what are these files? Does they really belong to the project you download? Do I need to understand them? In this blog post I look forward to answer all your question, as well as introduce you to not so popular Autotools – A GNU Build System.

Setting up Autotools on Debian?
Before we go ahead and understand what Autotools is, we will try building a HelloWorld package. Lets get started by setting up Autotools on debian machine.

  • apt-get install build-essential
  • gcc –version (verifying install)
  • g++ –version (verifying install)
  • apt-get install automake autoconf

You have your environment ready. Lets start packaging the HelloWorld package.

Hello World Source Code
Download full source code from here

We will need to create 5 files for our basic HelloWorld package. Start by creating a directory structure like this:
HelloWorld
    — configure.ac
    — Makefile.am
    — README
    — src
        — Makefile.am
        — helloworld.c

src/helloworld.c

#include <config.h>
#include <stdio.h>

int main (void) {
    puts ("Hello World!");
    puts ("This is " PACKAGE_STRING ".");
    return 0;
}

Note we don’t have a config.h file but still we include it here. In actual config.h will be autogenerated by the autotools, when we build the package. Similarly, PACKAGE_STRING will be a pre-defined variable inside config.h.

src/Makefile.am

bin_PROGRAMS = helloworld
hello_SOURCES = helloworld.c

Here we tell the build system to generate a binary named helloworld using the sources defined below i.e. helloworld.c

Makefile.am

SUBDIRS=src
dist_doc_DATA=README

Here we give information about the various sub-directory. For a bigger project you might have a man directory, data directory etc. Also we tell the build to package README file with the build.

README

This is a demonstration HelloWorld package for GNU Automake.
Type `info Automake' to read the Automake manual.

configure.ac

AC_INIT([helloworld], [1.0], [[email protected]])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_PROG_CC
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
 Makefile
 src/Makefile
])
AC_OUTPUT

Don’t leave the post on seeing the above file. We will go through each and every one of them. configure.ac contains a series of M4 macros that will expand to some shell code to finally generate the configure script. Autotools have utilities like automake and autoconf (details below) which read this file to generate intermediate and final build files. The variables starting with AC_ are Autoconf macros and those starting with AM_ are Automake macros.

  1. AC_INIT: Initializes autoconf. It takes 3 input parameters: Name of the package, Version of the package and Contact address for bug reports
  2. AM_INIT_AUTOMAKE: Initializes automake. It can take a number of available input parameters. -Wall -Werror specifically tells automake to turn on all warnings and report them as error. While development we will keep error reporting turned on. foreign tells automake that this package doesn’t follow GNU standard. As per GNU standards we should also distribute files like ChangeLog, AUTHORS and at this stage we don’t want automake to complaint about them.
  3. AC_PROG_CC: This line tells configure script to search available C compilers and define variable CC with its name. Later on many intermediate files will use this variable CC for building binary files.
  4. AC_CONFIG_HEADERS: It tells the configure script to generate a config.h file which is pre-included by helloworld.c. Generated config.h will have content like this:
    /* config.h.  Generated from config.h.in by configure.  */
    /* config.h.in.  Generated from configure.ac by autoheader.  */
    
    /* Name of package */
    #define PACKAGE "helloworld"
    
    /* Define to the address where bug reports for this package should be sent. */
    #define PACKAGE_BUGREPORT "[email protected]"
    
    /* Define to the full name of this package. */
    #define PACKAGE_NAME "helloworld"
  5. AC_CONFIG_FILES: This tells configure script list of files from which it should generate it’s *.in templates. This variable is also used by automake utility to know list of Makefile.am it should process. (Note: Each directory should have a Makefile.am file and as you keep adding new directories keep adding them to AC_CONFIG_FILES, else build will not consider your new directories while building packages.
  6. AC_OUTPUT: It is a closing command that actually produces the part of the script in charge of creating the files registered with AC_CONFIG_HEADERS and AC_CONFIG_FILES.

Building a Hello World package for distribution
Lets create our first package for distribution.

  1. cd path/to/helloworld/directory: Migrate to the project directory
  2. autoreconf –install: This command initiates the build system. You should see something like this as output:
    configure.ac:2: installing `./missing'
    configure.ac:2: installing `./install-sh'
    src/Makefile.am: installing `./depcomp'
    

    Also if you scan through the HelloWorld directory, you will find a lot of new files being generated by the build system. Particularly you will see a Makefile.in being generated for each Makefile.am. Apart from these files of interest are configure and config.h.in.

  3. ./configure: It utilizes *.in files generated by the previous step to build the Makefile, src/Makefile and config.h. You should see something like this on your console:
    checking for a BSD-compatible install... /usr/bin/install -c
    checking whether build environment is sane... yes
    checking for a thread-safe mkdir -p... /bin/mkdir -p
    checking for gawk... no
    checking for mawk... mawk
    checking whether make sets $(MAKE)... yes
    checking for gcc... gcc
    
  4. make
  5. src/helloworld: This will output this on the console.
    Hello World!
    This is helloworld 1.0.
  6. make distcheck: This utility finally creates the helloworld-1.0.tar.gz package for distribution. You should see this on your console on running this utility:
    ================================================
    helloworld-1.0 archives ready for distribution:
    helloworld-1.0.tar.gz
    ================================================

Installing distributed HelloWorld package

  1. Copy the generated package into your temp directory and then issue the following commands
  2. tar -xzvf helloworld-1.0.tar.gz
  3. cd helloworld-1.0
  4. ./configure
  5. make
  6. make install

make install will copy the helloworld binary into the /usr/local/bin directory. Try running helloworld from command line and you should see a similar output, as we saw above while building the package. Further it also copies the README file under /usr/local/share/doc/helloworld directory. If your built package includes the man directory, it gets copied to /usr/local/share/man automatically.

What is Autotools?
Autotools is a build system developed by GNU which helps you distribute your source code across various Unix systems. The files you are wondering about are auto generated by the Autotools.

Autotools is a combination of several utilities made available by GNU, including:

  1. Autoconf
  2. Automake

There are many others which can be listed above, but for this blog post we will restrict ourselves to Automake and Autoconf only.

Autoconf
autoconf process files like configure.in to generate a configure script. When we run the configure script, it reads other template files like Makefile.in to generate a final output file, in this case Makefile

Automake
It reads all Makefile.am and generate corresponding Makefile.in, used by the configure script as described above.

Happy Packaging!

Getting started with Openlaszlo – Framework for developing flash apps

Openlaszlo is an open source framework which simplifies development of flash applications. Openlaszlo allows you to code your flash apps using xml style laszlo code, and thereafter you can compile your code to output a .swf file for production usage. I first came around openlaszlo while I was developing Alterplayer – open source flash mp3 player.

In this post I will demonstrate:

  • Getting started with Openlaszlo – Setting up your dev enviornment
  • Hello World! in Openlaszlo
  • Upcoming tutorials

Setting up Openlaszlo development environment

  1. Download the latest openlaszlo release 4.4 from http://openlaszlo.org/download or alternatively download directly from http://download.openlaszlo.org/4.4.0/openlaszlo-4.4.0-windows-dev-install.exe
  2. Double click and install the setup. For me on WinXP, it installs in the following location. C:Program FilesOpenLaszlo Server 4.4.0
  3. Upon installation tomcat server will start automatically. If it doesn’t, click the following file to start the tomcat server. C:Program FilesOpenLaszlo Server 4.4.0Serverlps-4.4.0lpsutilsstartTomcat.bat
  4. At any point in time when you want to stop the tomcat server, click the stopTomcat.bat file lying in the same folder.
  5. Browse to the following location on your firefox, to see the opening welcome screen http://127.0.0.1:8080/lps-4.4.0/laszlo-explorer/index.jsp
  6. Create a folder inside C:Program FilesOpenLaszlo Server 4.4.0Serverlps-4.4.0, called Workspace. We will do all our development in this directory.
  7. Create a folder called HelloWorld inside Workspace. We will start developing our first project straight away

Hello World! in OpenLaszlo
Like in any other language and framework, we will learn how to write a Hello World! program.

  1. Create a file helloworld.lzx inside the Hello World folder
  2. 
      Hello World!
    
  3. Browse to the following location on your browser: http://127.0.0.1:8080/lps-4.4.0/Workspace/HelloWorld/helloworld.lzx
  4. Did you see HelloWorld! ? Bingo

Hello World! Explained

  1. Each and every openlaszlo code file have an extension .lzx
  2. Each and every laszlo code is wrapped inside <canvas></canvas> tag
  3. <text></text> is a class used for non-editable text fields. Here it will simply display Hello World! on the browser.

Debugging in Openlaszlo
One of the strong feature which comes packaged with openlaszlo, is it’s support for debugging. When you visited the above link in your browser, along with Helllo World! text you must have seen a debugger window too. Mainly because we had <canvas debug=”true”>, debug true in our code.

If you might have noticed, I have given an id to out <text></text> node. Lets see how can we make use of it while debugging. Suppose you didn’t get what you really wanted out of your code, for instance suppose you mistyped Hello World! as Helo World!. Simply go ahead and type the element id in the debugger window.

For instance here I will type in the id of the element i want to inspect i.e. id=”helloworld”. As I press enter, debugger shows me all the details about my element of interest.
getting_started_with_openlaszlo

Another thing you can do from within the code is, print out your debug logs on the debugger screen. For instance modify the above code as follows and refresh your app on the browser:


  
    Hello World!
  
  

Above code will simply throw a string “I just printed a Hello World!” on the debugger string. In you application you can ever throw a variable value for debugging purpose.

Upcoming tutorial
In the next tutorials on openlaszlo, I will explain:

  1. How to create an alterplayer out of openlaszlo. Meanwhile I would like you to go through my previous post on openlaszlo: How to create a single button flash audio player using Openlaszlo?
  2. How to build an imoracle video player out of openlaszlo.

Both the projects will be opensource under GNU General Public License v3.

Also you may want to visit the following reference on openlaszlo official site:
http://www.openlaszlo.org/lps3/docs/reference/

Toggle : A Javascript game, anyone up for the challenge?

This weekend I came across a game made using java applets. Initially looked like its possible to solve it, but slowly we realized that there might be no solution to this game. Finally I decided to clone it using javascript and see if you can solve the same.

Toggle

PS: Tested on all browsers except IE

Modes:
I included a custom mode in this game. Original game had only the classic mode.

  • Classic Mode: When you click a square in classic mode, that clicked square and all neighbourhood squares toggle their colors (excluding diagonal neighbours).
  • Custom Mode: In custom mode, when you click a square, the clicked square and all neighbourhood squares toggle their colors (including diagonal neighbours).

Rules:

  • Destination is to fill all the squares with black color.
  • Ideally game should be played in a single mode only. However I have provided an option where you can switch modes in between the game. So you are free to either play it in a single mode throughout, or switch modes as and when you feel is the requirement
  • If you are finally able to make it, click view history, copy the steps you followed to conquer this game and post it as a comment to this blog post

Source Code:
The source code consists of toggle.js and toggle.css. Find below the source code, and towards the end, find how to embed the same on your page/blog.

toggle.css

/*

  Script: toggle.css
  Author: Abhinav Singh mailsforabhinav[at]gmail[dot]com
  Website: http://abhinavsingh.com
  Code license: GNU General Public License v3

*/
.box {
  border:1px solid #000000;
  cursor:pointer;
}
.boxColored {
  border:1px solid #FFFFFF;
  background: #000000;
  cursor:pointer;
}

toggle.js

/*

  Script: toggle.js
  Author: Abhinav Singh mailsforabhinav[at]gmail[dot]com
  Website: http://abhinavsingh.com
  Code license: GNU General Public License v3

*/
Array.prototype.unique = function(b) {
  var a = [], i, l = this.length;
  for(i=0; i<l; i++) {
    if(a.indexOf(this[i], 0, b) < 0) { a.push(this[i]); }
  }
  return a;
};
var $ = {
  html: '',
  cid: 'container',
  xBoxes: 5,
  yBoxes: 5,
  boxWidth: 50,
  boxHeight: 50,
  version: 'classic',
  history: Array(),
  init: function() {
    var tmp = '';
    for(var i=0;i<this.yBoxes;i++) {
      for(var j=0;j<this.xBoxes;j++) {
        tmp += '<div onclick="$.toggle(this)" name="box" id="box-'+i+'-'+j+'" style="position:absolute; left:'+(j*this.boxWidth)+'px; top:'+(i*this.boxHeight)+'px; height:'+this.boxHeight+'px; width:'+this.boxWidth+'px" class="box">';
        tmp += '</div>';
      }
    }
    tmp += '<div style="position:absolute; top:'+((this.yBoxes*this.boxHeight)+5)+'px; left:0px;">';
    tmp += '  <b style="float:left">Version:</b> ';
    tmp += '  <select style="float:left" id="version" onchange="$.version = this.options[this.selectedIndex].value;">';
    tmp += '    <option value="classic">Classic</option>';
    tmp += '    <option value="custom">Custom</option>';
    tmp += '  </select>';
    tmp += '  <div style="float:left; padding-left:20px; text-decoration:underline; cursor:pointer;" onclick="alert($.history.unique())">View History</div>';
    tmp += '</div>';
    document.getElementById(this.cid).innerHTML = tmp;
  },
  toggle: function(t) {
    this.history.push((t.id.toString()).replace('box-',''));
    id = t.id; ids = id.split("-");
    xid = parseInt(ids[1]); yid = parseInt(ids[2]);

    for(var l=xid-1; l<=xid+1; l++) {
      for(var m=yid-1; m<=yid+1; m++) {
        if(l>=0 && l<this.xBoxes && m>=0 && m<this.yBoxes) {
          if(this.version == "classic") {
            if((l == xid-1 && m == yid-1) || (l == xid+1 && m == yid-1) || (l == xid-1 && m == yid+1) || (l == xid+1 && m == yid+1)) {

            }
            else {
              var boxid = document.getElementById('box-'+l+'-'+m);
              if(boxid.className == "box") boxid.className = "boxColored";
              else if(boxid.className == "boxColored") boxid.className = "box";
            }
          }
          if(this.version == "custom") {
            var boxid = document.getElementById('box-'+l+'-'+m);
            if(boxid.className == "box") boxid.className = "boxColored";
            else if(boxid.className == "boxColored") boxid.className = "box";
          }
        }
      }
    }
  }
}
$.init();

How to embed toggle on my page/blog?

  • Simply copy the js and css files from above or download them from here: toggle.js, toggle.css
  • Include the two on your page/blog. toggle.js automatically calls up $.init() on load. $.init() method will look for a div with id $.cid on you page, and populate the game in the same div. Hence make sure you have a div with id $.cid on the page.
  • $.xBoxes, $.yBoxes, $.boxWidth, $.boxHeight are a few tunable parameters you may want to play with

Happy Toggling!

Konami Code on Facebook : How to implement it on your site

Yesterday while chatting with friends, I discovered an unusual thing on facebook. Unusual because I didn’t see any sense in what I saw back then. The process to discover this unusual thing is as follows:

How to view lens flare on facebook
1. Login to facebook.com
2. Click once anywhere on your home page
3. Click the following sequence of characters using your keyboard
4. Up, Up, Down, Down, Left, Right, Left, Right, B, A, Enter Key
5. Click again on the page or try to scroll the page up or down

If everything is done correctly you will see something like this:
lensflare on facebook

On more investigation I found out this unusual thing is nothing but “Konami Code“, which is a cheat code that appears in many Konami video games. The Konami code was introduced to many gamers in the 1988 NES version of Contra. Due to the game’s intense difficulty, many Contra players became reliant on the cheat code, which increased the player’s lives from 3 to 30 (9 to 90 including continues), to finish the game. The game’s popularity, combined with the near-necessity of using the code, made it renowned to an entire generation of video game players. This led to the code being used in countless games, and even mentioned across popular culture.

Once the cheat code is entered, facebook extends it to enable Lens Flare on all the pages you visit thereafter. You can use the below code, to enable-disable komani code on your site, and thereafter extend it to anything you want to:

  <head>
    
  </head>
  <body onload="$.init()" onkeydown="$.konamiCode(event)">
  </body>

Try out once on facebook and then come back to grab it for your site.
Enjoy!

Getting Google Page Rank using Javascript – For Adobe AIR Apps

Last week while working on SEO Analyzer v 1.1 desktop application, I faced a challenge of getting google page rank for a particular site using javascript. I am not sure if someone has already done this before, but I thought of sharing this javascript code for all adobe air and web developers out there.

googlepagerank.js

var googlepagerank = {
	hexdec: function(hex_string) {
	    hex_string = (hex_string+'').replace(/[^a-f0-9]/gi, '');
	    return parseInt(hex_string, 16);
	},
	count: function( mixed_var, mode ) {
	    var key, cnt = 0;
	    if( mode == 'COUNT_RECURSIVE' ) mode = 1;
	    if( mode != 1 ) mode = 0;
	    for (key in mixed_var){
	        cnt++;
	        if( mode==1 && mixed_var[key] && (mixed_var[key].constructor === Array || mixed_var[key].constructor === Object) ){
	            cnt += count(mixed_var[key], 1);
	        }
	    }
	    return cnt;
	},
	sizeof: function( mixed_var, mode ) {
	    return googlepagerank.count( mixed_var, mode );
	},
	ord: function(string) {
	    return (string+'').charCodeAt(0);
	},
	strlen: function(string) {
	    var str = string+'';
	    var i = 0, chr = '', lgth = 0;
	    var getWholeChar = function (str, i) {
	        var code = str.charCodeAt(i);
	        var next = '', prev = '';
	        if (0xD800 <= code && code <= 0xDBFF) {
	            if (str.length <= (i+1))  {
	                throw 'High surrogate without following low surrogate';
	            }
	            next = str.charCodeAt(i+1);
	            if (0xDC00 > next || next > 0xDFFF) {
	                throw 'High surrogate without following low surrogate';
	            }
	            return str[i]+str[i+1];
	        } else if (0xDC00 <= code && code <= 0xDFFF) {
	            if (i === 0) {
	                throw 'Low surrogate without preceding high surrogate';
	            }
	            prev = str.charCodeAt(i-1);
	            if (0xD800 > prev || prev > 0xDBFF) {
	                throw 'Low surrogate without preceding high surrogate';
	            }
	            return false;
	        }
	        return str[i];
	    };
	    for (i=0, lgth=0; i < str.length; i++) {
	        if ((chr = getWholeChar(str, i)) === false) {
	            continue;
	        }
	        lgth++;
	    }
	    return lgth;
	},
	substr: function(f_string,f_start,f_length ) {
			f_string += '';
			if(f_start < 0) {
					f_start += f_string.length;
			}
			if(f_length == undefined) {
					f_length = f_string.length;
			} else if(f_length < 0){
					f_length += f_string.length;
			} else {
					f_length += f_start;
			}
			if(f_length < f_start) {
					f_length = f_start;
			}
			return f_string.substring(f_start, f_length);
	},
	zeroFill: function(a, b){
		z = googlepagerank.hexdec(80000000);
		if (z & a) {
			a = (a >> 1);
			a &= (~ z);
			a |= 0x40000000;
			a = (a >> (b - 1));
		}
		else {
			a = (a >> b);
		}
		return a;
	},
	mix: function(a, b, c){
		a -= b; a -= c; a ^= (this.zeroFill(c, 13));
		b -= c; b -= a; b ^= (a << 8);
		c -= a; c -= b; c ^= (this.zeroFill(b, 13));
		a -= b; a -= c; a ^= (this.zeroFill(c, 12));
		b -= c; b -= a; b ^= (a << 16);
		c -= a; c -= b; c ^= (this.zeroFill(b, 5));
		a -= b; a -= c; a ^= (this.zeroFill(c, 3));
		b -= c; b -= a; b ^= (a << 10);
		c -= a; c -= b; c ^= (this.zeroFill(b, 15));
		return new Array(a, b, c);
	},
	ch: function(url){
		length = googlepagerank.sizeof(url);
		a = 0x9E3779B9;
		b = 0x9E3779B9;
		c = 0xE6359A60;
		k = 0;
		len = length;
		while (len >= 12) {
			a += (url[k + 0] + (url[k + 1] << 8) + (url[k + 2] << 16) + (url[k + 3] << 24));
			b += (url[k + 4] + (url[k + 5] << 8) + (url[k + 6] << 16) + (url[k + 7] << 24));
			c += (url[k + 8] + (url[k + 9] << 8) + (url[k + 10] << 16) + (url[k + 11] << 24));
			m = this.mix(a, b, c);
			a = m[0]; b = m[1]; c = m[2];
			k += 12;
			len -= 12;
		}
		c += length;
		switch (len) {
			case 11: c += (url[k + 10] << 24);
			case 10: c += (url[k + 9] << 16);
			case 9:  c += (url[k + 8] << 8);
			case 8:  b += (url[k + 7] << 24);
			case 7:  b += (url[k + 6] << 16);
			case 6:  b += (url[k + 5] << 8);
			case 5:  b += (url[k + 4]);
			case 4:  a += (url[k + 3] << 24);
			case 3:  a += (url[k + 2] << 16);
			case 2:  a += (url[k + 1] << 8);
			case 1:  a += (url[k + 0]);
		}
		m = this.mix(a, b, c);
		return m[2];
	},
	strord: function(string){
		var result = new Array();
		for (i = 0; i < googlepagerank.strlen(string); i++) {
			result[i] = googlepagerank.ord(string[i]);
		}
		return result;
	},
	gethash: function(url) {
		return this.ch(this.strord("info:" + url));
	},
	getpr: function(baseurl) {
		var query = "";
		query += "http://toolbarqueries.google.com/search";
		query += "?client=navclient-auto";
		query += "&hl=en";
		query += "&ch=6"+googlepagerank.gethash(baseurl);
		query += "&ie=UTF-8";
		query += "&oe=UTF-8";
		query += "&features=Rank";
		query += "&q=info:"+baseurl;

		var req = new XMLHttpRequest();
		req.onreadystatechange = function(){
			if (req.readyState == 4) {
				var str = req.responseText;
				var pagerank = googlepagerank.substr(str, 9, 2);
				alert(pagerank);
			}
		}
		req.open('GET', query, true);
		req.send(null);
	}
}

How to use script in an adobe air application


	
        Google Page Rank
        
        
		
	
    

    

How to use script in an web applications
This script cannot be used directly for web applications, mainly because of cross domain XHR limitations. However the script can be modified to use with proxy script provided at developer.yahoo.com

Please Note: Getting google page rankings is/might be illegal as per google's policy. If you use this script from webservers, possibilities are google might block your server IP Address. However with adobe air applications (desktop apps), risk is minimized.

Enjoy and Do leave a comment.

Using Image Maps in Javascript – A Demo Application

Past month I was busy with project back in office, JAXL web chat client and photolog – a custom made wp-plugin for converting it into a photo blog. As I am close to finish them all, I am back to blogging after more than a month.

Here I would like to demonstrate a cool technique which I explored while working for the india elections site. We decided to have a cool india map where we could show data for each state. Though flash is always the best method to go with for such applications (and finally we did it with flash :D) I wanted to explore if we can do the same thing efficiently with javascript.

Not being a javascript expert, I first moved to various friends expert in javascript and they told me about image map technique in javascript. I did some research, read various blog posts and finally came up with the application below. (I will be demonstrating the application and challenges you will face while building such application, for basics of image map kindly search for it, you will get many tutorials on web on javascript image maps)

Challenges I faced:
Javascript image map technique utilizes the (x,y) co-ordinates which you provide to javascript. Depending upon the input (x,y) co-ordinates, javascript will build an image map over the image. When I was building this application, the biggest challenge was how to get the pixel by pixel border for each and every state. I don’t know dreamweaver, photoshop or any other software which can tell me this. Moreover, even if I knew, I was not sure how much effort will it require to note down each and every pixel lying on the state borders. Finally to counter this problem I came up with a javascript, which makes this task 99% easier.

Using javascript to detect image borders pixel by pixel:
Javascript image map requires pixel to be given in the following format (x1,y1,x2,y2,….,xn,yn). So I wrote a javascript which will automatically generate the current pixels of your mouse, in above format as you move it.

Lets try this out. Click here to open this javascript hack. Click CNTR++ (i.e. zoom into your browser) as many times as you can. You will now have a very enlarged and a bit blurred india map in front of you. But good thing is you can clearly move your mouse over state borders. This javascript gets enabled on your 1st mouse click on the map. So choose a state and click your mouse on its border. Now start moving your mouse on this state’s border till you come back to the same point, where you started. Click 2nd time on that point to disable this javascript function and WOW! Below you have the border pixel positions in the required format to be used straight with javascript image maps. Copy and paste that to get a final image map like this.

View the final image map file by clicking here.

edges.html


  
    
  
  
    

Study the source of the final application by visiting here and use the above javascript to extract edge information of your map file. I know there are some questions unanswered but I will wait for your comments to answer them 😀

PS: By demoing my application here, I permit you to use this sample code for any purpose. However I do not permit you to copy paste the indian map images for your personal or professional sites or works.