PicNet Custom Software Development

.Net and Javascript Development

PicNet Mouse Eye Tracking Service Limited Release

Posted on clock January 27, 2010 06:43 by author guido

You may have noticed that I have been a bit quiet over the last few weeks, this is because we have been working very hard to release a new product and it gives me great pleasure to announce that today we have flicked on the switch.

The product is called the Mouse Eye Tracking service. It is basically a web analytics product that records your visitors mouse interactions with your web site. You then use our product to analyse these interations and get value from them. You can think of it as a more visual 'Google analytics' (however the products are very different and supplement each other nicely).

Features
Heat Maps
Check out where our visitors are viewing our home page:


Or where they are 'clicking'


User Trackings
You can also just replay the user interactions on your site. Either one at a time or all at once:


Page Navigation
You can also visualize how your visitors are navigating around on your site:


Technology
One of the reasons I'm so proud of this product is because of the number of technical hurdles that had to be overcome to get a successful solution. I will be blogging about these in detail over the next few weeks in the hope that someone can learn from our trials and tribulations. But some of the issues we had to address were:

  • Capacity of a high volume, highly data driven application
  • Speed of visualisation generation on javascript
  • Threading in javascript
  • Best tools for large development team in a javascript project
  • Large javascript application programming practices
  • Html 5
  • IE Issues (Which we have deferred for now)
  • Unit testing in javascript (and continous testing) + multiple browsers


Limited Release
As mentioned above, this is a limited release. So no media releases yet, we are taking it slowly just to make sure we have nailed down all the capacity issues. But this is too exciting not to at least blog about it so feel free to subscribe and give it a try.
Please send me any feedback you may have, either through comments below, email or just use the built in feedback submission form in the system.

Links

Thanks All

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd


Javascript runtime compilation using Asp.Net and Google's Closure Compiler

Posted on clock December 10, 2009 09:00 by author guido


Overview

Working on complex javascript projects usually means working with lots of javascript files. When it comes time to deploy this to production it can be be very tedious and sometimes dangerous to do this manually. This solution compiles all the javascript files in a directory to a single minified file ideal for release. This code will also automatically recompile this file if any of the files change.

Code

/// 
/// This class will compile (using Google's Closure Compiler) a directory of javascript files if:
///     - In Release Mode
///     - The release (minified) file is older than other files in the directory (stale)
///     - Not on localhost (Google cannot access your files)
/// 
public class JavascriptRuntimeCompiler {
    private static readonly ILog log = LogUtil.Logger(typeof (JavascriptRuntimeCompiler));

    private const string CACHE_MARKER = "CACHE_MARKER";
    private readonly string releaseFileName;        
    private readonly string baseScriptsUri;
    private readonly HttpContextBase context;

    private FileInfo releaseFile;

    /// 
    /// Creates the JavascriptRuntimeCompiler.  It is safe to create this per request as it is very efficient and
    /// will only create the new minified file if required.
    /// 
    /// The relative file name of the release minified file.  Eg: 'mydir\scripts\myscript.min.js'
    /// The relative uri of the directory holding the javascript files. Eg: '~/mydir/scripts/'.  It is safe
    /// for this to be the same directory as the one holding the release file.
    /// 
    /// The HttpContextBase object (Asp.Net Mvc)
    public JavascriptRuntimeCompiler(string releaseFileName, string baseScriptsUri, HttpContextBase context)
    {
        this.releaseFileName = context.Request.PhysicalApplicationPath + releaseFileName;            
        this.baseScriptsUri = context.Request.Url.GetLeftPart(UriPartial.Authority) + baseScriptsUri;
        this.context = context;            
    }
	
	/// 
	/// Wether to use the release script or not.  If true ensure your page points to your release file.  If false
    /// your page should reference all of the debug scripts.
	/// 
    public bool UseReleaseScript()
    {
        bool debug = false;
         #if (DEBUG)
        debug = true;
        #endif

        if (debug || baseScriptsUri.IndexOf("localhost") >= 0) { return false; }

        CheckReleaseScriptValidity();
        return true;
    }

