Under the palm tree: Under the palm tree (ramblings-july-4-2011.html)

Ramblings, July 4th 2011

In which I ramble about recent events, being too lazy to compose separate updates for each..

Asus Transformer

Since my review of my long-time pal, the Asus 701 netbook, the poor thing has lost the use of all the USB ports down its left^Wright side. More recently, somehow the battery loses contact often enough to be quite annoying (aka the thing just turns off, no warning, if I reseat the battery it happily works again, for a while..) I spent a while watching the AlwaysInnovating site/forums to see if the TouchBookII would ever actually appear, but they still seem to be failing to produce one soo.. I bought an Asus Transformer complete with dock (keyboard).

So far, its been pretty good. The battery life is fantastic (charge full at home, spend a day and a bit travelling from Europe to the US, and its still working), the Android Honeycomb OS generally Just Works (tm). I've found useful apps for my general use-case - an ssh client, ConnectBot, a browser, Opera Mobile (recently updated to actually support Flash, hooray!), an editor, and some games.

Only one major annoyance so far, the power/charge cable is quite short (about 40cm or so), compared to the 701 cable which is 3m long. This means if I plug it in under my desk at home or next to the bed, it barely reaches my actual lap.. We tried extending with a USB A-A cable, but that fails to produce a charging light on the dock.

Travelling

This is mostly a reminder to myself: No matter how much you plan and organise (and I left several bits a bit late, this recent trip), some things will just always go wrong. After comparing prices of National Express and long-stay (a week) near Heathrow, it seemed that long-stay parking was now cheaper (50 versus 70 GBP), so I booked parking at NCP flightpath.

The flight being at 8am, we also decided to drive down the night before, and overnight at a nearby hotel, Hostelbookers found me the Heathrow Lodge Hotel.. Which was fine but for some errors on their website (and the hostelbookers site), see where it says "free parking"? That's rubbish, they charged us a fiver, and signs threatened to clamp/tow any unknown vehicles.

As we arrived there, paying for extra breakfast was suggested by the clerk, which could be delivered at any hour, he insisted.. So we said "yes, 5:30am please" (having planned to leave at 6).. Come 5:45am the next morning, no breakfast arrived, on enquiry, of the exact same guy at the front desk, he asked "when did you want it?" .. Sigh.. He did however manage to get us a packed version in the next 5mins, which was a fairly good breakfast.

We drove as planned (more or less) to the NCP flightpath parking place.. which, by the way, its useless to navigate via postcode to, satnavs get it all wrong.. Luckily they know this, and also post their lat/long coordinates on their website .. If only we'd thought to do that the first attempt to find it, instead of after the satnav failed.. On arriving, the auto-number-plate recognition system failed to find us, it turned out (much later) that this is because you have ±6 hours of your actual booking time to be recognised, and we'd booked for the previous morning just in case we wanted to park there all day.

Eventually the attendant just suggested we take a ticket and sort it out on the way back.

Services

Which brings me to service.. Several times on this holiday I've noticed how some companys, presumably mostly the ones with a fair amount of competition, have improved their service to the point of being genuinely nice and useful.

Notable was the parking attendant whom we saw when picking up the car on the way back. I'd managed to actually lose the ticket we'd taken (along with my notepad, sniff), but he found our actual pre-paid booking on the system anyway, explained the whole ±6 hours rule thing, and gave us a ticket to exit the carpark with. This was even replaced with another one that worked, as we'd taken more than 15mins to pack the car and decide where we were off to next (London Hackspace!). He said "I hope you'll use us again", I think I may well.

Hmm, ran out of steam at this point, posting anyway.. more ramblings to come!

@public,laptop,asus,travel,hotels

Under the palm tree: Under the palm tree (looking-at-forms-Spark-Form.html)

Looking at forms (5- Spark::Form)

What this is about

Spark::Form

I know who wrote this one.. They also asked me to contribute to the docs, which I should. I suspect there's a much improved version in the git repository, howver as its not on CPAN, it doesn't exist for my purposes.

Now I'm wondering if cpanm can/does/should install from a git URL.

Anyway, Spark::Form consists of a set of basic Roles for defining, printing (HTML, XHTML) and validating forms, or mostly the fields that forms consist of. As you can tell from my example, I can't actually tell from 30/40mins doc poking, how to make the validation work at all.

Pros

  • Modular, you can design subsets of field types or use someone elses.
  • Supports subforms, you can merge in fields from existing form objects.

Cons

  • Docs and SYNOPSIS are confusing
  • Not obvious how to output HTML at all, given a form object.
  • Links to docs that don't exist at all (Spark::Form::Manual).

Sample code (by me)

#!/usr/bin/env perl

use strict;
use warnings;

use Spark::Form;

my $form = Spark::Form->new( plugin_ns => 'SparkX::Form');

