A Mobile Tablet Interface

February 3rd, 2012

Recently I developed with Alexander Zeh an interface for an Android tablet app for the agents in an African mobile payment network. It was a pitch for the company, and while we weren’t selected we’re quite happy with our work and decided to share it with you. You can find our designs and analysis at http://bubblefoundry.com/tabletinterface/.

How to get enumerations when using Scala’s parser combinators

January 23rd, 2012

This took me a while to figure out, so I figure it’s worth sharing here. In the end it’s quite simple thanks to Parser’s ^? method, but it took me a while to figure out:

gitback

January 6th, 2012

Feargal had a good suggestion in response to my complaint that private repos on GitHub were too expensive, which was download old repos to Dropbox and then delete them from GitHub to make room for active ones. To do this I wrote gitback today. Enjoy.

Tips for merging a Git repository into an SVN one

December 22nd, 2011

Recently I finished a project that I’ve been working on and wanted to delivery it to the client. Unfortunately, I’ve been using Git, while they wanted me to commit the code into their monolithic Subversion repository. Of course the easiest thing would be to simply commit an export of the project into a new directory, but that would involve losing a lot of important information contained in the commits and their commit messages.

The solution, then, is some git-svn magic. I found most of the tips in one helpful article, but I still had enough gotchas that I figure it’s worth outlining my process here.

I’m assuming standard branch, tag, trunk organization for both the git and svn repos. We’re going to be working in a directory that initially only contains the git-tracked code in a subdirectory called repo.

      1. Move all files in your git repo into the desired subdirectory:
        cd repo
        git mv [all files] myproject

        What I’m doing here is preparing my code for life in the monolithic svn repo, where we’ll want it under a subdirectory, here named myproject.

      2. Clone the trunk of the svn repo:
        cd ..
        git svn clone svn://server/repo/trunk repo-remote

        Here I’m cloning the trunk of the svn repo into a git-svn repo called repo-remote.

      3. Fetch the git repo into the git-svn one:
        cd repo-remote
        git fetch ../repo
      4. Then go to the new tree and make it into a branch:
        git checkout FETCH_HEAD
        git branch tomergeTEMP
        git checkout master
      5. Now we’re going get the SHA1 hashes needed to graft the two trees:
        git rev-list --reverse FETCH_HEAD  | head -n 1
        git rev-list --reverse HEAD  | head -n 1

        Let’s call the first hash repo-SHA1 and the second repo-remote-SHA1.

      6. Put those into a graft file for git-svn to use:
        echo repo-SHA1 repo-remote-SHA1 > .git/info/grafts
      7. Rebase the git-svn repo:
        git rebase tomergeTEMP
      8. Now do a dcommit dry run:
        git svn dcommit --dry-run

        You’ll get a bunch of lines that look like:

        Committing to svn://server/repo/trunk ...
        diff-tree hashA~1 hashA
        diff-tree hashB~1 hashB

        All the articles just give the line above and say to check the patches, but how do you actually check them? It turns out it’s quite simple:

        git diff-tree hashA~1 hashA -u

        This will give you the patch that will be applied. (I’m not sure whether the -u is useful.)

      9. Finally, commit:
        git svn dcommit

        It should go through and commit to the svn repo each git commit.

When it’s finished the code from your git repo should be in svn://server/repo/trunk/myproject.

However, I had a few hiccups. First, I got a merge conflict on one of my commits.1 I resolved it like so:

git mergetool
git add [corrected files]
git rebase --continue
git svn dcommit

You’ll notice that not only did I have to continue the rebase operation that git svn dcommit had called internally, but I actually had to call git svn dcommit again.

Second, I had some unnecessary folders because I had moved my files in and out of some folders (hopefully you won’t have this problem because you followed my first two steps). Rather than try to remove the unncessary folders using my git-svn repo, I checked out a new working copying via svn:

cd ../
svn co svn://server/repo/trunk repo-svn
cd repo-svn
svn rm [extraneous dirs]
svn commit -m "Remove directories incorrectly left by git-svn"

And there you go. Hope that helps!

  1. Which is bizarre considering that I successfully committed it earlier. []

Archiving Old Git Repositories, Or GitHub Is Too Expensive

December 15th, 2011

I think I’m not alone in having many Git repositories, many of them I don’t currently use because they’re from old projects. However, I don’t want to delete them because I might want to refer back to one of them or make a change (which I’m doing right now for a three year old project). I absolutely love GitHub but their pricing is very unfriendly for people like me. Consider this:

I’m using 10 of the 10 private repositories under the Bronze plan, yet barely using any disk space. I have another maybe 15-20 repositories of old projects I’d love to add to GitHub, but upgrading to the level necessary to allow that would cost me $100 a month! That’s way too much for me as an independent developer!

Unfuddle, where I used to store my private repositories until I started paying for GitHub in August, had a more friendly limit but also allowed archiving, where archived projects didn’t count against your main limit. At the same time, they could still be restored into normal projects. Great! Unfortunately in every other way GitHub is superior…

So what’s the solution? Well, I first emailed GitHub to see if I could just buy more private repositories. No dice. If I want to avoid ballooning numbers of projects but stay on GitHub, I could try moving all my old projects into one archive repo. This sounds ugly – my first thought was doing it via submodules – though Eelco had the good idea of using headless branches for each project. Unfortunately this still strikes me as a hack.

So I fear I may need to host my old repos on another server. There are lots of other supplies with better private repository pricing, or I might just setup the repos on my own server. Thoughts?

AMEN!

December 11th, 2011

On the subject of passwords: F*&K PASSWORDS. Great, great blog post.

