Main logo
Digital Strawberry Girl (Chris) Blog

Over the past week I've made some great progress on my OpenSim experiment. For starters, I've got my server configured in Grid mode, and I have all four of the main servers running on SQL Server. This did require a bit of development - the inventory server was quite broken for SQL Server, so James and I fixed the code and submitted a patch, but the good news is that this means it'll be in a better state for the rest of you from now on.

If you're committed to switching from SQLite as much as possible then I would recommend configuring your server to run in grid mode. Even if you are working locally, there's something a bit more comforting about seeing messages relevant to each server on each of the console windows, rather than all jumbled up in one console window. Makes it much easier to see bugs and have a think about how to fix them, for starters.

So, where to start? Well, good news and bad news - the good news is that this is possible, the bad news is that it's not simple, and unless you figure out how to export content from a SQLite-based OpenSim, you'll be starting from scratch on your new sim. Before you start, you obviously need a SQL Server to work with. As long as you can install SQL Express on your OpenSim server, you have everything you need, and since SQL Express is a free download, there's no cost involved. Get SQL Express from here, then get SQL Management Studio Express from here - this will give you a tool for running queries and editing your database.

Now, I'm assuming you've done the right thing and already configured your system so you have a Subversion client installed, right? TortoiseSVN is my favourite, with its extremely simple shell integration. So, you have an OpenSim directory and you can grab the latest source code from the Subversion repository - this is pretty important, since the code changes very frequently. Now you will need to head to SQL Management Studio Express and create a database ready to store your OpenSim data. Right-click on the Databases node and and select New Database. Call it OpenSim, accept all defaults and click OK.

The next step is to create a user account for running your OpenSim on SQL Server. Firstly, you need to enable Mixed Mode authentication on SQL Server.

Right-click on your database server in Management Studio and select Properties, then go to the Security tab and select SQL Server and Windows Authentication mode, click OK. Back in Management Studio, expand the Security node and in the Logins section right-click and create a new user, called whatever you like, select SQL Server authentication, give it a strong password and select the OpenSim database as the default database. Click OK.

Then navigate to the OpenSim database and go to the Security, then Users section. In there, create a new user, select your new admin account and make sure it has the db_owner role in the Database role membership section. Click OK and you should be ready to use that account to connect to the database.

Next step is to create the tables you'll need to store all the data from OpenSim. I have my OpenSim code in C:\OpenSim, so on my system, I navigate to C:\OpenSim\OpenSim\Data\MSSQL\Resources to find the SQL scripts you'll be needing to create the base tables in the database. Open each script in turn in Management studio and click Execute against them all. Provided you have no errors, you will be good to go with running OpenSim in grid mode on SQL Server!

Time to edit the Ini file. I recommend heading to the OpenSim documentation on configuration for more in-depth details on this process, but here's an abbreviated version that might help fill in some gaps for you. While there is a mssql_connection.ini file, I also have settings in my main ini file too - I haven't yet dug through the code thoroughly enough to know which ones are used and which ones are not. There's a sample mssql_connection.ini.example file in the OpenSim code repository, so make a copy, rename it mssql_connection.ini and replace the appropriate values with the correct data for your server. As an example:

[mssqlconnection]
data_source=servername\SQLEXPRESS
initial_catalog=OpenSim
persist_security_info=True
user_id=adminuser
password=password

In the main ini file,

gridmode = True

storage_plugin = OpenSim.Data.MSSQL.dll
storage_connection_string = "Data Source=servername\sqlexpress;Database=OpenSim;User=adminuser;password=password;";
storage_prim_inventories = True

appearance_persist = true
appearance_database = "MSSQL"
appearance_connection_string = "Data Source=servername\sqlexpress;Database=OpenSim;User=adminuser;password=password;";

inventory_plugin = OpenSim.Data.MSSQL.dll
inventory_source = "Data Source=servername\sqlexpress;Database=OpenSim;User=adminuser;password=password;";

userDatabase_plugin = OpenSim.Data.MSSQL.dll
user_source = "Data Source=servername\sqlexpress;Database=OpenSim;User=adminuser;password=password;";

asset_database = MSSQL
asset_plugin = OpenSim.Data.MSSQL.dll
asset_source ="Data Source=servername\sqlexpress;Database=OpenSim;User=adminuser;password=password;";

The other part of the puzzle is getting your sim running in grid mode, and for that to work you need to be a little more clever with IP addresses and the like, but don't let that put you off. Know your server's IP address, then enter it in the following section with the following port numbers:

grid_server_url = http://192.168.0.1:8001
grid_send_key = null
grid_recv_key = null
user_server_url = http://192.168.0.1:8002
user_send_key = null
user_recv_key = null
asset_server_url = http://192.168.0.1:8003
inventory_server_url = http://192.168.0.1:8004

Notice there are some keys listed in here that are null - you should change these so that you only allow access to people who know both your server's IP AND the appropriate keys to grid up with you. And from looking through the code, it appears that the keys are any valid string value, though I haven't yet tested this out.

You may also want to double-check that the IP address is configured correctly for your region (head to the OpenSim\bin\Regions\default.xml file) and make sure that the IP addresses are set appropriately. Again, check the OpenSim site for a bit more information on this.

Once you have configuration sorted, time to run the servers and keep your fingers crossed! The OpenSim site strongly recommends starting servers in a specific order: UGAIS: UserServer, GridServer, AssetServer, InventoryServer, Sim. Note that the first time that you fire up the servers in grid mode, you are asked for some information to create some system-specific configuration files. Make sure that when you start up each server you enter the data correctly - the data you will need to enter is exactly the same as that entered in the ini file, so make sure you fill in the fields so that they match. Once you have configured one server, move on to the next. Once you have all five running, you're almost ready to log in!

Here's a handy tip - now you have 5 console windows open, click on one of them on the task bar, then ctrl+click on the other four windows. Right-click on any of them and select Tile Horizontally and you will see all your servers neatly arranged, and you can watch things happening as you log in and do stuff on your sim.

Just before you connect, you need to create a user account, so go to the user console and create a new user account. Then it's time for the client bit - if you're using the SL client, set your loginuri startup switch as before, but this time you'll connect to port 8002, not port 9000, so for example:

"C:\Program Files\SecondLife\SecondLife.exe" -loginuri http://192.168.0.1:8002 

Once you launch your client, you should be able to connect to your grid and off you go. Fingers crossed, and I hope it works for you. Note that I think there's a bug with creating folders in your inventory, so watch for errors there. You may have to go with a completely unorganised inventory for a while until that's fixed (which may well be soon).


I've just been through two days of pain trying to get content deployment to work from an internal authoring site, authenticated against Active Directory, to a live site that is Internet-facing (hence allows anonymous access), and has a forms authentication user store. It's more of an admin nightmare than a developer task, but as I've found over many months, working with SharePoint as a developer involves a lot of the admin side of things too. This blog post is a guide to a proof-of-concept, and not meant for a live production environment.

So, what can I share with you that might help? Well, let's list a few links that you need to read first:

http://technet.microsoft.com/en-us/library/cc263428.aspx

http://www.harbar.net/archive/2007/06/27/Content-Deployment-Ensure-your-platform-hygiene-before-randomly-abusing-the.aspx

http://blogs.msdn.com/sharepoint/archive/2006/05/02/content-deployment.aspx

So, that out of the way, here's how I got it to work. And bear in mind that this is on a development machine where all sites are hosted on the same box - albeit in different web applications. Different applications, different authentication, same central administration application.

Firstly, you'll need to have two sites, one for authoring, one for live. If you want a forms auth site as your live site, there are many resources - this one is pretty good. When you create your sites, the golden rule applies:

The target site for content deployment MUST be created using the BLANK site template

Even better, if you can get it to work (and I could only get this to work for an AD-based site, not the forms auth site, but I digress), you can try the following once you have created the web application to create your target site collection:

STSADM.EXE -o createsite -url <url-to-site-collection> -ownerlogin domain\user -owneremail <email-address>

So, you have a blank target site. I'm going to assume you have an authoring site set up to use some kind of template - I set mine up as a collaboration portal. Another word of warning - as yet, I've not tried content deployment against a site with custom features, web parts, etc. As far as I know, those have to be installed separately and available on the destination server prior to deployment - I may have to write a follow up to this article when I get that far. Enter some content to make it clear that your site has been deployed - I added some images to the main images library and edited a couple of content editor parts. Now, over to Central Administration console you go.

Head to the Operations tab and there you will find the option to change your content deployment settings and to set up deployment paths and jobs. In my Content Deployment Settings, I have configured my server to accept all incoming deployment jobs, and selected my server from the import and export server drop-downs. Worth a note - the temporary files entry on here specifies a local path for temporary storage of deployment data. I have read that you need to make sure this directory can be written to by your service account, so I added appropriate security settings to that path to make sure there would be no grumbles there.