$form->add('text', 'username', label => 'username', regex => qr/^.{2,}/);
$form->add('password', 'password', label => 'pasword', regex => qr/^.{2,}/);
$form->add('submit', 'submit');

foreach my $field ($form->fields) {
    print $field->to_html;
}

$form->data( {username => '', password => '' });
if($form->validate) {
    print "Valid!\n";
} else {
    print "Not valid\n"
}

Sample code output

<input name="username" type="text"><input name="password" type="password"><input name="submit" type="submit">Valid!

@public,perl,forms

Under the palm tree: Under the palm tree (first-ruby-code.html)

I wrote my first Ruby code this morning...

A few weeks back I bought a copy of Seven languages, in seven weeks by Bruce Tate (as an ebook, from pragprog.com). You can read what it's about behind the link, a short summary is that it covers Ruby, Clojure, Haskell, Prolog, Scala and Io, in a meaningful fashion.

I can't verify that yet, since I've just read Day One of Ruby, and so far managed to produce this:

(using irb)

num = rand();
guess = -1
while guess.to_i != num.to_i
  puts "Guess:"
  guess = gets
  if guess.to_i > num.to_i
    puts "too high"
  elsif guess.to_i < num.to_i
    puts "too low"
  end
end

That was the biggest "Day One" exercise, another that I attempted consisted of "find out how to get the index of a string inside another string in Ruby" .. I attempted 'string'.methods for this, but no "index". I then googled and found "ruby-doc.org", which found "index" when I looked under the "String" type..

I also assumed I'd have local docs, and skimmed "man ruby", which wasn't too helpful, then tried a "man -l ruby", which also didn't show up a lot. Is this normal, or just Ubuntu not installing docs by default again?

So far, so good.

@public,ruby,7langs7weeks

Under the palm tree: Under the palm tree (looking-at-forms-Form-Processor.html)

Looking at forms (4- Form::Processor)

What this is about

Form::Processor

Next on my list is Form::Processor, after reading its docs closely however, it does not seem to meet my requirements of drawing forms in HTML at all. This is a tool for processing and validating the data gathered from forms, or anywhere else really. Useful if you prefer to handcraft your HTML? The form object can be passed to the template and queried for the needed fields, so it doesn't make you define your fields in two places. (Or so I gather)

It was originally released in June 2007, and the most recent release was July 2008.

I've attempted to make something work, but it appears without crafting an appropriate Form::Processor::Model subclass I may not be able to at all.

Pros

  • Seems to support many field types

Cons

  • No HTML rendering at all.
  • Examples are a bit confusing if you're not using it to write to a Class::DBI -based database model.
  • Unresolved bugs.

(Attempt at) Sample code

#!/usr/bin/env perl

use strict;
use warnings;

use Data::Dumper;

my $form = MyApp::Form::Login->new();
print Dumper($form->fif);

$form->validate({ username => 'fred',
                  password => 'harry',
                });

print "Is valid? ", $form->validate();

package MyApp::Form::Login;

use strict;
use warnings;

use base 'Form::Processor';

sub profile {
    return {
    required => {
        username => 'Text',
        password => 'Password',
    },
    };
}

Sample output

$VAR1 = {};
Is valid? 0

Yes, I could do with some help on this one, it's failing to be usable in 30-45mins, which is my arbitrary target for getting up to speed with these.

@public,perl,forms

Under the palm tree: Under the palm tree (looking-at-forms-3.html)

Looking at forms (3 - Form::Sensible)

As previously mentioned...

Form::Sensible

Started in Jan 2010, and last updated this year (Jan 2011), this one looks slightly more alive than the previous candidates. Jumping straight to the Overview, it's worth reading through the rather long philosophy explanation to see whats going on here.

The aim of this module seems to be to define a set of fields based on what data you want to ultimately obtain, and leave the rendering end to figure out how to present that to the user. The advantage being that your data gathering end doesn't care if your frontend presents "pick one of these" as a drop-down, or a set of checkboxes, or something even stranger.

Pros

  • Nice separation of concerns
  • Built-in HTML rendering outputs labels, ids and classes and is valid.
  • Decent looking starter documentation.
  • Content validation can be done via regex, coderef or plain "required".
  • Error messages can be changed.

Cons

  • Doesn't seem to be a way to permanently define a form using a class. The simple data structure could be stored as XML, YAML or some other config type though.
  • Docs link to a non-existent wiki page.
  • Open and unsolved bugs.
  • Form structure hashref not validated (I typed "rehex" instead of "regex" and there was no error or warning).

Sample code (mostly from Overview doc)

#!/usr/bin/env perl

use strict;
use warnings;

use Form::Sensible;

