22 Dec 2009

HttpHandler EnableEventValidation Error

I wrote a HttpHandler to do some crazy thing or other. Put it in web.config's <httpHandlers> like this:


<add path="*/Pages/Review/*/*.aspx" verb="*" type="Freda.Classes.v3ReviewScreenHandler" />


Had to handle it in IIS7 too (or integrated pipeline mode on my workstation), so had to stick it in the <system.webServer>/<handlers> section like this:


<add name="v3ReviewScreenHandler1" path="*/Pages/Review/*/*.aspx" verb="*" type="Freda.Classes.v3ReviewScreenHandler" resourceType="Unspecified" preCondition="integratedMode" />


And to make both play nicely together, under <system.webServer> I had to also add:


<validation validateIntegratedModeConfiguration="false" />


The handler in this case is basically just a subclass of System.Web.UI.Page that dynamically loads a UserControl based on the requested URL path, or otherwise processes an ASPX page, which I did like so:


public override void ProcessRequest(System.Web.HttpContext context)
{
string candidateControlFilePath = context.Request.Path.Replace(".aspx", ".ascx");

if (System.IO.File.Exists(context.Request.MapPath(candidateControlFilePath)))
{
// Load Screen Control if available (the groovy new way)
base.ProcessRequest(context);
}
else
{
// Revert to aspx mode (the non-bulk-printable way)
Page page = (Page)System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(context.Request.Path, typeof(System.Web.UI.Page));
page.AppRelativeVirtualPath = context.Request.AppRelativeCurrentExecutionFilePath;
page.ProcessRequest(context);
}
}


And the "Load User Control" bit was like so:


protected override void OnInit(EventArgs e)
{
base.OnInit(e);

// Load ReviewScreen control
string candidateControlFilePath = Request.Path.Replace(".aspx", ".ascx");
v3ReviewScreen uctl = (v3ReviewScreen)LoadControl(candidateControlFilePath);
this.Master.MainContentPlaceHolder.Controls.Add(uctl);
uctl.Setup();
}


And to make the Handler play nice with Sessions it was declared like so:


public class ReviewScreenHandler : System.Web.UI.Page, System.Web.SessionState.IRequiresSessionState


And all was dandy! Except for some funky GridView Row-Rendering stuff that was working in normal ASPX pages but not in my HttpHandler-based pages, producing this error:


RegisterForEventValidation can only be called during Render();


Which was weird, because the code to supress this sort of thing was already in web.config:


<pages enableEventValidation="false" validateRequest="false">


And I tried setting EnableEventValidation programatically in the HttpHandler's OnInit method, but got:


The 'EnableEventValidation' property can only be set in the page directive or in the configuration section.


And in the end the only solution was:


protected void Page_PreInit(object sender, EventArgs e)
{
Page.EnableEventValidation = false;
}


Which, called by magic and with no override or event handler to obviously hang off, is stupid. But works.

Mac OSX Bootcamp XP funtime

I got a Mac. I always said I wouldn't. And now I have. A little Mac Mini 2.53Ghz Intel Core 2 Duo 4Gb. Just for research, you understand ;) And cos I fell in love with my iPhone 3GS. Damn it.

What I found out so far:

- Snow Leopard is teh sexeh.
- Objective-C sucks monkey balls.

Anyway, I wanted to set up a little XP installation so I could see how well Windows runs on a Mac, and to do stuff that the mac just won't do, like Visual Studio 2008 (soooo much better than XCode).

I thought I would be smart and use the OSX Disk Utility to partition the drive 3 ways so I could have a main mac partition, a FAT32 partition to share my music on, and a NTFS partition for XP. But all my manual blunderings and attempts with Bootcamp just shagged it up, and ended up with "Disk error" on boot-up. Thank goodness for holding down the Option key on reboot to choose the boot drive. I had to use Disk Utility to create one big contiguous Mac partition again.

In essence then, to get XP running happily:

1. In OSX run Boot Camp Assistant and create a Windows Partition (I chose 32GB)
2. Put the XP disk in the drive when it tells you and start the Windows installation process.
3. When the XP installer asks what partition to put it on, choose your new Bootcamp partition and SELECT NTFS FORMAT. *Not* Quick Format, Fat32 or "Preserve Existing". It must do it the long winded way.

Anyways, it works. I was very impressed by the XP drivers Apple included on the main OSX disc. XP runs fabbo on the Mac Mini, and it picked up my Logitech wireless keyboard/mouse combo without a hitch, even though the box for them says OSX only.

Oh, almost forgot. After installing the Apple XP drivers I could read files off the main OSX drive from XP with no problems (Read Only). I thought that wasn't possible! Well chuffed.

Toodles.

4 Nov 2009

UK Postcode Validation using C# Regular Expression

Sigh - look up UK Postcode Validation and you'll get about a billion different RegEx patterns, all subtly different and wrong.

The following one works because I use the official UK Postcode rules as defined by the government here.
public static bool ValidateUkPostcode(string postcode)
{
return Regex.Match(postcode, "(^gir\\s?0aa$)|(^[a-z-[qvx]](\\d{1,2}|[a-hk-y]\\d{1,2}|\\d[a-hjks-uw]|[a-hk-y]\\d[abehmnprv-y])\\s?\\d[a-z-[cikmov]]{2}$)", RegexOptions.IgnoreCase).Success;
}
NOTE: This solution requires you to include the Regular Expressions namespace at the top of your code:
using System.Text.RegularExpressions;
PS. Wondering why the regex allows "GIR 0AA"? For some reason Girobank were allowed their own non-conformant postcode. There's also "SAN TA1" for kids xmas posts, but that's just silly!!

29 Oct 2009

Dynamic Linq OrderBy - Sort Field known only at Run-Time

A common issue with my LinqToSql stuff is the need to do an OrderBy on an IQueryable a la:
myQueryable = myQueryable.OrderBy(item => item.mySortField)

However, often you won't know the sort field until runtime, e.g. for a dynamically sortable grid.

One solution is to use the DynamicQueryable library provided by MS. It lets you do string-based dynamic querying like so:
myQueryable = myQueryable.OrderBy(mySortFieldName + " ASC"); // or use DESC if you like it in descending order

However this didn't have an option for using an IComparer to sort the results, and I wanted to use my NaturalSortComparer for natural case sorting. The solution I came up with was this:
myQueryable = myQueryable.OrderBy(item => item.GetReflectedPropertyValue(mySortFieldName ));

Or, actually employing NaturalSortComparer, like this:
myQueryable = myQueryable.OrderBy(item => item.GetReflectedPropertyValue(mySortFieldName ), new NaturalSortComparer<string>());

The solution uses a little helper method called GetReflectedPropertyValue():

public static string GetReflectedPropertyValue(this object subject, string field)
{
object reflectedValue = subject.GetType().GetProperty(field).GetValue(subject, null);
return reflectedValue != null ? reflectedValue.ToString() : "";
}

OK, Reflection is slow (not sure how it compares to building a Lambda Expression tho) but it does the job for my purposes.

28 Oct 2009

AjaxControlToolkit Accessible Tabs

Can't believe it but MS forgot to make Tabs in the Ajax Control Toolkit accessible via the keyboard. Okay, they provide an access key property, but what about just being able to tab to the tab (ho ho) and press enter to open?

My solution is a snippet of JQuery to iterate through all the tabs and update the HeaderText of the TabPanel, turning it into a fake Html Anchor. Works fine in FF3 and IE6+ so I'm happy.

$('.ajax__tab_tab').each(function() { if ($(this).html().indexOf('<a') < 0)
$(this).html('<a href="" onclick="return false;">' + $(this).html() + '</a>'); });

If you want to hide the 'linkiness' of the updated headertext, just add a style directive to your CSS like so:

.ajax__tab_tab a { text-decoration: none; font-weight: normal; }

Probs? Let me know.

15 Oct 2009

JQuery and setting checkbox to checked except disabled ones....

Got a master checkbox that you want to control the toggling of a bunch of other checkboxes in a container (but only non-disabled ones)? Want to use JQuery to make it SUPER EASY?

$('#chkMasterCheckbox').click(function(event) {
$('#divContainer input[type=checkbox]:enabled').attr('checked', $(this).attr('checked'));
});


Oh yeah baby.

4 Sep 2009

Natural Sort Compare with Linq OrderBy

Having "fun" with IComparer<T> when trying to do OrderBy in Linq with a custom sort?

Me too. I wanted to sort some rows from a DB table by a string 'filename' field. The standard Linq (and SQL) OrderBy(item => item.sortProperty) sorts the strings like so:

image1.jpg
image200.jpg
image30.jpg
image4.jpg

