Code, Compose, Bike, Brew

…though not necessarily in that order

Interacting With a reCAPTCHA in Selenium

| Comments

This one was a bit of a headscratcher for me so I thought I’d share it here in case it helps anyone else.

I’m building web application which allows users to register for membership in a local community group, it’s web facing so it needs some pretty decent bot prevention to stop us getting scam submissions. After looking at a few products I decided to use Google’s reCAPTCHA. The app is written in Groovy and based on Spring Boot so I’ve used mkopylec’s excellent recaptcha-spring-boot-starter project to integrate the recaptcha validation in to Spring.

Everything was coming together nicely until I tried to add the recaptcha submission to my Selenium tests, the issue I had arises from the fact that the reCAPTCHA is (very sensibly) loaded in to an iframe which is sourced from a different domain. I presume this is done to deliberately make it hard for bots to interact with the recaptcha as browsers won’t allow it due to same-origin policy, for the same reason it makes automated browser driven testing just that little bit harder to achieve.

However after a bit of thought I discovered that it was possible to get this working. I’m using Spock, Geb and Selenium in this project so will explain my implementation in terms of these technologies.

The first step is to define a Page class which models the checkbox. I initially tried to do this using the CSS selectors which would have been appropriate if I was accessing the iframe within the context o the parent page, however I quickly realised this wasn’t possible. Instead the trick is to refer to it using the appropriate CSS selectors as it exists inside the iframe:

import geb.Page