my $form = Form::Sensible->create_form( 
    {
        name => 'login_form',
        fields => [
            { 
                field_class => 'Text',
                name => 'username',
                validation => { 
                    regex => '{2,}',
                    required => 1,
                }
            },
            {
                field_class => 'Text',
                name => 'password',
                validation => { 
                    required => 1,
                    regex => '{2,}',
                },
                render_hints => { 
                    'HTML' => {
                        render_as => 'password' 
                    }
                },
            },
            {
                field_class => 'Trigger',
                name => 'submit'
            }
            ],
    } );

my $renderer = Form::Sensible->get_renderer('HTML');
my $renderedform = $renderer->render($form);

print $renderedform->complete('', 'post'); 

Sample output

<div id="fs_login_form_form_div" class="fs_form_container fs_login_form_form_container">
    <form action="" method="post" id="fs_login_form_form" class="fs_form fs_login_form_form" accept-charset="utf-8" >
<div id="fs_username_div" class="fs_formfieldline fs_text fs_username  ">
    <label class="fs_label fs_text_label " for="fs_login_form_username_input">Username</label>
    <input type="text" id="fs_login_form_username_input" class="fs_input fs_text_input fs_username_input " name="username" value="" />
</div>

<div id="fs_password_div" class="fs_formfieldline fs_text fs_password  ">
    <label class="fs_label fs_text_label " for="fs_login_form_password_input">Password</label>
    <input type="password" id="fs_login_form_password_input" class="fs_input fs_text_input fs_password_input " name="password"/>
</div>

<div id="fs_submit_div" class="fs_formfieldline fs_trigger fs_submit  ">


    <input type="submit" id="fs_login_form_submit_input" class="fs_input fs_trigger_input fs_submit_input  " name="submit" value="Submit" />

</div>

</form>
</div>

Input validation

To validate the input values against the rules given earlier:

$form->set_values({ username => '1',
                    password => '',
                  });
my $result = $form->validate();
if(!$result->is_valid) {
    $renderedform = $renderer->render($form);
    $renderedform->add_errors_from_validator_result($result);
    print "Form with errors\n";
    print $renderedform->complete('','post');
}

and you get:

<div id="fs_login_form_form_div" class="fs_form_container fs_login_form_form_container">
    <form action="" method="post" id="fs_login_form_form" class="fs_form fs_login_form_form" accept-charset="utf-8" >
<div class="fs_errorblock fs_login_form_errorblock">    <span class="fs_error fs_login_form_error">Username is invalid.</span><br/>    <span class="fs_error fs_login_form_error">Password is a required field but was not provided.</span><br/></div><div id="fs_username_div" class="fs_formfieldline fs_text fs_username fs_has_errors ">
    <label class="fs_label fs_text_label " for="fs_login_form_username_input">Username</label>
    <input type="text" id="fs_login_form_username_input" class="fs_input fs_text_input fs_username_input " name="username" value="1" />
</div>

<div id="fs_password_div" class="fs_formfieldline fs_text fs_password fs_has_errors ">
    <label class="fs_label fs_text_label " for="fs_login_form_password_input">Password</label>
    <input type="password" id="fs_login_form_password_input" class="fs_input fs_text_input fs_password_input " name="password"/>
</div>

<div id="fs_submit_div" class="fs_formfieldline fs_trigger fs_submit  ">


    <input type="submit" id="fs_login_form_submit_input" class="fs_input fs_trigger_input fs_submit_input  " name="submit" value="Submit" />    

</div>

</form>
</div>

[% INCLUDE 'forms-list.txt' %]

@public,forms,perl

Under the palm tree: Under the palm tree (looking-at-forms-2.html)

Looking at forms (2 - Form::Factory)

Let's see how long I can keep this up.

Reminder of the plan + criteria

Form::Factory

Somewhat convoluted looking module, started in November 2009, last updated September 2010. It's Moose based, and made of many small modules for defining Controls, Features and bits of Interface. The main way to use it appears to be to define your own Action class, adding named controls as needed for the form.

I figured out how to make a simple form by reading Form::Factory, Form::Factory::Action then Form::Factory::Processor. No idea why this last one, but it has an Action example in it.

Pros

  • Can easily define collections of fields (Actions).
  • Creates compact HTML which seems to contain enough structure to be styled usefully.
  • Outputs labels for each control as requested.
  • Outputs elements for storing error messages.

Cons

  • Quite confusing documentation, which doesn't contain a full example in the synopsis
  • Docs are from the point of view of someone in the know (stashed? what?)
  • Error message elements are empty UL tags, this fails validation.
  • Relies on deprecated Moose API (Moose::Util::MetaRole API).
  • Rendered controls seem to appear in a random order when the entire form is rendered (I got Password, Username, Submit).

Sample code (created by me)

#!/usr/bin/perl

package MyApp::Action::Login;
use Form::Factory::Processor;

has_control username => {
    control => 'text',
    options => {
        label => 'Username',
    },
    features => {
        required => 1,
        length => {
            minimum => 2,
        },
    },
};

