 Sunday, October 01, 2006
[Test]
public void ExtendingClass()
{
PythonEngine engine = new PythonEngine();
engine.Import("clr");
engine.LoadAssembly(GetType().Assembly);
engine.ExecuteToConsole("from IronPythonLib.Tests import *");
engine.Execute(@"class MyTransformer(IStringTransformer):
def Transform(self, input):
return input + "" is now transformed""");
IStringTransformer transformer = engine.EvaluateAs<IStringTransformer>("MyTransformer()");
Assert.AreEqual("input is now transformed", transformer.Transform("input"));
}
hmmm?
edit: seems better now, swapped to a simpler layout though I
doub't it will work well for people with lower resolutions... most
people will (hopefully) read this via RSS at any rate.
Back once more...
I decided to spend ten minutes implementing a
version of the last post which didn't require us to generate a function
definition for a python method with a generic number of parameters... it's actually not too hard.
First off, the key to solving this problem is to generate a Type for
our custom delegate - for performance reasons you would want
to cache the results, but we won't do that here... Also I think it would
be more apropriate for the first 0->9 parameters that we just return
a generic Func delegate (generic Func & Proc delegates are going to
be part of .Net 3.0, as mentioned here - At the moment I use something similar from the RhinoCommons library, have a look here)
So, first off we build a helper method for generating our delegate - just heavy use of emit here, based off an example on MSDN:
public Type CreateCustomDelegate(Type returnType, params Type[] parameterTypes)
{
AssemblyName assembly = new AssemblyName();
assembly.Name = "CreateCustomDelegateAssembly";
AssemblyBuilder assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(assembly, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("TempModule");
TypeBuilder typeBuilder =
moduleBuilder.DefineType("TempDelegateType",
TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class |
TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeof (MulticastDelegate));
ConstructorBuilder constructorBuilder =
typeBuilder.DefineConstructor(
MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public,
CallingConventions.Standard, new Type[] {typeof (object), typeof (int)});
constructorBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
MethodBuilder methodBuilder =
typeBuilder.DefineMethod("Invoke",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot |
MethodAttributes.Virtual, returnType, parameterTypes);
methodBuilder.SetImplementationFlags(MethodImplAttributes.Managed | MethodImplAttributes.Runtime);
return typeBuilder.CreateType();
}
Basically it goes through the motions of building a delegate type, derived from MulticastDelegate with our selected output type and parameter types...
Now to put that type to use:
[Test]
public void WithCustomDelegate()
{
Dictionary<string, object> context = new Dictionary<string, object>();
context.Add("user", "alex");
context.Add("age", 26);
Proc testCore = delegate
{
List<string> parameters = new List<string>(context.Keys);
List<object> values = new List<object>(context.Values);
PythonEngine engine = new PythonEngine();
Type[] parameterTypes = new Type[context.Count];
for (int i = 0; i < parameterTypes.Length; i++) parameterTypes[i] = typeof (object);
Type delegateType = CreateCustomDelegate(typeof (object), parameterTypes);
Type pythonEngine = typeof (PythonEngine);
MethodInfo genericMethod =
pythonEngine.GetMethod("CreateMethod", new Type[] {typeof (string), typeof (IList<string>)});
MethodInfo method = genericMethod.MakeGenericMethod(delegateType);
object result =
method.Invoke(engine,
new object[] {"return user + ' is ' + str(age) + ' years old'", parameters});
Delegate myDelegate = (Delegate) result;
Assert.AreEqual("alex is 26 years old", myDelegate.DynamicInvoke(values.ToArray()));
};
// try it with our two keys in the dictionary
testCore();
// try it with another key in the dictionary
context.Add("monkey_colour", "brown");
testCore();
}
Our test creates our custom delegate type for the number of parameters we have, and then we use that when invoking the PythonEngine.CreateMethod<TDelegate>(string statements, IList<string> parameters) method.
Here we have to do a little reflection, simply because we cant directly
use a local variable of type "Type" as a generic type parameter, so we
grab the generic method, set the parameter and then invoke it.
However in the end, as you can see we get a real Delegate, which we can use DynamicInvoke upon.
This is actually pretty handy, and it's certainly a lot more
script-friendly, compared to the alternative of forcing users to look
up values from context by index ie.
context['user'] + ' is ' + str(context['age']) + ' years old'
vs.
user + ' is ' + str(age) + ' years old'
I know what I prefer ;o)
 Saturday, September 30, 2006
Part 2 - More IronPython and delegates…
So we have briefly covererd strongly typed delegates and event
handlers... But they make the assumption that we know what our
arguments are at compile time, what if we dont?
Say for instance you're expression engine has a bag of contextual values being passed around in a dictionary, like this:
Dictionary<string, object> context = new Dictionary<string, object>();
context.Add("user", "alex");
context.Add("age", 26);
What if we want to use python to evaluate expressions against that
context?... Say something like writing out “my name is alex and my age
is 25" - the expression in python is easy enough, we can go:
‘my name is’ + name + ‘ and my age is ‘ + str(age)
But how do we marry all these together... lets start exploring... ever noticed that delegates have a DynamicInvoke method with a signature like this?
object
DynamicInvoke(params object[] parameters)
Perhaps we can try and use this to our advantage... lets see shall we?
First Attempt
[Test]
[ExpectedException(typeof (ArgumentException), "T must be a concrete delegate, not MulticastDelegate or Delegate")]
public void LooseDelegateAndDynamicInvoke()
{
PythonEngine engine = new PythonEngine();
List<string> parameters = new List<string>(new string[] {"name", "age"});
Delegate func =
engine.CreateMethod<Delegate>("return ‘my name is’ + name + ‘ and my age is ‘ + str(age)", parameters);
string result = (string) func.DynamicInvoke("alex", 26);
Assert.AreEqual("my name is alex and my age is 25", result);
}
Sadly this doesn’t work so well, seems the PythonEngine is looking for
a concrete delegate... we could try giving it void delegate,
but it does type checking on the number of parameters and their type,
so we're a little stuck.
At this point I think the best answer is to actually build some code
which generates the apropriate delegate type, based on the supplied
dictionary, and then passing that onto the python engine, but there is
another way… it’s a little less elegant, but it’s at least amusing:
Round 2
First of let’s build a little helper method...
private static string GenerateFunction(string functionName, string[] parameters, string statements)
{
StringBuilder builder = new StringBuilder();
builder.AppendFormat("def {0}(", functionName);
for (int i = 0; i < parameters.Length; i++)
{
if (i > 0) builder.AppendFormat(", ");
builder.AppendFormat(parameters[i]);
}
builder.AppendFormat("):\r\n ");
builder.AppendFormat(statements.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", "\r\n "));
return builder.ToString();
}
You can no doubt see where this is going – so given a statement like this:
GenerateFunction("func", new string[] { "user", "age" }, "return user + ' is ' + str(age) + ' years old'")
We’d end up with a string like this:
def func(user, age):
return user + ' is ' + str(age) + ' years old'
And, moving on from there we build a test…
[Test]
public void GeneratingPythonFunction()
{
Dictionary<string, object> context = new Dictionary<string, object>();
context.Add("user", "alex");
context.Add("age", 26);
List<string> parameters = new List<string>(context.Keys);
List<object> values = new List<object>(context.Values);
PythonEngine engine = new PythonEngine();
engine.Execute(
GenerateFunction("func", parameters.ToArray(), "return user + ' is ' + str(age) + ' years old'"));
PythonFunction func1 = engine.EvaluateAs<PythonFunction>("func");
engine.Execute(
GenerateFunction("func", parameters.ToArray(),
"return user + ' is ' + str(age+1) + ' years old next year'"));
PythonFunction func2 = engine.EvaluateAs<PythonFunction>("func");
object result1 = func1.Call(values.ToArray());
Assert.AreEqual("alex is 26 years old", result1);
object result2 = func2.Call(values.ToArray());
Assert.AreEqual("alex is 27 years old next year", result2);
}
Are there problems with this?… well there’s a few, unsurprisingly!
• PythonFunction’s are not delegates.
• String manipulation is a bit clunky
• Because these are named functions, you probably
want to lock against some object when generating the function, to avoid
cross-threading issues…
Back to delegates
Aside from the problems it works alright, but what we really want is a
delegate… those PythonFunctions don’t give you the flexibility to
substitute IronRuby in the future now do they?
So first off, lets
declare a delegate suitable for our purposes.
[ThereBeDragons("Only use as a last resort")]
public delegate object UntypedDelegate(params object[] parameters);
Aint she a beauty ;o) - full credit for the ThereBeDragons attribute goes to Ayende,
though it's probably not really warranted in this situation - now,
let’s rework the last test to use a delegate instead, a simple
anonymous delegate will do the dirty work:
[Test]
public void UntypedDelegateForPythonFunction()
{
Dictionary<string, object> context = new Dictionary<string, object>();
context.Add("user", "alex");
context.Add("age", 26);
List<string> parameters = new List<string>(context.Keys);
List<object> values = new List<object>(context.Values);
PythonEngine engine = new PythonEngine();
engine.Execute(GenerateFunction("func",parameters.ToArray(),"return user + ' is ' + str(age) + ' years old'"));
PythonFunction func1 = engine.EvaluateAs<PythonFunction>("func");
UntypedDelegate func1Delegate = delegate(object[] param)
{
return func1.Call(param);
};
object result1 = func1Delegate(values.ToArray());
Assert.AreEqual("alex is 26 years old", result1);
}
It’s certainly better then passing around PythonFunction instances –
though you need to be a little careful… there’s a little quirk here, if
we were to use:
object result1 = func1Delegate.DynamicInvoke(values.ToArray());
It’s going to fail because the wrong number of arguments were supplied
(it expects only 1, an array), so our delegate doesn’t really behave
like it has multiple parameters.. so to dynamically invoke this
delegate we’d need to take special care, promoting the arguments into a
second array like so:
object result1 = func1Delegate.DynamicInvoke(new object[] { values.ToArray()});
Next Time
When I get bored I'll write a version which doesn't require the clunky generator and post it up...
Next time I'll talk about writing classes which are python-friendly, riveting stuff eh? As you were.
I felt like posting some code snippets… so I was looking around and
thought
perhaps some IronPython might be interesting…. Some of you may find
this useful, possibly not. I tend to explore functionality using
unit tests, so all my code will be test cases – I might make this part
of a small series on looking at python code with a view to integrating
it into an existing system as a scripting engine. Lets call the
series "IronPython is your friend"... because it really is.
Part 1 - IronPython and delegates….
So you have downloaded the IronPython runtime dll's, and you would like
to start integrating it into some project your working on… first off
lets create a python engine, and make sure it goes….
[Test]
public void GetGoing()
{
PythonEngine engine = new PythonEngine();
engine.Execute("myString = 'hello'");
Assert.AreEqual("hello reader", engine.Evaluate("myString + ' reader'"));
}
That was pretty easy; we executed some python code to assign the value
hello to myString, and then evaluated the expression – sweet you might
say – no effort required.
Now, you could write your scripting engine so that it passed the
strings to the engine for evaluation every time you wanted to evaluate
them – but this strings malarkey isn’t very pleasant… what we really
want is a decent god fearing .Net delegate, so we can call this without
having to think about the python engine…. Lets check out our first
destination, method delegates.
Method Delegates
Given a converter delegate like this:
Converter<int, string>
(Which by the way, if you haven’t stumbled across the generic
Converter<TInput,TOutput> delegate yet, effectively you end up
with a delegate method of the definition“TOutput Converter(TInput)” – pretty handy
actually)
We could do this:
[Test]
public void StatementsToStronglyTypedDelegate()
{
PythonEngine engine = new PythonEngine();
List<string> parameters = new List<string>(new string[] {"age"});
Converter<int, string> converter =
engine.CreateMethod<Converter<int, string>>("return str(age+1)", parameters);
Assert.AreEqual("11", converter(10));
}
Using a strongly typed overload for the engine's CreateMethod method,
we’re able to evaluate statements using our new delegate, which in turn
uses our IronPython method we created earlier… looks promising!
Events
Now delegates are cool, but it’s only half the story for
scripting in an application – depending on your model, you may be
aiming to produce results similar to a microsoft’s VBA in applications like Excel or Word – and for this
we need to be able to assign python code to events on our own classes…
we can do this using delegates of course, or we could let the python (user code)
do this itself, and save some time…. So lets have a look at the latter:
[Test]
public void HookingToEvents()
{
PythonEngine engine = new PythonEngine();
ManualResetEvent waitHandle = new ManualResetEvent(false);
WebClient client = new WebClient();
List<string> results = new List<string>();
engine.Globals["client"] = client;
engine.Globals["results"] = results;
engine.Execute(
@"def storeResult(sender, e):
results.Add(e.Result)
e.UserState.Set()
# assign out storeResult function as an event handler for the client class
client.DownloadStringCompleted += storeResult
");
client.DownloadStringAsync(
new Uri(
"http://api.feedburner.com/awareness/1.0/GetFeedData?uri=http://feeds.feedburner.com/BitterCoder"),
waitHandle);
Assert.IsTrue(waitHandle.WaitOne(10000, false), "timeout occured after 10 seconds");
Assert.AreEqual(1, results.Count);
Assert.IsTrue(results[0].StartsWith("<?xml"));
}
This test is a bit clunky, but you get the idea… we are:
- Creating a web client, for downloading some xml from a web site.
- Set the client as a global variable for the default module in the python engine.
- Execute some python, which creates a function, and assigns that
function as a handle for the web client's DownloadStringCompleted event
(take note at how concise the code is, this would be a lot uglier in C#)
- start the async download
- Make sure we got a response, and that the python code did what it should.
All in all, with a little finesse you can recreate a model similar to
VBA, driving your extension points from events – and this certainly has
some merit – obviously you want to create the code in their own
modules, as opposed to using the default module for the python engine
as we are.
We haven't quite finished with delegates yet though, I'll leave that for part 2 - which I'll post shortly.
 Wednesday, September 27, 2006
It seems like batching is a data access "theme" at the moment (much
like Castle, IOC & IronPython are all themes in the NZ Blogspace at the
moment... even though none of them could be considered new, I've
been using Castle IoC container for 1 & 1/2 years now!) - no
sooner do I discover the batching support in the Rhino.Commons
library, it appears NHibernate now supports it in the latest beta drop and it's a planned feature for the upcoming version 3 of the enterprise library ... It's interesting that this support never made it's way into the framework itself for version 2.0, it's all but there.
On the flip side, for NHibernate at least, the performance boons of
batching are impressive (see below for an image from Ayende's blog
where he's done some profiling), I haven't checked Base4.net out in
a while, but I wonder if Alex James has had a chance to implement
batching support yet? - maybe I should make that my task for the
weekend (checking out base4.net again that is heh... not implementing
support ;o)
Over the past couple of days I've been working on using
DirectShow and DES (DirectShow Editing Services) for re-encoding mobile
video content suitable for posting on the web... With the goal of
including video editing into our unified "media engine" which the Syzmk
line of products makes use of... as an off-shoot of that work I decided
to refactor the rather ugly code we had for working with DES over the
weekend into something a little less ugly, that hid most of the details
away, say hello to:
(sorry, couldn't resist the lame web 2.0 logo ;o)
A simple little library for doing most of the useful things in DES, the project is hosted here up on Codeplex.
It's currently in an alpha state, at version 0.9.0.0 - and should get
feature drops every week or so until I think it can go into beta.
To give an idea of what I'm up to, it's basically just wrapping up the
various DES components and removing alot of the unpleasantness (ie. you
get to deal with human-friendly units of time like seconds) .. and
seperating the concerns of the timeline, and rendering that timeline
into something useful like audio or video container (currently that's
just WAV, AVI & Windows Media formats). It's fully
functional, but the interfaces at this point it isn't very stable as
I'm likely to refactor the various interfaces mercilessly till I get it
working how I want, so if you build something with the library now,
it's likely to break in the future (but probably not in major way, it
is after all mirroring the functionality available in DES).
The added bonus of developing a set of rich wrappers for a lot of this
stuff is that I can mock away the requirement on DES altogether, which
is always a bonus considering how long the units tests currently take
to run for the Syzmk RMP product.
When I get a chance, I'll put up some code examples to demonstrate how
you might use it... At any rate it'll be going through some dog fooding
in the next month or so while I integrate it with the Syzmk product, so
you'll probably here a little more about in the future.
After a long hiatus from Blogging, I've returned... hopefully
with a vengence, but more likely with a small "vurrrrp" sound... like
hot air bubbling up through porridge.
Lets start off with a recap... Spectacles, testacles, wallet and all that jazz.
My name is Alex Henderson, 26 years young, living in Auckland, New
Zealand. I've been working on code since I was knee high, cut my
teeth in GW Basic while in primary school, and C++ a few years after
that... Now days I tend to spend my hours working in C# code, and my
spare time in either .Net and ruby or python when I feel like a change.
For the last year and a half I've been working for a start up company called Seismic Technologies which works in a rather ill-defined space, which I'll probably talk about in posts to come.
The main product I've been working on for Syzmk is the " Rich Media
Processor" - it's a message clearing house, geared towards taking
messages with rich content, transforming them, and then distributing
them... The messages might be files on a network share, emails, SMS or
MMS messages from a phone etc. It's all about rich content, so a
large part of the product deals with transforming the content before
furnishing it to line of business systems - we have been working with
companies like XSOL who use our product to use messages from mobile devices to extend their business processes outside of the host organisation.
Before I was working for the Seismic, I was travelling around Asia for
4 months... which was a lot of fun, I hope to visit europe next... Then
maybe Japan, Egypt and South America.
 Wednesday, April 05, 2006
With the first release of our COM interop SDK for the Syzmk Rich
Media Processor (yes, we have clients who want to integrate with the Rich Media Processor from legacy apps) suite coming out last week, I felt it necessary to put
some documentation together... internally we've been using FlexWiki
sporadically to document what's happening development-wise, iteration
feature sets etc. So It made sense to release our documentation on the
platform, and offer our clients that ability to augment the
documentation where appropriate.
Mixed Reactions
Wiki's get mixed reactions from a lot of developers - some love
them, others loathe them. I think it's generally related to two
problems:
- Lack of refactoring
- Ignoring beautification
A wiki is a living document, its structure should develop in-line
with your understanding on the topics - this includes revisiting old
topics, pulling content and moving it into new topics etc. If it
attempts to document a product then it must be aligned with releases,
otherwise you will forever be chasing your tale... If you can't get
commitment to this time allocation from management, just don't even
bother.
Stale documentation is often worse then no documentation.
Second to that, if the wiki is clunky, poorly formatted,
disorganised and generally lacking in beauty... Then it's not a
compelling resource for consumers - getting a wiki clean, well
organised and aligned with the rest of your web branding seems to go a
long way towards encouraging use.
Goodbye FlexWiki
We've been using FlexWiki partly through a loyalty to the .Net
platform (http://www.flexwiki.com/) and because internally it's what we
feel most comfortable with when it comes to have to modify or extend
products but the project has stalled for now and just doesn't reach
our needs for a commercially capable collaboration tool... (for
instance it doesn't support attachments) ... so I decided to go find a
new wiki... of which there are many... to many you might say!
WikiMatrix to the rescue
At which point I discovered wikimatrix: http://www.wikimatrix.org/ -
What a great little site! Especially there new Wiki Choice Wizard.. In
about 5 minutes I managed to narrow down what I was looking for, and
eventually selected TWiki (http://www.twiki.org/) as our prime
candidate (Confluence also looked very good, but the entry cost didn't
seem justifiable at this point).
Hello TWiki
TWiki does have some pitfalls for a Microsoft-focused house, mainly
that hosting it on windows is possible but going to cause tears before
bed time... luckily they have a debian vmware installation... so we
have avoided all the grief involved with windows, and gained a tasty
performance bonus over running it on windows (Because the project would
have required the cygwin tools & apache for windows... not
necessarily a high-performance combination)
The second best thing since sliced bread
VMWare server being free has to be probably the best thing since
sliced bread (Though I guess unbundling supersedes that for most IT
people in NZ of late) - as we're seeing a host of Linux based products
being released as pre-configured VM's - suitable as drop in "software
appliances" - with a lot less support problems then the normal process
of installing Linux onto a virtual machine and setting up the software
itself... and Often the memory foot print of the Linux distro + product
is half that of an empty windows 2003 standard install, before you've
deployed any applications onto it.
So within 15 minutes I had downloaded the 220mb virtual image,
booted it up and started editing wiki documents... It's not all quite
that easy though, you still need to get your hands dirty doing a little
shell based configuration if you want to securely host it on the web -
but it's all pretty painless especially if youve dabbled with Linux
in the past.
As for TWiki itself - so far it seems very very good, my only
dislike is some of the wiki-text conventions it uses, such as the
elaborate header mark-up... though FlexWiki was no better - why they
couldn't use the Confluence style mark-up of "h1. " through "h6." I'll
never know still the wysiwyg editor takes away most of the mark-up
pain for new users.
I've managed to avoid doing any Kriss Kross "wickety whack" references for the whole post too - be grateful ;o)
 Sunday, June 19, 2005
Well I’m back in New Zealand… after roughly 26 hours of flying and
stop overs (Hanoi -> Bangkok -> Sydney -> Auckland) I landed
back home… to be greeted by a selection of my family (Parents, Brother,
Nieces and grand parents no less) – which was all good.
My last few days in Hanoi were great – didn’t really do much sight
seeing... just enjoyed the good food and beverages on offer in Hanoi
and generally relaxed as well as I could – was lots of fun – and put me
in a good frame of mind to head home.
The trip out to the airport in Hanoi was also pretty cool – there’s
a funky bridge you have to travel over... wish I’d got some pictures of
it, pretty impressive.
And now that I’m home… well I’ve got the winter blues a little – to
come from 36 degrees and doing whatever I pleased all day long…
to 16 degrees, GST and income tax waiting in the wings and a town full
of generally unfriendly and distant people (in comparison to most parts
of Asia I visited).. It did/has left me in a bit of a daze – though
only temporary I’m sure.
Oh, and for the curious... If I was to list my favourite countries, it would be in this order:
- China
- Vietnam
- Laos
- Thailand
- Cambodia
Which isn't to say I hated any of them... but I did definitely loved
China just that little bit more then the others... if there was a place
I'd head back to for another visit (or to work...hmmm)... probably
Beijing or Hangzhou for a city.
Oh and as for some myths dispelled... I remember at first thinking
that woman were wearing masks perhaps because of fears of bird flu or
SARS... and I think Nikolai commented that it was probably because of
air pollution? Well we were both wrong, it was because the woman wanted
to hide from the sun and keep their faces as white as possible... they
even have shirts with extra long sleeves that button up/down (makeshift
gloves) and attached bonnets and face masks that look like giant
collars - just to hide from the sun when riding around on bikes.
Asian woman want to be white with big breasts (loads of adverts for
breast enlarging "cream" on the local TV)... Western woman want
tan's... cest la vie.
Another thing that puzzled me at first was the Cambodian kid I saw
with what looked like lash marks and scars on his back (who's family I
got a ride with over the Laos/Cambodia border)... It was actually
just a bad reaction to a big dose of tiger balm "stripes" - which they
normally apply when someone has a dose of the flu - saw loads of people
like this in Vietnam and Cambodia, that and people covered in lots of
black/purple round spots where they've been using vacuum "therapy" to
suck the "poisons" out of their blood... fun stuff.
Guess my next blog post will probably be a technical one – should make for a change!
 Saturday, June 11, 2005
Well I survived the 4 hour ride in Ninh Binh... it's a pretty flat town :) so it's not exactly taxing... though "Buck" (Clint, but we call him buck.. as he's a respected elder) did somehow cause his back tire to explode...
At any rate, after Ninh Binh I headed out to halong bay... went out overnight on a "chinese junk" like ship... which is pretty damn slow... hardly surprising for a 60 foot 3 story boat that only has a 4 litre nissan diesel motor pushing it along - Sadly it was overcast all day, so my pictures probably dont do it credit at all.. but this place is stunningly beautiful (and even hauntingly so when it's raining)... basically it's Yangshou/Guilin in China, but reproduced in the middle of the ocean - i.e. thousands of limestone peaks of various sizes that are amazingly steep and jagged.
After going for a bit of a swim in the sea.. and a kayak around some islands (even went through a cave and popped out in a completely enclosed lagoon in the middle of an island... stunning).. oh and visiting "surprising" cave.. which is surprising, in that ships ram each other for a chance to unload passengers on the island (bloody funny to watch) .. and that the cave from the outside looks "tasteful" - yet inside it's like some kind of really repetative disneyland.. coloured lights.. the odd sound effect... oh la la!
That evening I got myself a tad laquered... wine.. beer.. "hanoi" vodka.. and even some scotch.. needless to say it was an amusing evening.. and ended up spending a good four hours cloud watching with Helen out on deck and discussing the why's and where for's of being "barren" *snigger*... It's funny that because you generally bump into people with very diverse backgrounds and interests that inevitably discussions always end up going back to "people" and "relationships" as opposed to things - which, though it passes the time, slowly liquifies my brain... I can't wait to get back into some coding.
The following day we departed from Halong bay and headed up to Hanoi... ye olde capital of Vietnam - which is where I am now (sitting in the old quarter thinking how I really need some bia hoi and a shower).. for the ummm... 2nd day?
At any rate - I've been binging on western "treats" for the last 2 days... Tastey bbq ribs at Al'frescos last night... tastey lunch at Koto's (Koto stands for Know one, teach one... which is a restaurant started by an australian dude who trains street kids).. Halida beer - which only seems available up here in the north - and tastes pretty good... and I even sat down and watched a DVD this afternoon (the life and death of peter sellers... not that bad actually) while eating a take away "caramel cream" and some "tizzarisu" from the bakery down the street.. (poorly spelt tirramisu I suspect it was, damn tasty).
All in all, hanoi is treating me pretty damn well.. though being overcast here seems to make absoloutely no difference to this sodding heat and the humidity is sky high - so I just spend all day with my shirt soaking wet with sweat... I hope it's bloody miserable and freezing cold when I get home - that first kiss of cool eye should be brilliant!
On the cultural side of things... I've been to see Uncle Ho this morning.. so I can scratch another dead preserved communist/socialist leaders body of the list... it's actually pretty good, I think the setup and surrounding buildings and museum are a lot "nicer" then the tacky shit they try to sell as you depart from chairman Mao's mousaleum.. that probably only leaves Lenin? Unless I've forgotten someone else.
At any rate, couple more days and I'll be flying home.. for the curious I'm expecting to touch down at around 12:30pm on the 16th of June... And I figure that friday I'll probably head out for some drinks or a meal somewhere if anyone in the Auckland region is keen.
Oh and tomorrow night in Hanoi, the Culi Cafe is opening there downstairs italian cafe... and it's free beer and wine for all... if you can make it, I'll see you there!
© Copyright 2009 Alex Henderson
Theme design by Bryan Bell
newtelligence dasBlog 1.9.6264.0  | Page rendered at Tuesday, January 06, 2009 11:58:13 AM (New Zealand Daylight Time, UTC+13:00)
|
Search
FeedCount
Tags...
Who am I?

|
Alex Henderson
Auckland, New Zealand
Managing Director at Dev|Defined Limited
"Self Confessed Coding Junky for 15 years"
|
 |
| |
| Mobile: |
+64-21-402-969 |
| Email: |
bittercoder 'at' gmail 'dot' com |
| MSN: |
bittercoder_nz@hotmail |
| Skype: |
alex.devdefined |
Navigation
On this page....
Blogs I read by New Zealanders...
|