Friendcare, satisfying a curiosity

Quite often I find services I’m using inadequate. Something is missing, or not working the way I hope, I wish it could be changed. In a fraction of the cases it can actually be changed, and an even smaller fraction I go and change it myself.

This time it was bugging me that while I am always aware if I have new contact established on Facebook (or colloquially “friended someone”), but there’s just no way to know if someone cut ties (“defriended”) me. In some ways that knowledge is just as important, since the first means I succeeded in being interesting to another person in some way, the second means I was actually annoyance – not just being ignored and never talked to but people took the effort to never hear about me again. Recently quite a few people did that to me, or at least it’s only now that I try to find them for this or that but I can’t. I never want to be caught off-guard like this again, so I made Friendcare.

Friendcare interfacing

It was mostly an exercise in web app building, since if it was only for me, I could have just set up a script on my server that monitors things. It’s more fun as well. First I started it a long time ago, tried to work on it and rewrote from scratch a couple of times until getting here.

What does it do?

In this one the site just gets the user’s friendlist (a list of IDs) from Facebook and compares it with the last known friendlist. If there are new IDs, they are considered friend gains, if there are missing ones, those are friend losses.

Actually it got pretty complicated logic (for my usual thinking) inside because of the asynchronous management of good NodeJS apps, had to think a lot about what information is available at what step and what time of the usage. It also didn’t help that I haven’t really planed the user experience (UX) first, just started to code. Some of the things are surely pretty terribly done because of premature optimization and scaling I was doing while only havng a single user of the site. All in all, it’s an absolutely horrendous mess in the inside that still seems to implement a suitably close approximation of what I wanted. Surly will need some refractoring sooner rather than later.

The parts

It’s amazing how many different parts I need to use to make one complete site work, a total web-tech-soup. Everything is in a library or in an external service. It’s good and bad – good because other people did the heavy lifting for me already, bad because every one of them needs a non-trivial effort to learn and all of them different. Nevertheless, trying to keep things minimal. At the moment it’s NodeJS on Heroku, with MongoDB and using Heroku Scheduler to trigger the update service. The other modules and parts are:


Without Everyauth nothing would work, it handles the Facebook authentication on the backend. Also, it gave me ideas how the site can be extended to multiple services / multiple social networks.


There are so many interfaces to talk to Facebook, and the heroku-nodejs app I started off from uses one of them as well. That just seems to be too specialized for an example app, not in functionality but in implementation. Instead I found myself another library, fbgraph, and so far so good. If I really wanted to, I could even easier interface just the Graph API, but no need to do that at the moment.


I choose Mongoose/MongoDB to store the associated data, well, basically because MongoLab had the largest free database offering of all the databases I have checked. So far so good. I like the schemaless database, though already run into problems when I was updating wrong fields in the dataset I was surprised that the results didn’t show up at the right place. I guess that’s a danger I can live with at the moment. Will have to learn more about it, how to back things up, how to maintain it well, and about mongoose and it’s schemas.


The core functionality is basically taking the difference of two sets, and in general there is quite a bit of set manipulation, so Underscore works very well, I used for a couple of other parts as well (reduce, groupBy), and it works well. The whole thing feels like it should be part of the base library.

Twitter Bootstrap

While risking that I’ll look exactly the same as many others, Bootstrap does give some good-looking results with moderate effort. Will have to do some tweaking because I know so little about making good UIs, but it’s a start.


Used EJS for templating, and it’s great. Fast, flexible, and it’s not too bad that I have to fill in most of the HTML manually. I will know more about the structure of the client facing  side of the page more than I would otherwise.

Lessons learned

There are things that went well and not so well.

  • Maybe the most important: Facebook is unreliable. Sometimes I got missing people in the list that appear in the next update again. This happened when using Graph API, will have to see if FQL is any better. From my experience: not, it just has different problems.
  • For a while I started to write in Coffeescript, but then I just spent too much time trying to figure out how to get the right things, so went back to Javascript, at least until I learn that and can move up again to that higher level.
  • From the app’s point of view, some simplification needed. Too many middleware and helpers, this I quite often not sure about what is the state of my data, what variables were available and what are not.
  • Forums are not always helpful, quite often people have really dumb answers to questions, so have to figure things out myself.
  • Too many successful libraries mean that the library-soup will inevitably cause problems, and people start writing new libraries that connect and unify the old ones: mongoose & backbone, mongodb & everyauth, so much magic (ie. behind the scenes stuff) happens.
  • I still like to make logos and facicons, though I’m sure they are terrible, it makes good playtime in Inkscape and Gimp. Might have to change the colours, it does remind me of a strange toilet logo…
