Monday, November 23, 2009
Photos
Tuesday, September 01, 2009
Obligatory 9/11 post
Monday, August 31, 2009
Alan Turing Petition
Saturday, August 08, 2009
The Monomyth vs. the Automyth
- people: farm boy, new advertising executive, grizzled mountain man, washed out detective
- places: Alabama USA, the Shire (or an analogue of), a moon-base, a small shop in London
- challenges: alien invasion, disease, death of a parent, financial ruin (personal or global)
- monsters: the boss, an out-of-control robot, the Devil, the judge(s)
- assistants: the girlfriend, the grand-parent, the old mage, the bestest buddy, the advocate
- ... and so on
Thursday, August 06, 2009
VirtualBox on Windows Hosts
Andy, you might want to be careful about using a dynamically expanding disc file for your root file system. NTFS is notorious for fragmenting files as they grow - especially if your file is living on a partition with other activity. And as we all know, the more fragmented a file gets, the poorer the performance becomes as the disc heads have to seek across more and more diverse areas of the disc to get to the content of the file. Where you have a virtual file system in a file, this is only going to get worse, because the file system you have inside the file will have no knowledge of how the data is distributed over the real disc, so it can't make any decisions over data distribution within the file system that have any meaning on the disc platters.
Thursday, July 16, 2009
Logging out with HTTP Basic Authentication
There is a downside to this arrangement, and that is that HTTP BASIC authentication doesn't really support the concept of logging out!
As normal with a Java web application, the logout operation is a matter of invalidating the current HttpSession, throwing away any cached user configuration, and redirecting the user to a 'you are logged out' page. This can be achieved by having a filter or a servlet pick up the 'logout' request, mark the HttpSession associated with the current HttpRequest object, and deleting the JSESSION cookie that identified the session. The response then just needs to contain a logout message, or redirect, or whatever you desire for your site.
That's all well and good if it's just the web application involved. However, in our scenario, we have web server to consider too. As it stands, there's nothing in the HyperText Transfer Protocol ('HTTP' to you and me) that allows the web application to tell the web server that the HttpSession is over - the application doesn't talk to the server, so (according to almost all the web sites I could find with Google) there's no way to tell the server to invalidate it's knowledge of the end user and their credentials.
Or is there....
The key factor is that it is possible to make the server re-challenge the user for their credentials in the same way as they were when they started using the application, and this can be made to have the same effect as logging them out. Note that the critical fact that previous web-pages on this subject seem to have missed is that HTTP BASIC authentication has a realm parameter.
By knowing what the realm is that the web-server used to the authenticate the user, we can cause the browser to re-authenticate against that same realm, by challenging the browser with an HTTP 401 (just like the web-server does).
The process (in my application) works like this:
- The user clicks the logout link to go to /logout.html, which tells the user they are being logged out. This is a nice-to-have page to make this process a little more friendly, you could skip it and go straight to the next step
- The browser pauses for 1 second on this page, then redirects to /logout
- This url is mapped to a logout filter, which does the normal session termination activities I mentioned above. But in order for the next step to work, the filter also registers the current HttpSession key with the LoggedOutServlet (storing it in a singleton HashSet of keys), and creates a has-logged-out cookie with the HttpSession key as the value of the cookie.
- The logoutFilter then redirects to /loggedout which has been mapped to the LoggedOutServlet in my web.xml:
- The LoggedOutServlet looks for the has-logged-out cookie. If cookie exists, and the value is in the servlet's register of logging-out keys, then the key is removed from the register, the cookie marked as deleted, and an Unauthorised (HTTP 401) response is returned to the user:
public void setupResponseForLogout(HttpServletResponse response) { response.setStatus(HttpServletResponse.SC_ UNAUTHORIZED); // HTTP 401 response.setHeader("WWW- Authenticate", "Basic realm=\"xyzzy\""); } - The user is then prompted by the browser to re-authenticate. The critical thing here is that the realm (set to 'xyzzy' above) is set correctly in the response. If this is done, then the web-server (which must be authenticating with the same realm) will correctly re-authenticate the user if they try to login again. So the consequence is that the user is effectively logged out, and cannot get back into the application without being challenged for their credentials again. This works because the browser has been asked to authenticate against a specific realm, so that will be used in the authentication process, and will force the web server to full re-check the user's credentials - refusing access if they get it wrong.
<servlet>
<description>Logout Servlet</description>
<display-name>LoggedOutServlet</display-name>
<servlet-name>loggedout</servlet-name>
<servlet-class>
com.xyzzy.web.LoggedOutServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loggedout</servlet-name>
<url-pattern>/loggedout</url-pattern>
</servlet-mapping>
Wednesday, July 01, 2009
TreeSet and implementing the Comparator interface
My experience of Collections thus far has taught me that most of them are built upon detecting object equality through the equals() and hashcode() implementation in your class. See my earlier post and the posts of Andy Beacock referenced therein. However, today I ran into problems with objects vanishing in a TreeSet.
Back to the requirements first. I have list of Bank Account objects I wish to show on a web-form, but that list should also be modifiable by the user with an Add Form, and a Remove button on each listed account. So far so good. One more thing, the list has got to be in account name order on display. For this example, a Bank Account consists of a pseudo-primary key (id), a Bank Name, an Account Name, an Account Number, and a Sort Code. The id is not shown, and the records are unique by Account Number and Sort Code (and therefore implicitly by Bank Name).
Obviously, Bank Names should should not really be store in a Bank Account record - they should be stored separately and referenced by foreign key, as indeed, should Sort Codes - in fact, in an ideal world, the Bank Account record would be an id, a name, an account number and a foreign key to a branch as identified by the sort code. However, you know as well as I do that this is not an ideal world, and most of the time, we have to deal with the world as we come to it.
So, back to my slightly contrived example. I'm going to ignore completely all the contextual information about display technology, form interaction, transactions, etc., and concentrate on the core issue: SortedSets are nasty wee buggers!
There are two ways to manage the display of sorted data: sort on insert, and sort on display. If you're displaying often, and inserting & deleting infrequently (as in this example), sort on insert is preferable, otherwise you spend a lot of time sorting your data again and again with no change to the data.
Having looked at the implementations of the SortedSet interface, we really only have one available in the Java SDK (I'm staying away from the Apache Collections for now), and that is TreeSet, for which you specify a Comparator at construction time. Naively, I assumed that my comparator would just be interested in the Account Name - that's the field by which I wish to sort, after all.
@Override
public int compare(BankAccount o1, BankAccount o2) {
return o1.getAccountName().compareTo(o2.getAccountName());
}
(I'm leaving out the normal defensive programming and exception handling for clarity)
However, my BankAccount class implements equals() and hashcode() as normal, with the sortcode and the account number - these being the 'business key' if you like. So, on this basis, I expected TreeSet to sort on name, and use equals() and/or hashcode() to determine whether the Set contains a given BankAccount on insertion - in the same way that HashSet would.
Ooops, no.
Turns out that TreeSet doesn't use equals() or hashcode() at all. It uses the Comparator for sorting and contains() checking. So now, my Comparator implementation looks like this:
@Override
public int compare(BankAccount o1, BankAccount o2) {
int result = o1.getAccountName().compareTo(o2.getAccountName());
if (result == 0) {
result = o1.getSortCode().compareTo(o2.getSortCode());
}
if (result == 0) {
result = o1.getAccountNumber().compareTo(o2.getAccountNumber());
}
return result;
}
Now I have data sorted on insert and display, and the data doesn't get lost if someone enters two accounts with the same Account Name.
In conclusion, I think that the only reason this gotcha got me was that I was motivated to use the TreeSet simply by the requirement to sort by name, so I wrote the Comparator with only that in mind. A correct implementation of really should include the business keys of the entity under consideration... of course, I'd just done that, I might have had even more trouble with the sort-by-name requirement (i.e. a non-key property).
Friday, June 19, 2009
I want one...
Thursday, June 18, 2009
HashCodeBuilder is great, but ...
When doing domain modelling, one of the important things to get right is the definition of the equals() and hashcode() methods. I'm going to use a class that's used to represent a compound primary key in a Spring/JPA/Hibernate environment. The PaymentMethodId class has an owner, and two currency codes - one for the source of funds, and one for the destination of the funds, to allow for currency conversations between the two.
@Embeddable
public class PaymentMethodId extends CompositeId {
@Column
private Integer ownerNumber;
@Column
private String sourceCurrencyCode;
@Column
private String paymentCurrencyCode;
/**
* Compare unique business key (number, source code and payment code)
*/
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null || !(other instanceof PaymentMethodId)) {
return false;
}
PaymentMethodId paymentMethodId = (PaymentMethodId) other;
return ((this.ownerNumber == null ? paymentMethodId.ownerNumber == null
: this.ownerNumber.equals(paymentMethodId.ownerNumber))
&& (this.paymentCurrencyCode == null ? paymentMethodId.paymentCurrencyCode == null
: this.paymentCurrencyCode.equals(paymentMethodId.paymentCurrencyCode))
&& (this.sourceCurrencyCode == null ? paymentMethodId.sourceCurrencyCode == null
: this.sourceCurrencyCode.equals(paymentMethodId.sourceCurrencyCode))
);
}
@Override
public int hashCode() {
int result = 13;
result = (ownerNumber != null ? 19 * result + ownerNumber : result);
result = (paymentCurrencyCode != null ? 19 * result + paymentCurrencyCode.hashCode() : result);
result = (sourceCurrencyCode != null ? 19 * result + sourceCurrencyCode.hashCode() : result);
return result;
}
}
I've left out constructors and getters and setters as these should be obvious.
As you can see, I like to make use of the 'trinary if' expression for brevity. Just imagine how much more complex these methods would be if written out in full!
Anyway, similar to Andy Beacock's post on this subject, we can firstly simplify the above as follows:
@Override
public boolean equals(Object obj) {
if (obj instanceof PaymentMethodId) {
PaymentMethodId other = (PaymentMethodId) obj;
EqualsBuilder builder = new EqualsBuilder();
builder.append(getOwnerNumber(), other.getOwnerNumber());
builder.append(getSourceCurrencyCode(), other.getSourceCurrencyCode());
builder.append(getPaymentCurrencyCode(), other.getPaymentCurrencyCode());
return builder.isEquals();
}
return false;
}
@Override
public int hashCode() {
HashCodeBuilder builder = new HashCodeBuilder();
builder.append(getBrokerNumber());
builder.append(getSourceCurrencyCode());
builder.append(getPaymentCurrencyCode());
return builder.toHashCode();
}
Note the use of getters instead of properties - as Andy mentioned.
However, the important bit that really is the reason for this post is the last line:
return builder.toHashCode();
It is vital that you don't write:
return builder.hashCode();
Notice the subtle difference? The hashCode() of the builder itself is worse than useful as it will vary every time the method is run, so any Hash-based collection code will find your object has a different hashCode, every time it asks, risking the integrity of the data.
Thursday, May 07, 2009
The "Two Source" rule?
Okay, guilty as charged, I've only used one source, slashdot.org, but then I'm only a blogger so I don't count because my writing is too risky anyway.
Wednesday, May 06, 2009
Alexander Mosley, RIP
Friday, April 03, 2009
Once more with feeling...
Wednesday, March 18, 2009
Knife Crime in London
Voyage
Originally posted at GameBoomers:
What is it?
I was a young boy, just striking out on my own path at the town library when I first came across Jules Verne. My introduction to the French man's works of speculative fiction (as sci-fi used to be known) came in the form of the Journey to the Centre of the Earth. I loved it; I still do. There is one difficulty with Verne's work, however. It's all written in French, and so every time I read his work, it is through the filter of a translator's pen. This shows up in Journey to the Centre of the Earth in the fact that there are two main translations of the book, and they're completely different. The main character in one of the versions is a completely different man, in name as well as character, from in the other.
So it seems than game developers seem to like following in this tradition of 're-interpretation' rather than translation. In particular, the recent “Journey to the Centre of the Earth” and “Return to
Well, the answer is that they've done the same as they did with their first game - Voyage is a Verne-esque telling of a story that starts with an idea that he had. This is not to say that the result is somehow 'wrong', it would simply be a mistake to say that Kheops have told Verne’s story verbatim.
What we have instead is a nonlinear, point-n-click, mostly pre-rendered 360° bubble-based adventure game telling the story of Michel Ardan, a wild-hair, moustachioed 19th century French explorer, and his journey to the Moon. And, yes, he actually reaches the Moon, where Verne's characters did not.
Is there a plot?
The game begins with our hero, Michel Ardan, waking up in a bullet-like space capsule in the company of Barbicane and Nicholl - his fellow space explorers, after the violent launch of the capsule towards the Moon. However, he soon discovers that all has not gone well since the launch.
As I've already made it clear that Michel reaches the Moon, I think it fair to also mention that he also encounters intelligent life there. The backbone of the story is Michel's encounters with the Selenites, (from the Greek 'seleno', being the Moon) and his efforts to return to the Earth. Along the way he discovers some of the story of the Selenite civilisation and their relationship with Earth. And, of course, there are plenty of puzzles along the way, but then it wouldn’t be much of an adventure game without them.
Notable Features
In this highly puzzle-oriented game, the puzzles are pretty varied. Some involve the decipherment of the Selenitic written and spoken language – a tuneful thing that’s not as hard as it sounds; a fair few puzzles involve combinations of inventory items, some are mathematical in nature, some mechanical, and some are just pure logic. A number of the over-arching goals can be achieved through a variety of means. This is the source of much of the game’s nonlinearity. If you get stuck somewhere, you can often make progress in other parts of the game before coming back to the sticking point.
In addition, there are a number of optional side puzzles that aren’t essential to your progress towards home, but which reveal some extra facet of lunar life. From roughly halfway through the game (at least as I played it), you gain a small ‘helper’. The ‘helper’ is there to reveal information, clues and your score. Certain puzzles require you to have achieved a specific number of points before you can obtain information or inventory items. However, obtaining sufficient points is again possible in a variety of ways. Solving parts of the Selenitic language, or deciphering mathematical puzzles or manufacturing chemical substances using the Selenitic machines all improve your score.
Ardan automatically keeps a comprehensive log of his experiences. This includes some of the conversations, the details of his investigations as to what happened in the space capsule before he woke, and a number of key diagrams regarding his objectives later in the game.
A notable pair of features in this point-n-click adventure is the inclusion of a small number of timed sequences early in the game, followed by some hand-eye-coordination-based jumping puzzles. Unfortunately, these puzzles all result, upon failure, in the death of Ardan, but he is always resurrected to a point immediately before the timed sequence or jump began, so there’s no real penalty in failure, other than a certain gathering frustration. On the plus side, once each jump has been successfully performed, Ardan will be able to repeat them without the player having to beat the puzzle again. I found these a minor irritation rather than a serious problem.
Graphically, the experience of Voyage is colourful and imaginative. With our modern knowledge of the Moon, we would expect the palette of this game to be rather dull and leaden, but Kheops Studios clearly know better, with good texturing, a rich palette of colours, refined animation, and very detailed modelling.
Most of the audio in the game is top quality. The music is unobtrusive, but appropriately used to set the mood at various stages of the game. The voice acting of the Selenites is excellent – I particularly enjoyed their native voices, which are rather harmonious. The English voice acting was good, with the exception of Ardan himself, whose narration and accent I found jarred slightly. I think he was supposed to sound like an educated Frenchman speaking English – presumably he sounds better in the French version – but in English he came across as stilted and slightly manic at the same time.
Any other novelties?
Not having completed a Kheops Studios’ game before, I didn’t realise quite how much they like inventory combining puzzles. However, to their credit, the required combinations aren’t extraordinarily illogical, though some are surprising. A nice feature here is the pictorial log that is kept of all the successful combinations you’ve made throughout the game – this simplifies the task of re-creating earlier combinations later in the game.
An intriguing novelty in Voyage is the requirement that you don’t just have to click on a button to make the machines work, you have to understand what those machines are going to do. A number of the machines will ‘work’ by you pressing buttons, but will only do the ‘right’ thing when you understand them properly.
There are at least three puzzles that can be attempted several times, to a number of standards – in each case, the lowest standard is sufficient to ‘solve’ the puzzle, but you can significantly improve your overall score by achieving the higher levels. A feature here that is rather useful is that if you find that you’re weak in one puzzle – perhaps figuring out the Selenitic mathematics defeats you – you may well be able to make up for it with the sounds of the their spoken language.
Oddities
Now we reach the only really odd thing about this game. Although there are five profiles under which you can save your game, you must select your profile during level 1 of the game – however, there’s no warning as to when level 1 ends, so no indication when you should choose your profile. The manual states that level 1 is the capsule level, but it’s not clear whilst you’re playing the game when this level ends. So, I suggest that anyone playing this game saves their first game immediately the first cut-scene ends – thereby choosing a profile and eliminating any risk of getting caught out like I did.
Of course, if you’re not sharing your computer with other people, this oddity problem won’t even affect you, but it did me, so I choose to mention it.
Conclusions
This was an enjoyable telling of a Verne-inspired tale, though I’ve found it helpful to ignore the connection with Monsieur Verne in the long run. I would certainly play another game by Kheops Studios. So, to summarise: a point-n-click adventure, featuring a good story, some hand-eye coordination, a few timed sequences, plenty of opportunities to die, but with immediate resurrection to before the fateful decision was made, unlimited saves, but an odd profiling system, a variety of logical, mathematical, inventory, linguistic and mechanical puzzles, one musical puzzle, and no slider puzzles, nor mazes.
From a technical standpoint, there were very few graphical bugs, nor audio glitches, except during the final cut-scene, which was a shame, as it concludes with a nice little twist to the story. The game has no patches, and no serious crashes.
So, all in all, a good game, but not spectacular, hence the final grade.
Grade: B
What do you need to play it?
Minimum Requirements
· OS: Windows® 98SE/ME/2000/XP
· CPU: 800 MHz Pentium® III
· RAM: 64 MB
· CD-ROM/DVD-ROM: 16X Speed
· Video: 64 MB DirectX® 9 Compliant Video Card
· Sound: DirectX® 9 Compatible
· Input: Keyboard, Mouse and Speakers
Recommended Requirements
· OS: Windows® XP
· CPU: 1 GHz Pentium® 4
· RAM: 128 MB
· CD-ROM/DVD-ROM: 24X Speed
· Video: 64 MB DirectX® 9 Compliant Video Card
· Sound: DirectX® 9 Compatible
· Input: Keyboard, Mouse and Speakers
Saturday, February 21, 2009
Puzzles in Myst games
Fairness, novelty, and integration are all important for making good puzzles, but what makes the puzzles discussed here stand out is their payoffs. Each of them has a moment of epiphany, where the odd structure of the game world suddenly makes sense, and all the pieces fit together. Because they are especially tricky, the reward is sweeter, and the player feels a greater sense of accomplishment.
It's this puzzle with a twist that is the greatest strength of the Myst series. By starting with a solid puzzle and then adding a twist, developers can make their own puzzles stick in players' memories. This doesn't just apply to adventure games, either; any kind of game that uses puzzles will be better-served by a cleverly crafted obstacle rather than just another game of Nim.
Tuesday, February 17, 2009
Hydrogen fueled cars
- Tesla: 53kWh for 220 miles
- Honda: 240kWh for 270 miles worth of hydrogen, (or 195kWh for 220 miles to match the Tesla's maximum range)
Friday, February 13, 2009
Channelling Douglas Adams from 1999
Today I was reading the TechDirt blog, as I often do, and came across this article. However, it was not that article that really got my attention so much (sorry Mike) - it's their stock-in-trade kind of commentary on the madness and desperation of the old-skool media types trying to defend out dated business models. No, it was this little quote:
1) everything that’s already in the world when you’re born is just normal;
2) anything that gets invented between then and before you turn thirty is incredibly exciting and creative and with any luck you can make a career out of it;
3) anything that gets invented after you’re thirty is against the natural order of things and the beginning of the end of civilisation as we know it until it’s been around for about ten years when it gradually turns out to be alright really.
Friday, January 23, 2009
Enough talk of the recession already
Wednesday, January 21, 2009
President Barack Obama
W. E. B. DuBois started to teach so that Rosa Parks could take a seat.This says so much to me about how the way the political geography of the US has changed in just two generations (Rosa Parks sat in the 'wrong' seat on a segregated bus in 1955). Not everyone around me appreciates just how significant this is for the United States, but it gives me great hope for the future if such seemingly impossible odds can be overturned.
Rosa Parks took a seat so that we could all take a stand.
We all took a stand so that Martin Luther King, Jr. could march.
Martin Luther King, Jr. marched so that Jesse Jackson could run.
Jesse Jackson ran so that Barack Obama could win!
Cleo Fields at the State of the Black Union February. 23, 2008
Who among you, even in 2007, really could have said with any kind of confidence that 2008 would see the Democratic race for the nomination for president would be between a woman and an African-American man, let alone that the resulting candidate would win?
p.s. if you can watch BBC programs on iPlayer, I recommend this recent program on Barack Obama, it's available until 7:59pm Tuesday 27th January 2009.
Tuesday, January 20, 2009
Tips and Tricks
I've been using Eclipse for Java web application development for about 6 years now, and it's an excellent platform. However, there is a minor issue with upgrading eclipse versions. Each time you upgrade, you really need a clean install in the eclipse directory. So far, so good. The downside of this is that you lose all your plugins - one of the greatest strengths of the eclipse platforms - so that I usually have to write off a days work to do an upgrade (consequently, I'm still on the Europa release, as opposed to the more recent Ganymede release).
Now, this inertia isn't a huge problem; in fact, I'd say it's only an annoyance that hits once or twice a year, but it would be nice to have a solution.
Introducing 'externalised eclipse plugins'. It's surprising what you can learn when your not expecting to see anything remarkable on a site.
Now, you may say that any eclipse user worth their developer chops will have already have solved this problem three years ago, but so what. I'm still learning new vi tricks after more than 20 years daily use. But I'll take new learning any way I can get it.
So, if you're a developer in the Web arena, take a look at avaJava's Web Tutorials, you never know what might strike you.