has_control password => {
    control => 'password',
    options => {
        label => 'Password',
    },
    features => {
        required => 1,
        length => {
            minimum => 2,
        },
    },
};

has_control submit => {
    control => 'button',
    options => {
        label => 'Submit',
    },
};


1;

package main;

use strict;
use warnings;

use Form::Factory;

my $interface = Form::Factory->new_interface('HTML');
my $action  = $interface->new_action('MyApp::Action::Login');

$action->render;

Sample output (newlines added by me)

<div id="password-wrapper" class="form widget wrapper password"></div>
<label id="password-label" class="form widget label password"for="password">Password<span class="form required">*</span></label>
<input id="password" class="form widget field password"value="" name="password" type="password"/>
<ul id="password-alerts" class="form widget alerts password"></ul>
<div id="username-wrapper" class="form widget wrapper text"></div>
<label id="username-label" class="form widget label text"for="username">Username<span class="form required">*</span></label>
<input id="username" class="form widget field text"value="" name="username" type="text"/>
<ul id="username-alerts" class="form widget alerts text"></ul>
<input id="submit" class="form widget field button"value="Submit" name="submit" type="submit"/>

Update (input validation)

Looks like I forgot to attempt input validation with this one, which claims to support it. My excuse is that my 30min test time was up.

According to the SYNOPSIS, one does something like this:

## data validation test (empty form):
$action->consume_and_clean_and_check_and_process( request => {} );
if(!$action->is_valid) {

    print "\n Errors :\n", $action->error_messages, "\n";
    print "\n Rendered: \n", $action->render, "\n";
}

## data validation test (all values):
$action->consume_and_clean_and_check_and_process( request => { 
    username => 'Fred',
    password => 'Bloggs',
                                                  } );
if($action->is_valid) {
    print "It worked!\n";
}

However this is what comes out:

 Errors :
 Form::Factory::Message=HASH(0x89c95f8)Form::Factory::Message=HASH(0x894db60)
 <div id="password-wrapper" class="form widget wrapper password"></div><label id="password-label" class="form widget label password"for="password">Password
 <span class="form required">*</span></label><input id="password" class="form widget field password"value="" name="password" type="password"/>
 <ul id="password-alerts" class="form widget alerts password"><li id="password-message-1" class="form widget message password error">The Password is required.</li></ul>
 <div id="username-wrapper" class="form widget wrapper text"></div><
 label id="username-label" class="form widget label text"for="username">Username
 <span class="form required">*</span></label><input id="username" class="form widget field text"value="" name="username" type="text"/>
 <ul id="username-alerts" class="form widget alerts text"><li id="username-message-1" class="form widget message text error">The Username is required.</li></ul>
 <input id="submit" class="form widget field button"value="Submit" name="submit" type="submit"/>
  Rendered:

  Can't locate object method "run" via package "MyApp::Action::Login" at /usr/src/perl/forms/perl5/lib/perl5/Form/Factory/Action.pm line 605.

So not quite sure what the error_messages method is about, but at least result is "invalid", and the re-rendered HTML contains error messages.

[% INCLUDE 'forms-list.txt' %]

@public,perl,html,forms

Under the palm tree: Under the palm tree (looking-at-forms.html)

Looking at forms (1 - Form::Maker)

There seem to be many, many, modules on CPAN which deal with the business of UI (usually HTML) forms in one way or another. I've often wondered why there are so many, and why it is that the earlier ones are either not found, or not used, by those who made the later ones.

I think I'll take a look at some, and see what they do. First up is Form::Maker, from Simon Cozens (and Kasei), just because it appears near the top of my search, and seems relatively simple.

For now I'm going to look into how to create a simple Login form with each module, and list what seem to be the pros and cons. This will be after 30mins (ish) of attempting to get a login form working, and reading the available documentation, so it may miss a lot (but so will users looking for tools!).

Form requirements

Controls

  • username - text input
  • password - password input
  • login button - submit button

Submission validation

Each input field should contain a value longer than two characters.

HTML validation

The HTML created should be valid, for instance it should not have repeating ID attributes.

Accessibility

It should be possible to output a label for each input field, using the for attribute and the input fields id.

Form::Maker

Builds on existing HTML::Element objects (which already have as_HTML methods) using a simple framework of Fields, Buttons, Renderers and Validators. See Form::Maker::Introduction for an overview of how to use it. The documentation is somewhat sparse otherwise.

Pros

  • Has a way to specify / predefine collections of fields as a named form
  • Contains a predefined Login form with username, password, submit and reset.
  • Is easily extensible, and behaviour is easily overridden.
  • Re-uses HTML::Element nicely, no need to provide its own rendering.