Friendcare logo


In the end, I’m solving a very narrow problem at the moment, a problem that so rarely arises, that I don’t even know if it will happen again. But if it does happen, without this I wouldn’t know about it, so still worth it.

Might extend it later to count Twitter followers, Google+ circles, Github watch/fork, whatnot… But that’s later when I see how does this work, I care much less about those than my “friends” because of the symmetricity of it .

The good thing is that currently it works well enough that I kinda got this off my chest and can back to making a FUSE module for, a group based location sharing mobile app, an app to connect my Goodreads to-read list and bookstore databases,  adding Open Graph and Rich Objects to Octopress, getting out an update for WatchDoc, or even check out the games I just got from HumbleBundle. But will come back to this, will have to make it better (it’s a compulsion).

Finally, if you the site, let me know your suggestions, I’m eager to learn. The source is up on Github.

Programming Taiwan


The World Creativity and Innovation week (WCIW) goes on every year April 15-21 (set to coincide with Leonardo da Vinci’s birthday). This year we were making some events in Taiwan as well, first about creativity: Create @ Public, and another one a week later for innovation: Hack+Taiwan, a hackathon.

Of the two events, this one was the trickier to do. For Create@Public, all I had to do is pack a lot of stationery and start making stuff myself. For a hackathon, there’s much more preparation to do. Fortunately, I had some great mentors to get things going, James of Startup Digest Taipei and Volker from Yushan Ventures. They have a lot of experience pulling off great events, and I was glad to hear their advice. I was surprised that in less than 2 weeks something like this could be put together, even under not totally favorable circumstances.

First had to find a place to host it, and preferably with zero budget. Looking at who do I know, ended up at appWorks, a startup accelerator, whose founder, Jamie is indeed a hacker at heart, so wasn’t actually that bad to convince him to give us some space on a weekend day. Even got one of their teams working there, Fandora, to help us.

That’s a good first step, now have to get some people to participate. I set up the Hack+Taiwan blog (on Octopress, just trying something new, that was an “interesting” experience as well), the event, a sign up sheet and started to spread the word. It all went well, until one week before the event it turned out that the Open Source Developers’ Conference has a hackathon pretty much the same day & time as I planned. That freaked me out a little, and after asking around, I got many different advice: cancel so not to compete with them, cancel to take a rest, and give it my best try nonetheless. Of course the craziest option won, so started to spread the word even more, trying to invite mentors, getting catering, figuring out how the day should work and so on.

Let’s get to it

Since people don’t like to fill out sign up sheets, and Facebook event “join” is so easy, I had absolutely no idea how many people will come. It was just winging it, I knew I’ll be there and a couple of people who were helping me, but that’s all so far.

Hack+Taiwan logo posted on the day
Hack+Taiwan logo

I ordered breakfast for 30 (from Magic Bagels), and let’s see what happens. Around 9am, the advertised start time, people started to come, first a couple, then some more, and around 10 o’clock there were almost a dozen people. That’s not bad at all, even considering that a third of that was mentors and other organizers, but they took part just the same. Since most people didn’t bring any ideas (some even didn’t bring a laptop, now that I don’t understand), had to get them to come up with some stuff on the spot. It took a little pushing, some ideas were so specific and pretty much the same they are working on their normal time, but fortunately there were some interesting ones. In about half an hour we had 3 teams working on three completely different. In the afternoon there were even more people who dropped by for some time, and got another project working.

Arduino hacking
Making an Arduino piano

The projects we had:

  • Mobile reminder app + website
  • Android programming (the team had to leave before demo time)
  • Visualization of the Taiwanese power grid for monitoring and supervision
  • Arduino piano
These are all very different, and fortunately all was pushing the participants a little bit. The first team was mostly mentors, or from different startups working at appWorks, and they haven’t worked together before. It’s a good way to improve collaboration. The second team wanted to try Android out, maybe I should have talked to them more (having done one app at my time), otherwise they looked pretty lost for most of the time, hope they will carry on. The third team I gave some advice, but not sure if that actually took them on a sidetrack, it should be a very useful project if done, and has a lot of potential apparently for the local utilities companies. The last one, a one person team, was making some really cool stuff in a very short time and even with broken and sparse equipment. Not sure if she was really challenged by the task, it looked quite effortless.

