This year's TADHack was different to the others for me, because I had several months to prepare both the hack, and trip. That was the plan. Naturally, with so much time to prepare meant that other things took priority, and I'd prepared almost nothing. But I'm getting ahead of myself. Let me rewind.
After last year, there was no way I was going to miss a chance to compete in TADHack again, after learning so much and meeting so many new people. Last year, I turned up on the Saturday morning with no team, no technology in mind, and no ideas. For those keeping score, that's 0 out of 3.
This year, my Similarly Geeky partner-in-crime (@lily_2point0) was interested in attending so I'd already got a team. Looking at the sponsors list we favoured Tropo. Then, we looked at the locations and thought that Berlin would be good to visit. This in turn inspired us to think of the problems that can occur when you don't plan a trip properly. Consequently we had an idea.
3 out of 3.
Alas, I was busy looking for work at the time so although I thought I had an opportunity to prepare, I didn't. I'd also realized that there might be a couple of different solutions to the problem of "people not preparing properly for a trip", each requiring a different technology. So, I messaged founder and event organizer, Alan Quayle (@Alan_Quayle), if two submissions were permissible. They were! Not only that, but only two developers had submitted multiple projects in previous years. This gave me the impetus to join that illustrious elite. But, it didn't give me any more time, so all I could prepare was a login account for the two favoured technologies.
If you want the tl;dr version then I was part of two teams, making two hacks. One was called "Backup Call" and provided a method to store essential personal data, such as phone numbers, bank details, and passport numbers. It is useful for staying in contact after theft or loss. It is created in a web interface, but access via the touch tones on a phone.
The second was "Vodka", which is a test and development platform to expedite work on the Tropo platform.Here's a video of me demonstrating them...
For those wanting a longer version, it is this:
Fast forward to the Saturday morning of the hackathon, and the first problem showed itself pretty quickly. I'd forgotten my passwords! Oh, the irony of wanting to write a trip preparation app and not being prepared! Worse still, I'd forgotten the same password previously, so I had setup a second Tropo account! I did manage to recall one of my accounts and its associated password by trying all possible combinations, but it wasn't a particularly illustrious start.
At least the idea was becoming well-formed at this point: an emergency app where the user entered their personal data in the web interface (such as their contacts, passport numbers, and bank details) so they could retrieve them using the DTMF touch tones from a phone. Any phone. So, should someone have their phone lost or stolen, they could call a fixed emergency number to recover their contacts and emergency data. Lily (@lily_2point0) would make the front end using a database wrapper I'd written (in 13 lines!), while I built the telecomm elements in two different APIs so I could compare and contrast their approaches.
The database abstraction wrapper, by the way, was this.
class VDB { public function __construct($table) { $this->folder = "db/$table/"; @mkdir($this->folder, 0777, true); } public function doesRecordExist($id) { return file_exists($this->folder . $id); } public function getRecord($id) { return json_decode(file_get_contents($this->folder . $id)); } public function setRecord($id, $data) { file_put_contents($this->folder . $id, json_encode($data)); } }
It's quicker and less troublesome than a real database, and one of my (many) secrets about getting a lot of stuff done quickly and dirtily during a hackathon!
The first versions worked pretty well, as each data field was funnelled to the Tropo say method, via the database, in quick succession. It went so well that I added more clever bits than intended. For example, Google calendar gives you a URL which allows any user (even if not logged in) to view the calendar, or download it in iCal format. So, I found an ical parser, and added the ability for the person to dial into their calendar with a land-line, and have their appointments read out to them. Already, I felt this was a cool idea!
Not only that, but I'd added the hotel's address in the calendar. I figured I could then pull the last line of the address to get the country and use postcoder.com to convert into an ISO code... and feed this into emergencynumberapi.com which can tell the user of the emergency numbers (for Police, Fire, and so on) in that country. Of course, this is information which a visitor should be prepared with. But if not, we had a solution.
Unfortunately, there were bugs en route. For a start, the spelling of Germany in my calendar was 'Germny' so the emergency numbers never appeared. I was logging the results, but was word blind to my mistake. So much so that I got fed up and just wrote my own API! In doing so my bug was obvious. Stupid, even. But instead of switching back I took this as an opportunity to do something interesting. I added a Levenshtein distance computation to my API, so that even misspelt names would work!
In finding this meant that there was lots of server-side logging. One of the logging commands, however, was accidentally writing its information to the output stream, not the error stream. This meant the data returned to Tropo was not valid JSON, so it stopped working. Seemingly randomly and at will. Not that I knew this was the cause, so I contacted the support staff on IRC, and they used the ID to find information about my (broken) app but they reported information from one account as I was fixing the details on the other (remember my double accounts?) so this took a little while to track down and fix. Another stupid bug. My positivity was dented slightly, to say the least!
But onwards and upwards!
At least the front end was looking good and working well.
The next task was to speak the users address book. Why? Well, because in this age of mobile phones we didn't believe that everyone memorizes phone numbers any more, and the lack of a phone means a lack of contact. So, I added an option of having the numbers read out via text-to-speech, or having the current call forwarded to the user. Being abroad meant my own phone wouldn't work, so I used a SIP phone. But it didn't work, either. After working through every combination of address and protocol specifier, it seemed that Tropo would either ring once and fail, or ring for a minute and fail... neither was described in the documentation when asking for a timeout of 1000 seconds. It turned out that Tropo had issues talking with sip2sip.info addresses. So, after another ten minutes of setting up a second account, I verified the problem and moved on.
Another issue was with the API in use. I was using PHP, as opposed to my usual workhorse of Ruby, for a change of perspective. It turns out there were two ways of using some of the API methods: one was documented, and one worked. And they weren't the same one! Despite being referenced on the Tropo site as a suitable API they (naturally) take no responsibility for it, since it's a community library. However, I hadn't realized the issues, and had to dig into the methods to find the discrepancies.
While musing on third party libraries, the ical library also converted period and commas into \\. and \\, automagically. Normally this wouldn't be an issue, but when fed to the Tropo say API it breaks. A simple bug, solved with a simple string replace, but it uncovered a more esoteric edge case in the Tropo API.
The final option on the wish list concerned global emergencies. Losing your phone is stressful, but being in a location with a flood is more so. Particularly for friends and relatives who are unable to connect with you, either because the lines are blocked due to extra traffic, being rerouted for the emergency services, or even (as in the first use case) your phone has been lost or stolen. So we implemented a feature to allow the user to record an outgoing message, which could then be sent onto their most important contacts. This was easier than expected as I needed only to set-up a callback URL that would be passed the recording data (as a WAV) from the Tropo serve.
(Technically speaking, the final thing Lily & I agreed on was the name, Backup Call!)
That mostly sums up the telecomms component of Backup Call, helping solve peoples problems of being unprepared. But interleaved in this story is another...
Part-way through development, I had an idea. (I don't remember exactly when, but it was somewhere near the start.) The turn-around time between each successive code drop was quite extensive, maybe several minutes. This is because the time taken for the text-to-speech API to read out each option wasn't fast, and any errors in the fourth step required us to work through all three previous steps. Similarly, the time taken to use the touch tones wasn't the fastest either. They're certainly not something that can be copied-and-pasted into the application.
So, I wrote a fake Tropo class. It had the same methods as the normal PHP Tropo class, but instead of generating XML packets and making REST requests it would call traditional console methods like print and gets. In this way I could more quickly work through the menu systems I was creating.
I utilised the downtime between front-end integration, waiting for inspiration, dealing with support, and so on to add little bits to the testing and debugging wrapper class(es) I was building. After beer, gin, and pizza we went home, but I was still now convinced there was something of interest here. Instead of submitting two versions of 'Emergency', each with a different API, I would submit this testing wrapper as a project in its own right. (Which still got me my “2 in 1 at TADHack” achievement, and resulted in another project for my github that might convince recruiters that I'm worth hiring!)
BTW, being a telecomms hackathon, the gin was SIPsmith. Geddit? Who says the Germans don't have a sense of humour!
There's still scope to increase the library by allowing an input stream which isn't the keyboard, but a text file. In fact, I think this is its strongest point. By doing this you can have a true TDD approach to the IVR and specify every input and (expected) output to do a lot of very quick tests.
P.S. If you're wondering about the name, it comes as an extension of the original library I'd found to handle the REST calls – called Lemonade. Similarly, when faking a Tropo request to the Vodka platform, I used the term 'Tonic' as a fake voice channel.
There were a few things left on the Backup Call TODO list.
Adding playback and forwarding functionality for non-emergency contacts, since the current version only reads those contacts with a 'star'. Such work shouldn't be difficult.
Importing your contacts directly from your phone. Internally I believe there's a fairly standard format for this data, although the user flow of uploading that from the SIM or SD card might present some interesting challenges.
Finally, adding virtual numbers for permanent forwarding. This, I think, is where the big win will come. If, instead of giving you my number, I give you a virtual number then any call made to me will be automatically forwarded through Tropo and the Backup Call server. Consequently, I can switch my number into “I've lost my phone” mode, or “There's a hurricane here but I'm safe” mode. It can even playback a pre-recorded message. In either case, it helps with the problem of worried friends trying to call and getting no answer at all, for whatever reason. (Especially since it never need interact with my real phone.)
Vodka has a few bugs left, but nothing too painful. I hope! It's also something that might be portable by other platforms.
We won! Both prizes. In fact, every team in Berlin succeeded in winning the global prize in their category for their hacks! I would say that there's something in the water, but we were drinking German beer, so maybe that's the reason!
On a personal level I succeeded in becoming one of only 3 people to have submitted 2 hacks over the course of a TADHack weekend. And all because - or maybe despite - I didn't follow my own project's advise... and prepare!
Tropo.com The sponsor's technology.
Vodka on github A test and development platform for Tropo - The Berlin local winner.
Backup Call on github The Tropo global winner.
Country name to ISO2 converter I added a new feature to my '0day' API wrapper, as it's literally a five minute job to create a new API!
Find Germny Note the (intentional) spelling mistake.
ICS Parser Used to process the Google calendar data.
Emergencynumberapi.com Determine the police and ambulence numbers from an ISO2 country code.
TBD