Cons

  • HTML output using the HTML renderer (default) may change with HTML::Element updates.
  • No actual validation or parsing of submitted data possible, just provides a way to store validation info per field.
  • Only pure form controls are created, no UI elements such as labels or layout.
  • No element IDs or classes are added to the output.
  • Outstanding bugs.

Sample code (created by me)

#!/usr/bin/env perl
## A Login form using Form::Maker (0.03)

use strict;
use warnings;

use Form::Maker;

print "Using built-in login form outline: \n";
my $login_form = Form::Maker->make('Form::Outline::Login');
print $login_form, "\n";

print "Using manual form creation: \n";
my $login_manual = Form::Maker->make();
$login_manual->add_fields(
    Form::Field::Text->new({ name => 'username' }),
    Form::Field::Password->new({ name => 'password' })
);
print $login_manual, "\n";

print "Adding validation to built-in form: \n";
$login_form->add_validation(username => 'Form::Validator::Email');
print $login_form, "\n";

print "Rendering form parts: \n";
print "Start:\n";
print $login_form->start;
print "Fieldset:\n";
print $login_form->fieldset;
print "Buttons:\n";
print $login_form->buttons;
print "End: \n";
print $login_form->end;

Sample code output (added)

Using built-in login form outline: 
<form>
<!-- begin fields -->
<input name="username" type="text" /><input name="password" type="password" />
<!-- end fields -->
<input name="submit" type="submit" /><input name="reset" type="reset" /></form>
Using manual form creation: 
<form>
<!-- begin fields -->
<input name="username" type="text" /><input name="password" type="password" />
<!-- end fields -->
<input name="submit" type="submit" /><input name="reset" type="reset" /></form>
Adding validation to built-in form: 
<form>
<!-- begin fields -->
<input id="field1" name="username" onblur="validate(&#39;field1&#39;, &#39;username&#39;, /^[\w\-\+\._]+\@[a-zA-Z0-9][-a-zA-Z0-9\.]*\.[a-zA-Z]+$/)" type="text" /><input name="password" type="password" />
<!-- end fields -->
<input name="submit" type="submit" /><input name="reset" type="reset" /></form>
Rendering form parts: 
Start:
<form>Fieldset:

<!-- begin fields -->
<input id="field2" name="username" onblur="validate(&#39;field2&#39;, &#39;username&#39;, /^[\w\-\+\._]+\@[a-zA-Z0-9][-a-zA-Z0-9\.]*\.[a-zA-Z]+$/)" type="text" /><input name="password" type="password" />
<!-- end fields -->
Buttons:
<input name="submit" type="submit" /><input name="reset" type="reset" />End: 
</form>

Update: Added suggested criteria about labels and ids from David

[% INCLUDE 'forms-list.txt' %]

@public,perl,html,forms

Under the palm tree: Under the palm tree (walking_the_thames_path_4.html)

Walking the Thames Path, Part 4

Our Serial/USB adaptor is refusing to work, so no route of the walk yet. I shouldn't let that stop me from writing it up at all though.

There being lots of lovely long weekends lately, and one of them being mine to plan, I decided to walk another chunk of the Thames Path. Previously, I'd been from Cricklade to Ashton Keynes, Ashton Keynes to Somerford Keynes and Somerford Keynes to the Source. Having run out of Path towards the source, it was time to walk some of the rest of it.

James volunteered to join me for this one, and suggested we walk the Path one direction, Castle Eaton to Cricklade, then he hang about in Cricklade and wait for me, while I went back and got the car.

We drove to Castle Eaton on the lovely sunny Friday morning, while certain royals were busy getting married, and no doubt many other people were partying in the streets (not that we saw any of them). Packing this time consisted of lunch for two, choc snacks, drinks, my laptop (the packable EEPC, though still not super light!) including it's broadband dongle, umbrellas (hey, they said it would rain!), and I forget what else.. Ah, my eReader, weighing not much at all.

Following the satnav, and then my map, we parked on Long Row, which is actually part of the Thames Path, as it travels through Castle Eaton. We followed the Thames Path, with its distinctive wooden acorn signs (who maintains all those!?) quite easily to Cricklade, past enormous fields of yellow oilseed rape (James: Ick, organised farming), and little off-cut areas of land which seem to be just wild (James: Yay!).. There are pictures, somewhere.

Reaching Cricklade, we crossed under the A419 (hooray! I'd expected we were going to have to cross over it), and into the edge of Cricklade, which is a lovely large leisure+sports field. Shortly after that we reached North Wall, which was where I started my original Cricklade-to-the-Source walk, several years earlier (yes, it's going to take me a while at this speed!). Here we stopped for lunch, in a little corner with benches, in commemoration of a milkman, who died on his rounds.

30 minutes later I was ready to set off on the way back, James had pondered the 2.5hours waiting for me to fetch the car and changed his mind, so we set off again together.

