Blog

Blogging on programming and life in general.

  • Having the ability to run and develop Facebook applications within the comfort of a local environment is a must. Previously, I always thought in order to work on Facebook applications a public facing URL was required to allow Facebook to communicate with your application directly. Fortunately this is not the case.

    All you need to do is set up a server alias in your hosts file and use this alias as an “App Domain” within your Facebook Application settings.

    Quick Example

    I created a new site in Microsoft IIS called: “facebook.surinder-test.com” running under port 8008. Feel free to change the port number to your own choosing. To browse the site we need to add this web address to Windows host file (C:\Windows\System32\drivers\etc):

    # localhost name resolution is handled within DNS itself.
    #    127.0.0.1       localhost
    #    ::1             localhost
    
    127.0.0.1     facebook.surinder-test.com
    127.0.0.1     localhost
    

    This will route all your requests to ”facebook.surinder-test.com” to localhost.

    Next, make the following changes to your Facebook Application settings page:

    FB App Screen

  • Published on
    -
    1 min read

    Speed Up Firebug

    I noticed recently that Firebug was running very slow whilst inspecting elements or debugging client-side scripts. In the past when noticing performance issues in Firefox, a straight-forward opening and closing the browser normally resolved any issues.

    What I found after investigating this problem online is that Firebug keeps a record of all breakpoints and sites where Firebug was used. As you can imagine, this will accumulate over time. To remove all history, go to your Firefox profile directory which can be found here:

    C:\Users\<Windows User Account Name>\AppData\Roaming\Mozilla\Firefox\Profiles\<Firefox Profile ID>.default\firebug
    

    You will find two files within Firebug folder directory:

    • annotations.json - contains a history of website browsing.
    • breakpoints.json - contains currently set breakpoints.

    Close all running instances of Firefox and delete both files within the directory.

    Judging by posts from other users online, there could be other contributing factors to Firebug's sluggishness at times. Hopefully, by carrying out the steps above you will notice a difference.

  • We all know minimising our JavaScript files prior to moving a site into a production environment is best practise. The main reason why we do it is because compressed JavaScript files allow sites run faster at a lower bandwidth cost and (to some extent) make the code harder to understand.

    But what if we wanted to have the ability to render a JavaScript file completely unintelligible to prying eyes? This is the very question I asked myself prior to deploying a site I worked on to a live environment.

    Even though standard JavaScript minimisers remove comments, white space and use shorter variable names, we can take things a step further.

    I found a great site that manages to render your code into complete jibberish. You can give it a go by going to: http://javascriptobfuscator.com/.

    NOTE: Just as JavaScript code can be easily minimised, it can just as easily be “beautified” by going to: http://jsbeautifier.org/. Nevertheless, using the link above is a better deterrent when compared to other minimisers in my opinion.

  • Being a Web Developer and owning my own website, I’m quite interested in seeing how my site is doing when I am not in the vicinity of my computer – mainly analytics and advertising revenue. Even though Google Analytics and Adsense provides me with really good information, I was interested in seeing if there were any alternatives in app form on Android.

    To my surprise there were no official app alternatives for AdSense or Analytics. Thankfully, there are a few unofficial app's currently available to download free on the Android Market. Here are (in my opinion) the best ones:

    gAnalytics

    gAnalytics Screen Shot gAnalytics provides all the necessary types of stats you would require. Even though currently in beta, this hasn’t restricted the app in anyway and I haven’t experienced a single issue whilst using it. You have access to the following type of reporting (not a complete list):

    • Visitor stats –  pageviews, average time on site, bounce rate and new visitors.
    • Demographics – language, country and city.
    • System stats – browser, operating system, screen resolution and service provider.
    • Referral/Direct traffic.
    • Search Engine traffic – keyword and search query.
    • Content stats – page, search term and exit pages.

    If that wasn’t enough, gAnalytics lets you retrieve statistics from a given date period.

    To summarise, gAnalytics is a perfectly comprehensive and a brilliant all round app.

    AdSense Dashboard

    AdSense Dashboard ScreenshotI would say the AdSense offering in terms of reporting isn’t as comprehensive as gAnalytics. What AdSense Dashboard does do well is providing you with a heads-up view on all AdSense metrics, such as:

    • CPM
    • CTR
    • Page views
    • Clicks
    • Estimated revenue

    Unfortunately, you don’t get an option to view AdSense metrics over a specific date period. Only today, this month and year to date.

    AdSense Dashboard is a simple app giving you top-level on stats and revenue information over four different screens.

  • robocopyApologies for making a reference from the social-satire/sci-fi film that is RoboCop (1987) in my post title. It just had to be done when talking about some tool called RoboCopy. For those who aren’t aware of what RoboCopy is, where have you been? In all honesty, I myself never heard of it until a few days ago.

    RoboCopy is a command-line run tool that allows you to copy files from one directory to another. One of its most popular uses for RoboCopy is it’s ability to copy large volumes of files quicker than carrying out a manual copy and paste through a GUI, making it ideal for backup jobs. So you could easily write a backup script to run via a Schedule Task on a daily basis.

    I managed to backup around 80Gb of files in less than an hour. What’s even more impressive is that I could run numerous RoboCopy scripts at the same time. Currently, I have only run two scripts simultaneously just to be on the safe side.

    Prior to RoboCopy, I was using another command-line tool: XCopy. For my backup purposes XCopy did exactly what I wanted it to do until I came across a misleading error message: “Insufficient memory”. You would think this message would mean the destination directory to where your files are copying to is full or not enough memory resources. In matter of fact this error only happens when the fully qualified file path is longer than 254 characters. Unfortunately, I couldn’t get around this error due to the nature of how my directories are structured. Luckily, RoboCopy doesn’t have this limitation.

    One of the major strength’s of RoboCopy is the number of useful options you have at your disposal. A few example’s are:

    • Moving files.
    • Exclude certain files and file types.
    • Detailed logging that tells you new the files that have been copied or over-written.
    • Parameterised scripting.

    Example Script

    @ECHO OFF
    
    ECHO PROCESSING BACKUP ...
    
    robocopy \\work\Projects\ F:\Projects\Backup\ /mir /sl
    /log:"F:\Logs\Projects-%date:/=%.log"
    
    ECHO BACKUP COMPLETED!
    

    The script I have provided is what I use to backup files through a Schedule Task that runs at the end of every day. This script mirrors the source drive exactly. So any files that have been deleted, updated or created will have the same effect on the backup drive. In addition, a log file is created when RoboCopy is running.

    More Information

  • Moving blogAfter blogging under the “computing-studio.com” domain name for around 4 years, I think its time for a new chapter in my online presence. Last Friday I decided to buy a new domain name called http://surinder.me. At the time “computing-studio.com” domain seemed like a great idea where me and my fellow techy University friends would contribute. Unfortunately, things didn’t work out and decided to go it alone.

    From looking at the number of blog posts I have written (95 at the time of writing), you would be forgiven to make the assumption that I am not the most persistent blogger. I believe the domain has a part to play. After all, “computing-studio.com” somewhat limits what I can write and doesn’t really give me the freedom to talk about things outside my technical field.

    Even though I am a techy at heart (I guess being a web developer doesn’t help), I talk about other things non-code related through my Google+ and Twitter posts. I see having a new domain name is just the start. I am hoping to collate all my contributions from sites under the surinder.me address. So everything is about…well…me!

    All exciting stuff! I am not looking forward to implementing all the redirects and having to work my way up Google’s page rank again. But its something that has to be done.

    Watch this space!

  • I found there is an issue when implementing AddThis to a site that uses Selectivizr. Selectivizr (for those who don't know), is a JavaScript utility that emulates CSS3 pseudo-classes and attribute selectors for Internet Explorer 6-8.

    I noticed that my AddThis widget was not functioning correctly in Internet Explorer versions 6-8. So whenever Selectivizr was required, I encountered two issues:

    • Social bookmark buttons were not displaying.

    AddThis Issue No Icons

    • The AddThis popup to select more social bookmarking sites did not render correctly. It outputs all the popup contents to the bottom of the page.

    AddThis Issue Popup

    Just as I have experienced two problems with AddThis, there are two ways to resolve:

    1) Use custom buttons with AddThis

    Using custom buttons will get AddThis to display properly in your page. However, you will still experience viewing AddThis popup. So if you are not too fussed with viewing additional social bookmarking sites, then this will suffice.

    <!-- AddThis Button BEGIN -->
    <div class="addthis_toolbox addthis_default_style ">
    <a class="addthis_button_facebook"><img src="/images/facebook.png" height="16" width="16" /></a>
    <a class="addthis_button_twitter"><img src="/images/twitter.png" height="16" width="16" /></a>
    <a class="addthis_button_email"><img src="/images/email.png" height="16" width="16" /></a>
    <a class="addthis_button_reddit"><img src="/images/reddit.png" height="16" width="16" /></a>
    </div>
    <script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js#pubid=xa-4f0b42500b47b860"></script>
    <!-- AddThis Button END -->
    

    2) Modify Script tag in AddThis code snippet

    To get AddThis to work 100% alongside Selectivizr will require you to modify the script tag and add bit of jQuery. A user on Google Groups suggested this fix and resolved my issues.

    <!-- AddThis Button BEGIN -->
    <div class="addthis_toolbox addthis_default_style ">
    <a class="addthis_button_preferred_1"></a>
    <a class="addthis_button_preferred_2"></a>
    <a class="addthis_button_preferred_3"></a>
    <a class="addthis_button_preferred_4"></a>
    <a class="addthis_button_compact"></a>
    <a class="addthis_counter addthis_bubble_style"></a>
    </div>
    
    <script type="text/javascript">
    $(function()
    {
        $('head').append('<script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js#pubid=xa-4f0b42500b47b860"><\/script>');
    }); 
    </script>
    <!-- AddThis Button END -->
    
  • I’m using a jQuery plugin called “Isotope” to nicely output a mixture of news articles and advertising banners to a page.

    I came across a small issue when using advertising banner’s in Flash format. For some reason, Flash content displayed randomly and mouse-clicks were not registered. This issue only seemed to only occur in Firefox. I couldn’t replicate this issue on other browsers.

    Thankfully, only one additional line of code  needed to be added when when initially setting the Isotope plugin options:

    $('#wall').isotope({
        itemSelector: '.box',
        animationEngine: 'css,
        layoutMode: 'masonry',
        transformsEnabled: false //Disable transformations
    });
    

    The following example helped me further in resolving my issue: http://isotope.metafizzy.co/tests/flash.html

  • On Saturday 6th August 2011, I was waiting impatiently for my new phone to be delivered. It’s not just any phone. It’s the phone that will technologically enhance my productivity and will define what an Android operating system really has to offer in a small, slim and neat package. It was the Samsung Galaxy S2!

    I had been looking for a new phone for quite sometime to replace my “slow-mo” HTC Hero and the Samsung Galaxy S2 seemed to fit my requirements exactly. One of the things that attracted me to buying this phone was the fact that compared to other phones on the market, the Samsung was a performance powerhouse packing in a dual core processor and a lot of RAM that will future-proof my purchase for some years to come. So spending around £400 didn’t phase me.

    During this time, there was talk on the internet on how the 2012 release of Android 4.0 will not just be another Android release, it will be a release to remember. We all know Android has been fraught with fragmentation issues throughout its life due to phone manufacturer’s adding their own customisations thus adding further complexity in future Android upgrades. By starting over in a major new release, consumers will see more similarities between low and high spec handsets.

    Knowing I have a high-spec handset I was sure I will be getting Android 4.0.

    How wrong could I be…

    I was really annoyed to hear just before Christmas that Samsung will not be releasing Android 4.0 to its original Galaxy S phones and tabs. Even though Samsung Nexus S has similar hardware specification to my Samsung Galaxy S2, there is not enough memory available on the device to install Ice Cream Sandwich along with TouchWiz. Who actually wants TouchWiz? It’s an ugly interface. Android is a perfectly acceptable out-of-the-box. Long gone are the days when Android was a bit of an eyesore.

    The problem with Android is that its allows too much freedom allowing hardware manufacturers to do what they want. Having all this freedom in the initial stages is great, but there are bound to be complications as future upgrade will require a lot of time and money to get right. No hardware manufacturer would want to do that.

    So when will phone manufacturer’s STOP bastardising Android with their own customisations? No good can come of it. This is what really peeves me off about being an Android user. Its phone manufacturer’s like Samsung that are playing with customer loyalty. I think Samsung is not realising their business incentive to do these updates.

    Up until now, I’ve been a happy Android user and was proud to be different to the iPhone drones that surrounded me. Now I’m uncertain. Just as uncertain (I believe) the future of Android. I really like my Samsung Galaxy and it does everything I require. I can even make phone calls! But it’s a real kick in the teeth knowing I spent so much on a phone that is not upgradeable especially when its less than 2 years old.

    Google should really take more of an initiative. The following come to mind:

    1. Lock down Android to stop unnecessary modifications.
    2. Google take the Apple route and manufacture their own hardware.
    3. Make the latest OS available online for consumers to download and install on their phone.
    4. Allow manufacturer’s to make modifications through a separate driver layer. So consumer can ditch manufacturer customisations with ease.

    Smartphone Operating System Market Nov 2011

    According to Gartner, Android has now taken over 52.5% of the global smartphone market and stealing share from smartphone operating systems such as Symbian and Blackberry. With this in mind Google and its handset makers should be rewarding its customers and not penalising them. As John Gruber (http://daringfireball.net/) states in one of his posts:

    Why bother with software updates? We’ve got their money. Let them buy a new device if they want the latest software.

    I am afraid to say that this is the mentality of some Android handset makers where customer satisfaction is a low priority. I hate to say this is where Apple wins. They clearly have more respect for its customers and the longevity of their products.

    I wonder what 2012 will have in store for Android. No doubt the Android market momentum will continue to rise at the cost of consumers. I will definitely think twice before purchasing another Android handset.

  • One the drawbacks of using SCORM 1.2 is the inability of being able to read a “cmi.interaction.n.student_response” reference. In my mind this is very strange. Why allow a value to be written to but not read? Being able to read a users response to a question is an important feature. If anyone knows the answer to why this is the case, then please leave a comment.

    I guess under normal circumstances having a student_response reference that is write only would suffice. Unfortunately, my SCORM content required user’s to review all questions along with their submitted answers.

    Even though SCORM 2004 has corrected its previous error of misjudgement, what are developers who are forced into using SCORM 1.2 (like me) to do? Thankfully, there is a really useful reference called “cmi.suspend_data” that allows us to store any string value we want (up to 4096 characters). This is what I will use to store all users responses. I created a “semi-colon delimited string” to parse into the suspend_data reference. For example:

    q1=a;q2=1,4,7;q3=d;q4=air;q5=c
    

    The following code can be used to add/update values within the suspend_data:

    /*******************************************************************************
    **
    ** Functions to Add/Update CMI.suspend_data field
    **
    *******************************************************************************/
    function EditSuspendData(suspendId, suspendValue) {
        var suspendData = doGetValue("cmi.suspend_data");
    
        if (!SuspendDataExists(suspendId)) {
            AddSuspendData(suspendId, suspendValue, suspendData);
        }
        else {
            UpdateSuspendData(suspendId, suspendValue, suspendData);
        }
    }
    
    function AddSuspendData(suspendId, suspendValue, sdList) {
        if (sdList == null || sdList.length == 0) {
            sdList = suspendId + "=" + suspendValue;
        }
        else {
            sdList += ";" + suspendId + "=" + suspendValue;
        }
    
        doSetValue("cmi.suspend_data", sdList);
    }
    
    function UpdateSuspendData(suspendId, suspendValue, sdList) {
        var sdArr = sdList.split(';');
    
        for (i = 0; i < sdArr.length; i++) {
            pieces = sdArr[i].split('=');
            if (pieces[0] == suspendId) {
                pieces[1] = suspendValue;
                sdArr[i] = pieces[0] + '=' + pieces[1];
                break;
            }
        }
    
        //put the string back together;
        var sdList = '';
    
        for (i = 0; i < sdArr.length; i++) {
            marker = (i == 0) ? '' : ';';
            sdList += marker + sdArr[i];
        }
    
        doSetValue("cmi.suspend_data", sdList);
    }
    
    function GetSuspendDataValue(suspendId) {
        var sdArr = doGetValue("cmi.suspend_data").split(';');
    
        var answer = "";
    
        if (sdArr != "") {
            for (i = 0; i < sdArr.length; i++) {
                var qPieces = sdArr[i].split('=');
    
                if (qPieces[0] == suspendId) {
                    answer = qPieces[1];
    
                    NavButtonInactive("submit-button", false);
                    break;
                }
            }
        }
    
        return answer;
    }
    
    function SuspendDataExists(suspendId) {
        var sdArr = doGetValue("cmi.suspend_data").split(';');
    
        var sdFound = false;
    
        for (i = 0; i < sdArr.length; i++) {
            var qPieces = sdArr[i].split('=');
    
            if (qPieces[0] == suspendId) {
                sdFound = true;
                break;
            }
        }
    
        return sdFound;
    }
    

    You can now easily add/update/get your question values or any other values you store in your suspend_data. The functions you will need to use are:

    • GetSuspendDataValue() – to retrieve a value.
    • EditSuspendData() – to add/update a value.