2009-08-07

A Wonderful Example of Comments Causing Problems

Current thinking is that comments in code should be helpful and should only document why and not how, that is what the code is for. That wasn’t always the case, for example

$courseNick = $_POST[‘courseNick’]; //Course nick
$phone = $_POST[‘phone’]; //Course nick

See how useless that is?

2009-06-23

HTML Helper for Including and Compressing Javascript

This article is outdated and ill advised

If you’re like me then you probably have a whole bunch of javascript includes on your site cluttering up the top of your page. I tend to keep most of mine in Site.Master, it isn’t so much that I use them all on every page but I do make use of a large enough subset that I can’t be bothered to load them in each view. For example here is what I have at the top of a Site.Master page for my Activity Tracker project:

2009-06-22

Bar Graphs Using Flot and ASP.net MVC - Part II

I wasn’t really planning a part II to this article but I left the code in something of a mess and we can do much better than having to write a bunch of javascript each time we need to make a graph. Let’s use the HtmlHelper and extension methods. The HtmlHelper is a class in System.Web.Mvc which is often extended to supply shortcuts for writing out HTML. xVal extends it to add client side validation and we’re going to do the same thing to write out the javascript for our graphs. We start by creating a new extension class to complement HtmlHelper

public static class HTMLExtensions  
 {  
 public static string BarGraph(this HtmlHelper helper, string divName, IDictionary dataPoints)  
 {  
 String dataPointsArrayName = divName + "Values";  
 String dataPointLabelsArrayName = divName + "Labels";  


 String returnText = @"  
 var {0} = [";   

 int counter = 0;  
 foreach (KeyValuePair kvp in dataPoints)  
 {  

 if (counter > 0)  
 returnText += ",";  
 returnText += "[" + counter + ".5, " + kvp.Value + "]";  
 counter++;  
 }  
 returnText += "];n";  

 returnText += @"var {1} = [";   
 counter = 1;  

 foreach (KeyValuePair kvp in dataPoints)  
 {  
 if (counter > 1)  
 returnText += ",";  
 returnText += "[" + counter + ","" + kvp.Key + ""]";  
 counter++;  
 }  
 returnText += "];n";  

 returnText += @"$(document).ready(function()   
 {  
 $.plot($(""#{2}""), [{0}], {   
 series: {  
 data: {0},   
 color: ""rgb(182,188,194)""   
 },   
 bars: { show: true, barWidth: 1.0 },   
 yaxis: { min: 0 },  
 xaxis: { ticks: {1}}   
 });  
 });";  

 returnText += "";  

 returnText = returnText.Replace("{0}",dataPointsArrayName).Replace("{1}", dataPointLabelsArrayName).Replace("{2}", divName);  

 return returnText.ToString();  
 }  

 }

This class is a bit of a mess of string appending but hopefully changes to it will be infrequent. I know somebody is going to jump on my string appending but before you do take a read of Jeff Atwood’s excellent examination of micro optimization. The key take away is that all the messy javascript generation which we did have in the views is now centralized into one place.

So now we have an extension method we can call from our View, so let’s pop back over to that. The page has two graphs on it and it use to have a huge amount of hand coded javascript. That can all be replaced with

<%Dictionary topTeamsDictionary = (ViewData[“TopTeams”] as List).ToDictionary(n => n.team.teamName, n => n.total);
Dictionary userActivityTotals = (ViewData[“UserActivityTotals”] as List).ToDictionary(n => n.ActivityName, n => n.TotalPoints);%>

The data in the ViewData was in a list and that list is need by other things on the page so we quickly transform the List into a Dictionary using LINQ. That is pretty much it. So long as the div referenced in the call to BarGraph exists you should get the same stylish graphs as yesterday. Obviously there are a lot of other options which can be passed through to the graph, these are left as an exercise for the reader. I’ve always wanted to say that.

2009-06-21

Bar Graphs Using Flot and ASP.net MVC