Not liking to retrace my exact steps, I'd decided previously that it looked possible (from the OS map, #169), that one could follow the disused canal on part of the way back.. Let me say now, this is a bad idea. There is indeed a nice walk from the Thames Path just east of the A419, up towards and along what is presumably the old canal.. However it does not meet up with the Thames Path again, at all. You end up in a field on the wrong side of it, and unless you can long jump or pole vault, no way to get across. After getting annoyed with ourselves a fair bit, tramping through brambles on the wrong side of the Thames, and James sinking his shoe up to the ankle in mud.. We retraced our steps back through the field, to the canal (which at that end actually contains water, and was in the process of having a lock repaired), and walked back to Castle Eaton (mostly) along the road.

All in all, we did 23,000 steps, according to my pedometer, around 15.1km or 9.4 miles.

I may post pictures later..

@diary,walking,public

Under the palm tree: Under the palm tree (window-managers-and-desktop-environments.html)

Window managers and desktop environments

Currently using: UDE / UWM

Likes

  • No panels, menu bars, icons etc cluttering up the screen

  • Simple mouse based handling of windows, menus, and actions; using a UI that only appears when needed.

  • Colours easily configurable

  • Window edge "snap-to" support (easy to align windows)

Dislikes

  • Little keyboard support (ALT+TAB etc would be handy)

  • Some software needs an icon tray.

What Window Manager / [Desktop environment]http://en.wikipedia.org/wiki/Desktop_environment)( do you use, and why? (If you don't know, "the default one with will also do as an answer)

@public,ude,uwn,window-managers

Under the palm tree: Under the palm tree (review-asus-701.html)

Durability review - Asus 701 "netbook" laptop

  • Gadget
    • Asus 701 laptop (4G)
  • Owned
    • 3 years
  • Modified (from new)
    • 16 Gb SDHC card
    • Extended battery
    • Mobile broadband dongle
    • Replaced OS
  • Usage
    • Daily - Terminal (SSH) and browser. Occasional video watching.
  • Verdict

    • 4.5/5
  • Review

    This laptop has occasionally frustrated and confused (what hardware doesn't?), but on the whole generally worked. I had originally set up a replacement fund over two years, but since it doesn't need replacing yet, spent some of that on a new gadget instead!

    I quite liked the Asus-ified Linux OS it arrived with, however the version of unionfs used was buggy. The bug manifests itself by applications inexplicably reporting disc full, when there is plenty of space left. What actually happens it that the system runs out of inodes, as deleted files leave ghost copies on the hidden partition. In addition upgrades to software would install in the user partition, not the hidden system partition, and generally get in the way.

    In spite of these errors, Asus managed to pack a lot of software into the 4Gb of space, a feat I've failed to replicate using "netbuntu" (now "netbook edition" of ubuntu itself). The addition of an extra SDHC card permanently mounted to /usr has solved this issue.

    The extended battery means I can leave it on/suspended all day and still be able to use it on the way home or in the evening.

Summary

I'd buy one of these again, maybe to replace this one if/when it dies. The Asus tablets are looking interesting though..

@public,review,laptop,asus,701

Under the palm tree: Under the palm tree (blog-with-comments.html)

Blog with comments

Well that was too easy. Why write my own commenting system when Disqus just appears to work?

@public,comments,disqus

Under the palm tree: Under the palm tree (2010-09-walking_the_thames_path_3.html)

on August 23rd, 2010

Walking the Thames Path, part 3

Time to write some shorter blog posts, rather than none at all.

Previously, on walking the Thames Path, I walked from Waterhays to Somerford Keynes. This time, I walked from Somerford Keynes to the Source.

Here's the route

And some pictures, via Flickr

@diary,walking,public,thames

Under the palm tree: Under the palm tree (dbic-sql-hackers-cont.html)

DBIx::Class for SQL hackers

Work in progress:

Introduction

Database structure (DDL)

INSERTing data

SELECTing data

@public,perl,ironman

Under the palm tree: Under the palm tree (dbix-class-for-sql-hackers-1.html)

DBIx::Class for SQL Hackers (1)

History

I volunteered (or was nudged) to apply to get the Enlightened Perl Organisation's grant to document/write-up some material on using DBIx::Class for SQL Hackers. The idea is to show folks that traditionally use plain DBI in their Perl code, how to do the same queries and much more, using DBIx::Class.

Plan

Still waiting for Matt to look at this, or say something about it. Will assume for now that its all fine.. ;)

  • User participation - TODO

I hope to post links to editable content via the EPO Wiki, helpfully both my blog/doc format and that of the Wiki are Markdown, so I can shunt things around easily.

  • Tutorial update/conversion - TODO

The DBIC Tutorial is a long-time work-in-progress which I really need to get into a state/place where others can use and contribute to it. Is it a good idea to convert to markdown and then add sections on "from SQL" to complete the grant?

Introduction (Why ORMs and DBIx::Class)