class CaptchaFrame extends Page {
  static content = {
    checkbox { $(".recaptcha-checkbox-checkmark") }

Once we’ve got this the next step is to identify which index the iframe has in the page being tested. Unfortunately we’re unable to load the iframe its name as Google recently removed it, so we have to refer to it using its 0 based index. In my case its the first (and only) iframe on the page hence we find it using index 0. In addition to this we need to tell Geb that we’re accessing our CaptchaFrame class within the context of the specified iframe, rather than trying to find it in the parent page. To do this we can use Geb’s withFrame method.

withFrame(0, CaptchaFrame) {

Now we can put the above in to a simple test to demonstrate it working. This is what it looks like demonstrated as a simple Spock test:

def "can click the reCAPTCHA and submit the signup form"() {
        to SignupPage // This is a Geb Page which models my signup form (not shown here).
        withFrame(0, CaptchaFrame) { }
        at SignupCompletePage

Hope that helps someone, happy testing!


Conditionally Collecting Objects in Groovy

| Comments

Groovy’s Collections collect() method is great for iterating a collection and generating a new collection containing transformed results. For example:

import groovy.transform.Immutable

// Define a 'User' class
class User {
  String firstName
  String lastName
  boolean administrator

// Create a couple of users
def users = [new User("Edd", "Grant", true), new User("Jon", "Doe", false)]

// Use collect() to generate a list of their full names
def fullNames = users.collect() { user ->
  "${user.firstName} ${user.lastName}"

assert ["Edd Grant", "Jon Doe"] == fullNames

Sometimes, however, what we really want is something more akin to ‘collect where some criteria is met’ and collect() doesn’t provide a mechanism for doing this. This is because this functionality is provided by a different method, Groovy implements the findResults method which collects only non-null results. This allows us to filter the source collection really easily. For example:

import groovy.transform.Immutable

// Define a 'User' class
class User {
  String firstName
  String lastName
  boolean administrator

// Create a couple of users
def edd = new User("Edd", "Grant", true)
def users = [edd, new User("Jon", "Doe", false)]

// Use findResults() to generate a list of administrators
def administrators = users.findResults() { user ->
  user.administrator ? user : null

assert [edd] == administrators

collect() has been around since v1.8.5 whereas findResults() is a more recent addition, being introduced in v2.2.0.

Running Logitech Media Server in Docker

| Comments

I recently signed up for Spotify’s 30 day free trial, having such convenient access to so much music was great, but when it came to an end and I was faced with the prospect of paying for my first month I was reminded just how little Spotify actually pays musicians per play. Despite being a software engineer in a very digital age I have always preferred to buy music on a physical artefact on Vinyl or CD. I prefer to have the artefact itself as I find it gives me a different listening experience when compared to digital media, I tend to give the music more time and attention if I sit down and listen to the CD or record vs just bunging some ear phones in and playing some tunes on my phone. Where possible I also prefer to buy from the artist or their label direct to make sure that they are adequately compensated for their work so that they can earn a living and can carry on making the music that I love. Finally having the physical CD also gives me the ability to control how I store the music in my digital library e.g. what software and format I use to rip the physical media.

So having said no to Spotify I found myself missing the ability to choose from a wide range of Music when on the go, so I thought I’d set up Logitech Media Server (LMS) (formally known as ‘Squeezeserver’ or ‘Slimserver’) on my Fitlet-h. I’m sharing my notes on how I went about this in case it’s useful to anyone.


I wanted to try running the Squeezeserver in Docker, a quick search on the Docker Hub showed that there is already a Docker image which does just that. So let’s see if we can run it locally first of all:

mkdir -p /tmp/squeezebox # This is just a temporary directory in which the Squeezeserver will store its state
export MY_MUSIC_DIRECTORY=/Data/Music # This is the path to my music directory on my local machine
docker run -d \
           -p 9000:9000 \
           -p 9090:9090 \
           -p 3483:3483 \
           -p 3483:3483/udp \
           -v /tmp/squeesezerver/state:/srv/squeezebox \
           -v ${MY_MUSIC_DIRECTORY}:/srv/music \

Note: the docker image name is specified incorrectly on the Docker Hub page as larsks/logitech/media-server. It is in fact larsks/logitech-media-server

Let’s see if it’s running:

➜  ~ sudo docker ps                   
CONTAINER ID        IMAGE                          COMMAND             CREATED              STATUS              PORTS                                                                                            NAMES
9a8f50ea19c5        larsks/logitech-media-server   "/"    About a minute ago   Up About a minute>3483/tcp,>9000/tcp,>9090/tcp,>3483/udp   amazing_mccarthy

So far so good. Opening a browser at brought up the LMS interface and everything worked perfectly.


So we’ve got a Docker image which we think is good enough to use, the next step is to orchestrate the provisioning of this container on to the host that we want to run LMS from.

The outline of what we want to do is something like:

  • Install Docker
  • Pull the image
  • Start the image, exposing the relevant ports and mounting the appropriate paths etc
  • Do a bit of extra configuration to ensure the container starts on boot etc.

I’m a big fan of Ansible and it seemed like a natural fit here, so that’s what I’ve used.

Installing Docker

A quick check of Ansible Galaxy brought back quite a few Docker roles. I had a quick scan of them and settled on angstwad.docker_ubuntu which seems to be very well written is very comprehensive in that it does all of the required post-installation configuration required in order to get Docker to work.

To pull and install the role locally I did this:

ansible-galaxy install angstwad.docker_ubuntu

Writing the Playbook

Next task was to write a basic playbook to do the necessary bits and pieces, here’s a very basic play which covers all of the steps required.

# Install logitech-media-server
- hosts: fitlet
    logitech_media_server_base_directory: /Data/logitech-media-server

    - file:
      become: true
      tags: logitech

    - { role: angstwad.docker_ubuntu, become: true, tags: logitech}

    - docker_container:
        name: logitech-media-server
        image: larsks/logitech-media-server
        published_ports: ["3483:3483", "9000:9000", "9090:9090"]
              - /Data/Music:/srv/music
              - ":/srv/squeezebox"
        restart_policy: unless-stopped
      become: true
      tags: logitech

Run the Playbook

Now we’ve got our playbook it’s time to run it against the target host, in my case the magic incantation is:

ansible-playbook -i inventories/dev/dev.ini fitlet.yml -vv --tags logitech

Having provisioned the host we should now be able to acess the LMS webapp on port 9000 of the IP address that it has bound to, in my case this was the IP on eth0 which gave me a URL of

Secure it with a username and password

Important note: The security that comes with LMS is terrible, it runs over http only and uses basic auth, which as I’m sure you know is a completely insecure combination. In its defense, I would imagine that exposing one’s music collection over the internet was not a key design consideration. However given that we’re just playing here I’ll continue to detail the steps I followed to make it accessible to me from anywhere, but please, if you set this up yourself remember that the username and password you use here should not be considered secure.

The security menu is buried several levels down in the UI, to access it navigate through the following:

  • Settings button (Bottom right hand corner)
  • Advanced tab
  • Click the twisty on the left hand side (which probably says ‘Formatting’)
  • Select ‘Security’
  • Configure the page appropriately for your needs.

Making it accessible from anywhere

Now that we’ve ‘secured’ the UI we can make it accessible from the outside world, the exact steps required will vary from setup to setup but a simple setup probably won’t be a million miles away from the following:

Export ports

Expose the following ports and protocols on your WAN interface:

  • 3484 tcp (for connections from players) and udp (for SlimProto commands)
  • 9000 tcp (for http access to the webapp)
  • 9090 tcp (for telnet *shudder* access to the CLI)

Configure Dynamic DNS (Optional)

Unless you have a static IP address you’ll probably want to configure Dynamic DNS to point a particular DNS name to your WAN interface e.g. Once you’ve done this you should be able to access the LMS webapp at the DNS name you’ve configured e.g.

Get an App

The final step I took was to configure my Android phone as a LMS ‘player’, this typically requires 2 apps: The first app talks the LMS protocols and registers your device as a ‘player’. The 2nd app provides a UI of your music collection to you and provides the ‘controls’ e.g. play/ pause/ volume/ search etc.

I use Squeezeplayer as the controller app and Squeezer as the player app, I find this combination of apps to work really well. I have also tried the official Logitech Squeezebox Controller app in the past but couldn’t get it working reliably as it seems to require your local LMS server to be on a local network, which of course in this case is not the case. I have also tried Squeeze Commander but recent versions seems to have stopped working for me and I found its UI quite unintuitive.

I don’t use Apple devices so I’ve no idea what apps are available here but if you do then let me know and I’ll happily add some notes here.

Future tweaks:

Functionally speaking the above works really well, I have access to my entire music collection anywhere I have my phone and can stream over $g or Wireless depending on what’s available. However the security issue really irks me, so perhaps a next step would be to see if it’s possible to put LMS behind something which will do TLS termination (perhaps nginx)… I’d be interested to hear from anyone who has done any securing or hardening of LMS so drop me a line in the comments if you have and don’t mind sharing the details of your implementation.

That’s it for this entry, I hope this helps someone achieve portability of their music library, please drop me a line in the comments if you spot any inaccuracies or have any questions or comments.



A Song a Day - Day 5 - Elbow - the Stops

| Comments

A couple of friends have nominated me on FaceBook to post a song every day for seven days, and nominate someone each day to do the same. This is Day 4.

This is The Stops by Elbow, definitely one of my favourite Elbow tunes. I love the imagery that Mr Garvey conjures up in this one, not many do folk do words better than he in my opinion.

A Song a Day - Day 4 - Squarepusher - Beep Street

| Comments

A couple of friends have nominated me on FaceBook to post a song every day for seven days, and nominate someone each day to do the same. This is Day 4.

Today I’m giving you ‘Beep Street’ by Squarepusher. Why? Because it’s one of the most amazing tunes I’ve ever heard and because nobody will ever be able to program beats like Mr Tom Jenkinson can!

Get yer lugoles wrapped around this one!

A Song a Day - Day 3 - Lewis Parker - Communications (Feat. Jehst)

| Comments

A couple of friends have nominated me on FaceBook to post a song every day for seven days, and nominate someone each day to do the same. This is Day 3.

Today I’m going with some UK Hip-Hop. This is Lewis Parker - Communications (Feat. Jehst) from the album ‘It’s All Happening Now’ (The Ancients Series Three)

Lewis Parker and Jehst are two of my favourite producers/ MCs and have contributed a lot to the development of Hip Hop in the UK. Jehst’s verse on this track reminds me of my own childhood spending probably hundreds of hours starting at Notator/ Cubase on an old Atari ST and later a PC learning how to make beats and music.

A Song a Day - Day 2 - Cat Stevens - Where Do the Children Play

| Comments

A couple of friends have nominated me on FaceBook to post a song every day for seven days, and nominate someone each day to do the same. This is Day 2.

Today I’m sharing ‘Where do the children play’ by Cat Stevens (now known as Yusuf Islam), it’s from his album ‘Tea for the Tillerman’ which is one of my favourite albums.

The song was written in 1970 but I think the questions he asks are every bit as relevant today. As a dad of 3 it inspires me to think about and try to positively influence the environment that we’re building for our kids’ generation.

This song also makes me think of family, in particular my Mum, as it was through her record collection that I was introduced to Cat Stevens. Thanks Mum!

A Song a Day - Day 1 - Nuyorican Soul - I Am the Black Gold of the Sun (4 Hero Remix)

| Comments


A couple of friends have nominated me on FaceBook to post a piece of music which means something to me each day for 7 days. I haven’t written anything here in an awfully long time so I thought I’d post them here too.

It’s amazing what a simple nomination can do, my mind has immediately gone in to overdrive trying to figure out how to whittle down all the music I love to just 7 songs… I’m going to need to make a list!

This is Day 1. I’m starting with Nuyorican Soul: I am the black gold of the sun (4 Hero Remix). It’s a hugely positive tune and never fails to cheer me up if I’m down. I also love the fact that it puts together computers and real instruments so seamlessly. My favourite thing though is that the drop is four and a half minutes in! That’s four and a half minutes of Nuyourican goodness followed by another four or so of some of Luke Parkhouse’s finest beats all put together with Marc Mac and Dego’s wizardy!

Vagrant-roller Now Updated for Roller 5

| Comments

Last year I put together a little GitHub project called vagrant-roller which provisioned an Apache Roller VM with very little effort. The initial version of the project provisioned a Roller v4 VM but there were a couple of issues getting the latest version of Roller (v5) to work.

I have had a bit of spare time recently and managed to get everything working so you can now provision either v4 or v5 as you prefer. I have also re-written the provisioning mechanism to use Ansible as I find it to be a much more capable and productive tool than Puppet, which I was previously using.

Any questions etc welcome either on the vagrant-roller project itself or as comments here (see below).



Alpine 3552, 3353, 3354 Car Amplifier Manuals

| Comments

Waaaay back in 2005 I posted on a car audio forum asking if anyone had the manual for an Alpine 3553 amplifier. I had the amp but no manual and couldn’t figure out the power ratings and whether it was stable at 2 ohms. Unfortunately Alpine themselves didn’t seem to have it in their manual database.

Some kind soul sent me what they had of the 3553 manual along with the 3552 and 3554 manuals, from this I managed to figure out the information I needed. Every month or so I now get an email or two from people who happen upon my post asking me if I’ve still got the manuals, just goes to show how, after all these years, the 3553 is still alive and kicking!

So, for anyone who’s after these manuals here are the files as I received them:

Alpine 3552 Manual

Alpine 3553 Manual - Single Page only I’m afraid

Alpine 3554 Manual

Note: By posting these here I am not claiming any right of ownership of the files, which of course belong to Alpine.

@Alpine: If there’s a problem with me hosting these files please let me know and I’ll duly remove them (and please add them to your manual Database so people can get to them!).