At 5:30pm we had a demo time, everyone showing off what they made, people switched to speaking Chinese since I was the only foreigner around, so I got to train a little better next time to be able to follow tings. I could see their demos, though, and it’s so impressive how far people got in pretty much 6 and half hours….

Here’s the photo album of what went down. I’ve also taken a timelapse image series of the event, been planning to make a video of it….and then successfully overwritten all the photos with a bad command of ffmpeg. That’s my way.

Lessons learned

  • Coming up with ideas is hard
  • It is still possible to come up with ideas. Look for issues that kept bugging you for a while, and do something about those
  • Everyone gets out different thing from these events
  • Don’t force things, everything will work out anyway
  • Don’t have to overplan, before one establishes their name in the community as good organizer, it is usually more likely to overestimate how many people will come to an event
  • Everyone loves bagels and cake (okay, that’s not new lesson)
  • Unless there are enough people, don’t have to focus the topic of a hackathon, see whatever people come up with. More difficult brainstorming, but better chances of success
  • Don’t drink too much coffee – I couldn’t get much done from the shakes

I really liked the feedback I had from the participants, and also from other people: there were some who were just working in the background on their own stuff, and when we finished they came and asked what was it, because they’d like to take part next time. That’s the spirit! And we might just do that, for example at the end of the summer. In the meantime, I will try to focus on earning back my own hacker badge.

Life Programming

StartupBus rolling again

If there was a place I’d like to be now…. then it would probably be actually 11 different places. It’s that part of the year, that crazy and incredible people get on a some buses, travel across the US to the SXSW festival, while building companies. Altogether dozens of them. While riding freakin’ buses…. I know, I can still hardly get over my own experience last year, though I don’t want to get over it, I want to cultivate, nurture and expand that feeling. Pretty much the whole last year was about that expansion, and it just continues to motivate me.

Fortunately I still keep in touch with some of the people from there, and when they are on the way right now as I write this, I cannot help but show my affiliations.

Wearing my StartupBus shirt for work today
Silicon Valley Bus 2011 represent

I’m really glad that I could contribute something as well. One of the core features of their site is the ability to see where everyone is right now. Cheer all the way as they fight through several states towards their destination, how they converge onto Austin, Texas in the end. For this to work, there has to be some way to track those buses. And as it is the tradition – and inevitable if you have a pile of the best hackers together – everything is pretty much custom built. The site, the virtual stock market game, the map – and the tracking app as well. This last thing is made by me, after a few evenings back last year while hanging out in San Francisco before getting on bus. I can’t believe that I even had time for sight-seeing while doing this…. Anyway, it worked like a charm on 6 buses, and I was quite satisfied. Pretty surprised, but also satisfied. It was great, especially because if something, then I didn’t want to let down this guy – one the craziest and most kick-ass person I had a chance to know.

Then again in the winter there was StartupBus Europe, which worked out fine, beautiful trace on the map from the Netherlands, through Scandinavia, then back to the continent all the way to Paris.

For this year’s event, I wanted to change it a bit around, make it more independent from me – and a bit less hackish. I gave up on improving the looks, but the functionality should be better.

Too bad that this time I wasn’t there in SF, working together with the team, inspiring and motivating each other. This made everything much slower for me, and much more “normal”, in the bad sense of the word. In the end I had a new version that worked, and was kinda okay, but wasn’t as well tested as I hoped to.

BusDroid interface
I wish there was a Taipei bus – not sure how to cross the Pacific, though

Of course bits are rotting when they are not developed, and one year in Android world is more than I’ve expected. Too bad that many of the problems came to light when the buses were about to head off. Turns out that aiming for the oldest version of Android to cover all different versions is not necessarily the right thing to do. I don’t need anything fancy, but the APIs changed a bit, some things got depreciated, and looks like some phones can’t run my very simple app. After all this craziness dies down, will have to investigate and figure out what went wrong.

In the meantime, fortunately 10 out of 11 traces are on the map, there’s only Las Vegas missing last time I’ve checked, and not sure what happened to them. I don’t like unsolved mysteries, especially when it’s my job to get them solved.

Screenshot of live map with buses
Startup Bus buses 2012 on their way