There are a bunch of posts out there about using flot to create nifty HTML graphs but the Internet is all about reiteration and I need to start posting more frequently. Flot is a javascript library which uses HTML Canvas) from HTML 5 to draw simple vector graphics. It works natively on good browsers and with a little bit of hacking on IE8 too. At its most simple one needs only include the jquery libraries and the flot libraries. Technically the excanvas library needs only be included for IE but it doesn’t seem to do any harm to include it all the time and the packed version is just a few kb.

2009-04-29

Building Adobe Air Files

Assembling Adobe Air installers is pretty easy. In this article I’ll show you how to put together an ant build.xml file which will build for you.

For the incurably impatient here is the whole thing:

Let’s break it down a bit

Here we set up some properties to be used in the rest of the file. I’m sure I don’t have to quote the Pragmatic Programmer about repeating yourself.

Air applications have to be signed. As part of a release process you’ll want to generate a proper key and keep in somewhere safe like on a cd in the cat’s litter box. However we don’t want developer builds getting out into the wild so we’ll just generate a key here and use it.

You’ll notice on line 12 we sleep for a couple of seconds. Why is that? It turns out that the key generator returns before it is actually done generating so we’ll give it a few more seconds otherwise you’ll get an error like

failed while unpackaging: [ErrorEvent type=”error” bubbles=false cancelable=false eventPhase=2 text=”invalid package signature” errorID=5022]
starting cleanup of temporary files
application installer exiting

