Real-Life Metaphors for Web Design

July 11th, 2011 No comments

When I started on thinking on how I was to build my all new awesome website, I pretty quickly decided that all I need is a private beta sign up screen. Now all that was left was to style it up with some CSS. My first instinct was to see what the big boys are using (Apple, Google, Facebook), then it was to turn to the up and coming companies from various awards crunchise2010, Webby Awards or TheNextWeb. Maybe turn to some expert advice in the field Smashing Magazine – web design trends 2010. Plenty of gradients, shinny buttons, 3D effects and the like. I want something more!

So let’s step back a little. In real life when we want to paint a wall white, we try everything to make the finish as smooth as possible. We would hate anyone to notice a brush stroke, an uneven paint roller mark, where we cut in with a hand brush or any unevenness were we masked for a 2 tone finish. On the web on the other hand if we want to paint a screen white we just set it to white .body {background-color: #FFFFFF;} and absolute perfection.


The thing is we don’t want perfection, it is so perfect that it does not look right. Change the colour a little and adding a gradient makes it much better immediately. This is where all the 3D like effects have come from. Mimicking lighting and other effects to give a sense of real-ness, roundness, to entice the person to press that button. Maybe a bit of a glimmer of light across the button to remind the user that
they may want to press it.

gradient below on modern browsers

So if we have taken the 3D paradigm across from the real world to web design, what else can we bring across. What other real-life metaphor can be used in web design?

I started to look around at the web and found some interesting articles but mostly about existing paradigms. The interest is also more in interface metaphor and how users will operate an application. Others like Smashing magazine – web design trends 2010 real life metaphors and css3 adaptation looked like almost the answer but around existing web sites and analysing which real life metaphors are at work. Usually for practical reasons (navigability, discoverability, usability) and not only for aesthetics although these things can go hand in hand. Promising is this paper on The Role of Metaphor in Interaction Design – Dan Saffer (PDF) where the author discusses the use of the galaxy – depicting data interrelation and geological stratification depicting data stacked over time.

 

So what is an example of a real-life metaphor for web design? One that may not have been used yet? Well I argue that they are all around us, question is how can we apply them to web design and ultimately are they a good idea.

Lets take the theatre as an example. There is the curtain and the facade for the viewers, and then there is the reality of the backstage.

 

The same could be done for a web site. The front end of the web site pristine and the admin interface with on purpose less finish and in fact many of the underlying structure (ropes) uncovered so that the operator can see what the effect of pulling a rope is. This is kind of what we already get. The idea would be to extend that and highlight it, make it even more obvious.

 

I haven’t found the secret sauce of the “next best” real-life metaphor for web design but I am planning on putting forward some real-life metaphors and seeing how they could be applied to web design. I expect most will be failures and simply an analysis of the grimy world we live in. I am hoping that inside there will be a gem and it will be worth waiting for.

Categories: design Tags: , , ,

Open Social at Lonely Planet – GTUG

November 5th, 2009 No comments

Yesterday I attended the GTUG (Google Technology Users Group) in Melbourne for a talk by Julian Doherty on Open Social at Lonely Planet. Basically Lonely Planet have created their own community site using OpenSocial technology. They are using Shindig as the OpenSocial container but have built all the logic behind it in a Ruby on Rails application. Some interesting points in the presentation were

  • OAuth is handy but LP had problems implementing it at times, they decided to drop it for some of their own data access
  • A lot of their data like hotel locations they have opened up as a basic HTTP call just to make it dead simple to use and mash up
  • “Testing is a bitch” with developers needing to run their own Shindig container out of eclipse and a copy of the RoR app to get things up and running but ultimately a lot of things only come about with integration tests.
  • Getting things up is easy and uses a lot of dynamic HTML, JavaScript coding with apps being wrapped in some XML to be understood by the OpenSocial container
  • Quick demo of LonelyPlanet’s wave app trippy
  • Lonely Planet have found the OpenSocial platform very useful for internal development
  • Lonely Planet wants to encourage adoption and development of their OpenSocial platform through their first ever hack day

Lonely Planet is running a hack day for their OpenSocial API in conjunction with the GovHack in Melbourne this coming weekend. There are still spots so go and register at http://lplabs.com/ . Hope to see you there.

Steve Hayes – Covey 7 habits applied to developers

November 5th, 2009 1 comment

My notes from Steve Hayes presentation at agile australia 2009.

  • individuals know all problems in project
  • communications need to improve -> People need to speak
  • problems and solutions these days are more complex
  • develop individuals is ket to agle team success
  • people motivation
    • good video of ted talk “Dan Pink

    • basic reward and recognition will not work
    • ie. if you do this you will get this DOES NOT WORK!!!
    • what to do?
    • Autonomy – self direction
    • Mastery – get better at what we do
    • Purpose – part of something large
  • Autonomy example – Atlassian FedEx days, hack days to deliver in 24 hours
    • things covered under Covey’s 7 Habits
    • use proactive language
    • be proactive to enlarge circle of influence
    • have the end in mind (what do you want to be rememberred for)
    • self awareness and re-script messages in your head
    • have personal mission statement
    • make sure company mission statement agrees with your own
    • have a team mission statement
  • put first things first
    • things in “important” and “not urgent” are strategic and should be worked on most
  • mentioned emotional bank account
    • ultimately led to story about Steve Hayes standing on table and yelling at LonelyPlanet workers (after 6 weeks of filling emotional bank account). This was in regard to no one doing anything about a broken build.
    • the team rule was back out broken build immediatley
  • talking stick
    • don’t give up the stick till everhone “understands” (not necessarily agrees) your points
    • ultimate test of this is to have some one else talk back what you mean in their own words.
  • renew – recover
    • sustainable production capability of individual and company
Categories: agile Tags: , , ,

12 Failure Modes – Jean Tabaka keynote at Agile Australia 2009

November 5th, 2009 1 comment

Here are some of my notes around the keynote at this years Agile Australia 2009 conference. The video of this is available here http://vimeo.com/7160163.

Note: the items below are failure modes, the comments under each item are
around things that need to be looked at to prevent them

  1. checkbook commitments
    1. need engagement
    2. takes time
    3. will requre organisational changes
    4. different metrics
  2. follow the plan
    1. ask team what are best practices
    2. knowledge creating companie
    3. PMO should not be enforcers but enablers
  3. Ineffective use of retrospection
    1. have them
    2. don’t ignore ideas
    3. take action
  4. Ignore need for infrastructure
  5. lack of full planing participation
    1. may look too expensive to get everyone together
    2. keep everyone involved and engaged
    3. need right people to get commitment
    4. waiting for decisions (because people are not around) is a waste.
    5. Must have everyone around.
    6. full team in room brings about more insight!
    7. have had up to 100 people in a 2 day startup
    8. Unavailable product owner OR too many product owners
      1. have commitment with team
      2. multiple stakeholders are ok
    9. bad scrum masters
      1. master of process
      2. NOT! command and control
      3. they are facilitators
      4. command & control lowers peoples morale and IQ (there is a study to prove this)
    10. not have agile evangalist on location
      1. especially for distributed teams
    11. team lacking authority
      1. team needs to have control of destiny
    12. testing not pulled forward
      1. testing culture
      2. invest in infrastructure (One example where Dev/QA/CI/Perf environments cost over $2M)
      3. don’t try to push code (in the aim to optimise developer utilisation)
    13. performance appraisals
      1. do 360 degree feedbach
      2. ask “how are you as an individuall working in a team”
      3. ask “what did you do to imporve the team?”
    14. reverting to form
      1. change is hard
      2. revert to waterfall

    Call to action:

    • choose one of these failure modes
    • create an action plan for your own team
    • do a self retrospective in 30 days to see how you went

    Appraisals:

    • do self appraisals and hold people to what they can bring to the team

    When to give up (on agile):

    • do a 6 month retrospective
    • give yourself 2 years to scale

    Tech lead and scrum master

    • enable team
    • take self ego and turn it to how great your team is
    • otherwise what are you not doing for the team?

    XML parsing with groovy on the command line

    October 8th, 2009 2 comments

    To continue with the command line programming theme, I will move over to Groovy. One of the strengths of Groovy, and something I have been doing a lot of lately, is XML processing. Groovy has 2 standard libraries for parsing XML, XmlSlurper and XmlParser. In this post I will look at using XmlSlurper as a pseudo grep tool for looking up values in XML.

    Now grep is great for finding instances of a string in files. Problem with XML is that every string is wrapped by ugly XML tags and a lot of XML documents are not neatly split over new lines. Also the requirement may want to find 2 relevant tags that relate to each other in a given XML structure but which may be many lines apart. Also there could be tags named the same way at different levels of the XML, so intelligent parsing is the only way to go.

    For an example I will use the following XML:

    <listings>
      <listing>
        <agency>
          <name>Obera Associates</name>
          <suburb>MELBOURNE</suburb>
          <post-code>3000</post-code>
        </agency>
        <price>$4,500</price>
        <address>
          <suburb>RICHMOND</suburb>
          <street>Victoria Street</street>
          <state>Vitoria</state>
          <post-code>3121</post-code>
        </address>
      </listing>
    </listings>

    Each file can have many listings, and there could be many files. To find out if all the “listings” for RICHOMOND 3121 have been uploaded to the listings ingest-a-nator, a crude test may be to double check how many such suburb/postcode instances there were in the original files. As already mentioned grep would be a pain to use especially as there are 2 suburb/postcodes for each listing node and you are only interested in one. So here is the Groovy solution.

    $ groovy -e 'dir = new File("."); dir.eachFileMatch(~".*xml") { file -> \
        doc = new XmlSlurper().parse(file); doc.listing.address.each { address -> \
             println address."post-code".toString() + address.state \
        } \
    }'

    One gotcha that I found was that to print 2 nodes in a row, a + sign is not enough. As they are of type
    groovy.util.slurpersupport.NodeChildren
    , at least the first needs to be changed to a string with the toString() call.

    To expand this to use larger files more memory may have to be given to the executing process, to give 1GB this would mean adding
    JAVA_OPTS="-Xmx1024M"
    like so:

    $ JAVA_OPTS="-Xmx1024M" \
    groovy -e 'dir = new File("."); dir.eachFileMatch(~".*xml") { file -> \
        doc = new XmlSlurper().parse(file); doc.listing.address.each { address -> \
            println address."post-code".toString() + address.state\
        } \
    }' | sort | uniq -c

    this also includes a pipe to unix favorites sort and uniq -c to give a histogram like count of each suburb/postcode combination.

    I was going to suggest that if the XML is not perfect (like if it is HTML) or may have some badly encoded characters that are not valid UTF-8 and which would return an error similar to:

    org.xml.sax.SAXParseException: An invalid XML character (Unicode: 0x1c)
    was found in the element content of the document.

    a more lenient parser like TagSoup could be used. In my case this worked but unfortunately in this case this silently fails like so

    $ groovy -e 'println new XmlSlurper().parseText("""
    <ls><l><a><n>micsar</n></a><adr><suburb>RICHMOND</suburb></adr></l></ls>
    """).l.adr.suburb'
    RICHMOND
    $ CLASSPATH=tagsoup-1.2.jar \
    groovy -e 'println new XmlSlurper(new org.ccil.cowan.tagsoup.Parser()).parseText("""
    <ls><l><a><n>micsar</n></a><adr><suburb>RICHMOND</suburb></adr></l></ls>
    """).l.adr.suburb'
     
    $ CLASSPATH=tagsoup-1.2.jar \
    groovy -e 'println new XmlSlurper(new org.ccil.cowan.tagsoup.Parser()).parseText("""
    <ls><l><a><n>micsar</n></a><adr><suburb>RICHMOND</suburb></adr></l></ls>
    """)'
    micsarRICHMOND

    It is the 2nd scenario above that seems not to work when using TagSoup, maybe some combination with Groovy? not sure for the moment.

    ruby from the command line, taking it too far

    September 24th, 2009 No comments

    In my last post I looked at using -e to run scripting languages directly from the command line. Just as I was not sure what would make ruby a good candidate for an example, a colleague from work scoffed at some image manipulation suggestion I made which I claimed would take only half an hour to code. If something takes 30 minutes to code then it surely can be run directly from the command line?

    The problem is such, given a company logo of a particular aspect ration, create a new logo, with a different aspect ratio and fill out the logo with the predominant color (most used color) from the original logo. Of course there are other ways around this like setting transparent backgrounds and default to something neutral like white but in this case I suggested that using the predominant color of the logo would maintain the branding of the company logo.

    A search on the internet for “color quantization”, “color count” and “color histogram” quickly directed me to ImageMagick and in this case RMagick for ruby bindings to the library. More info can be found at http://www.imagemagick.org/RMagick/doc/

    As a starting point I simply required the library, instantiated an image and returned the width and height of it

    ruby -e 'require "rubygems"; require "RMagick"; \
    img = Magick::ImageList.new("filename.gif"); puts img.columns; puts img.rows'
    160
    30

    Ok having to require rubygens and RMagick as well as using the package name Magick starts making the command line a little bit unwieldily. Considering up to this moment I had not done anything, it was going to get worse. First some code to return the histogram of colors and how many pixels use it, sorted to get the main color, then one which is used by the most pixels

    main_color = img.color_histogram.sort{|a,b| b[1] <=> a[1]}.firtst

    then create a new larger image in this case 2 x width and 6 x height, fill it’s background with the main color, create a drawing object, create an image composite using the original image and place it so that it will be centered on the new larger image, finally draw the composite on the new larger image and write to disk

    l_img = Image.new(img.columns*2, img.rows*6) {
      self.background_color = main_color[0]
    };
    gc = Magick::Draw.new;
    gc.composite((l_img.columns - img.columns)/2,(l_img.rows - img.rows)/2,0,0,img);
    gc.draw(l_img);
    l_img.write("large_file.gif")

    to make the work worth while, wrap it in a find to look for all gif’s in a given directory tree, and create new large_<filename>.gif image

    ruby -e ' \
    require "rubygems"; \
    require "find"; \
    require "RMagick"; \
    include Magick; \
    Find.find("images") {|file| \
      if file =~ /gif$/ then \
        img = ImageList.new(file); \
        main_color = img.color_histogram.sort{|a,b| b[1] <=> a[1]}.first; \
        l_img = Image.new(img.columns*2, img.rows*6) {self.background_color = main_color[0]}; \
        gc = Magick::Draw.new; \
        gc.composite((l_img.columns-img.columns)/2,(l_img.rows-img.rows)/2,0,0,img);  \
        gc.draw(l_img); \
        l_img.write(File.join(File.dirname(file), "large_"+File.basename(file))) \
      end \
    }'

    or if you want to just run this and use some images directly from the internet try this

    ruby -e 'require "rubygems"; require "RMagick"; include Magick; \
    img = ImageList.new("http://cdn-0.nflximg.com/us/layout/signup/950/header/netflix_logo.gif"); \
    main_color = img.color_histogram.sort{|a,b| b[1] <=> a[1]}.first; \
    l_img = Image.new(img.columns*2, img.rows*6){self.background_color = main_color[0]}; \
    gc = Magick::Draw.new; \
    gc.composite((l_img.columns-img.columns)/2,(l_img.rows-img.rows)/2,0,0,img); \
    gc.draw(l_img); img.write("original.gif"); l_img.write("large.gif")'

    and the results are

    Ok so in this case I am taking the command line programming a little too far. I did manage to do the whole task above without ever opening up a text editor but I had some clever command line tricks up my sleeve which I will cover in a future post. Still it is good to know that such power is available from the command line.

    -e to execute from command line

    September 23rd, 2009 2 comments

    One of the useful tools in the unix world is the command line. Often you may have a request like

    give me a list of all the unique Agencies specified in all the XML files in a given directory tree where an agency is shown in an element <agency id="IJKXYZ">

    this can be easily achived (for pretty printed XML documents, each element on it’s own line) with a variety of unix tools like so

    find . *xml | xargs grep agency.id $1 | awk -F '"' '{print $2}' | sort | uniq -c

    find all the *.xml files from the current directory, for this list execute grep using xargs and grep for the agency.id pattern (the ‘.’ matches any character, in this case a space, ‘ ‘) use awk, delimiting on double quotes, to print out the ID’s, then sort them and run them through uniq with -c flag to get the count of occurrences for every agency ID. Yes, there are no doubt other ways of doing this, and different sort’s of optimisations but this is just the way my brain thinks and wire’s together these commands.

    As already mentioned, this will only work if the XML is pretty printed and not if all the white space has been removed, there may also be many cases where the request is more complicated but it feels like opening up a text editor to write a program should not be necessary. This is where the -e option of many scripting languages comes in, it lets you run the language from the command line.

    The basic hello world in a couple of such languages

    groovy -e "println 'hi'"
    perl -e 'print "hi\n"'
    ruby -e 'puts "hi\n"'
    jruby -e 'puts "hi\n"'

    As a more complex example you may want to find out the day of the week for a given date. This can be done like so

    $ groovy -e 'println Date.parse("MM/dd/yyyy", "12/13/1974").format("EEEE")'
    Friday

    of course again there may be a unix command out there which is more concise or which the user may be more familiar with, in which case great, use that instead. If on the other hand it is a situation where the code solution comes to you immediately then why not use it? If this is the way your brain is wired, and you are more competent at using your programming language of choice then why go reading man pages when you can do this simply with a scripting language and the -e flag.

    Counter to that argument I had a snippet in PowerShell, the Microsoft Windows shell language for finding the day for a given date and it goes like this

    PS> (get-date "12/13/1974").DayOfWeek

    Very concise indeed.

    Of course the real power of scripting languages is when you use them in conjunction with pipes and unix tools. In this case I want a histogram of how many files I modify for each day of the week for a given directory.

    groovy -e 'new File(".").eachFile{file -> println new Date(file.lastModified()).format("EEEE")}' \
     | sort | uniq -c | sort -rn
     
    19 Monday
    15 Tuesday
    10 Wednesday
    5 Friday
    4 Thursday

    Given that it was a work directory then the work day’s only is understandable. Also as I am running this on a Wednesday morning that may skew the results of “last modified” if I have modified most files. Still it seems that Thursday and Friday are the low parts of the week.

    Feel free to add how you use scripting languages from the command line in the comments. Do be careful cutting and pasting any code samples and make sure you know what you are doing prior to doing so.

    I will look at a few common examples I use regularly in future posts and I hope to see more people using scripting languages from the command line to solve their problems.

    confusing “Enterprise” open source

    August 2nd, 2009 4 comments

    MySQL is the free and open source database of choice but you would be hard pressed to find the free download link on the front page. You need to follow the download and the modern naming of “community edition” to lead you in the right direction. Now having seen the transformation over some time means you generally have an idea of where to find it. In the end it is only a database and one package is all you requrie, maybe to find the documentation download as well.

    I have also followed along the transformation of Pentaho for BI and reporting. Again this was a lot cleare in the past in terms of finding the downloads and also understanding what each product does.  With names like:

    All that said and done I was most impressed by an inital download of Mondrian and the Foodmart database for OLAP slicing and dicing of data through a simple jPivot web interface. For basic data analysis this is still my prefered method, especially when giving it to Business Analysts who may not be too comfortable with SQL queries. But from the Pentaho page how would you even expect to find these tools? confusing?

    During some investigation around new tools, I thought I would take a look at Jasper reports and someone mentioned the JBoss stack of tools. Both are well known names but I must confess I have never used either of the products. First for Jasper.

    Going to the site http://www.jaspersoft.com/ brings up a very professional looking site. Now in this case you really need to look hard to find a link to the community site. In this case there is a whole site dedicated to the open source part of the business http://jasperforge.org/ . Either way you are stuck with a choice between

    • JasperReports
    • iReport
    • JasperServer
    • JasperAnalysis
    • JasperETL
    • JasperSoft

    Ok so it is mostly in the names but which do I need to solve which problem? which play well together? where to get started and what is possible? I am stuck in the middle of having a JasperServer up and running but with no reports and the installation document talks of an installer script which will not run under Mac OSX and no manual override to bring in the reports. I am sure I will work it out at some stage but for the moment it would be much easier to give up and move onto the next candidate.

    Finally I was recommended some tools from the JBoss stable. In this case there  is a community link is there and leads the user to http://www.jboss.org/community/index.jspa . In this case there are a mutlitude of tools but in now way does the site help a user work out that for a given problem  Teiid is an option and in fact the right answer. In this case Teiid is a data virtualization tool that lets many data sources be represented as a single JDBC connection but try working that out when your problem is simply disperate data sources.

    Categories: Uncategorized Tags:

    Groovy script to find country origin of IP

    February 8th, 2009 No comments

    After listening to grails podcast #77, I was interested in some of the code snippets available around the site for the gr8conf “Conference dedicated to Groovy, Grails & Griffon and other Great technologies”. The direct link is http://www.gr8conf.org/blog/2009/02/02/5#comments. I was looking at code around utilising some of the webservicex.net webs services and in particular Geo IP Service for “Finding the visitors country by IP“. The example given was for a Grails service. I was interested to run it as a script.

    Seems simple, cut, paste, run … class could not be run! Ok so I am trying it as a script from a command line. I need to either create a main or easier still just invoke the method from a command line groovy script

    groovy -e "gips = new GeoIPService(); println gips.getCountryByContext()"
     
    Caught: groovy.lang.MissingPropertyException: No such property: log for class: GeoIPService
    at GeoIPService.getProperty(GeoIPService.groovy)
    at GeoIPService.getCountryByContext(GeoIPService.groovy:9)
    at script_from_command_line.run(script_from_command_line:1)
    at script_from_command_line.main(script_from_command_line)

    Ok so I need a logger library. To keep things simple I try java.util.logging.Logger and the method Logger.getAnonymousLogger() . Unfortunately this led to an exception along the lines of

    Caught: groovy.lang.MissingMethodException: No signature of method: java.util.logging.Logger.warn() is applicable for argument types: (java.lang.String, groovy.lang.MissingMethodException) ...

    java.util.logging.Logger is not compatible with the log4j logger used in grails which allows passing of a String and an Exception to the warn. Who needs logging anyway, this is a script right? next step was for me to uncomment the log statements and the script ran. Yeah! output was the disappointing statement

    null

    What? where did that come from? sure there are return null’s in the code returned from exception code but the exception is … silent :( … as I have commented out the log statements. Now in desperation I would just change them to println statements and be done with it but why not stay with the “logging” best of breed methodology. Back to trying to find a version of log4j lying around. In the end I found one in my maven home ~/.m2 . I suppose this raises the question should I be using maven or other build/dependency tool for building this simple learning script? is that too much for a script? TDD says not it ain’t. Just to make sure it runs I tried

    import org.apache.log4j.*
     
    CLASSPATH=$CLASSPATH:~/.m2/repository/log4j/log4j/1.2.14/log4j-1.2.14.jar groovy -e 'gips = new GeoIPService(); println gips.getCountryByContext()'


    null

    damn, and this time with logging statements. Maybe it is time to put this into an IDE and get some suggestions as to what is going on. I give up on the TDD and start out putting print log statements through the code. I find the bug

    def response = "http://www.webservicex.net/geoipservice.asmx/"+method.toURL().text

    the toURL() method is only acting on part of the string, the method string, which fails to be a proper URL so it fails, but silently as it is in a method which throws exception and is only reported by a log.warn and by default my logging is set to the highest I presume log.fatal? now how to change the level of the logger? ok I should have guessed setLevel(org.apache.log4j.Level level) now where to set it? I do not have a constructor everything is pretty much static so I suppose I can just use a static block like so

    static def log = Logger.getRootLogger()
    static{
        log.setLevel(Level.INFO)
    }

    now I get the full pleasure of a groovy style exception

    java.net.MalformedURLException: no protocol: GetGeoIPContext
    at java.net.URL.&lt;init&gt;(URL.java:567)
    at java.net.URL.&lt;init&gt;(URL.java:464)
    at java.net.URL.&lt;init&gt;(URL.java:413)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.toURL(DefaultGroovyMethods.java:2479)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.codehaus.groovy.runtime.metaclass.ReflectionMetaMethod.invoke(ReflectionMetaMethod.java:51)
    at org.codehaus.groovy.runtime.metaclass.NewInstanceMetaMethod.invoke(NewInstanceMetaMethod.java:54)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:912)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:756)
    at org.codehaus.groovy.runtime.InvokerHelper.invokePojoMethod(InvokerHelper.java:766)
    at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:754)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:170)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethod0(ScriptBytecodeAdapter.java:198)
    at GeoIPService.getCountryByUrl(GeoIPService.groovy:33)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:912)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnCurrentN(ScriptBytecodeAdapter.java:78)
    at GeoIPService.getCountryByContext(GeoIPService.groovy:14)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:912)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:756)
    at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:778)
    at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:758)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:170)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethod0(ScriptBytecodeAdapter.java:198)
    at script_from_command_line.run(script_from_command_line:1)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:912)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:756)
    at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:778)
    at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:758)
    at org.codehaus.groovy.runtime.InvokerHelper.runScript(InvokerHelper.java:401)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
    at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1105)
    at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:749)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:170)
    at script_from_command_line.main(script_from_command_line)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
    at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1105)
    at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:749)
    at groovy.lang.GroovyShell.runMainOrTestOrRunnable(GroovyShell.java:244)
    at groovy.lang.GroovyShell.run(GroovyShell.java:453)
    at groovy.lang.GroovyShell.run(GroovyShell.java:433)
    at groovy.lang.GroovyShell.run(GroovyShell.java:160)
    at groovy.ui.GroovyMain.processOnce(GroovyMain.java:496)
    at groovy.ui.GroovyMain.run(GroovyMain.java:308)
    at groovy.ui.GroovyMain.process(GroovyMain.java:294)
    at groovy.ui.GroovyMain.processArgs(GroovyMain.java:111)
    at groovy.ui.GroovyMain.main(GroovyMain.java:92)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:101)
    at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:130)

    as opposed to what java would give me (here demonstrated with a groovy script)

    groovy -e "println 'http://'+'GetGeoIPContext'.toURL()"
    Caught: java.net.MalformedURLException: no protocol: GetGeoIPContext
    at script_from_command_line.run(script_from_command_line:1)
    at script_from_command_line.main(script_from_command_line)

    which lets me take it one step further and confirm

    groovy -e "println new String('http://'+'GetGeoIPContext').toURL()"
    http://GetGeoIPContext

    and back to the original,

    def response = new String("http://www.webservicex.net/geoipservice.asmx/"+method).toURL().text

    and as a complete script (heavily borrowing from the original Finding a users country by IP)

    import org.apache.log4j.*
     
    class GeoIPService {
     
        static def log  = Logger.getRootLogger()
        static{
            log.setLevel(Level.INFO)
        }
     
        def getCountryByContext() {
            try {
                return getCountryByUrl("GetGeoIPContext")
            } catch (Exception e) {
                log.warn "Exception in GeoIP service", e
                return null
            }
        }
     
        def getCountryByIp(String ipAddress) {
            try {
                return getCountryByUrl("GetGeoIP?IPaddress=" + ipAddress)
            } catch (Exception e) {
                log.warn "Exception in GeoIP service", e
                return null
            }
        }
     
        def getCountryByUrl(String method) throws Exception {
            def response = new String("http://www.webservicex.net/geoipservice.asmx/"+method).toURL().text
            def slurp = new XmlSlurper()
            def geoip = slurp.parseText(response)
            if (geoip.ReturnCode == 1) {
                if (geoip?.CountryName?.text() == "RESERVED") {
                    return null
                } else {
                    def country = geoip.CountryName.text()
                    return country != null ? country[0].toUpperCase() + country[1..-1].toLowerCase() : null
                }
            } else {
                throw new Exception(geoip.ReturnCodeDetails.text())
            }
        }
        static void main(args) {
            def gisp = new GeoIPService()
            println args ? gisp.getCountryByIp(args[0]) : gisp.getCountryByContext()
        }
    }

    now for TDD and dependency management of log4j libraries and the like … maybe another day ;)

    How to “stick” several PDF’s into 1 document

    February 7th, 2009 No comments

    I had some paperwork that I needed to scan and email out for my son’s kinder. Scanning was easy, even with some OCR, the scanner automatically created 4 separate PDF documents. Now to bring them into 1 document, hmm? Let’s try google.

    Sure every man and his dog is suggesting methods under searches like “merge pdf documents” from how to articles that say to click on the “combine” menu item, which seems not to apply to my Mac all the way through to a bunch of shareware/freeware/paid software. But how do you know which is best? which one is safe? and which one is worth the purchase? for something this small nothing. I don’t want to go through the pain of working this out, trying some software, only to find out it will water mark the result or something.

    Why not write it myself? I am playing around with the groovy programming language at the moment so why not try that? I took a look, “groovy pdf library” of course with a name like that I found a lot of groovy “really cool” PDFs. As Groovy works seemlesslly with Java and the JVM, next stop was searching for “java pdf library” a few other libraries made the front page but everything seemed to point to iText. It looks pretty comprehensive, there is even an “iText in action” book available. I start looking at the documentation and decide it is too much. I just want to merge 4 PDFs into 1 and I don’t want to use any more then 4 lines!

    Time to have a look at the root of my scripting knowledge, Perl. Soon enough I found PDF::Reuse and its prDoc command. The result is

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    #!/usr/bin/perl
    use warnings;
    use strict;
    use PDF::Reuse;
     
    prFile("kinderNewsletter.pdf");
     
    prDoc('kinderScan_01.pdf');
    prDoc('kinderScan_02.pdf');
    prDoc('kinderScan_03.pdf');
    prDoc('kinderScan_04.pdf');
     
    prEnd();

    I later also found that there is some unix command line tool pdftk which would have done the same but I would need to install that and work out how to use it, maybe next time.