Now, to set up some paths and jobs. I created a new path and selected my source application as the authoring site. Make sure you select the appropriate site collection - mine all use the root site collection, so this was a simple setting. The URL to your Central Administration application should be simple enough to enter, and you need to make sure you can connect to that application using the appropriate credentials. One of the benefits of a hacky dev environment is a central user account for all application pools. Again, this is a proof-of-concept. Select the destination web application and site collection, then decide on what to export - user names, other security information - the choice is yours depending on your configuration. I've set this up to only deploy role definitions. Click OK, and fingers crossed the first part is done.

If this works ok, you'll have a quick deploy job set up already. Try running that and pray for success (keep clicking on the Status column header to refresh the grid). If you get a fail, you may need to double-check some settings. And if you chose anything other than a blank site when you started out, don't blame me :) Now, bear in mind that this quick deploy doesn't deploy the content! This is a big thing I found - I was expecting it to have deployed everything - not so. If you browse to your site now it will look pretty empty, so you should now create a new job to deploy content from authoring to live.

Create a new content deployment job for that same path and set it to deploy the entire site collection, and deploy all content, including anything previously deployed. You may be able to run this with just deploying new content, but my first instinct was to deploy everything first time. Later on, create a job to deploy changed content and set it to run on a schedule if you like. Run the job, make a coffee, then come back and find that the whole thing has run perfectly... well, that's the theory, and I certainly hope it works for you. If not, there are a lot of resources out there with suggestions for how to make it run a bit more smoothly, and there's a great blog post from Andrew Connell with information on a couple of hotfixes that might help solve some issues.

I'm going to be doing a lot of work on a project that involves this configuration over the next few weeks, so I may write some more on this as and when I can. In the meantime, I'd like to thank Nebulae Voom, friendly SharePoint guru from the .NET group in Second Life, and SharePoint from twitter (The official tweetstream of the SharePoint product group) - while neither solved this for me, you helped my brain think the right way!


Over the past few weeks I've taken a big leap into the world of Open Source development and started messing around with OpenSim, the BSD licenced 3D virtual world based on Second Life, but reinvented from scratch using C#. It's an immense project that's been in development for a while, and it's starting to look pretty good.

Getting hold of OpenSim is relatively easy, especially if you're a developer and have used Subversion before. Grab the latest code, run the pre-build tool, build the solution and you're just about ready. Make sure you run the correct exe for your system (64bit machines have to run a 32bit launcher), and you are hosting your own little simulator that you can connect to.

So, next step is to connect to the newly-created world. You can either use the standard Second Life client with a modified startup shortcut, or you can download and use the realXtend viewer and specify your server as part of the launch. And then you're in your own little world...

sf5

Now, since that picture was taken I've completely broken the server by attempting to hook it up to SQL Server, but that's all part of the fun - and there are so many bits and pieces to look at and tweak that this is proving to be quite an entertaining project.

So, why am I doing this? Well, I've been working with Kyle for a while on MS Island on Second Life, and this is part of an exploration of open source alternatives to the Linden Labs controlled world. Project Manhattan is the first project we're working on, and it's still in its early stages - but it certainly makes a welcome change from SharePoint development.


Handy tip that James pointed out the other day - my Virtual PC machine console window keeps disappearing (perhaps thinking that I have an external monitor plugged in). You can see it on the task bar, but clicking on it doesn't bring it to the top of the pile on the desktop, so, how do you get it back on your main screen?

In the following order:

  • alt
  • space
  • m
  • any arrow key
  • move the mouse

Hey presto, the window snaps to under your mouse cursor and you can drop it wherever you like. Very handy and useful to remember.


April 26th is the day for your diary; all our preparation work finally gets load tested to the extreme as we host the Heroes Happen Here launch event for Visual Studio 2008, Windows Server 2008 and SQL Server 2008 on Second Life. We're getting three extra islands for launch day so we can make the event run as smoothly as possible for all the attendees, and there'll be much partying and some freebies for those who come along to the island.

Before that happens, I'm travelling to Orlando for 3 days (figured I'd need jet lag before a major launch event), for the DevConnections conference, where I'm hoping to get up to speed on some of the cool new stuff that's been coming out recently. I've not had a chance to play with Silverlight yet, or look into the new MVC framework, since I've been so busy with SharePoint code and SL fun. And there's also a load of SharePoint talks happening at the same time, so I'm hoping to chat to some gurus about SharePoint Internet site projects (my next piece of work, starting soon).