    private void CheckReleaseScriptValidity()
    {
        releaseFile = new FileInfo(releaseFileName);            
        
        if (releaseFile.Exists && !IsReleaseFileOutOfDate()) { return; } 
        RebuildReleaseScriptFile();

        // This marker allows us to do a date check on all the files that the minified release file depends on
        context.Cache.Add(CACHE_MARKER, new Object(), new CacheDependency(GetJSFiles()), Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);       
    }

    private bool IsReleaseFileOutOfDate()
    {
        if (context.Cache[CACHE_MARKER] != null) { return false; }
        DateTime releaseFileDate = releaseFile.LastWriteTime;
        foreach (string s in GetJSFiles()) {
            if (File.GetLastWriteTime(s) > releaseFileDate) { return true; }
        }
        return false;
    }

    private void RebuildReleaseScriptFile()
    {
        string uri = "http://closure-compiler.appspot.com/compile?compilation_level=SIMPLE_OPTIMIZATIONS&output_format=text&output_info=compiled_code";
        foreach (string f in GetJSFiles()) {
            uri += "&code_url=" + baseScriptsUri + f.Substring(f.LastIndexOf("\\") + 1);           
        }
        log.Debug("Requesting Compiler: " + uri);
        WebRequest r = WebRequest.Create(uri);
        r.Method = "POST";
        r.ContentLength = 0;
        using (Stream s = r.GetResponse().GetResponseStream()) {                     
            using (StreamReader sr = new StreamReader(s, Encoding.UTF8)) {
                string content = sr.ReadToEnd();
                log.Info(content);
                FileUtils.WriteFileContents(releaseFileName, Encoding.UTF8.GetBytes(content));            
            }                
        }                             
    }

    private static string[] cached_js_files;
    private string[] GetJSFiles()
    {
        if (cached_js_files != null) return cached_js_files;
        List jsFiles = new List();
        if (releaseFile.Directory == null) throw new ApplicationException();

        foreach (FileInfo f in releaseFile.Directory.GetFiles()) {
            if (f.Name.Equals(releaseFile.Name) || f.Extension != ".js") { continue; }
            jsFiles.Add(f.FullName);                
        }
        return cached_js_files = jsFiles.ToArray();
    }
}


Using this Class

This example uses Asp.Net Mvc and the Spark view engine. However it should be trivial to change the above file or this example to use any other framework.

<if condition="new JavascriptRuntimeCompiler('resources\\scripts\\custom\\scripts.min.js', Url.Content('~/resources/scripts/custom/'), Context).UseReleaseScript()">
    <script language="javascript" src="${ Url.Content('~/resources/scripts/custom/scripts.min.js') }"></script>            
</if>
<else>
    <script language="javascript" src="${ Url.Content('~/resources/scripts/custom/Util.js') }"></script>    
    <script language="javascript" src="${ Url.Content('~/resources/scripts/custom/Class1.js') }"></script>    
    <script language="javascript" src="${ Url.Content('~/resources/scripts/custom/Class2.js') }"></script>    
    <script language="javascript" src="${ Url.Content('~/resources/scripts/custom/Class3.js') }"></script>                
</else>


Thanks

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd


Game of Life in JQuery

Posted on clock November 10, 2009 10:56 by author guido

Hi All,

I've just done a tutorial video on JQuery, I chose to hack together a quick version of the Game of Life.  This tutorial aims to show how JQuery can help you modify the DOM on the fly and do some nifty manipulations.  I hope you enjoy.

Please let me know if there are other JQuery topics you would like to see covered in a 'practical' style video.

Demo


Part 1

Part 2

Part 3

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd


Advanced Javascript Tutorials

Posted on clock October 27, 2009 04:47 by author guido

I've decided to do a series of videos on using Javascript. I believe that js is one of the most poorly used tools out there and I think that is because it is different to most languages and those differences are slight enough to slip under the covers. I.e. People can develop in javascript using their Java/.Net skills but they do it badly. 

I will try to do a video or so every week, each week highlighting pitfalls for experienced developers may find. I will keep this blog post updated when a new video is added.

<b>Note</b>: The series is complete, please let me know if you would like me to cover any other topics.

YouTube Play List
http://www.youtube.com/view_play_list?p=27D444D6286E3C3E

Videos

Let me know what you think and how I can improve these videos.

Thanks

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd