11 Mar 2010
Planet Twisted
Jonathan Lange: Have you tried lptools?
Have you tried lptools?
It's not at all officially associated with the Launchpad project, of course, but it's got a few nice things that you might want to look at, including:
- a milestone manipulator
- a code review notifier, and
- a milestone to iCal exporter
For other extensions, check out the lpx project or our list of clients.
11 Mar 2010 5:25pm GMT
10 Mar 2010
Planet Twisted
Jonathan Lange: launchpadlib powerup
In my last post, I introduced launchpadlib and demonstrated a very simple script that uses it. In this post, I'd like to build on that a bit and show you how to do something actually interesting.
In particular, I want to show you how to search for bugs, teach you a bit about Launchpad's internal data model and help you help yourself when it comes to figuring out Launchpad APIs.
The script at lp:~jml/+junk/bugstats is designed to tell you how good you are at filing bugs. It uses a very simple metric: out of the bugs that you've filed, how many actually have been fixed.
$ ./bugstats.py ubuntu jml
jml is 22.22% successful on bugs in Ubuntu
$ ./bugstats.py launchpad-code jml
jml is 47.63% successful on bugs in Launchpad Code
To do that, we need to:
- get the "project" and person referred to on the command line
- search for all fixed bugs filed by that person
- search for all bugs in total by that same person
- count them both
- divide them
- print them!
I say "project", but I really should say "pillar", which is the Launchpad technical term for a project (e.g. "bzr"), distribution (e.g. "ubuntu") or project group (e.g. "gnome"). A pillar is anything in first part of Launchpad URL that isn't a person.
We get the pillar and person like this:
pillar = launchpad.projects[pillar_name]
reporter = launchpad.people[reporter_name]
Pretty easy, huh? Now, how do we search for bug tasks?
The first port of call is to go to the Launchpad API reference page. I'm going to look for the string 'reporter', since that's the one thing I definitely know I want to find.
Eventually, I found the searchTasks method (named operation) that's on pillars and takes a bug_reporter parameter and a status parameter. It returns a collection of bug_tasks, which are the objects that represent the rows in the table you see at the top of a bug page.
I can find the bugtasks for the bugs I've reported that have been fixed by doing:
fixed_bugtasks = pillar.searchTasks(
bug_reporter=reporter, status=['Fix Released'])
It took me a while to figure out exactly how to spell "Fix Released". I ended up using trial and error.
Similarly, I can all the bugtasks for bugs I've filed by doing:
total_bugtasks = pillar.searchTasks(
bug_reporter=reporter,
status=[
"New",
"Incomplete",
"Invalid",
"Won't Fix",
"Confirmed",
"Triaged",
"In Progress",
"Fix Committed",
'Fix Released'])
I cheated a bit for that one and looked at the launchpad code to get a list of all bug statusus. The default for searchTasks is to only return open bugs.
Once we've got the collections of bug tasks, we need to get their counts. In an ideal world, it would be len(total_bugtasks), but sadly bug 274074 means that len is really, really slow here.
Instead, I wrote this helper function:
def length(collection):
# XXX: Workaround bug 274074. Thanks wgrant.
return int(collection._wadl_resource.representation['total_size'])
With that, I can calculate & print my success rate at filing bugs:
percentage = 100.0 * length(fixed_bugtasks) / length(total_bugtasks)
print "%s is %.2f%% successful on bugs in %s" % (
reporter.display_name, percentage, pillar.display_name)
Next up on the API, I'll talk about some of the gotchas and what you can do about them.
10 Mar 2010 6:59pm GMT
Jonathan Lange: Get started with launchpadlib
In my spare time, I sometimes talk to people about how they can get started with launchpadlib hacking.
launchpadlib is the Python client-side library that talks to Launchpad's own REST API. It turns out that customize scripted control of a bug-tracker-code-hosting-translation-distribution-building-cross-project-collaboration thing is actually quite handy.
If you want to get started hacking with launchpadlib, and you have Ubuntu, then install 'python-launchpadlib' now. I'm pretty sure you can also get it from PyPI.
You can check that it works by running:
$ python
>>> import launchpadlib
>>> launchpadlib.__version__
'1.5.1'
I'll be assuming you're running 1.5.1 or later.
I've written a very simple launchpadlib application that you can get with 'bzr branch lp:~jml/+junk/bugstats'. Each revision shows a meaningful launchpadlib script. You can get at the old revisions with 'bzr revert -r1' or 'bzr revert -r2' or '-r3'.
Here's what the simplest launchpadlib script that I could think of looks like:
import os
import sys
from launchpadlib.launchpad import Launchpad, STAGING_SERVICE_ROOT
APP_NAME = 'jml-bug-stats'
CACHE_DIR = os.path.expanduser('~/.launchpadlib/cache')
SERVICE_ROOT = STAGING_SERVICE_ROOT
launchpad = Launchpad.login_with(APP_NAME, SERVICE_ROOT, CACHE_DIR)
print launchpad.bugs[1].title
(Adapted from r2 of the above branch).
A few points.
- We use
STAGING_SERVICE_ROOT, which means that we're pointing
at Launchpad's staging service,
just in case we screw up any data. - We give the application a name, when you run the application, launchpadlib
opens up a browser window letting you decide how far the application
can act on your behalf. - We provide a cache directory. Credentials, among other things, get stored
here. - We then login and get an object that represents a Launchpad instance
- Once we've got it, we look at the collection of bugs, get Bug #1 and then
print the title
Very simple. To learn how to write this application, I looked at the main Launchpad API help page, the
examples page and the reference documentation. You'll notice that I had to translate the reference documentation from REST-speak into Python-speak.
Already you have enough to go exploring with the Launchpad API and think of cool things to do. A bunch of people are already doing cool stuff and there are many projects that use launchpadlib.
Next up, I hope to show you some more complex things you can do with the API.
10 Mar 2010 10:43am GMT
Paul Swartz: It’s days like this that make me realize why some people...