I also mentioned recently that I was in a recording of .NET Rocks recently; well, the show is now live, so hit the link and hear a bit more about what I've been doing (along with Kyle and Zain) on Second Life, and some discussion of why it's not (as many people think of it) a game. Zain Naboulsi does a great job of explaining that too in his recent video interview with Keith Combs and Matt Hester.


Since I got involved with the Second Life .NET group, my free time has been eaten up by a monster! Ok, not the bad kind, but it's amazing how addictive Second Life is once you start to get involved with something worthwhile. We've been tackling this monster from two perspectives - one is to think about what members would like to see and do on the Microsoft Island, and the other is to get very geeky and enthusiastic about what the technology can do for us and figure out ways of making it work. It's a fun little hobby, made all the more exciting by the constant stream of client updates coming out from Linden Labs; the most recent Release Candidate viewer (1.19.1) has got us most excited, since it gives us the option of showing a web page in-world with very little effort. Ok, so it doesn't seem to work on any of my Vista machines, but I'm sure this will be fixed soon.

Anyway, as a result of all the work that's been done in-world, friend of the group, Todd Anglin of Telerik had a word with Richard Campbell of .NET Rocks (the excellent long-running podcast show on .NET development), and to cut a long story short, Kyle Gomboy (G2 Proto in SL) and I will be participating in a recording of the show next week about .NET in Second Life. I'm sure it'll be a fairly strange experience, but hopefully I won't make a complete fool of myself.

13/03/2008 Two and a bit

I have been amazed at how quickly Nathan has changed over the past few months. He never stops talking, and while we may not catch every word, he tries so hard and you can hear his pronunciation improve daily. His rapidly exploding vocabulary is amazing - he knows numbers up to 12, all the letters by name, and takes pride in telling me how we have "one gate, two gates" on our stairs. His enthusiasm for life is fantastic, and it makes for some hilarious moments - shopping in Sainsburys is possibly the best example, since he will shout out the numbers of each of the aisles as we go down them. He's also getting the hang of brands, and enjoying the likes of Bob and Thomas - partly though exposure at the nursery. And his friends at nursery are very sweet - each morning when I drop them off, they run over to say hello.

Of course, he has his little moments - he gets very frustrated if we don't understand what he's saying, and if he decides he wants to do something, we have to tread very carefully if we don't really want him to do it. We get told off regularly, and we get told what to do quite often. "Sit down, play cars", for example. And then last night, he was being cheeky and refusing to go to bed by telling me, with a smile on his face, how "Bob's hat is yellow..., aaaaand Wendy's hat is blue..., aaaaaand Scoop's yellow, aaaaand... " and so on - makes it _very_ hard to tell him it's time to go to sleep!


I've been having fun getting objects in Second Life talking to a database on my dev server using .NET code, so I thought I'd share the magic with those of you who are interested.

For the SecondLife bit, I'll use the llHTTPRequest object to request data from my external source. The real-world bit is some ASP.NET code running on a development server. In order to understand how this code works, you need to understand the underlying structure of a HTTP request. If you've not done anything like this before, here's a quick dive in.