Tropo is broken

December 10th, 2011

Oh. my. god. What a giant disaster.

I’ve been raving about how awesome Tropo is at handling SMSes to everyone I talk to, but no more. Tropo expects EVERY interaction to be the in the form of a response to a request that they’ve POSTed to your API endpoint.

Everything is part of a session THROUGH THEIR SERVER AND BACK TO YOUR CALLBACK URL. Want to send an SMS? First you need to create a session. Consider the Java library (in Scala):

val result = api.launchSession(token)
if (result.getSuccess) {
  api.message(...)
  ...
}

All valid, type-safe code. launchSession() returns a TropoLaunchResult, which indicates whether the session was successfully created and, if so, its session id.

We can work with this, right? WRONG! As part of the session creation Tropo will throw a session creation object at your callback URL:

00020	0000	11:22:41 PM   	ApplicationInstance[http://miogiro.pr1001.cloudbees.net/tropo.json , sas_2-15-sm1778xfp7g8g0dtropo] starts execution on Thread Tropo-Thread-3899e36f1ad7650f2848c3ac12332b96
00021	0000	11:22:41 PM   	Thread Tropo-Thread-3899e36f1ad7650f2848c3ac12332b96 acquired engine com.tropo.rest.engine.TropoScriptEngine@78ded0e7 of type tropo-web, activeEngines = 4
00022	0000	11:22:41 PM   	Sending TropoML Payload on Tropo-Thread-3899e36f1ad7650f2848c3ac12332b96 [url=http://miogiro.pr1001.cloudbees.net/tropo.json]: {"session":{"id":"3899e36f1ad7650f2848c3ac12332b96","accountId":"notsharing","timestamp":"2011-12-09T23:22:41.612Z","userType":"NONE","initialText":null,"callId":null,"parameters":{"token":"notsharing","action":"create"}}}
00023	0000	11:22:41 PM   	Received non-2XX status code on Tropo-Thread-3899e36f1ad7650f2848c3ac12332b96 [url=http://miogiro.pr1001.cloudbees.net/tropo.json, code=500]
00024	0000	11:22:41 PM   	Thread Tropo-Thread-3899e36f1ad7650f2848c3ac12332b96 returned engine com.tropo.rest.engine.TropoScriptEngine@78ded0e7 of type tropo-web, activeEngines = 3
00025	0000	11:22:41 PM   	ApplicationInstance[http://miogiro.pr1001.cloudbees.net/tropo.json , sas_2-15-sm1778xfp7g8g0dtropo] ends execution on Thread Tropo-Thread-3899e36f1ad7650f2848c3ac12332b96
00026	0000	11:22:41 PM   	sas_2-15-sm1778xfp7g8g0dtropo invalidated
00027	0000	11:22:41 PM   	Instance 3899e36f1ad7650f2848c3ac12332b96 removed

See what’s happening? If you fail to handle it and return a 200 status code (and a Tropo JSON verb?) it kills the session, never mind that I have no need for that. That means it’s literally impossible to send an SMS without a server setup to receive callback messages from Tropo. Oh, and of course you can only specify one URL: you’re supposed to route all the different requests based upon extra parameters you stick in the session creation requests.

It literally boggles the mind how someone could have thought this was a good idea.

Tropo, if you want to fix this and need help send me an email at peter@bubblefoundry.com. Tropo competitors, if you have a sane API to send SMS messages and callbacks to response to received messages (bonus points for a Scala or even Java library) and provide UK numbers that can handle both inbound and outbound SMS, feel free also to email me at peter@bubblefoundry.com.

Because I needed it

December 5th, 2011

A story in pictures…

The whole thing took maybe 45 minutes thanks to Foursquare and the php-foursquare library. Probably one of the best examples of the joy and power being able to program gives you.

Is it possible to read on a news site?

December 4th, 2011

Last week I had a rather good bon mot, if I may say so:

Not surprisingly, I’m not alone in thinking that it’s impossible to read text online.

While I’m not a designer, let alone one with his chops, let me try to pull a Dustin Curtis. Consider an article on the BBC site:

I find that I like to read farther away from the screen these days and like large type. So, I decided to read the article using the Instapaper Text bookmarklet.

Isn’t that better?

Well, yes of course, it’s streets ahead for me the reader. But you can barely tell that it’s from the BBC. The Corporation isn’t going to like that, yet alone that I, a non-license fee paying foreigner, am not seeing their ads. Maybe we can find a happy medium:

It’s a basic cut-and-paste hack job but I think it gets the job done. The key thing is that it gives the text the entire large center column, while the section links and ad units are relegated to the left and right columns that essentially look like a background layer behind the main, article layer. So yes, they’re de-emphasized but, unlike the Instpaper version, they’re still there. If you run the BBC wouldn’t you prefer that?

A Handcrafted Curated Selection of Handcrafted Curated Selections of Products Sites

December 4th, 2011

As I said the other day:

If only recently people were bemoaning that “the best minds of my generation are thinking about how to make people click ads” (and they’re right), then now I’ve noticed another trend: an explosion new startups, many by friends of mine, selling various ‘heritage’, ‘handcrafted’, etc, etc products that people probably don’t need or, if they do, hardly at the prices they’re charging.

I’m afraid I’m thinking of you Wantful, Everlane,  Cavalier, Best Made (admittedly around for a few years but still), etc, etc, etc. Heck, we even have A Startup Store! (My friends at Gidsy probably get a pass because they’re focusing on experiences, not products.) Forbes has a recent article on Wantful that lists a bunch of startups in this vein.

Sorry, friends, I love you but it’s starting to get ridiculous!