in the Air installation log. (See http://kb.adobe.com/selfservice/viewContent.do?externalId=kb403123 to read how to enable logging of Air installations)

Finally we come to actually building the application

Here I’m replacing the version number in the application.xml with the SVN_REVISION. Our builds run from inside the wonderful Hudson build management system which is kind enough to pass through a token containing the revision number from SVN. We finally execute adt the Air packaging tool giving it a list of the files we would like to have inside the package. We list them by hand as a double check against accidentally including extra files, like bankingInformation.xls.

That’s it! The only real trick is pausing for the key generation to complete.

2009-04-18

ASP.net MVC returning JSONP

I’ve been working on a piece of code which returns JSON in response to some request. It has all being going fine on the local host but I’ve just deployed it up to my new test server and started to access it using JQuery and it stooped working. This is, of course, typical. This time however, my problem was ignorance rather than a programming blunder. As it turns out when returning JSON across domains you need to actually return JSONP in order to get call backs working. What is JSONP? I’m glad you asked, because I had no idea either. Basically it is the same JSON you love but wrapped with a bit of text which specifies the name of the function to call upon returning.

JSON:

{“userID”:”00000000-0000-0000-0000-000000000000”³,”success”:”false”}

JSONP:

somefunction({“userID”:”00000000-0000-0000-0000-000000000000”³,”success”:”false”})

Easy enough. In JQuery you need to just add another parameter to the JSON call in order to pass the name of the function to the server

$.getJSON(URL +“/json/Message/sendMessage?userName=”+ $(“#userName3”).val()+
“&messageText=”+ $(“#message”).val()+
“&userKey=”+ key +
“&jsoncallback=?”,
function(json)
{
}
);

JQuery will automatically replace the ? with the name of your callback function, in this case an anonymous function.

Having discovered all of this I realized that I now had a ton of code returning JsonResults which needed to be changed. I figured the best way to do this was to actually create a JsonpResult which was based off of the JsonResult. So I did just that, basing it off of the now open sourced ASP.net MVC JsonResult

publicclass JsonpResult : System.Web.Mvc.JsonResult
{
publicoverridevoid ExecuteResult(ControllerContext context)
{
if(context ==null)
{
thrownew ArgumentNullException(context);
}

HttpResponseBase response = context.HttpContext.Response;

if(!String.IsNullOrEmpty(ContentType))
{
response.ContentType = ContentType;
}
else
{
response.ContentType =application/json;
}
if(ContentEncoding !=null)
{
response.ContentEncoding = ContentEncoding;
}
if(Data !=null)
{
// The JavaScriptSerializer type was marked as obsolete prior to .NET Framework 3.5 SP1

#pragma warning disable 0618
HttpRequestBase request = context.HttpContext.Request;

JavaScriptSerializer serializer =new JavaScriptSerializer();
if(null!= request.Params[jsoncallback])
response.Write(request.Params[jsoncallback]+(+ serializer.Serialize(Data)+));
else
response.Write(serializer.Serialize(Data));

#pragma warning restore 0618
}
}
}

I then extended Controller

publicclass WopsleController : Controller
{
protectedinternal JsonpResult Jsonp(object data)
{
return Jsonp(data,null/ contentType /);
}

protectedinternal JsonpResult Jsonp(object data,string contentType)
{
return Jsonp(data, contentType,null);
}

protectedinternalvirtual JsonpResult Jsonp(object data,string contentType, Encoding contentEncoding)
{
returnnew JsonpResult
{
Data = data,
ContentType = contentType,
ContentEncoding = contentEncoding
};
}

}

and altered all my controllers to extend WopsleController rather than Controller. Seems to work pretty well.

2009-02-28

Best Bug I've Written Today

Today I create a handy little class in my attempt to rewrite wordle. It encapsulated a word and a word count and implemented comparable

1 package com.simontimms.wordle;
2
3 public class WordCountElement implementsComparable<WordCountElement>{
4
5
6 privateint count =0;
7 privateString word;
8
9
10 publicWordCountElement(String word,int count)
11 {
12 this.word = word;
13 this.count = count;
14 }
15
16 publicintcompareTo(WordCountElement toCompare)
17 {
18 return this.count - toCompare.getCount();
19
20 }
21
22 publicvoidsetCount(int count) {
23 this.count = count;
24 }
25
26 publicintgetCount() {
27 return count;
28 }
29
30 publicvoidsetWord(String word) {
31 this.word = word;
32 }
33
34 publicStringgetWord() {
35 return word;
36 }
37 }

At another point in my code I created a sorted set out of these WordCountElements

1 publicTreeSet<WordCountElement>getSortedSetOfWordCounts(String textToAnalyze)
2 {
3 HashMap<String, WordCountElement> unsortedSet =getWordCounts(textToAnalyze);
4 TreeSet<WordCountElement> sortedSet =newTreeSet<WordCountElement>();
5
6 for(String s : unsortedSet.keySet())
7 {
8 sortedSet.add(unsortedSet.get(s));
9 System.out.println(s);
10 }
11 return sortedSet;
12 }

I couldn’t get my unit tests to pass when I had more than one word in the unsortedSet. I ended up debugging it and found that even though I was adding two different words only the first was present in the sorted set. Well select might not be broken but perhaps sorted sets were. Can you see the bug?

That’s right, the custom comparator resulted in two words with equal counts being equal. So select wasn’t broken. Drat.

2009-02-26

Tweetdeck on 64bit Ubuntu Llinux

Tweetdeck is a very powerful twitter client which is written in the rather nifty Adobe Air framework. Unfortunately the air platform does not yet have support for 64-bit Linux. I imagine it will come along once flash 10 for 64 bit Linux comes out of beta. There is a rather long tutorial on how to work around the limitations and run it in 32-bit mode on 64-bit linux right here but that isn’t enough to run tweetdeck. You’ll also need to pull down a copy of 32 bit libgnome-keyring to allow it to access your keyring.

wget http://ubuntu.interlegis.gov.br/ubuntu/pool/main/g/gnome-keyring/libgnome-keyring0_2.22.2-0ubuntu1_i386.deb
ar x libgnome-keyring0_2.22.2-0ubuntu1_i386.deb data.tar.gz
tar -xzvf data.tar.gz
cp usr/lib/* /usr/lib32/
On a related note it is a shame that the default Air page is so pedestrian. I am filled with no excitement upon visiting it.