Let’s see if I can get a seat next year again. And also see if that year in the meantime is long enough to figure out some better solution. Will likely need to do things very differently as I was, will likely have to rewrite the whole app onto new foundations, and make it work on iPhones or iPads (do those actually have GPS in them? I actually don’t have any iProducts…), and more reliably work in general. Feels a little sucky, that I’ve let some people down that things didn’t work better. That’s what startups’ life is a little bit as well.

Now let’s pivot, and back to doing awesome.


Facebook Hacker Cup 2012 Qualifier 1

This is that time of the year once again, when coders gather to take part in some good programming fun, the Facebook Hacker Cup. It’s only the first qualifier round, and while I hoped it will go better than last year, well, it didn’t. Not that I’m really surprised.

My Facebook Hacker Cup 2012 Qualifier score
I needed one right to qualify, but I wish I haven't messed up the easiest problem.

After that 72 hours results are in, as is the explanation and example source code for the solutions. It’s good that the example solutions are in Python, I might even learn a trick or too.

Alphabet Soup

The problem setting is easy enough. Funny thought that no matter how many times I counted the letters in the world “HACKERCUP”, I didn’t notice that there are two Cs. I mean, duh! As usual, the example input set was designed such that it wouldn’t trigger the bug of miscounted Cs. This carelessness is one thing that comes up quite often in my programming, probably should take better care of it.


This problem actually worked, which means I’m in Round 2, but I guess it can be improved quite a bit, make it more efficient or come up with some heuristics. Or maybe it doesn’t matter much.


This problem was on a whole different level. While the first two had apparently more than 5000 and 3000 correct solutions respectively, this had only 28… I was thinking about it for quite a while, drawing diagrams, trying to use my intuition and imagination to see where the trick is since the naive O(N^2) algorithm is definitely unusable on the N~10^18 level. On the other hand, I might have tricked myself. Reading the solution the trick was completely different than I expected – I thought there’s some weakness in the random number generator that can be used to express everything analytically, while it is actually just about keeping good track of things. There’s no fancy algorithm to break this problem, just pure logical thinking. Now that’ll teach me as well…

Looking out

This of course means that I have a lot more to learn, and most likely I’m not cut out to be a Facebook caliber hacker. That’s no problem, but good to know. Whenever I think about it, the picture that comes to me is the hacking competition scene from The Social Network, where they hire their first employee. I’d love to be in the middle of such brainfest, such intense creation, such inspired learning from one another while having an an amazing time. Well, fortunately there are other places where I can have that experience, like the Startup Bus. And maybe, I can also set out to create that environment over here in Taiwan.

But first, let’s get ready for round 2, should make that one better.



WatchDoc – an experiment in Chrome Extensions

I keep remembering that good ideas start from doing something fun, instead of doing something easy. About a month and a half ago I was reading the Google Doc that I have with some friends, listing ideas about “Changing the World”. It’s all the things that should/could be better in the world and “I wish….” it would be some way.

In the list of  a hundred or so I’ve seen one entry that was wishing for a way to see changes to our shared documents in an easier way than going back to the Docs home page and seeing if something has happened. Been thinking that that would be something I myself would totally use. Couldn’t find anything like that yet, but I had sometime in my hand to experiment, so WatchDoc was born….

Dropdown menu of WatchDoc
The interface of WatchDoc with lots of testing documents, emails blurred out just in case.

Getting it done

I haven’t written a Chrome Extension before, but seemed like such a suitable fit, and been looking for a project that I can try myself with. They are practically open source (since you can look into any one of them regardless of where you installed them from) and only using standard web tech, just like making a website (HTML + CSS + JavaScript). Indeed, all Chrome extension are some web-pages displayed in a special way, some javascript running in the background and/or javascript modifying the page you are on. Very neat, I would say…

Since I didn’t know where to start, I tried to find an extension that I can take apart and learn from. Fortunately, there was one, straight from Google, called YouTube Feed. So the first part of the project was slowly gutting that one out and replacing parts until I get something working that I wanted. It is easier to say than do, because the feed reader has somewhat different requirement than the code I had in mind, but at least close enough that most of the internal structure I could keep.