Each time you view a web page with your browser you're making a request to a web server for a web page. In response, the server sends the requested page data back to you. Each web request consists of request headers and the body of the request. Request headers are sent as a series of key/value pairs (though each key could have many values). The request headers that are sent as part of a request from IE7 (32bit) on a Windows Vista 64 machine with a fair few applications installed may contain the following values for the Accept and User-Agent keys respectively:

Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-ms-application, 
application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, 
application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, 
application/x-silverlight, application/x-shockwave-flash, */* 
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64; 
SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; Media Center PC 5.0; InfoPath.2; .NET CLR 3.5.21022; MS-RTC LM 8) 

Chances are you'll be sending information like this with every request you make to a web server (note to self - that's a LOT of information!), and it helps application developers to know who their audience are and what browser they are using. In addition, if you fill in a form online and submit it to the server, you'll also be sending information as part of the body of the request. For example, I've got a simple HTML page with an input box and a submit button (which comes in handy for testing later):

<form action="VisitorTracker.aspx" method="post">
<input name="avatar" type="text" />
<input type="submit" />
</form>

Nothing special here, and no server-side code to look at, but the interesting bit is in the request body once the form is submitted. If I enter "MyAvatar Name" in the textbox and submit the form, I will have sent a key of "avatar" (because the input has a name attribute of "avatar") with the value of "MyAvatar Name" to the server. As long as your target for the submitted form, in this case, a page called VisitorTracker.aspx, exists, you can add code to that page to handle the data when it arrives and do something with it.

As well as using an HTML form to gather data and send it to the server, I can send the same request to the server from Second Life if I create a prim in-world and add some script to that prim. The following is an extract from some code I'll show you later:

llHTTPRequest("http://devsite/visitortracker.aspx", 
[HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/x-www-form-urlencoded"], 
"avatar=MyAvatar%20Name");

There are a few things to note here. The llHttpRequest method takes three arguments; a string of the url of the page you are sending the data to, a list of HTTP request parameters, and the body of the request. Since we want to send the request data using a POST (the method you'd use if submitting a form to a server), this is specified in here, along with the fact that the form data has to be URL encoded. This is why the avatar name "MyAvatar Name" has a %20 in the middle of the string, since a space character becomes a %20 when it's encoded.

Right, so we've made a request to a web server for a page and have sent some information in the body of the request. Time to tell the server how to handle the request. Because my development server runs Microsoft's IIS web server, which supports writing server-side code using the ASP.NET platform, I'm going to use a simple ASP.NET page (on other servers you might use PHP or Perl or Ruby). If you are using Visual Studio 2005/2008 (Visual Web Developer Express edition or better), you can create a new web project with just one page in it. Call it visitortracker.aspx, and make sure you check the box to place the code in a separate file. I'm a C# person, though you can do it with whatever language you feel comfortable using. Here's my code:

VisitorTracker.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="VisitorTracker.aspx.cs" Inherits="VisitorTracker" %>

(yes, that's all of it - delete everything else in the file; you don't need it)

VisitorTracker.aspx.cs:

using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;

public partial class VisitorTracker : System.Web.UI.Page
{

  protected void Page_Load(object sender, EventArgs e)
  {
  }

  protected override void Render(HtmlTextWriter writer)
  {
    string detectedAvatar = (string)Request.Form["avatar"];
    writer.WriteLine("Detected avatar: " + detectedAvatar);
    base.Render(writer);
}
}

This code essentially turns the page into a web service of sorts - I'm making a very simple request of the page, and all I'm getting back is data, without any markup or presentation logic. As it happens, the data is human-readable, and we can use this to display a confirmation message on a test prim in Second Life. You can send back whatever you like in the Render method using the writer object, but bear in mind that there is a restriction on the length of the response body in Second Life - you get a maximum of 2048 bytes; if it is longer it will be truncated (with thanks to the LSL wiki for that nugget of information!) Make sure it all builds, then, if you want to test this file without logging into SecondLife, you can create a simple HTML page containing the code I showed earlier between the HTML body tags, then try submitting that form. You should see the message:

Detected avatar: MyAvatar Name

(or whatever name you entered in the input box.)

Back in SecondLife, you can enter the following script into the script file on your prim (changing the name of the server as appropriate) to submit a nice request when the prim is touched, and handle the response received from the server:

key http_request_id;
default
{
state_entry()
  {
  }
  http_response(key request_id, integer status, list metadata, string body)
  {
    if (request_id == http_request_id)
    {
       llOwnerSay(body);
    }
  }
  touch_start(integer total_number)
  {
    integer i = 0;
    while (i <= total_number)
    {
      if (llDetectedKey(i) != NULL_KEY)
      {
        string avatarName = llEscapeURL(llDetectedName(i));
        string formData = "avatar="+avatarName;           
        http_request_id = llHTTPRequest("http://devserver/visitortracker.aspx", [HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/x-www-form-urlencoded"], formData);
      }
      ++i;
    }
  }
}

Now, when you save the script and touch the prim, assuming everything worked as planned, you'll see that same confirmation message in your chat window, except with your avatar name inserted into the message. Notice the http_response handler in this code that takes the response data and tells you all about it. The truth is that there's not a lot to this stuff - send a request, handle the response - more simple than it might first appear.

One last thing you might want to try. In the request headers that come across from Second Life, there is a surprisingly large amount of data. To see this data, add the following code to your render method in your aspx.cs file (insert it just before the call to base.Render):

string[] keys = Request.Headers.AllKeys;
foreach (string key in keys)
{
  if (key.Contains("SecondLife"))
  {
    writer.WriteLine("Key: " + key);
    // Get all values under this key.
    string[] values = Request.Headers.GetValues(key);
    for (int i = 0; i < values.Length; i++)
    {
      writer.WriteLine("Value " + i + ": " + Server.HtmlEncode(values[i]));
    }
  }
}

Now, you will probably find that when you get this data back in Second Life that you hit the maximum for the size of the response, but in there you could well see the name of the owner of the prim, the region and co-ordinates in that region in which the prim currently resides, and much more. A full list of Second Life http headers can be found on page on llHTTPRequest on the LSL wiki. I'll leave it up to you to decide what to do with these headers and the code on the prim... You could add a sensor to the prim to detect arrivals to your plot and record the name of the visitor and the time they came to visit in a database, or you could detect visits by newcomers to your plot and send them a welcome message detailing upcoming events. There are so many different things you can do with both prims and data on the server that really it's up to you what you do with the data - the mechanism of sending data to and from Second Life and a web server in the real world is extremely simple, and that's what I find so appealing about it. I don't have to spend hours writing pages of code to get things working, and I don't need to install special components on my web server, and yet I have this elegant and simple mechanism to talk to Second Life. It's not the same as pushing data in-world (for that you will need to look into XML RPC, XML RPC in LSL, and possibly XML RPC in .NET, if you're a .NET person), but for most situations where you might want to send data in-world, you can probably find a way to pull it in instead using one of the built-in methods of LSL as a trigger (sensor, timer, listener, etc.) and handle the data appropriately on the server.

31/01/2008 A .NET Second Life

I've recently become involved with the .NET user group on Second Life, which (for those of you who've not yet tried it), is a great way to meet people from all over the world in a 3D virtual world. I've been a resident on there for a while now, but I'm only just starting to really make the most of it, and it's a real buzz. Last weekend, the Microsoft Visual Studio Island on Second Life played host to a talk on Silverlight by Todd Anglin from Telerik. Members of the user group, represented by Avatars in this virtual world, sat around in an outdoor auditorium and were able to listen to the talk, and to view the slide presentation, in a similar fashion to a real world presentation.

I worked alongside the team who rebuilt the new auditorium for the island (the old one was not universally liked!), and I've had a great time bouncing ideas off G2 (GSquared), in particular, for figuring out how we can improve the experience for session attendees. With a complete lack of US TV imports to watch over the past couple of weeks, James and I set about designing some special chairs for the auditorium that would give the audience some increased level of participation in the event. We ended up with a system that gave the speaker some control over the session, enabling the audience to vote yes/no on various matters, with arms being raised and lowered accordingly, and with a visual indicator at the back of the stage for live poll results. We intend to make it possible to upload these results to the website (http://www.sldnug.net) for viewing later, and we've got plenty of other ideas to help make the whole experience more worthwhile.

Perhaps one of the best things about a user group of this nature, aside from the fact that it's free, is the fact that you don't have to worry about travel costs, accommodation, or any of the other factors that could get in the way of attending (such as having a small child to look after!) And while you can watch webcasts online, or listen to podcasts, the freedom of just walking up to a speaker and asking them questions, very much like you can do at a real conference, is liberating. In addition, I've made some valuable business contacts, and some good friends, which makes working from home that little bit easier. So, if you happen to be visiting Visual Studio Island on Second Life, and happen to bump  into my avatar (Strawberry Fride), feel free to pop over and say hi.


I recently purchased an item on Amazon that I needed delivered quickly, so I selected Express delivery from the delivery options. I saw a message - did I want to spend £49 and get express delivery on all my orders for a year? I decided against it - most of the time I can live with the delay of supersaver delivery. On the same day, I bought a load of stuff with free delivery.

You may see where this is going - yes, the free delivery stuff arrived yesterday, without a hitch. The doorbell is in need of batteries, so I didn't hear it arrive. No problem - the Postie left it in my Parcelsafe. The express delivery stuff shipped yesterday, and was attempted delivery today. I'd popped into town with Nathan at the time. Thing is, Express delivery requires a signature, and my Postie wouldn't leave it in the Parcelsafe and has had to take it back to the depot. And if you've ever done a big trip into town with a nearly-2-year-old, you'll understand my reluctance to venture back again this afternoon!

So yeah, stick with free delivery - most of the time it works out fine.