Posted on

January 27, 2010 06:43 by
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
Posted on

December 10, 2009 09:00 by
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
Posted on

November 10, 2009 10:56 by
guido
Posted on

October 27, 2009 04:47 by
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