Some notes about the journey:

  • Authentication: oAuth can be pretty troublesome, but in the end it was easier this time than I expected from past experience. Maybe because YouTube Feed was written reasonably well already
  • Icons: Wanted to take the icons for the different document types from Google Docs itself. Took some time, but using the developer tools (inspect element) in Chrome I could finally find the links and download them.
  • More icons: Wanted to use the icons as a CSS image sprite just like the original extension, but couldn’t find some good program to combine PNG files into a single image. In the end wrote a quick Python script to do just that.
  • Extension icon: For the extension icon I used Google Docs’ own little icon (I think it’s kinda fair to use, especially now that they have changed it, it’s v9 of their icon theme compared to v7 at the time of my programming) and also on a free icon site I had found a matching hi-def icon. I just wish I could find it again for proper attribution, that still nags me.
  • Buggy notification: Some parts of the extension writing was pretty annoying. For example I wanted to get desktop notification work just the way it does in Gmail. I don’t know how do they do the auto-hiding, but I’m pretty sure not from the standard simple desktop notification type, because that I simply make to hide itself after a certain time. Instead I had to make it the more difficult way of using a HTML page to define content and then internal JavaScript to close it. Took a while to realize that I have to pass my parameters (the data that I wanted to display) as query parameters, but now it works pretty well.
  • Buggy libraries: this is always fun to have because have to find to work around it or  fix it. This time it was a jQuery URL Parsing library that crapped out on corner cases that the developer didn’t thought of but I fortunately run into. Took a while, but fixed it up, let’s see if upstream will incorporate it.
  • Optimization: it’s good to have things working first and then have them work well. For example originally I re-read the user’s whole feed, now it can read the part of the update feed that can contain relevant information, so I can have fewer requests to the server, and the updates come in several seconds quicker.


After some work I thought it’s better to release first and ask questions later. So I registered on the Chrome Web Store (registration is $5 on time fee to get rid of spammers). Not much hustle, in about 20 minutes everything is done and now you can find WatchDoc in the Chrome Web Store. You can also find the source on GitHub.

The Chrome Web Store seems to have some strange policies, though, eg. didn’t let me update if I didn’t have the right shapes of preview pictures, and sometimes they only told me halfway into the submission of the new release, and I had to scramble to make some test documents and nice screenshots of the right aspect ratio so I can finish the submission. Nevertheless it is pretty easy to handle and useful too.

One beef I have is that I don’t have any way to reply to reviews. Much more people post negative stuff than positive and once I fixed something there’s no way to get in touch with the reviewers to ask for re-evaluation. This makes a very one-sided experience.

It is good – though addictive – to watch the number of +1s grow, as well as installs and users. The site must have some way to check people’s installations because the total number of users did decrease after the initial increase (the high water mark somewhat above 1500, now a bit below 1400). I guess I would need to improve the quality a bit more, and maybe there are not that many people sharing Google Docs with others than I have thought. :) Anyway, I think this is much more than how many people used any other software/site I made, so no ground to complain.


The release was picked up surprisingly quickly by other websites, I think there are some automatic ones monitoring the latest submissions to the Web Store, and others take the news from them.

WatchDoc Google Analytics as of date
WatchDoc Google Analytics as of date, some review of it in the text, click to enlarge (in new window)

Here’s my Google Analytics since the release. The big spikes in the beginning go up to about 500 visit / day (tiny, but much more I have ever had), and are mostly due to Lifehacker. After that I have basically just a trickle of visitors (about 20 / day), with a little spike recently that is direct traffic, I wonder where from….

Some sites that reviewed WatchDoc (the ones with the highest referral counts)

I got up a support site on GetSatisfaction as well to be able to have a conversation with those who are persistent enough and submit some feedback regarding bugs. Used it a couple of times, and it’s quite practical. I finally learn how to do product support, which doesn’t mean it became easier. Still surprisingly maddening to debug a problem until it hits me as well by chance so I can check it locally. Got to figure out some superior remote debug system. At this point it seems to work well enough for about 1400 people, but the fact that I have lost about 200 shows that I still have a lot of problems to fix.

Into the future

It was a fun project to work on and it does most of the things I wanted to, but it’s dead ugly. I either find a designer and fix it, or just leave it like this because it doesn’t matter much…

I might work on it a bit more, especially bugfixes, though it would be better to have some ideas what is missing. Everything I can think of would complicate the user experience and that’s not my plan: document preview, ignore updates of certain documents, multiple-logins,…. What else?

Guess it is more likely that soon I will start to work on something else, let me know if you have something fun you wish to see :)