Almost every sizable Perl application these days needs a method of long term data storage. When the data needs to be easily retrieved as well as stored, we often use a database. Most databases can be comfortably accessed using SQL. Using the DBI module, and a DBD for the particular database, we can write SQL in our Perl code, and retrieve the results as arrays or hashes.

## Example
my $dbh = DBI->connect("dbi:SQLite:mydb.db");
my $sth = $dbh->select("SELECT artist.id, artist.name FROM artists");
$sth->execute;
my $results = $sth->fetchrow_arrayref({});

foreach my $row (@$results) {
  print $row->{name};
}

There are several things we can do to make this code more usable, for example store the database connect string (DSN) in a configuration file so that users of the code can use different databases without editing the code. We can also write a separate method or module for creating and returning the $dbh, so that we don't create a lot of db connections unnecessarily.

The part we can't do much about is the SQL in the code. We can move it around, put it in libraries, but it's still there, somewhere.

Why would you not want SQL in your Perl code? For a start, it's just a string to pass to the database interpreter, there is no syntax checking at the Perl compilation level. Thus it fails late, not early. Your editor will also not syntax check what it just sees as strings of text.

Modern Perl should also leverage OO where it can. DBI is a low level library that gets things right, but returns plain hashes and arrays, not objects.

Perl ORMs still use DBI underneath, extending it to catch coding errors early (names of columns, SQL clauses), and to return the results as objects containing the database values, which work just like any other Perl object.

Comments

@public,perl,dbix-class

Under the palm tree: Under the palm tree (london_perl_workshop_2009.html)

London Perl Workshop 2009

Several days later, what do I remember from LPW 2009?

Piers' talk on New beginnings. Interestingly, it's mostly the structure of the talk that I remember, not the content. Only a few days before, Simon Cozens had pointed out a post of Yuval's, and specifically praised it as a post with good structure: Show where there is a problem, solve that problem with a particular coding technique (or technology), dont waffle too much. Simon was so impressed he posted a meta-post on the subject.

Pier's talk was about why he left Perl for Ruby, and why he came back again. Perl has some "boilerplate" code that one typically needs when writing all methods. Instead of declaring the methods incoming arguments, one has to explicitly pull them off of the argument array, @_. Piers returned because the Perl community has been solving this and similar annoyances. In this case with Devel::Declare. And it's not even a "source filter"!

Problem; Solution; Done.

Another talk I still remember is Andy Wardley's on Template Toolkit 3. It's been many years in the making, much like Perl 6^WRakudo. It's looking pretty good however, and much evolved. I made myself some TODO notes as he was talking. Andy's talk style was the opposite of Piers', so I will have to ask him later; What problems does TT3 solve (better, more elegantly) that TT2 doesn't? Why would I use it over TT2? He also zhas some ambitious ideas to add a C library so that it can be used from other programming languages. This is another good way to spread good things that come from Perl.

That's it, most of the rest is a blur. Hallway chats, hot drinks, food, books. O'Reilly were there with a table as usual, with 35% off usual prices, so I bought "Beautiful Teams" to add to my collection of projecty books.

It was good to see friends again, to actually talk to people outside the confines of IRC. I came away somewhat more motivated to join in non-work projects than of late.

So much so that I've picked up on the EPO grants again. Having been voted on, decided, had money assigned and then listed.. They've been sitting there idle, waiting for someone to speak up and offer to complete them. Maybe its a lesson in time management, these things don't run themselves, mebbe volunteers need to be able to dedicate X amount of hours per day/week to help. Oops, minor side-rant, I'll go and write that proposal now, and assign myself time to work on it!

@diary, public, perl, lpw2009

Under the palm tree: Under the palm tree (ironman-update.html)

IronMan Update

No really, not just because I've not posted anything in.. a while. I got bored reading mst's mbox of ironman stuff, converting blog urls into atom/rss feeds, and typing the results into Plaggers yaml configuration file.

So I replaced all those manual entries with:

- module: Subscription::DBI
  config:
    schema_class: 'IronMan::Schema'
    connect_info: ['dbi:SQLite:/home/castaway/plagger/subscriptions.db']

And wrote one of these to convert the existing junk:

 #!/usr/bin/perl

 use strict;
 use warnings;
 use YAML 'LoadFile';
 use Data::Dumper;
 use Data::UUID;
 use IronMan::Schema;

 my $yamlfile = shift;
 my $dsn = shift;
 my $yaml_dump = LoadFile($yamlfile);

 my $schema = IronMan::Schema->connect($dsn);

 my ($sub_conf) = grep { $_->{module} eq 'Subscription::Config' } 
  @{ $yaml_dump->{plugins} };
 print Dumper($sub_conf);
 my $feeds = $sub_conf->{config}{feed};

 my $uuid = Data::UUID->new();
 foreach my $feed (@$feeds) {
     print "Feed: $feed->{url}\n";
     my $fdb = $schema->resultset('Feed')->find_or_new({ id => $uuid->create_str, %$feed}, { key => 'url' });
     if($fdb->in_storage) { 
         print "... already exists\n";
         next;
     }
     $fdb->insert;
 }