But because I am a human being, I don't want that. No, instead I wanted them sorted like:

image1.jpg
image4.jpg
image30.jpg
image200.jpg

What I want is "Natural Sort". C# doesn't offer a built-in solution, but the Linq OrderBy method does have an override that allows you to use your own IComparer<T> function, a la
myLinqQuery.OrderBy(item => item.sortProperty, new MyComparer<string>())


(Edit: Incidentally, I now have a way of doing this dynamically, if you don't know what sort field will be used until run-time. See here.)

Building your own "Natural Sort" IComparer is not for the faint of heart, or the lazy, so I just nicked some code from Justin Jones and tweaked it a bit:

    public class NaturalSortComparer<T> : IComparer<string>, IDisposable
    {
        private bool isAscending;

        public NaturalSortComparer(bool inAscendingOrder = true)
        {
            this.isAscending = inAscendingOrder;
        }

        #region IComparer<string> Members

        public int Compare(string x, string y)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IComparer<string> Members

        int IComparer<string>.Compare(string x, string y)
        {
            if (x == y)
                return 0;

            string[] x1, y1;

            if (!table.TryGetValue(x, out x1))
            {
                x1 = Regex.Split(x.Replace(" ", ""), "([0-9]+)");
                table.Add(x, x1);
            }

            if (!table.TryGetValue(y, out y1))
            {
                y1 = Regex.Split(y.Replace(" ", ""), "([0-9]+)");
                table.Add(y, y1);
            }

            int returnVal;

            for (int i = 0; i < x1.Length && i < y1.Length; i++)
            {
                if (x1[i] != y1[i])
                {
                    returnVal = PartCompare(x1[i], y1[i]);
                    return isAscending ? returnVal : -returnVal;
                }
            }

            if (y1.Length > x1.Length)
            {
                returnVal = 1;
            }
            else if (x1.Length > y1.Length)
            { 
                returnVal = -1; 
            }
            else
            {
                returnVal = 0;
            }

            return isAscending ? returnVal : -returnVal;
        }

        private static int PartCompare(string left, string right)
        {
            int x, y;
            if (!int.TryParse(left, out x))
                return left.CompareTo(right);

            if (!int.TryParse(right, out y))
                return left.CompareTo(right);

            return x.CompareTo(y);
        }

        #endregion

        private Dictionary<string, string[]> table = new Dictionary<string, string[]>();

        public void Dispose()
        {
            table.Clear();
            table = null;
        }
    }


The first time I tried to use this, it failed with the rather useless error: "Unsupported overload used for query operator 'OrderBy'."

Turns out it was because I had tried to use my custom OrderBy on the Linq query before it had got the data records from the server, and hence it thought I was trying to run the natural sort in SQL. So I fixed the prob by getting the results first with a quick call to AsEnumerable(), a la:

List<Photo> photos = DataManager.MainContext.Photos
     .Where(item => item.PhotoFilename != null)
     .AsEnumerable()
     .OrderBy(item => item.PhotoFilename, new NaturalSortComparer<string>())
     .ToList();


Works a treat!

26 Aug 2009

ASP.NET Web Form Code Blocks

Just found this neato summary of all the different ASP.NET web form code-block / data-binding syntax options, i.e. <%= , <%# etc.

http://quickstarts.asp.net/QuickstartV20/aspnet/doc/pages/syntax.aspx

It was nice to put a name to the different syntax types :) Also, I didn't know about the ability to register C# variables inline i.e <object id="DateOfBirth" class="System.DateTime" runat="server"> , although I'm not sure when I would use it :)

Also, this blog posting helped clear up my "voodoo" perception of the Container and Eval syntax available when databinding in a template:

http://weblogs.asp.net/rajbk/archive/2004/07/20/what-s-the-deal-with-databinder-eval-and-container-dataitem.aspx

7 Aug 2009

Running VS2003 on Vista Business with debugging

It's a pain in the arse!

1. Install VS2003
2. Install .NET 1.1 SP1 (download from MS)
3. In Control Panel > Classic View > Programs and Features > Turn Windows Features On or Off :

IIS > Web management Tools > IIS 6 Management Compatibility
IIS > Web management Tools > Management Console
IIS > World Wide Web Services > Security > Basic Authentication
IIS > World Wide Web Services > Security > Windows Authentication

4. In IIS7 (Control Panel > Classic View > Administrative Tools > IIS Manager)