It's days like this that make me realize why some people think CrossFit is nutty.
10 Mar 2010 5:07am GMT
09 Mar 2010
Planet Twisted
Thomas Vander Stichele: ski
As we are deluding ourselves here into thinking it's snowing in Barcelona, I thought it appropriate to post some videos from the past few snowboarding trips.
Coincidentally, this is my first foray into the HTML5 video world - more on that later.
Let's start with my favorite, the one where I show off how years of gymnastics in my youth help me keep my body in one piece:
Could not use HTML 5 or Flash for playback. You can download the file as MPEG4/H.264 or Ogg Theora file.
(Also notice the cool new orange snowboard pants that I settled on. Snowboard fashion was really boring this year, mostly grey and black only, with some ugly flashy colours as exceptions. I leave it to you to judge whether orange is one of them).
We spent eight full days in Tignes, France, with only about three days of sunny weather, and the rest filled with clouds and snow.
My goal this year was to learn how to do a 180. With the help of an instructor, that's exactly what I did! Here's an admittedly simple one - all the good ones are not caught on video.
Could not use HTML 5 or Flash for playback. You can download the file as MPEG4/H.264 or Ogg Theora file.
Here's a more aggressive one with a bad ending:
Could not use HTML 5 or Flash for playback. You can download the file as MPEG4/H.264 or Ogg Theora file.
A few weeks before our snowboard trip, we also had a business planning weekend which included one day of skiing. Xavier risked life and limb following me around with his iPhone to record this. It's not the most exciting descent in the world, and he ended up missing my one fall in it, but I was surprised to see how short the whole descent really is if you don't take any time to stop!
Could not use HTML 5 or Flash for playback. You can download the file as MPEG4/H.264 or Ogg Theora file.
And here are Xavi and me relaxing over cheese fondue and raclette the day before the skiing:

Some notes about the HTML5 video part:
- there is an enormous difference in colour between playing Ogg in Firefox, MP4 in Safari, and MP4 in Quicktime, on the same MacBook. My pants range from a soft orange to a bright red. Something is obviously up!
- To learn about HTML5, I started with Dive into HTML5 Video, then learned about Video for Everybody, some web code that handles all of the stuff I don't know how to do for me and just makes sure the video can play on Firefox/Chrome/Safari/iPhone/…
- Then I looked for WordPress integration, and found a plugin with a long name that implemented most of Video for Everybody. I modified it a little to do something more sensible for the poster image in case it's external, and to accept .mp4 as an extension instead of .m4v (which is not suggested by Dive into HTML)
- I configured our transcoding platform to generate the three types of output file needed to support HTML5: the thumbnail, Ogg/Theora/Vorbis, and .mp4 with H264 and AAC.
The embedded video should work fine in Firefox/Safari/Chrome/iPhone/Opera (except in Aitor's "I plug mplayer into Opera" case), and work fine in Explorer too where it falls back to Flash.
I couldn't get this to work in Android. 2.0 is rumoured to support the video tag, but so far no dice, and I couldn't find a single HTML5 video page online that the Android phones over here can play. If you can see these videos embedded in Android, or know what I should to fix them, please do let me know!
09 Mar 2010 12:42am GMT
08 Mar 2010
Planet Twisted
Moshe Zadka: Buffy, Season 2, “Surprise”
Angel: It's a claddagh ring. The hands represent friendship, the crown represents loyalty… and the heart… Well, you know… Wear it with the heart pointing towards you. It means you belong to somebody.
My titanium claddagh ring just arrived in the mail. Now I can observe this proud Irish tradition.
08 Mar 2010 11:43pm GMT
Twisted Matrix Laboratories: PyCon 2010 sprint report
Residents of the once-great city of Atlanta are only now beginning to piece their lives back together after the event that Glyph Lefkowitz described as "the best Twisted sprint ever".
Quite apart from the unprecedented levels of wanton destruction, Twisted's PyCon 2010 sprint was also better attended than any previous sprints, which have laid waste to the outskirts of Boston, inner-city Dallas and regions of Australia.
At its peak, there were eighteen people seated around the two tables where the sprint took place. People even joined in remotely, working with the Atlanta team through #twisted on freenode.
Although buried deep within a secret bunker in Atlanta, the sprint still managed to attract a fair number of new contributors and Twisted users who wanted to help out.
Attendees who made themselves known to your correspondent include:
- Jonathan Lange
- Jean-Paul Calderone
- David Reid
- Thomas Hervé
- Tim Couper
- Pavel Pergamenshchik
- Maciej Fijalkowski
- Glyph Lefkowitz
- Itamar Turner-Trauring
- Terry Jones
- Wilfredo Sánchez Vega
- Kevin Horn
Jessica McKellar, Ralph Meijer and Andrew Bennetts also participated remotely.
Attendees all had immense fun and expressed a desire to have another sprint soon. One observed that it had been far too long since giant mecha robot warriors descended on Paris.
Twisted prevails,
jml
More simply, we had a great time at the sprint and got a ridiculous amount of stuff done.
We fixed many, many bugs, including all of the known regressions since the 9.0 release. Once we fixed the regressions, we started work on getting the first 10.0 pre-release out the door.
The pre-release probably would not have been possible without the sprint since it allowed the new release manager ready access to Jean-Paul, who has quite a lot of knowledge stuck in his head. One result of this is a new release process document, which is being developed alongside the actual 10.0 release.
We also reached an in-principle agreement to aim for a release every three months. This means that although hardly any of the good work from the sprint is in the 10.0 release, you won't have to wait long for it to appear in 10.1. Hopefully. I plan write up how this will work as soon as the 10.0 release is done.
The sprint proved to be a perfect opportunity to talk about some of the more gutly bits of Twisted, including Deferred cancellation (see #990) and endpoints (see #1442). The former is done, and the latter has made good progress. Stay tuned.
Thomas Hervé did a lot of work on upgrading our Trac instance, which was getting kind of old and currently crashes all of the time.
We talked a bit about how we could make it easier for people to contribute to Twisted without compromising our high standards of quality. We put as many of the ideas that we could remember on to http://twistedmatrix.com/trac/wiki/ContributionIdeas.
Maciej Fijalkowski was at the sprint working on getting PyPy benchmarks for Twisted and on making PyPy work faster with Twisted. Personally, it's really exciting to see PyPy live up to its promise of a faster Python, particularly with a big codebase like Twisted.
As I said, we fixed lots of bugs. Here's the complete list:
- #4179 - HTTP proxy hanging in Twisted 9.0
- #3056 - twisted.spread.pb.IUsernameMD5Password's docstring should say it accepts an MD5 digest of a password, not plaintext
- #3289 - startLoggingWithObserver raises IndexError
- #4178 - Function singleSearchStep was renamed to _singleSearchStep not everywhere
- #4192 - Move the content from exarkun's Twisted Web in 60 Seconds series into the Twisted Web howto
- #4284 - t.e.adbapi leaks threads
- #4282 - _release.filePathDelta is broken
- #3718 - twisted.internet.posixbase._Waker not defined on Jython
- #4143 - twisted.web.wsgi incorrectly unquotes QUERY_STRING
- #4255 - BaseLogFile should provide a method to reopen logs
- #972 - Add linux inotify support to twisted core
- #2367 - twisted.test.test_failure.FailureTestCase.testBrokenStr break #trial in debug mode
- #1083 - gtk2reactor thread initialization confuses python-2.3
- #3462 - FTP server: upload should support async close
- #990 - Deferred cancellation
- #733 - twisted's SIGCHLD handler breaks popen.
- #2376 - release-twisted should generate guides with links to API docs
- #4272 - flavors.py still talks about getObjectAt
- #4172 - UDP crashes python.exe when using IOCPReactor
- #3925 - test_addresses fails with Glib2 and Gtk2 reactors
- #4255 - BaseLogFile should provide a method to reopen logs
- #4293 - Update links in testing documentation
- #4311 - XMPP Stanza Error 'remote-server-timeout' yield no type and code
- #3811 - Allow aborting HTTP client connections in the _newclient API
We also worked on:
- Getting rid of 3k warnings and generally doing 2to3
- Event support for iocpreactor
- Making Deferreds more iterative (see #411)
- Twisted Web features and bug fixes
- Fixing obscure Windows/gtk2 compatibility issues
Thanks also to the attendees for making it such a blast.
If you want to encourage more of this sort of behaviour, then please donate to the Twisted Software Foundation.
jml
08 Mar 2010 10:14pm GMT
Jonathan Lange: Monitor & keyboard
I want to get a shiny new monitor and keyboard. The monitor is for coding, writing docs, answering emails and watching films. The keyboard is for same. They'll both plug into my Thinkpad X200 for now.
08 Mar 2010 12:27pm GMT
03 Mar 2010
Planet Twisted
Jp Calderone: Include version information in your Python packages
Quite some time ago, I wrote a list of what to do and what not to do when creating a Python package. In the spirit of that post, I have another do item:
Do include version information somewhere in your package. When I say package here, I'm referring to the Python concept - the thing which can be imported and manipulated programmatically. Here is a random assortment of real-life examples of what I mean:
>>> import sys >>> sys.version '2.6.4 (r264:75706, Dec 7 2009, 18:45:15) \n[GCC 4.4.1]' >>> import OpenSSL >>> OpenSSL.__version__ '0.10' >>> import gmpy >>> gmpy.version() '1.04' >>> import gtk >>> gtk.gtk_version (2, 18, 3) >>> gtk.pygtk_version (2, 16, 0) >>> import pyasn1 >>> pyasn1.majorVersionId '1' >>> import win32api >>> win32api.GetFileVersionInfo(win32api.__file__, chr(92))['FileVersionLS'] >> 16 212
You can see several conventions represented here. Some of them are better than others (in case you need a hint, gtk is doing something pretty nice; win32api is towards the other end of the spectrum). However, even the worst of these is providing the desired information. Compare this to:
>>> import zope.interface >>> [x for x in dir(zope.interface) if 'version' in x] [] >>> import subunit >>> [x for x in dir(subunit) if 'version' in x] []
This is a simple piece of information, and after you've actually picked a version of something and installed it, it's hardly ever of much interest. However, when it is of interest, you really want to be able to get it. You don't want to rely on the memory of some user about which version they installed when you're tracking down some poor interaction.
So. Do you maintain a Python package? Does it expose its version somehow? If not, fix it!
03 Mar 2010 11:36pm GMT
Twisted Matrix Laboratories: Twisted 10.0.0 released
On behalf of Twisted Matrix Laboratories, I am honored to announce the release of Twisted 10.0.
Highlights include:
- Improved documentation, including "Twisted Web in 60 seconds"
- Faster Perspective Broker applications
- A new Windows installer that ships without zope.interface
- Twisted no longer supports Python 2.3
- Over one hundred closed tickets
For more information, see the NEWS file.
It's stable, backwards compatible, well tested and in every way an improvement. Download the tarball, the Windows installer for Python 2.5 or the Windows installer for Python 2.6.
Many thanks to Jean-Paul Calderone and Chris Armstrong, whose work on release automation tools and answers to numerous questions made this possible. Thanks also to the supporters of the Twisted Software Foundation and to the many contributors for this release.
03 Mar 2010 11:28pm GMT
Jonathan Lange: Back from PyCon
I had a great time at PyCon 2010. The best part was definitely the Twisted sprint, which gave me a long overdue opportunity to do some actual coding.
Well, actually, I ended up spending a lot of the time organizing a release and writing process documents, so I didn't escape management as much as I would have liked.
Now I'm back, planning on doing the Twisted 10.0 release and working with didrocks to get better Launchpad integration with Quickly, as my contribution to Project Awesome Opportunity.
03 Mar 2010 9:59am GMT
01 Mar 2010
Planet Twisted
Thomas Vander Stichele: N900 Facebook plugin problems
One of the things I really love about my N900 is the ease with which I could share photos. You take the picture, click a few buttons, and there it is, your photo on flickr on Facebook. I'm sure other devices offer a similar experience, but this really is the first time I've been able to appreciate
Since a few weeks my Facebook sharing has stopped working. At first it only seemed like a missing icon and broken config. But I had a really really hard time to figure out the problem, much harder than it should have been for a mostly open platform. Of course, for some reason this sharing part is closed, which doesn't make much sense at all. What secrets can Nokia possibly have invested in some code that pushes photos to flickr or Facebook.
So, as part of the debugging process, over various weeks, I've seen and done the following:
- When sharing through the Facebook account, the little 'I'm sharing' icon that pops up in the status area went away almost immediately, compared to sharing through Flickr
- Sharing stores outgoing stuff in $HOME/.sharing/outbox - files were piling up there
- At first I thought I had some login details problems, so I went to Settings > Sharing accounts and clicked on the Facebook account. That didn't do anything at all, no dialog popped up. Since the Delete button is in that popup, I also couldn't use the UI to recreate my Facebook sharing account.
- I started learning about where the N900 stores account info, following some dubious posts until I found out about signond, a daemon running as root that stores login information. This daemon uses the file $HOME/.signon/user_db.xml (You get no points at all for correctly guessing whether this file contains XML data, but please do go look for yourself!)
- I moved this file around to force recreation of data, which seemed to work after a reboot, since my Flickr data was now gone, as well as the Facebook one. I was able to click Flickr in Settings > Sharing accounts, but the Facebook still didn't pop up a dialog. At least this narrows down the problem I should solve for now: I can't even configure the service from scratch even when deleted, so let's focus on that first.
- I reinstalled the package that contained the facebook sharing plugin. This restored the icon, but the popup still didn't work.
- Usually I would just strace the relevant binary, but I considered the friction too high at first since there is no strace in fremantle, and I would have to set up a chroot for this.
- But what binary ? I didn't even know what program handles the settings. After comparing a few ps listings, I figured out the program was controlpanel.
- Interestingly, you can just ssh into the device as the user, and execute controlpanel, and it will pop up the binary on the phone (even with X forwarding), which I didn't expect, but is fine by me. This gave me a message like "sharing-accountstore.c 516 sharing_account_store_add_account Last added id exists: 35
" which I wrongly took to mean that adding a facebook account was failing because it was still somehow present in the config. This is when I figured out that this code is closed, because I wasn't able to figure out where to get accountstore.c and look at what it is doing. I'm pretty sure it's not storing its settings in gconf (at least I couldn't find anything related to facebook sharing when walking the gconf tree), and it doesn't seem to be in any dot folders in my home dir. Anyone know ? - Finally, I gave up, set up the chroot, and straced that binary. And I should have known this would have led me to the right solution. Among all the noise, there were some calls trying to open a library. It's normal for a bunch of calls to fail as it searches the whole LD_LIBRARY_PATH, but usually the last one of those in an strace log should succeed. But they weren't; apparently /usr/lib/libfacebookcommon.so.0 was missing!
- Looking for that file on disk confirmed that it wasn't there, and doing dpkg -L feedservice-plugin-fb-common showed that it should in fact be there. This reminded me of a pet peeve I have with those people who claim Debian's packaging system to be far superior to rpm - apparently dpkg doesn't have any equivalent of rpm -qv which allows you to verify that the files that should be installed by a package are indeed on disk. This would have saved me *a lot* of time figuring out this problem, and is typically the first thing I do on an rpm-based system where things act funny.
- With my first real clue in hand, I used ldd to verify that indeed there were libraries missing:
ldd -r /usr/lib/sharing/plugins/libfacebooksharingservice.so
…
undefined symbol: facebook_credentials_free (/usr/lib/sharing/plugins/libfacebooksharingservice.so)
undefined symbol: facebook_request_reset (/usr/lib/sharing/plugins/libfacebooksharingservice.so)
undefined symbol: network_utils_post_multipart_with_progress (/usr/lib/sharing/plugins/libfacebooksharingservice.so)
undefined symbol: facebook_get_email (/usr/lib/sharing/plugins/libfacebooksharingservice.so)
undefined symbol: facebook_login (/usr/lib/sharing/plugins/libfacebooksharingservice.so)
undefined symbol: generate_signature (/usr/lib/sharing/plugins/libfacebooksharingservice.so)
undefined symbol: facebook_store_credentials_to_gconf (/usr/lib/sharing/plugins/libfacebooksharingservice.so)
undefined symbol: facebook_request_new (/usr/lib/sharing/plugins/libfacebooksharingservice.so)
undefined symbol: facebook_request_free (/usr/lib/sharing/plugins/libfacebooksharingservice.so) - Using dpkg -S to figure out what package this belonged to, I apt-get remove'd that package, then reinstalled it and dependencies.
- Still didn't work, so repeated the process, this time libfeeserviceutils.so.0 was missing, so reinstall feedservice-utils and dependencies.
And finally! The sharing plugin can again be configured, and all is well. But this experience was needlessly painful…
For the record, I didn't tinker with any package files by hand (anyone who knows me a little knows my stance on packages and /usr), and I have no idea what I did to get into a situation where files that should be on disk aren't. And I'm worried about what else is missing, so if anyone can point me to some resources explaining how to verify installed package manifests, that would be awesome.
01 Mar 2010 7:15pm GMT
28 Feb 2010
Planet Twisted
Kevin Turner (LJ): oatmeal with hemp milk and rasins
Changing dietary restrictions has got me really curious about where to go to find new recipes. I've spent a lot of time over the past few days looking at various recipe catalogue sites. I'm focusing more on public recipe repositories, less on individual chefs. I thought I'd share some of my impressions:
- Best for answering "What do I want to eat?"
-
cookthink asks "What are you craving?"
I'm very impressed by the design here. I find my attempts to describe it don't really do it justice. Next time you have a moment of "I'm not sure what I want," try it out!
It does not, however, have a way to filter its suggestions for dietary restrictions, and you cannot add recipes to its collection.
- Best for answering "What can I make now?"
-
Supercook. Searching for recipes by ingredient is pretty common now, but Supercook seems to be unique in that it stores the list of things you have in your kitchen. That is, I can ask it for recipes with lentils now, and it already knows I have coconut milk and ginger from the last time I told it, and will suggest recipes accordingly. It also suggests things I should get to broaden my choices (at the moment, it suggests I buy more lemon, carrots, and spinach), and will remember that I don't want to see any recipes with tofu.
Supercook's collection of recipes comes from automatically searching other recipe sites. You cannot add recipes to it directly.
- Most Comprehensive Search Site
-
I believe that Recipe Puppy does ingredient-based search across more sites than anything else I've seen. In some ways, Recipe Puppy (and companion CookThing) are similar to SuperCook, but their interfaces are different and CookThing doesn't have Supercook's memory about my kitchen inventory and restrictions.
- Least Obnoxious Megasite
-
allrecipes.com probably deserves better than a back-handed compliment like this. Unlike the sites above, you can add your own recipes, or links to recipes. The sheer size of its collection and community counts for a lot.
But for me, choosing between allrecipes.com and its competitors was a process of elimination. RecipeZaar has pop-up ads. And I failed to make it through the sign-up process for Epicurious when it kept redisplaying the registration form like I had omitted some required element, although I couldn't find what. Coulda been a Chrome bug. Or could be some additional flag or checkbox I didn't see buried amongst the various "partner offers" on the lengthy form.
- Best at Building a Recipe Box
-
I'm not really sure how the size of the catalogue or the vitality of the community at Springpad for foodies compares, but their recipe box has this thing where you can point it at an arbitrary URL and it will grab the list of ingredients. Nice!
- Go-to site for Indian food
From an informationology perspective, the recipe-sharing world is kind of interesting. With the exception of some highly-competitive subcultures, there's a lot of sharing that happens, relatively unhindered by intellectual property concerns. Indeed, lists of ingredients are not eligible for U.S. copyright protection, but cookbooks are, so a lot of this happens in a grey area.
At the same time, you've still got content providers with the same revenue models as elsewhere: old media publishing books or magazines, and online media wanting users to keep coming back to keep their ad impressions up. So you still get big content silos, whether they be driven primarily by user-submitted content like allrecipies or professionally sourced content owned by media giants.
None of the sites I've found so far seems to have a public API, not even Foodista (wikipedia of the cooking world) or Nibbledish (nee OpenSourceFood). It may be that some of the silos have private APIs for those who are willing to negotiate a license.
So we end up with sites with a variety of properties:
- SparkRecipes has a nutritional info feature, is connected to a nutrition-tracking system, and is tied to an active community, but has very stringent terms about only submitting original work.
- GroupRecipes has the Recipe Robot, a recommendation engine. But it can only operate within its own content silo.
- Sites like Recipe Puppy have figured out how to break the content out of the silos to some extent, but I wonder to what degree they're just flying under the radar for the time being.
So, once again, the stronger the silos are, the more the users lose. People come up with these great products to base on a collection of recipes, like nutritional analysis, or a recommendation engine, or filtering by the contents of your fridge, but users have to choose between the site with the feature or the site with the recipe catalogue. Which means that even though I love the idea of an expert recommendation engine, I will probably never use GroupRecipe's Recipe Robot, because having other features or a larger recipe catalogue is more important.
This is probably the best case for microformats I've ever considered. Generally, I've been skeptical of microformats (if you have structured data, I want to access it through a specific API, kthx), but given the amount of distributed recipe data out there amongst these various sites and food bloggers, it might be quite valuable. And in fact, it looks like here is hRecipe, which still says "draft" but is reportedly used by Williams-Sonoma and the Food Network. Perhaps there is hope yet!
28 Feb 2010 11:23pm GMT
Paul Swartz: Even the New York Times doesn’t think Hawaii is part of...

Even the New York Times doesn't think Hawaii is part of the US
28 Feb 2010 4:45pm GMT
27 Feb 2010
Planet Twisted
Thomas Vander Stichele: Book: 33 1/3 – Pixies – Doolittle
My latest Amazon order arrived at work. One of the books was the Doolittle book in the 33 1/3 series. For those who don't know, this series dissects an album track by track and tells stories about the recording. The first one I read was on Afghan Whigs's "Gentlemen", for obvious reasons.
These books tend to be a little top-heavy, saying less about the band and more about the reviewer, and they can be hit-and-miss because a lot depends on the actual writer/journalist. It seems the band remembers little about making the album. Two things stick after reading this one:
- Apparently I'm as prone to mishearing lyrics as anyone else. This book tells me that the first lines of La La Love You are "Shake your butt / Not too hard". All my life I've been hearing that as "Take the bus! Not the car!" Somehow I'm going to keep preferring mine, although I have to admit shake your butt makes more sense in the context of the song.
- If you' re doing a 100+ page book on Doolittle, how on earth do you manage to not talk at all about the hidden mini-album in Doolittle that you get when you play the tracks as numbered in the CD booklet ? Gouge away/Mr. Grieves/Dead/Wave of Mutilation/Tame/Hey/I Bleed/Monkey gone to Heaven tell a very different story than the main album. If there's one question I'd ask mr. Thompson about Doolittle, it would have been about this one…
The book was written before the recent Doolittle tour, as it mentions Silver has never been played live by the band. Which I'm going to assume was correct before that tour since I have no bootleg evidence to the contrary…
27 Feb 2010 11:52am GMT
25 Feb 2010
Planet Twisted
Moshe Zadka: Seeing “Sneakers” With the Girlfriend
I wanted to introduce T to one of my favorite all-time movies, "Sneakers".
Yes, yes, I know the technical premise is ludicrous (clearly, Russian math is different than US math), and on watching the movie, there were some painful parts (like the genius mathematician explaining to fascinated listeners, all of them are implied to have at least a basic grounding in math, things like "there are numbers so big
that not all the computers in the world could factor" or something to that effect). But the characters are wonderful, the plot is fascinating and the dialogue amusing.
T, of course, commented on the way they dressed, "that movie is from the early '90s, right?". I laughed, kissed her, and replied, "that's one comment I never heard when seeing this movie."
I find it fascinating - though we were looking at the screen at the same time, we were clearly watching different movies. I was watching a movie about a post-math-talk conversation, and she was watching a movie about
a formal party.
25 Feb 2010 10:46pm GMT

