<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Available Imagination]]></title>
  <link href="http://availableimagination.com/atom.xml" rel="self"/>
  <link href="http://availableimagination.com/"/>
  <updated>2012-02-21T23:47:03+00:00</updated>
  <id>http://availableimagination.com/</id>
  <author>
    <name><![CDATA[Donovan Hide]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Gyms Near Me]]></title>
    <link href="http://availableimagination.com/gyms-near-me/"/>
    <updated>2012-02-21T22:30:00+00:00</updated>
    <id>http://availableimagination.com/gyms-near-me</id>
    <content type="html"><![CDATA[<p>I&#8217;ve been very busy working on <a href="http://superfastmatch.org/">Superfastmatch</a>, but I wanted to spend a day or two trying out a few ideas with the <a href="https://developers.google.com/fusiontables/">Fusion Tables API</a> and static hosting on <a href="http://code.google.com/appengine/docs/python/gettingstarted/staticfiles.html">App Engine</a>. One of the interesting things with App Engine is that you get 1GB a day of bandwidth for free. If you use static files, then no CPU cost is incurred, effectively giving you a high performance CDN for zero pence!</p>

<p><a href="http://www.gymsnear.com"><img class="left" src="http://availableimagination.com/images/gymsnear.jpg" width="320" height="175" title="Gyms Near Me" alt="Gyms Near Me"></a>
Fusion tables are intriguing because they offer <a href="https://developers.google.com/fusiontables/docs/developers_reference">spatial query processing</a> and very thorough Google Maps integration. What this means is that you can completely avoid setting up any database infrastructure such as <a href="http://postgis.refractions.net/">PostGIS</a> and any tile generation services like <a href="http://tilestache.org/">Tilestache</a>.</p>

<p>I employed these two services to come up with a simple app called <a href="http://www.gymsnear.com">Gyms Near Me</a> which does what it says on the tin! It uses Google Maps with a <a href="http://code.google.com/apis/maps/documentation/javascript/reference.html#FusionTablesLayer">Fusion Tables Layer</a> to show colour-coded pins for all the gyms in your vicinity. When you select a gym, a JSONP call finds the five nearest gyms by ordering by ST_DISTANCE from the selected latitude/longitude with a LIMIT of 5. The really cool thing about Fusion Tables Layers is that they are delivered as PNG tiles which gives the potential to a have huge number of points on a map, avoiding the issues you might encounter if you were creating individual markers via javascript.</p>

<p>The app is now live, so I&#8217;ll soon see if it gets picked up for any Google search keywords. Looking at autocomplete it seems like <a href="http://www.google.co.uk/search?&amp;q=gyms+near+me">Gyms Near Me</a> is the top term so maybe it will get picked up! In the future I might also look at feeding in gyms for global locations and saving map positions like <a href="http://www.gymsnear.com/london/">Gyms in London</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Unordered map with custom structures]]></title>
    <link href="http://availableimagination.com/unordered-map-with-custom-structures/"/>
    <updated>2011-11-06T18:27:00+00:00</updated>
    <id>http://availableimagination.com/unordered-map-with-custom-structures</id>
    <content type="html"><![CDATA[<p>I encountered the problem of trying to put custom data structures into the key of an unordered map and found different answers all over the Internet. The same question came up on the sparsehash <a href="http://groups.google.com/group/google-sparsehash/browse_frm/thread/891fd35c00363ac1">mailing list</a> so I thought I&#8217;d put an example up here:</p>

<div><script src='https://gist.github.com/1343184.js?file=vector_map.cpp'></script>
<noscript><pre><code>#include &lt;cstdlib&gt;
#include &lt;iostream&gt;
#include &lt;google/dense_hash_map&gt;

using google::dense_hash_map; 
using namespace std;

struct Vector3D{
  uint32_t x;
  uint32_t y;
  uint32_t z;

  Vector3D(const uint32_t x,const uint32_t y,const uint32_t z):
  x(x),y(y),z(z)
  {}

  Vector3D():
  x(0),y(0),z(0)
  {}
};

typedef struct{
  inline size_t operator() (const Vector3D&amp; v) const {
    return (v.x*73856093)^(v.y*19349663)^(v.z*83492791);
  }
} Vector3DHash;

typedef struct{
  inline bool operator() (const Vector3D&amp; lhs, const Vector3D &amp;rhs) const { 
    return (lhs.x==rhs.x)&amp;&amp;(lhs.y==rhs.y)&amp;&amp;(lhs.z==rhs.z);
  }
} Vector3DEq;

typedef dense_hash_map&lt;Vector3D,uint32_t,Vector3DHash,Vector3DEq&gt; vector_map_t;

int main(int argc, char** argv) {
  const uint32_t MAX_DISTANCE = 1000;
  const size_t LOOP_COUNT = 100000;
  vector_map_t vectors;
  
  // This assumes a vector with x:0 y:0 z:0 will never exist
  // If this is not true use tr1/unordered_map !!!
  vectors.set_empty_key(Vector3D());
  
  // Fill with some random vectors and keys
  for(size_t i=0;i&lt;LOOP_COUNT;i++){
    Vector3D v(rand()%MAX_DISTANCE+1,rand()%MAX_DISTANCE+1,rand()%MAX_DISTANCE+1);
    vectors[v]=rand();
  }
  
  // Display whole map
  for(vector_map_t::const_iterator it=vectors.begin(),ite=vectors.end();it!=ite;++it){
    cout &lt;&lt; &quot;Vector with x: &quot; &lt;&lt; it-&gt;first.x &lt;&lt;&quot; y: &quot; &lt;&lt; it-&gt;first.y &lt;&lt; &quot; z: &quot; &lt;&lt; it-&gt;first.z &lt;&lt; &quot; has value: &quot; &lt;&lt; it-&gt;second &lt;&lt; endl;
  }
  
  // Do some random lookups
  for(size_t i=0;i&lt;LOOP_COUNT;i++){
    Vector3D v(rand()%MAX_DISTANCE+1,rand()%MAX_DISTANCE+1,rand()%MAX_DISTANCE+1);
    vector_map_t::const_iterator it=vectors.find(v);
    if (it!=vectors.end()){
      cout &lt;&lt; &quot;Found vector with x: &quot; &lt;&lt; it-&gt;first.x &lt;&lt;&quot; y: &quot; &lt;&lt; it-&gt;first.y &lt;&lt; &quot; z: &quot; &lt;&lt; it-&gt;first.z &lt;&lt; &quot; value: &quot; &lt;&lt; it-&gt;second &lt;&lt; endl;
    }
  }
  return 0;
}
</code></pre></noscript></div>


<p>The trick is to define both a hash and an equality function for the custom data structure. The prime numbers in the 3D vector hash function come from this <a href="http://www.beosil.com/download/CollisionDetectionHashing_VMV03.pdf">paper</a>. The &#8220;correct&#8221; hash function depends a lot on the distribution of the keys and only real world benchmarking will give a satisfactory answer as to what works best for your data.</p>

<p>The output of the above code would be something like:</p>

<div><script src='https://gist.github.com/1343184.js?file=output'></script>
<noscript><pre><code>$g++ vector_map.cpp -o vector_test &amp;&amp; ./vector_test
Vector with x: 645 y: 413 z: 958 has value: 1312704908
Vector with x: 496 y: 358 z: 749 has value: 1988979514
Vector with x: 223 y: 868 z: 203 has value: 141221503
Vector with x: 345 y: 350 z: 869 has value: 1678149073
Vector with x: 565 y: 366 z: 722 has value: 1934444366
Vector with x: 934 y: 419 z: 619 has value: 560261625
Vector with x: 426 y: 92 z: 351 has value: 427818382
Vector with x: 24 y: 263 z: 407 has value: 760253072
...
...
...
Vector with x: 124 y: 98 z: 792 has value: 1145850991
Vector with x: 907 y: 710 z: 889 has value: 765247744
Vector with x: 779 y: 248 z: 943 has value: 976951297
Vector with x: 917 y: 929 z: 736 has value: 112463024
Found vector with x: 744 y: 492 z: 624 value: 1436855325
Found vector with x: 587 y: 110 z: 825 value: 24739836
Found vector with x: 707 y: 356 z: 243 value: 1515119730
Found vector with x: 610 y: 194 z: 331 value: 19997493
Found vector with x: 693 y: 59 z: 907 value: 502595634
Found vector with x: 57 y: 128 z: 923 value: 100460565
Found vector with x: 15 y: 512 z: 879 value: 248460847
Found vector with x: 256 y: 434 z: 859 value: 313975801
Found vector with x: 388 y: 42 z: 542 value: 473907356
Found vector with x: 409 y: 822 z: 963 value: 100666490
</code></pre></noscript></div>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Developer Diary]]></title>
    <link href="http://availableimagination.com/superfastmatch-developer-diary/"/>
    <updated>2011-09-10T23:43:00+01:00</updated>
    <id>http://availableimagination.com/superfastmatch-developer-diary</id>
    <content type="html"><![CDATA[<p>SuperFastMatch is a project which began life as a piece of research and
development in the production of
<a href="http://churnalism.com/">Churnalism.com</a> in 2010/2011 for the <a href="http://mediastandardstrust.org/">Media Standards Trust</a>. A means was
required of comparing a given text with over 3 million news articles in
the <a href="http://journalisted.com/">Journalisted.com</a> archive. The idea was
to find the articles which had the longest sections of common text and
to then rank them according to their respective percentages of reuse.</p>

<p>Initially, we looked at existing search engines like
<a href="http://xapian.org">Xapian</a> and <a href="http://lucene.apache.org/">Lucene</a> and
although being very effective at finding articles containing the same
words, they weren&#8217;t particulary good at finding the articles with the
longest common strings. More info on this can be found
<a href="http://mediastandardstrust.org/blog/the-technology-driving-churnalism-com/">here</a>.</p>

<p>Besides spotting <a href="http://en.wikipedia.org/wiki/Churnalism">churnalism</a>,
the software seemed to have other potential uses and the <a href="http://sunlightfoundation.com/">Sunlight
Foundation</a> believes it could be applied
to spotting duplicated federal law. To facilitate this application they
have generously offered to fund the open sourcing of this software, and
the results should hopefully be soon tested against the <a href="http://openstates.sunlightlabs.com/">OpenStates</a> project. I&#8217;d like to thank Martin Moore, Ben Campbell, Tom Lee and everyone else at Sunlight for the opportunity to work on this great project!</p>

<h1>Week 1</h1>

<p>This is my first attempt at a truly open-source project so I&#8217;ve had a
lot to learn about making software accessible by more than just the
development team I am working with. SuperFastMatch originally started as
the algorithm, developed over many sleepless nights, for comparing press
releases with newspaper articles used by <a href="http://churnalism.com">Churnalism.com</a>. This was a
single use-case, but as the site became known to the public, other
use-cases became apparent. One is to track legislation for lobbyist
influence. Others might include tracking plagiarism in fiction or making
sure academic texts have correct citations.</p>

<p>The point is that when more than one use-case comes up, a piece of code
needs to develop into a framework which is easy to understand, is well
documented and is easily integrated and installable in concert with
other software. Seeing as the majority of the existing code is written
in <a href="http://python.org">Python</a> it made sense to look at how some other Python projects
made use of existing infrastructure to meet these ends. I examined
<a href="http://github.com/ask/django-celery">Celery</a>, a distributed job engine and tracker, as I was familiar with
it from previous work, and saw how it made use of tools to assist its
open source development. Below are some ideas and tools that I borrowed
from it:</p>

<ul>
<li><p><a href="http://github.com">Github</a> has become the de facto platform for sharing and
distributing code. It&#8217;s free for open source projects and is built
on top of <a href="http://git-scm.com/">git</a>, which has many advantages over previous
generations of source code control software. It also offers static
file hosting, from where you are probably reading this
documentation!</p></li>
<li><p><a href="http://pypi.python.org/pypi">Pypi</a> is a centralised index of Python packages that allows for
the versioning and sharing of Python software without the need to
remember lots of urls and is reliable enough to be referred to in
bootstrap scripts.</p></li>
<li><p><a href="http://sphinx.pocoo.org/">Sphinx</a> is a documentation generator that works well with Python
packages as well as C++ (and hopefully Lua!). This page and the rest
of the docs are written in <a href="http://docutils.sourceforge.net/rst.html">reStructured Text</a> and then passed
throught a batch process which converts them into HTML, after which
they are uploaded to the static Github hosting.</p></li>
<li><p><a href="http://paver.github.com/paver/">Paver</a> is a combination of tools which allows for the scripting
in Python of many development workflows such as bootstrapping,
documentation generation, packaging and test execution. I&#8217;m used to
using <a href="http://fabfile.org/">Fabric</a> for deployment, and Paver seems to offer a similar
experience for development. It will be interesting to see if I
integrate some of the C++ build process into the <a href="https://github.com/mediastandardstrust/superfastmatch/blob/master/pavement.py">pavement.py</a>
file.</p></li>
<li><p><a href="http://pypi.python.org/pypi/virtualenv">VirtualEnv</a> is an essential tool for isolating Python packages
into an application-specific environment. This ensures you always
know which versions of software are present and can accurately
recreate this when you deploy to either a production or staging
server. It comes with <a href="http://www.pip-installer.org/">Pip</a> installed in the created environment
for easy integration with Pypi.</p></li>
<li><p><a href="http://www.djangoproject.com/">Django</a> is the platform on which <a href="http://churnalism.com">Churnalism.com</a> is built and
is widely used so it seemed like the natural choice for building an
example usage of SuperFastMatch.</p></li>
</ul>


<h1>Week 2</h1>

<p>Now that all the open source infrastructure is in place it&#8217;s time to
start learning a bit more about the use-case in hand, US Congress and
state legislation.</p>

<h2>Legislature</h2>

<p>The US Congress has two chambers, both elected, the House of
Representatives and the Senate. Both chambers can introduce bills and
the bill can take one of many paths through both chambers. The passage
of a bill through Congress appears to be quite undefined with a whole
series of possible routes and referrals being possible before an Act is
signed by the President.</p>

<p>The end result of acts of Congress is the <a href="http://www.gpo.gov/fdsys/browse/collectionUScode.action?collectionCode=USCODE">US Code</a> which is an up to
date record of all enrolled bills. States in the US are also capable of
passing their own local laws.</p>

<h2>Data Access</h2>

<p>The US has a well maintained <a href="http://www.gpo.gov/fdsys/browse/collection.action?collectionCode=BILLS">digital archive</a> of all House of
Representative Bills from 2004, and a more recent archive of Senate
Bills. The data is accessible in XML form which allows for metadata
extraction of Bill information and easy manipulation of the Bill text
itself, ideal for the purposes of this project. Text-only bills are
available from 1993 onwards.</p>

<h1>Week 3</h1>

<h2>Framework design</h2>

<p>The aim of the project is to design a reusable tool for bulk text
comparison and analysis. To succeed in becoming reusable, at least two
use-cases have to be considered and a clean, easy to understand
interface for the user has to be designed. <a href="http://www.djangoproject.com/">Django</a> offers many ways
of designing models for data storage, and this flexibility is useful -
but there can be a number of caveats that can obstruct progress further
down the line.</p>

<p><a href="http://docs.djangoproject.com/en/dev/topics/db/models/#model-inheritance">Model Inheritance</a> allows for the subclassing of a Model which itsef
permits further extension. This is an ideal pattern for different types
of Document. Say that you have Press Releases and News Articles, or
State Law and Congress Law, all with potentially similar content. When
you search, you might not know what to expect as results and would like
to search all Document types simultaneously. By defining a Document base
model, this is possible because it can be assumed that the necessary
content in it&#8217;s indexable form is present.</p>

<p>With Django, there is a choice of either abstract or multi-table
inheritance (and also proxy&#8230;). Multi-table inheritance results in an
extra table, while abstract inheritance just adds fields to the
subclasses&#8217; tables. The simplest choice is abstract inheritance and I
went for this. However, the disadvantage is that you cannot define a
ForeignKey to the abstract base class itself but the related clean
indexed content needs to be stored somewhere as a cache so that updates
can be detected. To solve this issue I turned to <a href="http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/">content types</a>,
which makes it possible to relate any model instance to any other model
instance, regardless of type. This means that the cleaned Content can be
related to any of Document&#8217;s subclasses. At this point it&#8217;s probably
worth looking at the <a href="https://github.com/mediastandardstrust/superfastmatch/blob/master/superfastmatch/django/models.py">model definition</a>.</p>

<h2>Faceting</h2>

<p>One of the limitations of the original Churnalism code is the inability
to search for news articles, only press releases. However, both document
types have very similar features, such as date published, an author, a
publisher and of course the content itself. Therefore it makes sense to
also be able to search for news articles with either a news article,
press release or other text as the input text. This would be useful for
journalists to check for plagiarism and is useful in lots of other
contexts.</p>

<p>The challenge is that the script that builds the search results needs a
limit on the number of results to return to make the data and server
load manageable. However, imagine searching for both news articles and
press releases with a limit of 20 results. It might be the case that 20
news articles have higher ranking than matching press releases. The
press releases might be a more interesting result though, so excluding
them could omit valuable data. The solution to this is <a href="http://en.wikipedia.org/wiki/Faceted_search">faceted
search</a> where extra data, in this case the document type is stored
along with the document id in the index. The number of results returned
is per document type, and therefore useful data should not be missed.
This has implications for total index disk space usage, but is a truly
useful addition to the capabilities of SuperFastMatch.</p>

<p>Other fields, such as published date, could be used as filter, but then
we are entering the territory of advanced search engines like <a href="http://xapian.org/">Xapian</a>
and <a href="http://lucene.apache.org/solr/">Solr</a> which are already good at that type of thing!</p>

<h1>Week 4</h1>

<h2>Kyoto Cabinet</h2>

<p>Storing and processing data is a challenging task with many, many
options! Often the performance characteristics and ceilings of a
platform only become apparent after a large amount of implementation for
that platform has occurred. These evaluations can take a lot of time and
definitely help form an opinion on which platform is good at a
particular task. SuperFastMatch works on the simple concept of storing
every hash of every window of text in a document with the associated
document id (and now document type). This is done for every document and
yields an inverted index of hashes to documents. Thus, for a search
document or text, hashing its windows allows for a fast search of
matching documents.</p>

<p>The storage requirement for this is very high - typically 5x the
original document size. Access speed is very important, given that a
search of a document n characters long requires (n-window_size)
lookups. Also index creation speed is vital. If it takes 2 days to index
1 days worth of news, Churnalism.com would be behind the current affairs
very quickly!</p>

<p>The obvious starting candidate for a platform is SQL, and I experimented
with Postgres, testing out such features as the <a href="http://www.postgresql.org/docs/current/static/intarray.html">intarray</a> data type
for storing document ids and <a href="http://www.postgresql.org/docs/current/static/ddl-partitioning.html">partitioned tables</a> as a means for bulk
loading daily data whilst maintaining insert speed. However, even with
24-bit hashing (ie. 16,777,216 possible hashes), lookup and insert
speeds proved to be poor.</p>

<p>The next candidate was the sexy new key value store on the block!
<a href="https://github.com/antirez/redis">Redis</a> has lots of nice features ideal for storing the index. High
speed inserts and the <a href="http://redis.io/commands#set">sets</a> command set, great for ensuring no
duplicate id is saved for a hash. However, again a performance ceiling
reared its skull-damaging surface! Redis operates great when the data
set fits totally in memory, but as soon as that limit is surpassed, the
paging virtual memory kicks in - but very slowly. The release notes and
commit history showed that this was a known issue, but it made Redis
impractical for use.</p>

<p>A lateral solution was to consider using <a href="http://hadoop.apache.org/">Hadoop</a> in the form of
<a href="http://aws.amazon.com/elasticmapreduce/">Elastic Map Reduce</a> as a way of solving the daily index creation
problem. It was interesting to stray into the realms of Java land (with
its verbosity quite overwhelming at times!). Issues found included the
need to code a simple CSVReader - not included in the vanilla
distribution. The difficulty of getting something out of Hadoop in
binary rather than text file form. The misleading and, in the end, very
expensive pricing of both the EC2 service and the S3 costs for
downloading the processed data to an external server. I can see that if
you are Yahoo and have 1000&#8217;s of servers, Hadoop is a great way to
distribute jobs across many machines. However, if you have a continuous
data processing task that could be run on one very powerful machine the
economics of it don&#8217;t quite make sense.</p>

<p>At this point, despair was near! A final gambit seemed to be the service
offered by the <a href="http://www.google.com">search giant</a> themselves. <a href="http://code.google.com/appengine/">App Engine</a> had a lot of
ticks in it&#8217;s favour. The datastore is capable of massive scaling with
no configuration required. API calls to the datastore are very
performant (and now can run in <a href="http://code.google.com/appengine/docs/python/datastore/async.html">parallel</a>). The <a href="http://code.google.com/appengine/docs/python/taskqueue/">task queue</a> is
fantastic at allowing extra instances to be pulled up as and when needed
for processing the index. All in all, Appengine was the preferred choice
and I had a great working prototype. The one major headache was the
billing cost for Datastore API writes. Because the data was incoming in
unsorted form, each hash for each document required an API write, which
added up to about £6,000 just to index 3.5 million news articles! This
meant any mistakes in indexing would surely kill the project&#8217;s budget. A
postscript to this might be that the recent addition of the shuffle and
reduce phases of the <a href="http://code.google.com/p/appengine-mapreduce/">map-reduce project</a> might make the insertion
costs considerably less. Also the recently <a href="http://www.youtube.com/watch?v=7B7FyU9wW8Y">announced</a> full-text
search API has a numeric data type that could be <em>misused</em> to simulate
the inverted index.</p>

<p>So after a very large amount of time spent evaluating performance, cost
and practical implementation it became clear that was a definite
advantage to investing in some serious hardware to negate the higher
than expected cost of high performance cloud infrastructure. A server
configured by Pete at <a href="http://www.mythic-beasts.com/">Mythic Beasts</a> with 64GB of RAM and an <a href="http://www.intel.com/design/flash/nand/mainstream/index.htm">Intel
X25-M</a> faciliated the speedy operation of the final solution that we
decided upon.</p>

<p>And that final solution was to use a combination of <a href="http://fallabs.com/kyotocabinet/">Kyoto Cabinet</a>
and <a href="http://fallabs.com/kyototycoon/">Kyoto Tycoon</a> written by the talented <a href="http://fallabs.com/mikio/profile.html">Mikio Hirabayashi</a> (now
gainfully employed by Google) who kindly incorporated some feature
requests to do with the bit length of <a href="http://code.google.com/p/smhasher/">Murmur hashing</a> exposed to Lua
and gave very useful implementation advice. The pros of Kyoto Cabinet
are numerous and include:</p>

<ul>
<li>Very fast insertion and lookup speed, whether accessing from disk or
memory.</li>
<li>High tunability of indexes in terms of memory usage and algorithms
employed in sorting of keys.</li>
<li>Embedded Lua scripts can be run in multithreaded HTTP aware server.</li>
<li>Designed to be used both as a toolkit and a framework for
development allowing tighter integration as bottlenecks are
encountered, ie.e the library and header files allow for everything
to be used in a custom C++ project if desired.</li>
<li>Great documentation.</li>
</ul>


<h2>Filtering Junk</h2>

<p>After examining the data for US Congress bills it has become clear that
this a far less heterogenous data set than that found with
Churnalism.com. For instance phrases like &#8220;is amended by adding at the
end the following&#8221; and &#8220;Notwithstanding any other provision of&#8221; appear
in nearly every bill. These phrases in themselves do not indicate
similarity with another bill, but they might if they are part of a
longer chunk. So how to ignore the stock phrases when they they are just
stock phrases, but include them when they are part of something more
unique?</p>

<p>A natural by-product of the index creation, especially as the corpora
becomes larger, is that for every window, or in fact hash, there is a
sequence of document ids and document types, which are themselves vital
for search, but when accumulated together the count per hash gives an
indication of the originality or cliché of that window. Say that this
sentence is present in both search text and a match candidate:</p>

<p>&#8220;The Tobacco Smoker&#8217;s compensation bill is amended by adding at the end
the following&#8221;</p>

<p>The last half of the sentence consists of very frequently occurring
windows, whilst the start is very likely less common. We want the whole
sentence to be given prominence in the fragment results. We can do this
by averaging the counts of each hash, perhaps with a high cut-off, say
100, for the high counts. This would allow us to filter out the very
common phrases, which would tend to score around 100. This is yet to be
implemented, but should be easy to achieve and is scheduled for version
0.4.</p>

<p>Another possible use of this sort of &#8220;heatmap&#8221; might be to visualise the
originality of texts, with common phrases coloured red perhaps and more
original phrases in a cooler tone!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Back to Blog with a Bang!]]></title>
    <link href="http://availableimagination.com/back-to-blog/"/>
    <updated>2011-08-11T14:22:00+01:00</updated>
    <id>http://availableimagination.com/back-to-blog</id>
    <content type="html"><![CDATA[<p><a href="http://www.flickr.com/photos/donch/6083774828/" title="DSC_0247.jpg by Donovan Hide, on Flickr"><img src="http://farm7.static.flickr.com/6078/6083774828_ee47c22c9b_b.jpg" width="1024" height="551" alt="DSC_0247.jpg"></a></p>

<p>Well, not for the first time, there has been somewhat of a gap in the continuity of posts on this blog. I could say sorry, but then I&#8217;d risk ending up <a href="http://sorry.coryarcangel.com/">here</a> as Jack has <a href="http://mottr.am/2010/09/15/sorry-i-havent-posted/">noted</a>.</p>

<p>There is a rites of passage in Web Programming, whereby you write your own blog software in whatever framework you are learning; you write a few posts and then stop because each new post has some CSS requirement or weird formatting that makes you give up. I did that.</p>

<p>I write code. I often read other people&#8217;s code. I&#8217;d like to share my code. <a href="http://stackoverflow.com">Stack Overflow</a> is good for this if you have a question, or know the solution to another person&#8217;s problem. But what if you have found a nice solution to a problem in your own code. Sharing code on the previous two incarnations of this blog was a pain. Moving posts between different blog platforms is a pain. Logging in to whatever website to make a post is a pain. Lots of pain!!!</p>

<p>Content is generally written in <a href="http://daringfireball.net/projects/markdown/">Markdown</a> at a point in time on a subject. <a href="https://github.com/mojombo/jekyll/wiki">Jekyll</a> aims to keep that simplicity and <a href="http://octopress.org/">Octopress</a> builds on that to make sharing code easy. So here goes with this (yet another) new framework. Hopefully the big advantage will be that all the content is now much easier to play with using text editors and grep!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Experian's rise in local council administration]]></title>
    <link href="http://availableimagination.com/experians-rise-local-council-administration/"/>
    <updated>2010-02-04T15:10:40+00:00</updated>
    <id>http://availableimagination.com/experians-rise-local-council-administration</id>
    <content type="html"><![CDATA[<p>I&#8217;ve had a recent experience with Liverpool City Council that has raised my awareness of the increasing role of the credit agency in the decisions made by local government officials. It has also highlighted the detachment and lack of accountability that a public-private-partnership run call centre affords these officials. The credit reference agency in question is <a href="http://www.experian.co.uk">Experian</a> and the product that they sell is called <a href="http://www.experian.co.uk/www/pages/what_we_offer/products/residency-checker.html">Residency Checker</a>. The PPP call centre is called <a href="http://www.liverpooldirectlimited.co.uk/">Liverpool Direct</a> and is 80% owned by <a href="http://www2.bt.com/static/i/media/pdf/liverpool_council_cs.pdf">BT</a>. The third party who brings an added bonus to the formula is <a href="http://www.royalmail.com">The Royal Mail</a>.</p>

<p>First, a chronology (personal details included for clarity!):</p>

<ul>
<li>I live with my New Zealand girlfriend in a flat in Liverpool City Centre.</li>
<li>We split up in August 2009 and she moves out from the flat by the end of that month.</li>
<li>In September 2009 I post this <a href="http://www.liverpool.gov.uk/Images/tcm21-25154.pdf">form</a> to the Revenue Services applying for the Single Occupancy Discount of 25%. I do not know the forwarding address of my girlfriend at this point - such is the nature of ended relationships!</li>
<li>In October 2009 I get the same form resent to me asking for the forwarding address. My ex-girlfriend now gives me this information. I post the form again.</li>
<li>I hear nothing for the next two months, so ring up Liverpool Direct in January 2010. They inform me that they sent a letter refusing the discount on the grounds that they cannot confirm my ex-girlfriends new address and <i>fiscal records</i> indicate that she still lives at this address. This letter, dated the 24th November 2009, never reached me.</li>
<li>I request that Experian explain how their data indicates that my ex-girlfriend still lives at my flat. They explain the concept of a <a href="http://www.experian.co.uk/consumer/faq/AR3.html#q1016">financial association</a>. On the 5th January 2009 I request that this information is removed as it is incorrect. On the 7th January 2009 I receive acknowledgment that this has taken place.</li>
<li>I appeal the decision in person at Dale Street&#8217;s One Stop Shop on the 12th January 2010 and inquire as to the nature of this <i>fiscal</i> information.</li>
<li>No reply. I phone Liverpool Direct and they inform me of another unreceived letter, dated 20th January 2010. Again, another refusal, saying that my ex is still in occupation, according to an unnamed &#8220;Credit Reference Agency&#8221;. I request copies of these letters. Mysteriously, they all turn up at the start of Februray 2010.</li>
<li>On the 4th February 2010, I phone Experian again and discover the information has not been removed, as they had previously said had been the case. I request that the information is removed again. It turns out the specific information relates to a joint personal loan application in April 2009 (that was turned down) to help my ex-girlfriend consolidate her considerable debt. Interestingly, the association is based around the fact that we lived together in London before we lived together in Liverpool. Experian removed the Liverpool association, but not the London association. A key fact in this horribly bungled and failed process.</li>
</ul>


<p>And so we go on &#8230;.</p>

<p>Kafka would have been proud of the communication cycle that occurs with Liverpool Direct&#8217;s council tax department. You phone the call centre and supply your reference number. You give the operator information about your case. They make a &#8220;service request&#8221;  that goes to the revenues service in a separate building. A randomly-selected revenues officer writes a vague reply without details of which Credit Reference Agency is used and what alternative evidence can be accepted. This reply is sent in the post. The Royal Mail have a deal with someone, whereby they don&#8217;t deliver the letter. You phone Liverpool Direct, they make a &#8220;service request&#8221; for letters to be resent. The letter does not help explain what next steps need to be taken.</p>

<p>Revenues Officers refuse to take phone calls explaining and justifying their decisions.</p>

<p>The fact that needs to be up for debate is why the council can use a failed personal loan application in April 2009 as proof that two people share a flat between September 2009 and February 2010. Also, why do the council even have access to this information? The answer to that question seems to be a market opportunity spotted by Experian to reuse credit data as something that can be assumed to be the truth of where people reside at certain points in time. My case study is an example of where Experian&#8217;s data can be proved to be incorrect. There seems to be no indication on the Liverpool City Council website or in any of their communications on how to correct the wrong data. For the record, the request form is <a href="http://www.uk.experian.com/contactforms/consumer_onlinedisassociation.html">here</a>.</p>

<p>Another fact up for debate is why council officials can have a one-way dialogue with borough residents. The answer to this is the help desk outsourcing of Liverpool Direct. In exceptional circumstances, process must be overridden and direct conversation permitted.</p>

<p>How could this whole problem have been avoided? Very simply and cheaply. A letter could have been sent to the forwarding address I provided, asking for confirmation of residence. This was not done. Shocking.</p>

<p>Two questions for MP&#8217;s and councillors. How much is being spent on the Residency Checker licensing? How many single occupancy discount requests have been wrongly declined against based on bad data from Experian?</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Archimedes memories]]></title>
    <link href="http://availableimagination.com/archimedes/"/>
    <updated>2009-06-14T02:34:04+01:00</updated>
    <id>http://availableimagination.com/archimedes</id>
    <content type="html"><![CDATA[<p>Almost bought tears to my eyes &#8230;</p>

<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/cu7nAMLnFao&hl=en&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/cu7nAMLnFao&hl=en&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object>


<p>Brings back memories of trying to do animation in Render Bender and writing parallax star fields in Assembler!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Linq To SQL Wish List]]></title>
    <link href="http://availableimagination.com/linq-sql-wish-list/"/>
    <updated>2008-12-23T22:44:13+00:00</updated>
    <id>http://availableimagination.com/linq-sql-wish-list</id>
    <content type="html"><![CDATA[<p>I really like using Linq, it is an elegant query language that can be applied to in-memory objects as well as translated into SQL dialects behind the scenes. What this gives is a common means of expressing filters, orderings, groupings and aggregations throughout your code. I have battled with massive reports using the CROSS JOIN with LEFT OUTER JOIN pattern in SQL, passing stacks of parameters into the stored procedure to get the report results out. Admittedly, it could be tweaked to make it run pretty fast, but it was sheer hell to maintain.</p>

<p>Linq allows queries to be composed at runtime and built to arbitrary levels of complexity, as needed by the consumer of the code. This is a win situation compared to versioning strings of SQL that are not type-checked and prone to error. However, if we go down the Linq route we also need an ORM solution to go with it. Currently there are four choices:</p>

<ul>
<li>Subsonic</li>
<li>Linq to SQL</li>
<li>The Entity Framework V1</li>
<li>Nhibernate with Linq to Nhibernate</li>
</ul>


<p>I like Linq to SQL because it is lightweight, the documentation is fairly complete and I&#8217;ve invested time learning it. It has some missing features, though, and now Microsoft are deprecating it in favour of the Entity Framework V2.</p>

<p>Please don&#8217;t do this! Improve what is already a good product with some simple additions:</p>

<ul>
<li>Add a many-to-many association</li>
<li>Add the two other patterns of inheritance: <a href="http://martinfowler.com/eaaCatalog/classTableInheritance.html">Class Table Inheritance</a> and <a href="http://martinfowler.com/eaaCatalog/concreteTableInheritance.html">Concrete Class Table Inheritance</a></li>
<li>Improve the CreateDatabase() method and extend the MetaModel to include database default values (newid() for example) and a PostCreateDatabase hook for inserting any custom SQL</li>
<li>Add a versioning feature to the mapping source which can deal with migrations from one version to another.
Currently Linq to Sql works well for DB-first design, as long as you automate the process as follows:</li>
<li>Introspect the db with sqlmetal to create a .dbml file</li>
<li>Patch the dbml file with changes using MSBuild Community Tasks for instance</li>
<li>Run the second half of the sqlmetal process to generate the code</li>
</ul>


<p>This means that you don&#8217;t end up with nice clean POCO code, however. I would prefer, in a DDD way, to start with some POCO&#8217;s and then create mappings using a fluent interface, and then have some SQL DDL&#8217;s created. Maybe this is possible now. I just don&#8217;t want to plough through the horrid NHibernate documentation and the EF looks like a mess that won&#8217;t be sorted out until VS 2010 hits the streets. Subsonic is an option but Rob Conery seems awfully busy at the moment!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Thurstaston Day Trip]]></title>
    <link href="http://availableimagination.com/thurstaston-day-trip/"/>
    <updated>2008-09-27T21:43:19+01:00</updated>
    <id>http://availableimagination.com/thurstaston-day-trip</id>
    <content type="html"><![CDATA[<p>Had fun taking photographs around the church where the owner of the White Star Line ended up being buried.</p>

<p><a href="http://www.flickr.com/photos/donch/2895619401/" title="Gothic Angel by Donovan Hide, on Flickr"><img src="http://farm4.static.flickr.com/3125/2895619401_c1bf629f97.jpg" alt="Gothic Angel" /></a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Other Worldly Transport]]></title>
    <link href="http://availableimagination.com/other-worldly-transport/"/>
    <updated>2008-09-27T12:22:00+01:00</updated>
    <id>http://availableimagination.com/other-worldly-transport</id>
    <content type="html"><![CDATA[<p>There&#8217;s something unreal about the way this Russian Sea Plane floats just above the water. Like something from a Philip K Dick novel. That would be some way to cross an ocean!</p>

<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/NpGacOmSeHc&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="http://www.youtube.com/v/NpGacOmSeHc&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed></object>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Fun with Libyan Domain Names]]></title>
    <link href="http://availableimagination.com/fun-with-libyan-domain-names/"/>
    <updated>2008-08-24T02:22:10+01:00</updated>
    <id>http://availableimagination.com/fun-with-libyan-domain-names</id>
    <content type="html"><![CDATA[<p>Heard <a href="http://www.torchbox.com/blog/libyan_domain_names.html">here</a> that domains ending in .ly where available from the <a href="http://nic.ly">Libyan Registrar</a> so thought I might investigate. <a href="http://libyanspider.com/lydomains.php">Libyan Spider</a> seemed like the most respectable agent, although at $149.50/year, they are not cheap.</p>

<p>It was quite a lot of fun searching all the short words ending in &#8216;ly&#8217;, and believe me, there are quite a few left! I ended up going for:</p>

<ul>
<li><strong><a href="http://rap.id.ly">rap.id.ly</a></strong></li>
<li><strong><a href="http://luc.id.ly">luc.id.ly</a></strong></li>
<li><strong><a href="http://viv.id.ly">viv.id.ly</a></strong></li>
</ul>


<p>and</p>

<ul>
<li><strong><a href="http://app.ly">app.ly</a></strong></li>
</ul>


<p>If you are interested in lightening me of one of these domains, then feel free to comment!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[PopcornHour Review]]></title>
    <link href="http://availableimagination.com/popcornhour-review.markdown/"/>
    <updated>2008-08-23T16:24:13+01:00</updated>
    <id>http://availableimagination.com/popcornhour-review.markdown</id>
    <content type="html"><![CDATA[<p>I think it would be fair to say that <a href="http://www.bittorrent.org/beps/bep_0003.html">BitTorrent</a> has already begun to radically change the viewing and spending habits of the connected world. I know how much I hate watching adverts and having my attention disrupted by non-public service channels. I also dislike having my viewing schedule dictated by television station controllers. Broadcasters are starting to awaken to this, and the BBC seems to be leading the way with its <a href="http://www.bbc.co.uk/iplayer/">iPlayer</a> offering. However, the content available on this conduit isn&#8217;t exactly premium viewing.</p>

<p>So, along comes an interesting company by the name of <a href="http://www.syabas.com">Syabas</a> with a product that will potentially change the way you enjoy your living room. The <a href="http://www.popcornhour.com">PopcornHour</a> is a small box, maybe twice the size of an external hard drive. It gets delivered  from China for about £100, but comes without an internal hard drive. The model I received at the end of last year accepts an old-fashioned PATA hard drive, whilst the newer A110 model takes the better-performing SATA types. You don&#8217;t need to get a hard drive if you have some fancy Network Attached Storage on your home network, but I don&#8217;t think you get all the extra applications without the internal drive.</p>

<p>I went for a 500GB Western Digital, which is excellent in terms of quantity of media that it can store. Unfortunately a bug exists in combination with that drive, so don&#8217;t buy it! Details <a href="http://www.networkedmediatank.com/showthread.php?tid=2716&amp;highlight=repeating">here</a>. A better buy might be one of <a href="http://www.aria.co.uk/Products/Components/Hard+Drives/IDE/Seagate+500GB+IDE+7200rpm+8MB+?productId=30265">these</a>. Don&#8217;t worry if you do pair the errant drive with the PopcornHour, there is a preference to stop the remote from repeating itself, which is annoying, but does solve the problem.</p>

<p>So, what does it do? Everything!!! You can watch virtually any format of media on it, from .mkv to quicktimes, from DIVX avi&#8217;s to DVD backups. You name it, it seems to play it. It even has an interface to watch <a href="www.youtube.com">YouTube</a> and other online video sources. It plugs into any television via SCART or HDMI, so it works nicely with the new LCD high definition screens starting to creep into our lives. Perhaps the biggest boon is that it has a scheduled BitTorrent daemon running, so you can queue up your .torrent files and let it happily chug through them overnight, without having to leave your laptop turned on. What would be nice is an unrar utility built in, to unpack the compressed downloads that are so prevalent.</p>

<p>The really cool bit is that Syabas keep adding features. Every month or two a new firmware update is released, which packs even more utility and bugfixes into the small box beneath your telly! The latest <a href="http://www.popcornhour.com/download/A100/01-17-080812-15-POP-402.html">update</a> includes the <a href="http://www.transmissionbt.com">Transmission</a> web client for visual pleasure. However, it does seem to be a bit slow at the moment, compared to the previous, but still present, <a href="http://www.murmeldjur.se/btpd/">BTPD</a>. I&#8217;m sure this will be fixed in the next update though!</p>

<p>So here are some pros and cons:</p>

<p><strong>PROS</strong></p>

<ul>
<li>Plays everything you can throw at it</li>
<li>Relatively cheap</li>
<li>Commitment to future updates from Syabas</li>
<li>Makes BitTorrent a pleasure rather than a file download nightmare</li>
<li>You&#8217;ve got one before any of your friends!</li>
</ul>


<p><strong>CONS</strong></p>

<ul>
<li>No wireless networking built in</li>
<li>Interface is a bit cludgy</li>
<li>Requires a bit of technical know-how to get going</li>
<li>Remote is painful with my chosen hard drive</li>
<li>USB ports at the front of the box</li>
</ul>


<p>In conclusion, get one!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[New Blog]]></title>
    <link href="http://availableimagination.com/new-blog/"/>
    <updated>2008-08-21T17:02:52+01:00</updated>
    <id>http://availableimagination.com/new-blog</id>
    <content type="html"><![CDATA[<p>For me it has been a bit of an off and on relationship with the world of blogging. I really enjoy writing, but find it hard to think of things that I want to share with the world! <a href="http://submitresponse.co.uk/weblog/">Jack</a> has an excellent blog, full of journalistic content presented in a minimalist style. His writing is the first thing I check for when using <a href="http://www.google.co.uk/reader">Google Reader</a>. One of his <a href="http://submitresponse.co.uk/weblog/2008/06/16/todays-links-160608/">posts</a> eventually led me to a <strong>really</strong> minimal <a href="http://www.ifany.org">blog</a> which stuck out for it&#8217;s elegant layout, intelligent navigation and a complete absence of crud.</p>

<p>Full credit must go to Jonas for releasing his WordPress <a href="http://www.ifany.org/2008/theme/">theme</a> to the world under a GPL license. I was using <a href="http://www.dasblog.info/">DasBlog</a> which had more than a whiff of ASP.NET to it, but served a purpose when I had a <a href="http://www.discountasp.net/">DiscountASP.NET</a> server account without any cheap SQL access. Now, with my pleasant 1 &amp; 1 hosted server I&#8217;ve looked towards <a href="http://www.djangoproject.com">Django</a> to provide coding pleasure and here is the result! The code is inspired by, but not lifted from <a href="http://code.google.com/p/django-basic-apps/">Django Basic Apps</a> and the templates and styling are <strong>heavily</strong> influenced by <a href="http://www.ifany.org">Jonas&#8217;</a> html and css.</p>

<p>I realise that both those bits of work are released under different licenses which means I should distribute the derived code freely. If anyone is interested, then I would be happy to put together a Google Code project to share it, although I cannot vouch for the quality of the code!!</p>

<p>Anyway, I&#8217;m back!</p>

<p>P.S. As soon as Sophie gets back from holiday I should have a nice brand spanking new logo!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Camouflage]]></title>
    <link href="http://availableimagination.com/camouflage/"/>
    <updated>2008-08-20T16:33:44+01:00</updated>
    <id>http://availableimagination.com/camouflage</id>
    <content type="html"><![CDATA[<p>A short film I helped work on while at <a href="http://www.sherbet.co.uk">Sherbet</a>. I really enjoyed that period of work and look back with fondness at what was done there:</p>

<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/RG_xh-RZLKA&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="http://www.youtube.com/v/RG_xh-RZLKA&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed></object>


<p>Full film <a href="http://www.animateprojects.org/films/by_date/films_2001/camo">here</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Student Videos]]></title>
    <link href="http://availableimagination.com/student-videos/"/>
    <updated>2008-08-20T16:21:02+01:00</updated>
    <id>http://availableimagination.com/student-videos</id>
    <content type="html"><![CDATA[<p>Some short videos that we did at Sunderland University. Embarrassing but funny!</p>

<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/MRHh97XlsGA&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="http://www.youtube.com/v/MRHh97XlsGA&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed></object>




<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/pT-oGBEJUz4&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="http://www.youtube.com/v/pT-oGBEJUz4&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed></object>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Seasonal Rants are the best]]></title>
    <link href="http://availableimagination.com/seasonal-rants-are-best/"/>
    <updated>2007-12-21T21:40:41+00:00</updated>
    <id>http://availableimagination.com/seasonal-rants-are-best</id>
    <content type="html"><![CDATA[<p>Jack journalistically <a href="http://submitresponse.co.uk/weblog/2007/12/21/city-link/">describes</a> a protracted interaction with our wonderful friends at City-Link!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Virgin Trains - The Horror Worsens]]></title>
    <link href="http://availableimagination.com/virgin-trains-horror-worsens/"/>
    <updated>2007-12-21T01:01:04+00:00</updated>
    <id>http://availableimagination.com/virgin-trains-horror-worsens</id>
    <content type="html"><![CDATA[<p>It&#8217;s Christmas, I want to go home to see my family. The media points out that there are terrible timetable delays to look forward to. I fear the &#34;turn up at Euston and not get a seat, or even get on the train, because of overcrowding&#34; scenario. I therefore try and make a seat reservation at <a href="http://www.virgintrains.com">www.virgintrains.com</a> for travel tomorrow. I see things have changed, a new website design with a new fare matrix.</p>

<p>Bottom line: it used to be possible to buy a saver return on the website which meant as long as you picked the outward day of travel, you could return on any subsequent day within a month of the outward journey date. Things have changed &#8230;</p>

<p>A Half Saver Return is now offered, which basically means that you are pinned down to a return date too. The added benefit of a £5 penalty to change this date comes for free. If anyone from Virgin ever reads this, then let me tell you: <strong>YOU ARE #£*&amp;!</strong></p>

<p>I can understand fare increases, over-inflated as they are, but the constant reduction in ease of travel is a disgrace. The train system of this country is not RyanAir; it is a public service for the population to travel around the country for business, pleasure and family reunions. It should be easy to use, flexible and affordable. Tying people down to deciding on times and days of travels weeks ahead of time is not on. Things happen: the Underground fails to get people to mainline train stations on a daily basis, MerseyTravel staff go on strike, the Liverpool tunnels close unexpectedly for maintenance. It is virtually impossible to ensure you can get to Euston for any set time without either hiring a taxi or getting there hours in advance. I suppose this is an argument against the penalty for missing an Advance ticket booking, but the decrement of the availability to buy full saver returns on the website hints that eventually all tickets will be in the discount airline style. That is, unless you can afford the high-priced Open tickets.</p>

<p>I have previously written to two Department of Transport secretaries on ticketing issues and they have both said that only the saver and open return tickets are regulated. Please regulate that they are available on the website to purchase, or please get rid of Virgin.</p>

<p>Rant over.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Moviedrome Reminiscing]]></title>
    <link href="http://availableimagination.com/moviedrome-reminiscing/"/>
    <updated>2007-12-03T00:37:55+00:00</updated>
    <id>http://availableimagination.com/moviedrome-reminiscing</id>
    <content type="html"><![CDATA[<p>Been a while since I posted, so thought I&#8217;d share a <a href="http://www.geocities.com/kurtodrome/drome.html">link</a> that I found to a site listing all of the films shown in the Moviedrome slot that used to be on Sunday evenings on BBC 2. The selection is an excellent one and I really enjoyed scanning through and remembering watching nearly all of them from 1988 to 1993. Not totally sure that the list is complete as I&#8217;m certain I recall Alex Cox introducing The Wages Of Fear too. It was an excellent format with a quick introduction giving the historical context and things to watch out for, and then the film was shown in its entirety without adverts (God bless the BBC).</p>

<p>The slot was scheduled on a Sunday evening and sometimes the films would run past midnight, but my mother, another film buff, was more than happy to let me stay up and watch the films with her, despite an imminent school day. A quick <a href="http://www.youtube.com/results?search_query=moviedrome">search</a> yields some of these intros and I definitely intend to watch them before I watch any of the movies again. Bring back Alex Cox!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Notes From Vietnam]]></title>
    <link href="http://availableimagination.com/notes-from-vietnam/"/>
    <updated>2007-11-27T16:28:27+00:00</updated>
    <id>http://availableimagination.com/notes-from-vietnam</id>
    <content type="html"><![CDATA[<p>It&#8217;s  a rainy day in Hue so I thought I&#8217;d get down a few notes while I&#8217;ve got nothing better to do &#8230;</p>

<p>Travelling in Vietnam by myself has so far been a varied and interesting experience mixed with lows and extreme highs. To spoil the ending, the best part of it by far has been interacting (ie. talking, smoking, drinking, bartering, clinging on to while riding scooters, joking) with the Vietnamese people (they (I hate using that word) call themselves Vietnami). The warmth, friendliness and genuine smiles just cannot be matched by any other culture that I have encountered (not that many in reality &#8230;). The smile itself is an act of greeting and once that has been established the usual starter questions are &#8216;Where you come from?&#8217;, &#8216;How long you stay in Hue/Hoi An/Doc Let/Sai Gon?&#8217;, &#8216;You travel alone?&#8217;, &#8216;Michael Owen?&#8217;.</p>

<p>The Vietnami have good English vocabulary but some of the pronunciations can be hilarious - I met a ceevill(sic) engineer who was travelling back from Nha Trang (said Na Tran) after having been there for the Miss Earth beauty contest. I&#8217;m not sure if he was the official photographer or had just taken lots of photos, but Miss Sweden was his definite favourite! He had a wife and child in Hoi-An and the whole  trip seemed innocent enough. A sudden connection was made in my head though. Two Russian Lesbians from Vladivostok who were staying in my previous residence (Ki-Em - very good for honeymoons) had mentioned that they were keen to visit Nha Trang that day and I suddenly realised why!</p>

<p>Another hilarious conversation arose in a Sai Gon park one boiling hot afternoon. I was speaking to Tuan (a he) and Tham (a she) and discussing life in Sai Gon/Ho Chi Min City and Tuan mentioned that, at university, he had entered and won a beauty contest. I said he was a very handsome man (in truth he looked like he had seen better days) and he returned the compliment and proceeded to give me his mobile number in a completely heterosexual way! I got Tham&#8217;s number too! The pattern seems to be start talking , and  people literally queue up to have a chat - wanting to practice their English. I spoke to an old lady who had perfect English and French - it seems that the older people possess good French as a vestige from the colonial days. Indeed a lot of French tourists are here and in some restaurants the lingua franca is French.</p>

<p>The downside of the interaction can be the hawking of goods and services in tourist trap areas. On every corner is a cyclo-rider intent on giving you an hour&#8217;s tour on his vehicle or, if you sit down for a rest, a selection of postage stamps collections and old coins in ring binders will be offered for your perusal. I soon got the hang of fending off this menace though. A friendly smile, a shake of the head, and a raising of the palm  seems to elicit an equally friendly relief of the sales  pitch.  Another technique that works well particularly well at train stations is just offer the chap who won&#8217;t leave you alone a cigarette and have one with him. The conversation will soon drift to football! A funny faux-pas to make is to offer a cigarette to a lady. They almost crease themselves laughing at the impossibility of accepting one! Vietnami men do not like their women to smoke, apparently.</p>

<p>Everything is cheap here, very cheap. The difficulty is knowing the price of things, which only comes from being ripped off the first time. A packet of Vietnami-brand cigarettes (White Horse, Hero, Craven-A (as smoked in Liverpool)) is 10,000 Dong (about 30p) while the American Brands are 17,000 Dong (just over 50p). Beer is about 10,000 Dong for a bottle and fresh beer, which is actually very good, is 3,000 Dong (10p!!!!). The other thing which is very cheap, is 4 star accomodation! I can&#8217;t stop myself from reserving myself into the poshest hotel in every city I visit. It&#8217;s a bad habit, but this seems like one of the few countries in the world where it is an affordable option. You are looking at roughly 75 pounds/night for the highest end, although the Majestic did hit a 100. It was worth it though for the cocktails on the top floor balcony, overlooking the Sai Gon River. Very Graham Greene/The Quiet American.</p>

<p>As to the issue of travelling alone. I&#8217;m enjoying it a lot. The bad bits are occasional bouts of boredom with one&#8217;s own thoughts and the Western perception that a man travelling alone is something slightly strange. The uncomfortable moment comes at breakfast time in these swanky hotels when all the Amercian and English  middle-age types and honeymooners are gorging on their Continental servings of  bacon, omelettes, croissants and coffee. They avoid my friendly waves and smiles and I imagine, in my deepest mode of paranoia, that they think I am a sex tourist, here to indulge dark cravings for the things of beauty that are Vietnami  women. Or perhaps they think I just look a bit scruffy for this type of place!</p>

<p>Talking of sex tourists, I have seen a few Northern English men in their 50&#8217;s/60&#8217;s walking hand-in-hand with some stunning 20 year old beauties. Just another aspect of globalisation I suppose.</p>

<p>The benefits of single travel are fairly numerous. No need to make any decisions until you have to. The ability to stay in posh places without having to justify the cost to anyone else. The potential for serendipity to kick in is greater. More able to meet unlikely people (such as a bunch of sailors gambling on the slow train from Hoi-An to Hue). The inclination to meet Vietnami people is greater, if simply for the conversation. In fact, I suppose subconsciously, I have been veering away from  trying to find other Western travellers to hang out with, preferring the more difficult task of speaking to Non-English speakers.</p>

<p>Now, the food &#8230; The reason I came really, apart from the Socialism! It gets better the further North you go. Sai Gon was all Pho Ga and Pho Bo. Hue and Hoi-An both have their speciality dishes. Cao Lau (porky crouton soup) and Banh Bao (White Roses - soft dumplings) where omnipresent in every Hoi-An eatery and where very good. The Hoi-An fish was about as fresh as I&#8217;ve ever eaten. Hue offers the Banh Khoai (Song Que style pancake mixed with a very peanuty sauce and unripe banana!) and other dishes that I intend to devour tonight. I am resolving to eat more street food too, served on the pavement and seeming to be the most popular amongst the locals. Trouble is the rain keeps falling. Apparently it&#8217;s drier in the North, where I&#8217;m heading next (Sa Pa). The more remote accomodation seem to offer breakfast, lunch and dinner as part of the deal. The Ki-Em place was of this ilk and the food there was, while simple, incredibly tasty and beautifully presented. It was a compromise between Western dishes and Vietnamese ingredients, but it worked very well and I spent four days happily stuffing my face there and then swimming in the beautiful ocean.</p>

<p>A few travel tips:</p>

<ul>
<li>Dollars are accepted everywhere except train stations and are easier to convert into mental pounds (divide by 2), but you tend to get change in Dong and some less scrupulous cigarette vendors/ taxi drivers will use a less favourable exchange rate. Also $1 is the smallest denominator available. Better to operate in Dong and give the exact amount where possible.</li>
<li>Carry a wallet where you can conceal the vast majority of your dosh in a zipped section. Every time you pay for something, the seller will have a good peer in your wallet, and if it&#8217;s visibly stuffed with $20 bills your bartering edge has definitely been lost.</li>
<li>Don&#8217;t buy cigarettes from train station platforms - they are all fake!</li>
<li>Talk football. Most people, including the girls, seem to know the names of their favourite teams full squad, along with transfer histories. West Ham is surprisingly popular!</li>
</ul>


<p>My advice, come to Vietnam, it&#8217;s really good!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Excellent Jogger's Mash Up!]]></title>
    <link href="http://availableimagination.com/excellent-joggers-mash-up/"/>
    <updated>2006-08-01T21:18:35+01:00</updated>
    <id>http://availableimagination.com/excellent-joggers-mash-up</id>
    <content type="html"><![CDATA[<p><a href="http://www.gmap-pedometer.com/">Gmaps Pedometer</a> is undoubtedly the most useful application of Google Maps I have come across. You can calculate the distance you have just jogged and plot your route on a pretty map. Saves carrying a pedometer or a GPS! Simple to use, click &#8220;Start Recording&#8221; and then <em>Double-Click</em> for each of the vertices of your route. Brilliant!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[URLDecoder SQL CLR UDF]]></title>
    <link href="http://availableimagination.com/urldecoder-sql-clr-udf/"/>
    <updated>2006-07-18T10:03:13+01:00</updated>
    <id>http://availableimagination.com/urldecoder-sql-clr-udf</id>
    <content type="html"><![CDATA[<p>Annoyingly the SQL CLR engine does not allow the use of the System.Web assembly and consequently you cannot use the very helpful HttpServerUtility.UrlDecode member in your User Defined Functions. Here is a quick hack which does something similar. Useful if you are in a rush!</p>

<pre><code>using System;
using System.Collections.Specialized;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

public partial class UserDefinedFunctions
{
    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlString URLDecode(SqlString URL)
    {
       string[]Encoders=new string[]{\" ","%20","!","%21","\\"","%22","#","%23","$","%24",
           "%","%25","&amp;","%26","'","%27","(","%28",")","%29","*","%2a","+","%2b",",","%2c",
           "-","%2d",".","%2e","/","%2f",":","%3a",";","%3b","&lt;","%3c","=","%3d","&gt;","%3e",
           "?","%3f","@","%40","[","%5b","\\\\","%5c","]","%5d","^","%5e","_","%5f","`","%60",
           "{","%7b","|","%7c","}","%7d","~","%7e","","%7f","€","%80","","%81","‚","%82",
           "ƒ","%83","„","%84","…","%85","†","%86","‡","%87","ˆ","%88","‰","%89","Š","%8a",
           "‹","%8b","Œ","%8c","","%8d","Ž","%8e","","%8f","","%90","‘","%91","’","%92",
           "“","%93","”","%94","•","%95","–","%96","—","%97","˜","%98","™","%99","š",
           "%9a","›","%9b","œ","%9c","","%9d","ž","%9e","Ÿ","%9f","","%a0","¡","%a1",
           "¢","%a2","£","%a3","","%a4","¥","%a5","|","%a6","§","%a7","¨","%a8","©","%a9",
           "ª","%aa","«","%ab","¬","%ac","¯","%ad","®","%ae","¯","%af","°","%b0","±",
           "%b1","²","%b2","³","%b3","´","%b4","µ","%b5","¶","%b6","·","%b7","¸","%b8",
           "¹","%b9","º","%ba","»","%bb","¼","%bc","½","%bd","¾","%be","¿","%bf","À",
           "%c0","Á","%c1","Â","%c2","Ã","%c3","Ä","%c4","Å","%c5","Æ","%c6","Ç","%c7",
           "È","%c8","É","%c9","Ê","%ca","Ë","%cb","Ì","%cc","Í","%cd","Î","%ce","Ï",
           "%cf","Ð","%d0","Ñ","%d1","Ò","%d2","Ó","%d3","Ô","%d4","Õ","%d5","Ö","%d6",
           "","%d7","Ø","%d8","Ù","%d9","Ú","%da","Û","%db","Ü","%dc","Ý","%dd","Þ",
           "%de","ß","%df","à","%e0","á","%e1","â","%e2","ã","%e3","ä","%e4","å","%e5",
           "æ","%e6","ç","%e7","è","%e8","é","%e9","ê","%ea","ë","%eb","ì","%ec","í",
           "%ed","î","%ee","ï","%ef","ð","%f0","ñ","%f1","ò","%f2","ó","%f3","ô","%f4",
           "õ","%f5","ö","%f6","÷","%f7","ø","%f8","ù","%f9","ú","%fa","û","%fb","ü",
           "%fc","ý","%fd","þ","%fe","ÿ","%ff"};
        string URLString = URL.ToString();
        for (int i =1;i&lt;Encoders.Length;i+=2)
        {
            if (URLString.Contains(Encoders[i]))
            {
                URLString = URLString.Replace(Encoders[i],Encoders[i-1]);
            }
            else if (URLString.Contains(Encoders[i].ToUpper()))
            {
                URLString = URLString.Replace(Encoders[i].ToUpper(),Encoders[i-1]);
            }
        }
        return new SqlString(URLString.ToString());
    }
};
</code></pre>
]]></content>
  </entry>
  
</feed>