- Click on the Server node and make sure you're in Features View
- Select ISAPI and CGI Restrictions
- Make sure ASP.NET v1.1 is "Allowed"

5. In IIS7 (Control Panel > Classic View > Administrative Tools > IIS Manager)

- Click on the web site node (or your V1.1 application if you've installed it under the default node)
- Click on Authentication and enable Windows Authentication

6. In Local Users and Groups (Control Panel > Classic View > Administrative Tools > Computer Management)

- For Group "Debugger Users", add your user account and the IUSR account
- For Group "VS Developers", add your user account and the IUSR account

30 Jul 2009

Ironic Ads

Moh! Funneh.

“Label For”, Selects and IE6

Good accessible sites use LABEL tags to describe the purpose of other controls on the page; for example a login control should have LABELs in it that tells the user which textbox is for the Username and which is for Password. To be completely groovy the LABEL should also have a FOR attribute in it that explicitly declares which control it refers to, like so:



<label for=”txtUsername”>Username</label>

<input type=”text” id=”txtUsername” />


BUT there is one problem – f*%!&ing IE6 does something very stupid when you use LABEL FOR with dropdownlist boxes (SELECTS). In IE6, if you click on the label, the SELECT resets its currently selected item and reverts to the first in the list. GOD *DAMN* IT.


Anyway, I knocked up this blob of JQuery which empties the LABEL FOR with SELECTs in IE6 and below. Hope it’s useful to someone.


<!– Script to disable Label.For attributes for SELECT elements in IE6 (otherwise they reset the selected OPTION)  –>


<!–[if lte IE 6]>

<script type=”text/javascript”>

$(’label’).each(function() {if ($(’#’ + $(this).attr(’for’)).attr(’tagName’) == ‘SELECT’) $(this).attr(’for’, ”) ;});

</script>

<![endif]–>

7 Jul 2009

Interviewing IT Development Candidates

Man, I've pondered on the best way to do this so many times, and according to Joel, I've made many of the classic mistakes in the past:

http://www.joelonsoftware.com/articles/GuerrillaInterviewing3.html

What a great site.

30 Jun 2009

Faking and Mocking: HttpContext and HttpSessionState

HttpContext.Current is all well and good until you want to do unit tests on your business logic, and they explode because there's a reference to the Session collection somewhere, which returns null because you're not in a web context. You get to thinking that your business logic should be context-agnostic anyway, and so you want to provide your own context objects for Session, Items, User etc.

So then you run the gamut of HttpContext fakery, thinking about moq, TypeMock etc - only you don't want to go to all that trouble. Phil Haack's HttpSimulator hoves into view but just doesn't feel right for this particular task (although it IS uber cool). His SimulatedHttpRequest class was pretty cool but sadly the Session object was null when I referenced it.

Finally I stumbled on this post (specifically the one by radmanmm). Using the GetMockHttpSessionState() with my SimulatedHttpRequest object solved the problem. Wooot!

PS. Mr Walther's Fake Intrinsic Objects looked pretty cool too, check them out.

28 May 2009

Indexing SQL Server 2005 Temporary Tables

Simple really - if you create a large temporary table in your sproc, you may need to index it to improve performance on queries you subsequently run on it, e.g.

CREATE CLUSTERED INDEX IX_blah ON #YourTempTable (YourPKCol)

22 May 2009

SQL Server performance and statistics

Queries started running slowly on your SQL Server? Maybe your db statistics need updating.

A quick and dirty way to do this for all tables in your DB is the sp_updatestats sproc.

27 Apr 2009

Walk like an Egyptian

Ruth and I just got back from a jolly holiday in Egypt. Here's what we found.

  1. El Gouna is a nice, safe, gated town about half an hour's drive up the red sea coast from Hurghada.
  2. The Moevenpick El Gouna is a nice hotel complex composed of several "clusters" of rooms set around a number of lagoons and pools. However, some clusters are nicer than others. We initially got put in cluster 7 in a grim room and a sewage smell outside. We complained to our Thompson rep and got moved to a great room in cluster 3.
  3. Downtown El Gouna is good for supermarket shopping but poor for evening eating.
  4. El Gouna Marina is very nice for evening nosh, especially Bleu Bleu restaurant.
  5. The TukTuks are everywhere and cheap.
  6. The Mosquitos are buggers! Bring protection.
  7. You have to swim out quite a way to get to decent coral, but it is out there.
  8. The purple jellyfishes are harmless.
  9. The desert tour to see the bedouin camp is not worth it.
  10. Hurghada is a sad, ugly post-credit-crunch disaster.
  11. The Red Sea in April is lovely and warm but not overbearingly hot.
In short, lovely holiday!

Parse CSV files with the MS ODBC Driver

Easy way to read CSV files in .NET just like connecting to an SQL table - just use the standard Microsoft Text Driver.

public DataTable GetData(string FullPath)
{
string strPathWithoutFileName = Path.GetDirectoryName(FullPath);
string Name = Path.GetFileName(FullPath);

DataSet dsData = new DataSet();
System.Data.Odbc.OdbcConnection conCsv = new System.Data.Odbc.OdbcConnection();
conCsv.ConnectionString = @"Driver={Microsoft Text Driver (*.txt; *.csv)};Dbq=" + strPathWithoutFileName + @";Extensions=csv;";
conCsv.Open();

System.Data.Odbc.OdbcDataAdapter oda = new System.Data.Odbc.OdbcDataAdapter();
oda.SelectCommand = new System.Data.Odbc.OdbcCommand("SELECT * FROM [" + Name + "]", conCsv);

try
{
oda.Fill(dsData);
}
catch (Exception ex)
{
throw new InvalidOperationException("Csv File Read Error: " + FullPath, ex);
}
finally
{
oda.Dispose();
conCsv.Close();
conCsv.Dispose();
}

dsData.Tables[0].TableName = Name;

return dsData.Tables[0];
}


A note on configuring the Microsoft Text Driver for your CSV file:

If you place a Schema.ini file in the same location as the CSV file, you can declaratively specify the expected columns and datatypes. See this article for info: http://msdn.microsoft.com/en-us/library/ms709353.aspx

A note about System Regional Settings vs Application Culture when using the Microsoft Text Driver:

I noticed something weird when I specified a column as DateTime in my Schema.ini file. The Text Driver was reading the dates in US format (mm/dd/yy). My testing indicates that even though my ASP.NET web app was explicitly set for British culture ("en-GB" in the web.config's globalization section), the Text Driver uses the Windows Regional And Language Options setting. Annoying eh!

Note also that if the Text Driver cannot resolve a DateTime value according the Regional Settings format, it doesn't throw an exception. It just treats the value as Null. Yuck.

9 Apr 2009

SqlMetal + Visual Studio Jollity

Whack the following code in a .bat file, register it with Visual Studio's "External Tools" under the Tools menu, and call it whenever you want to regenerate your LinqToSql ORM goodness:

@ECHO OFF
ECHO # GENERATING "MyProject.Classes.ORM" CLASSES - THEY MUST BE CHECKED OUT FOR THIS TO WORK!
ECHO.

"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\SqlMetal.exe" /server:localhost /database:MyProjectDB /code:MyProject.Classes\ORM\MyProjectDBContext.cs /namespace:MyProject.Classes.ORM /pluralize

ECHO # GENERATION COMPLETE - CHECK ABOVE FOR ERRORS

8 Apr 2009

31 Mar 2009

Undocumented SQL Server Stored Procedures

This article documents some groovy system stored procs:

http://www.mssqlcity.com/Articles/Undoc/SQL2000UndocSP.htm

Sprocs include stuff like "FOR EACH DB/TABLE DO X" and "GET QUALIFIED OBJECT NAME".

Mucho useful. Now why the hell are they secret?

12 Mar 2009

Embed images in your web DLLs

You can embed all sorts of stuff into an assembly - javascript, css, pdf etc. Here I quickly detail how to embed an image file.

1. You have a solution with a web project and a separate class project
2. In Visual Studio, drag the image you want to embed into your class project
3. In the Properties window of the Image, select Build Action: Embedded Resource
4. Add a new class to the project, call it EmbeddedResources.cs for the sake of argument. Put the following code in it:

[assembly: WebResource("YourProjectAssemblyNamespace.YourPic.jpg", "image/jpeg")]

namespace YourProjectAssemblyNamespace
{
public class EmbeddedResources
{
}
}


5. Reference the image from your web project like so:

<img src="<%= Page.ClientScript.GetWebResourceUrl(typeof(YourProjectAssemblyNamespace.EmbeddedResources), "YourProjectAssemblyNamespace.YourPic.jpg") %>" />


Woop!

Resolve Virtual Path From Physical Path (ASP.NET)

Quick code snippet to help people who want to derive a Virtual (web) path from a Physical (file) path:

string strVirtualPath = VirtualPathUtility.ToAbsolute("~/" + strPhysicalPath.Replace(Request.PhysicalApplicationPath, "").Replace("\\", "/"));


VirtualPathUtility FTW!

5 Mar 2009

.NET Regular Expression Reminder

I must be dense - I *heart* regex but every time I need to use one in .NET, I spend about 5 minutes trying to remember

  • what the right grouping character is
  • whether I need to escape it or not
  • which Regex class to start with
  • what the right terminology is for getting the sub-matches out of the match etc.
Which is weird cos when I was king of perl I could do this stuff lickity split. So I guess MS just like making it confusing. Evidence 1 - the regex syntax in Visual Studio is totally different to that in .NET. Duh.

Anyway here's a handy reminder to myself:

string strServer = System.Text.RegularExpressions.Regex.Match(strCon,"Data Source=(.+?);").Groups[1].Value;


Note the (.+?);
The trailing ? forces the match not to be greedy and only match up to the first semi colon.

26 Jan 2009

Fun around Hogwarts

Last week Ruth and I drove oop north for a weekend in Northumberland.

We stayed at a "luxury" B&B called The Old School at Newton-on-the-Moor. It was cute, and Kath and Malcolm were great hosts. However we felt a bit restricted by the usual mom n' pop B&B issues like breakfast being available only for an hour in the morning, and being locked out of the place between 11 and 4 in the day. Also our room got chilly, there was no bath, and the shower never worked properly. I think they are in the middle of sorting out issues with their heating system so I'll let them off, but it makes us think about staying at a hotel next time. The breakfasts were excellent though :)

On Saturday, we went to the Holy Island of Lindisfarne, managing to drive across the causeway both ways without getting trapped by the rising tide. However we soon found that there is bugger all to do there during the winter months. The castle was sweet (albeit closed) and the landscape lovely, but the bitter wind soon drove us back to the car.

We then pootled down the road to Bamburgh with its amazing castle - also closed for winter. In fact the entire place seemed closed. We ventured into a coffee shop called The Copper Kettle and had really crappy service, hooray. God they were miserable. At least the beach was nice.

The saving grace of the day was Alnwick, where we completely avoided the Harry Potter freaks by spending almost FOUR HOURS in Barter Books, the funkiest (in a skillo kind of way) bookshop in the universe. If you're in Northumberland and you like books, you must visit. It's enormous and friendly and great. Nuff said.

On Sunday we went to Durham. It was like York, only not as good :) THAT IS ALL.

Oooh, apart from the food. Two things

  • The Linden Hall Hotel does lovely posh nosh for ~50 quid a head
  • The Cook and Barker pub in Newton-on-the-Moor does lovely unexpectedly posh nosh for ~25 quid a head.

There is good eatings to be had in the North! Yay!

6 Jan 2009

2008 Product Roundup

Hi Zootfans, and a happy new year to y'all!

Someone just left a comment on one of my posts saying it helped them out, so I feel satisfied enough to continue this most unrewarding job :)
So, a quick round up on some material stuff I bought, in case it helps anyone out:

Toshiba Regza 37" LCD Television (2007 model)

SUCKS. Do not buy. How does it suck? Let me count the ways. Rubbish remote control range - have to point right at the receiver too. SLOOOOOW channel hopping and menu response. Poor sound. Now also has a fault meaning the backlight doesn't fire up when you first turn the telly on. You have to turn it off and on again. Annoying. The telly has one saving grace - good picture quality. I won't buy Tosh again - I had one of their DVD players too and it was also crap.

Sony Bravia 32" LCD Television (2008 model)

IS GOOD. The remote control is responsive and bounces off walls, yay. Good sound, picture, menu system. Just the ticket.

Mazda RX-8 (2004 model)

This car is heaven and hell. Heavenly handling. Hellish fuel consumption - I averaged 21mpg!. Angelic practicality for a sports car - big boot and real adult seating in the rear. Demonic depreciation - I lost £5k in 9 months :p The wankel rotary engine is interesting and helps the 50:50 weight distribution, but has poor low-down torque, and also has a design fault: If you don't let the engine warm up before cutting the ignition, e.g. if you just need to move the car off the drive - when you come back to the car you'll find it won't start. You need to faff about removing the fuel pump relay and gunning the engine until it's spat all the unburnt fuel out that's accumulated at the bottom of the rotor chamber. You shouldn't have to do this in a modern car. Nor should you have to put a litre of oil in every month.

Overall I loved owning such an exotic piece of hardware for my day in the sun - on twisty roads on a summers day it was brilliant. But as winter closed in, petrol prices went up, and I found it was useless on cold roads, I wasn't sad to say goodbye. I'll remember it fondly though :)

Audi A4 Avant 2.0 TDI SE Multitronic (2005 B7 model)

I've only had it a month but I like it. Things that are good:

- Fuel consumption: Average 41mpg, not bad for an automatic.
- Loadspace: lots of it.
- Multitronic CVT transmission: Smooth and powerful.
- Bluetooth phone integration: works the moment you get into the car, phone in pocket. So much better than having an earpiece, and lets you browse your phonebook using the steering wheel controls.

Things that are less good:

- Headlight range isn't great (non-xenon).
- The auto-locking and single-door unlocking "features" are annoying (anyone with a VAG-COM can fix it though).
- The voice-command features for the phone don't work very well, always making mistakes.

DICE Ipod Integration for Audi (2008 model)

I have fitted this to my new Audi A4 (B7 model) and amazed myself with my mad engineering skillz ;) I had to buy stereo removal keys off ebay to pull the Concert stereo system out of the dash (tip: the keys go in pointy-side out, and are removed by pushing in the locator clips on the stereo). I also had to remove the glovebox, which is easy when you know how:

1. Remove side panel to the glovebox. Prise it carefully with a flat screwdriver wrapped in electrical tape. It's only held in by clips.
2. Use an 8mm socket to remove the 5 bolts that hold the glovebox in place. 3 bolts are on the top edge of the opened box. The other 2 bolts are underneath the box.

Voila, the box comes out. Don't forget to reattach the light connector when you put it back.

The DICE unit installation was dead easy really as you just piggy-back the old audio harness into the new DICE harness, and shove that in the back of the stereo. Then you put the ipod connector cable through the back of your glovebox - I cut out a pre-formed square that Audi have thoughtfully left for you there. I didn't have to unplug the car battery during the install, and I didn't have to re-input the stereo code afterwards either.

And finally - how well does it work? Works ok. The ipod charges in the glovebox and you can skip track / change volume from the main car and steering wheel controls. Playlist and track navigation is poor because the Audi Concert stereo can't display tracknames. So I'm just going to create a few playlists and leave it on shuffle. It has one other nice feature - a separate aux-in cable so you can attach non-ipod sources too. Sound quality is good. Overall - a vast improvement over my old FM transmitter.

Asus Eee 901 netbook computer (1Gb RAM, 20Gb SSD model)

This has to be my most satisfying purchase this year! It took ages to get my hands on the 20 gig solid-state-drive linux model because they were out of stock everywhere. I played with the custom linux interface for a while and decided it wasn't for me. Seemed to have a few bugs that Asus weren't interested in fixing, and a few of my favourite apps and emulators weren't available for linux. Crucially, the flash player seemed to make videos jerk which was really annoying as I'm a YouTube / BBC iPlayer junkie.

So I installed XP instead. I used nlite to shrink down the install footprint, and installed off an 8gb memory stick. That was the major pain in the bum, XP just wasn't built with USB installs in mind. I had to jump through a hell of a lot of hoops to do it, and tried a lot of different methods that didn't work for me (e.g. BartPE). In the end I did it using USB_Multiboot_10 : http://www.msfn.org/board/index.php?s=962f023b64ec36301f9ea200d4ea3ed8&showtopic=111406&st=0&p=737643&#entry737643

Anyways, the Eee 901 with XP kicks ass. Lasts over 5 hours without recharging. Quiet - no moving hard drive parts, just a little fan that kicks in when you do something intensive, like amiga emulation :) Performs brilliantly for its specs. You can surf comfortably in bed. I love it!

Roland TD-3KW V-Drums

I've decided to learn to drum, so V-Drums are a great choice cos they don't annoy the hell out of everyone else in the neighbourhood. I'm just getting started really, but they sound good with my new AudioTechnica MTH50 headphones, and were easy to set up.

And with a crash-boom-bang, that wraps up this entry! Byeeeee
If I helped you out today, you can buy me a beer below. Cheers!