Ramblings on code, startups, and everything in between
It’s that time of the year that Setfive has retreated to warmer environments to focus on internal team building, communication, and management. I write this post as we fly past Florida on JetBlue to the Caymans and wanted to reflect on the struggle it has been to get to this point.
As we all know, weather in the Northeast the past month or so has not been very forgiving to anyone, especially airlines. Noone controls the weather so only best efforts can be made to work around it. Before I dive into some thoughts on how airlines may be able to improve the experience for their passengers, I want to give a up-to-date accounting of everything that has occurred thus far to show what I am drawing some of these suggestions from, I’ll try to keep this somewhat short and concise.
Thursday I realize that the majority of our team has a 45 minute layover in Newark which is already tight and with the recent weather unlikely to be enough time. I call up United Airlines and ask if we can move the group up to a flight that leaves on Sunday (the same day as originally planned) but about an hour earlier. I’m told it would be 200 a person if we wanted to make the change, but there is plenty of room. I suggest that we’re trying to just make sure we make our flight and United only has one flight out of Newark to the Caymans on Sunday so if we missed it, we’d be stuck. I’m assured we’ll be there in plenty of time.
Saturday I decide to tweet “@united we have developers flying down tmrw morn. w/45 min layover, there is an earlier flight to have 1.5hr layover, can move them up” to see if I have better luck. United is very responsive and quickly look through options via direct messages. The earlier flight is full and all other routes don’t look promising. I understand they can’t make seats appear and understand we’re hoping for the best. Saturday night at 9:55PM we get a notification from United our flight is delayed 20 minutes due to “Crew availability”.
We arrive Sunday morning and talk with an United service rep to see what we can do about our situation. We’re told that we still may make the connection with only 10 minutes now at the layover with our delay, but they have already double booked us on a backup flight to fly to Miami, stay the night, and fly out Monday morning to the Caymans. After another delay sets us back now an hour, we go back to the same rep and see if there are other routes we can take, like directly to Miami and catch a flight that night to the Caymans. Unfortunately all the seats straight there are full, but the rep says we have our Miami flight on “backup” and that we may be able to catch the last flight to the Caymans and to just board our delayed Newark flight.
We arrive in Newark and talk to a service rep to get our backup boarding passes. We find out that there is no booking for us at all, in fact the system couldn’t find any good alternatives so the automatic rebooking didn’t even work. At this point the rep in Newark says the rep in Boston never booked us on anything. Newark rep proceeds to try to get us on a later Miami flight, can’t get us confirmed, and then says we’ll rebook you tomorrow morning on a flight with an hour layover which you have to re-checkin for another airline and then will get to the Caymans. I brought up the last time the hour layover didn’t work so hot, but the rep said she wasn’t concerned we could always get another flight to the caymans later that day or the next day.
At this point we decide that the Jetblue direct flight from JFK is worth the extra money to have less of not arriving for another day at the Caymans. I call up United and try to get any sort of refund but am told our Boston-Newark flight was the majority of the cost so no refund would be given. We try to get our luggage from United which they say wait for at least an hour and it should come out on that belt. 2 hours later we find out that 2 of the 3 bags we’re waiting for are now Miami bound and they’ll try to figure it out in Miami what to do with them.
Looking back on this we all thought the biggest problem was the lack of communication and accountability. The group of us all felt that if there had been clear communication (or in some cases any communication) that much of the stress and problems would have been mitigated. The other problem is each time we did anything, we started having to double check that it was actually done.
Here are a some suggestions for possible improvements that I think may help all airlines (and possibly other industries) work better with their customers. Some of these may already exist at some airlines or not be feasible to do in some situations; I just wanted to get some thoughts out and see what people think.
I understand our troubles with the airline getting down are no more important or different than the thousands of other’s that had problems. I’m more interested in seeing what ways we can try to improve the experience overall for both customers and airlines alike. I know running a business is never as simple as it seems and some of these suggestions may be implemented behind the scenes. However, there is always room for improvement.
What do you think? How can airlines improve the customer relations experience?
Posted In: General
A couple of months ago I ran across the lob.com API on ProgrammableWeb and was intrigued. One of the features of the Lob API is that it allows you to programmatically send postcards by just providing address details and images. I’d been itching to find a use case for the API since who doesn’t love physical mail? Following a few beers on a snow day an idea struck – why not send Valentines day postcards with lob!
Overall, the idea was straightforward, allow users to compose a message on one of a few available templates, enter some address details, and then send their postcard. Given the short timeline and relatively few features, the main factors behind picking an implementation stack were something “lightweight” that I was already comfortable with. After drawing up some options I decided to use Silex since it’s based on Symfony components, it’s lightweight, and we’ve used it in the past.
The main UI for the cards ended up looking like:
One of the “fun” features I did implement was that instead of using a big header background image, I used a HTML5 Canvas to render frames from Beauty and the Beast as the page’s background.
Anyway, we might bring this back next year so be on the lookout around Valentines day.
Recently I was working on a project where part of it was doing data exports. Exports on the surface are quick and easy – query the database, put it into the export format, send it over to the user. However, as a data set grows, exports become more complicated. Now processing it in real time no longer works as it takes too long or too much memory to export. This is why I’ll almost always use a background process (notified via Gearman) to process the data and notify the user when the export is ready for download. On separate background threads you can have different memory limits and not worry about a request timeout. I suggest trying to not use Doctrine’s objects for the export, but get the query back in array format (via getArrayResult). Doctrine objects are great to work with, but expensive in terms of time to populate and memory usage; if you don’t need the object graph results in array format are much quicker and smaller memory wise.
On this specific export I was exporting an entity which had a foreign key to another table that needed to be in the export. I didn’t want to create a join over the entire data set as it was unnecessary. For example, a project which has a created by user as a relation. If I simply did the following:
I’d end up with an array which had all the project columns except any that are defined as a foreign key. This means in my export I couldn’t output the “Created by user id” as it wasn’t included in the array. It turns out that Doctrine already has this exact situation accounted for. To include the FK columns you need to set a hint on the query to include meta columns to true. The updated query code would look similar to:
Now you can include the foreign key columns without doing an joins on a query that returns an array result set.
Because sometimes it’s just fun to make something absurd: http://taken.setfive.com/.
If you aren’t familiar, the Taken movie series (http://www.imdb.com/title/tt0936501/) is a set of ridiculous action dramas that have acquired a strong cult following over the years (deservedly or not). All of the movies basically involve someone close to a retired CIA agent, played by Liam Neeson, being “Taken” and Neeson subsequently raining hell over anyone involved in wronging him. As a result of the movie series, Liam Neeson has made a formidable run at Kiefer Sutherland’s title of today’s Chuck Norris. Neeson, who plays the main character in the movie employs his signature throat punch in place of Norris’ roundhouse kick.
Our team seems to share a fondness for laughable action movies and actually took the afternoon off to watch the latest Taken 3 film when it debuted a couple weeks ago. With a little bit of vacation downtime prior to the debut and the urge to develop a web application as preposterous as the film series, we came up with the idea of creating Taken Audio MadLibs (http://taken.setfive.com/). For those of you not familiar MadLibs (http://en.wikipedia.org/wiki/Mad_Libs) is a phrasal template word game where one player prompts others for a list of words to substitute for blanks in a story, before reading the – often comical or nonsensical – story aloud.
So our take on the MadLibs program works something like this:
-There are four different “story lines” which all involve dialog between Liam Neesons character and a second character
-Neesons lines are actual lines from the Taken movies
-The other character’s lines are transformed into audio clips by Google’s unofficial Text To Speech (TTS) API and are based on the words you enter into a simple webform
-The lines are combined together into a hilarious back and forth dialog between Neeson and your character
Technically, there really isn’t too much “magic” going on with the program. It’s built on the Symfony2 framework and employs a simple one page parallax scrolling design for the web forms. Once the user submits the web form for their story we send it off to the controller where the user entered words are inserted into a set of templated lines. These text lines are then sent off to the Google TTS API which returns an .mp3 audio file with the audio representation of the text. We then splice together the Google TTS mp3 lines with the Taken audio files that we have stored on the server and combine into one audio file. The audio file is returned to the UI in the form of a HTML5 audio tag where the user can play or download the file. We also provide the user with the option of emailing the audio file to a friend if they would like to.
There were two problems that we ran into worth mentioning for those of you playing around with Google’s TTS api or combining multiple audio files of different formats.
1. Google’s TTS API only accepts 100 characters per call so you’ll have to split a given line or sentence into 100 character chunks and then combine the multiple mp3s back into one. This isn’t too difficult to do but worth mentioning if you ever plan to play around with this API.
2. We did run into a bit of trouble trying to combine the .mp3 files that Google returned with the Taken audio .mp3 files we got from (http://www.soundboard.com/sb/Taken_sound_clips). The problem is that the frame rate of the Google .mp3 files is different than the Taken files so when we tried to combine them into one some audio players would not render the resulting file. To get around these issues we took the following steps the combine and massage the audio files via a couple different server-side Linux-based Audio programs (avconv and oggCat):
Anyways, if you haven’t checked out the final program yet it can be seen here http://taken.setfive.com/ and if you have any questions, comments, or feedback feel free to leave them below.
Posted In: Tips n' Tricks
A couple of months ago I decided to use Scala with the Play Framework for a Bitcoin related project. The decision to use Play was motivated primarily by the goal of implementing a “pure” Bitcoin application, leveraging bitcoinj to interact with the Bitcoin network as opposed to a third party service. Overall, everything was pretty straightforward but one thing that stuck out was how the Play framework handles parsing JSON.
Coming from loosely typed PHP I knew that handling serializing and unserializing of JSON data was going to be different but Play’s approach is a completely new paradigm. If you use Play with Scala, you can handle parsing JSON input back into objects using Scala’s Parser Combinators syntax. I’m going to butcher this description so check the wikipedia entry but the idea is that parser combinators let you “build up” increasingly complex parsers by combining functions that recognize smaller inputs. If you’ve taken a compilers or programming language class, Scala’s parser combinators end up looking a lot like Backus–Naur Form for the input you want to recognize.
Anyway in an effort to learn Scala a bit better and take Parser Combinators for a spin I decided to build out a small project. What I ended up building is a really simple implementation of a Turtle Graphics system. You basically feed it a series of “turtle” commands and it’ll move the “turtle” around on a Swing window drawing some graphics.
Here’s an examples of the input and output:
Which was generated by:
Overall, parser combinators seem to be a really powerful Scala feature that would make developing domain specific languages relatively straightforward. Compared to messing around with a parser generator, using parser combinators seems to more closely mirror what the formal grammar of a language would be.
The entire project is available on GitHub. If you clone that project, there’s a runnable JAR which you can run with:
java -jar logoparser.jar /home/ashish/workspace_java/logo-parser/samples/face.txt
You’ll need to provide an absolute path for the “filewatcher” to work. Once the app starts, if you modify the file you specify it’ll repaint the canvas with your updates. Note: I’m not sure why but certain text editors don’t seem to register in the Java “filewatcher” interface so if your updates aren’t showing up try using a different editor.
Anyway, as always I’d love any feedback!
Posted In: Scala