The twiddly part was setting up an app (form) for people to sign up, which now exists in the ironman repo, and runs on my local box, at the moment.

Thoughts of things to add:

  • Make the config for the app and the one for plagger use the same info for the database dsn?
  • Confirm signup by sending an email including a link back to the app using the guid of the signup.
  • Allow users to edit/remove their feeds using the guid/email key.
  • ??
  • Profit

Someone also needs to make the thing prettier!

Btw to install, symlink the css and image dirs from "plagger/assets/plugins/Publish-PagedPlanet/default/static" to the catalyst "root" dir.

@public,perl,ironman

Under the palm tree: Under the palm tree (making-a-difference.html)

Making a difference

I failed in the end, to Reproduce my URI problem, but that hasn't deterred me from helping to improve random parts of CPAN in general.

Recently I've been struggling with Crypt::RSA. It's API is not all that complicated, however a small typo caused me quite a bit of grief. A typo in my own code, misspelling one of the argument names for the verify function.

I had this:

$rsa->verify(
  Messsage => $mess,
  Key => $key,
  Signature => $signature
);

Spot the problem? It took me ages, and some perl -d debugging, to realiase that Crypt::RSA happily attempts to verify an empty (undef) message. It didn't use warnings, or check it's arguments, so my extra "s" in message wasn't noticed.

I reported the problem to the author, using CPAN's RT installation, which is available to all modules, as Bug #46577.

The author responded rapidly, understood my problem, improved his code, and uploaded a new release to CPAN. You can see the fixes using the CPAN diff tool: Diff from Crypt-RSA-1.98 to Crypt-RSA-1.99. Yay!

The second (actually chronologically first) fix was related to my mumble about XML::Atom::SimpleFeed, on a previous blog entry. Aristotle got in touch with me to say "That shouldn't happen, is all sane" .. But eventually James proved him wrong with a patch including a test case, and a new release of that appeared too.

@public,perl,crypt-rsa,xml-atom-simplefeed

Under the palm tree: Under the palm tree (are-we-going-to-need-it.html)

Are we going to need it?

Odd flash of inspiration while washing up (yay for mindless activity) and also listening to a TED talk.

I often grumble at Moose. Though not actually at Moose itself, just at seemingly everyone and everything jumping on the bandwagon. I also want to use Reaction, cos Matt wrote/writes it, and from the outside it feels like a great idea.

But part of me doesn't think so. I think I know why now. Maybe I've been reading too many articles on Agile and so on. Specifically the principles of DoTheSimplestThingThatCouldPossiblyWork, and YouAintGonnaNeedIt.

Reaction is a complex piece of software, built on top of two other pieces of complex software, Catalyst, and Moose. That's a whole stack of code. As people jokingly say "It installs half of CPAN". Don't get me wrong, software re-use is good and if I actually needed a piece of software that does all the many things that these three do, I'd use them.

But I don't. Applications (and websites) don't often start complex, they gather complexity over time.

For one or two web pages, maybe even ten, I can write them by hand. Ok so I probably copy the header and footer after a few. When I come to write the eleventh one, this becomes tedious. So instead I could use something like Template Toolkit's ttree, to produce a bunch of pages out of some templates. At some point I find myself needing something dynamic, or the concept of users, then I may go fetch Catalyst.

And that's as far as I've got. Which step makes me need Reaction? The one where 90% of my website is interactive? I've not written too many of those, but the few I have, Catalyst has sufficed.

You're probably thinking now, that I just don't write the same kind of applications/websites as others do. Thats possibly true.

But again, Agile ways of doing things suggest we write the minimal amount of code we can get away with, to imlement the currently required features. That we don't plan ahead and add more code for potential features later, they will be re-thought anyway. That we release early, and often, and gather feedback for improvement, and then add new features.

Not forgetting to refactor. To upgrade, to replace the entire framework if needed.

To be practical

I think, what I'm looking for is, a guide for newcomers to explain and help ths progression. How to upgrade your site or code, from a few pages, to some dynamic bits, to a full blown interactive site. Or even not, not every site wants or needs to go that far. Not all code needs to be able to use email.

There seem to exist many articles on how to write this complex code, but not enough that explain how to come to the conclusion that you need it.

Maybe this is also why there are still many many more people writing about how to do CGI scripts in Perl, than how to use Moose. The transition is missing.

(With thanks to Elizabeth Gilbert on nurturing creativity)

Right, now I'm off to move the fledgling DBIx::Class website from some hand written pages to ttree.

@public,programming,perl,thinking