If programming languages were literary genres...
From a conversation at the pub this evening with Jonathan and Glenn...
- JavaScript would be science fiction. Easy to get into, and while there's an incredible amount of crap out there, there are also many gems that, carefully considered, will completely change your outlook.
- C and C++ would be "literary" fiction. Somewhat old-fashioned, occasionally brilliant, but frequently clunky and never quite as good as its devotees and creators like to think it is...
- LISP and Scheme would be obscure branches of poetry; densely packed with information, a few words express something that would take that would take tens of thousands to express in other languages. But only a few dozen people in the world would understand it.
...and somewhere around there, we ran out of steam. Java as corporate mission statements? Not quite... VBA as newspaper cartoons? Hmm. COBOL as... God only knows. And we couldn't even place Python.
Anyone got any ideas?
Busy, busy, busy
A couple of weeks back we were brainstorming about other ways we could make use of the code infrastructure we'd put together for Dirigible. We had loads of stuff for running functional tests, determining dependencies between spreadsheet cells, executing untrusted user code safely on our servers, and so on. Any of those could potentially make an interesting product, so we put together some basic landing pages, one for each idea, and put a bit of money into Google AdWords to see if any of them got any interest.
One of them took off immediately, and even started getting traction on Twitter: PythonAnywhere, an online Python IDE and web application environment -- basically, Dirigible without the spreadsheet grid. This fits in with what we suspected -- lots of people were interested in Dirigible, but it wasn't the spreadsheet side of it that excited them, it was the easy Python grid computing.
What's been particularly cool with this idea is not only that most of it is done and "just" needs breaking out of Dirigible and putting into a new product, but that people are keen to engage with us about it. When people signed up on our landing page, we sent them an email with a few questions -- "What would you use it for? Which features excite you? What would you pay for it? Any suggestions for other features?" About 25% of people have replied, with lots of great feedback, and we've changed our plans (and altered the relative priorities of features) based on their input. All very Lean Startup...
Anyway, all good clean fun. If you'd like a look at it when it goes into beta, you can sign up on the site, or just leave a comment below.
Some old JavaScript
I was digging around in my archives and discovered some old JavaScript demos I wrote back in 1999 — long enough ago that I thought of them as "DHTML pages". It turns out that they only needed a few minor tweaks to make them work on modern browsers; the bulk of that was removing the browser-sniffing code, and then in each case where I was deciding what to do based on whether the browser was Netscape 4 or Internet Explorer 4 (!), deleting one or the other case. Looks like it was about 50/50 as to which browser won.
Anyway, without much further ado, I bring you the holding page for my old personal/political blog, before it went live (and you can really see how this would have pulled the readers in), and a page in the style of 1980s/early 90s Amiga demos. The latter is particularly worthy of note because when I originally posted it, I made sure it only appeared in 640x480 windows — because anything larger would make even fast machines grind to a halt, all those years ago back in 1999. The tagline really made sense, back then.
Excuse me, I just need to go into a corner and feel old...
[UPDATE] I kept track of the changes required to convert 1999-vintage DHTML to modern JavaScript in a Git repo, if anyone's interested in doing a similar conversion then let me know in the comments and I'll put together something.
Fun with the Audio Data API
The latest beta version of Firefox 4 has an API for reading and writing audio data -- right down to the sample level, right from JavaScript. JavaScript is, of course, totally the wrong language to write DSP-style code in, so that's what I decided to do :-)
If you fancy downloading FF4 beta and trying out some of the demos, here they are. There are lots of (much better) demos by other people here.
And if you try out the musical temperament example and have any thoughts on which chords sounded nicest, leave a comment below!
(Update: the Mozilla Audio API no longer works, as far as I can tell -- a different Web Audio API wound up becoming the standard -- maybe I'll port the examples over to that!)
A big announcement from Resolver
So, I've let various hints drop over the last few months, but we did the official annoucement today: a new product from Resolver, called Dirigible (thanks to Wikipedia's "Random page" link :-). It's been in private beta for a few weeks, and we decided it was time to get the news out there about it. As to what it is... our tagline is that it is "a spreadsheet-like tool for Python grid computing". That's kind of fuzzy (and probably needs a bit of work), but what I do want to make clear is what it's not: it is not just a web-based version of Resolver One, our desktop Python spreadsheet.
Instead, it's something much more developer-focused, built from the ground up -- sharing code with Resolver One, of course, but not trying to duplicate it. To quote the official annoucement:
We took the things from Resolver One that made software developers say "wow" -- like Python-based formulae, objects in the grid, and the ability to treat a spreadsheet as a function and call it from another sheet. Then we worked out what we could make better by coding just those things as a web application backed by traditional Python -- not IronPython -- on a grid of Linux servers.
You can read more about Dirigible and how it relates to Resolver One on the company blog, or there's a more concise version on the product's own web page. If you'd like to try it out, there's a signup form on the main Dirigible page; we're keeping beta user numbers small for now, but building up as we gain confidence that we've not done anything totally stupid with regard to security or scalabity...
I think everyone at Resolver's done a great job in putting it all together -- of course, being able to share code with Resolver One helped a lot :-) And I'm sure that Dirigible's going to be a great addition to the company's product line.
Bare Git repositories
We started a new project at Resolver today -- I'm pretty excited about it, and will be blogging about it soon. However, in the meantime, here's something that's half a note-to-self and half something to help people googling for help with Git problems.
We've previously been using Subversion as our main source code control system, but for more recent projects we've moved to Mercurial. When we started the new one today, we decided to try out Git for a change; I use GitHub for my personal stuff, but hadn't used it for anything involving multiple developers -- and various people had been telling us that it wasn't subject to some of the problems we'd had with Mercurial.
So we created a new Git repo on a shared directory, by creating a directory and
then running git init
in it. We then cloned it into a working directory on my
machine, and started work. After a while, we had our first checkin ready, so we a
dded the files, committed them, and then decided to push to the central repo to
make sure everything worked OK. We got this error message:
remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.
remote: error:
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error:
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
It took us a while to work out precisely what this meant, because we'd never heard of "bare" repositories before. It turns out that there are two kinds of repository in Git: bare and non-bare. A non-bare repository is the same as the ones we were used to in Mercurial; it has a bunch of working files, and a directory containing the version control information. A bare repository, by contrast, just contains the version control information -- no working files.
Now, you can (in theory) push and pull between repositories regardless of whether they are bare or not. But if you were to push to a non-bare repository, it would cause problems. Part of the SCC data that Git keeps is an index, which basically tells it what the head of the current branch looks like. Now, if you push to a non-bare repository, Git will look at the working files, compare them to the index, and see that they differ -- so it will think that the working files have changed! For example, if your push added a new file, it would notice that the working directory didn't include that file, and would conclude that it had been deleted. There's a step-by-step example here.
You can see how that could be confusing. So bare repositories exist as a way of having central repositories that a number of people can push to. If you want to transfer changes from a non-bare repository to another, the correct way is to pull from the destination rather than push from the target -- which makes some kind of sense when you think about it. In general, any repository that someone is working on is not something that should be receiving changes without their approval... on the other hand, we've not encountered problems with pushing to regular repositories with Mercurial.
Anyway, this was our first checkin, so we had no history to lose, we fixed the
problem by creating a new central repository using git --bare init
in a new
directory on the shared drive, cloning it to a new working repo, copying our files
over from the old working repo to the new one, committing, and pushing back to
the bare repository. It worked just fine. If we'd done multiple checkins before
we tried our first push, we could have saved things by hand-editing the central
repository; it had no working files (because we'd only just created it) so we
could have moved the contents of the .git
directory up to the repository's root,
and deleted .git
-- this would have "bared" it so that we could have pushed
from our working repo. That would have been a bit scary, though.
Running Resolver One on Mono for Windows
Mono is an open source version of the .NET framework; it allows you to run .NET applications not just on Windows but on Linux and the Mac. I've spent quite some time over the last week getting our Python spreadsheet, Resolver One, to run on the Windows version, and thought it would be worth sharing some experiences.
Generating political news using NLTK
It's election week here in the UK; on Thursday, we'll be going to the polls to choose our next government. At Resolver Systems, thanks to energy and inventiveness of our PR guys over at Chameleon, we've been doing a bunch of things related to this, including some analysis for the New Statesman that required us to index vast quantities of tweets and newspaper articles.
Last week I was looking at the results of this indexing, and was reminded of the fun I had playing with NLTK back in February. NLTK is the Python Natural Language Toolkit; as you'd expect, it has a lot of clever stuff for parsing and interpreting text. More unexpectedly (at least for me), it has the ability to take some input text, analyse it, and then generate more text in the same style. Here's something based on the Book of Genesis:
In the selfsame day entered Noah , and asses , flocks , and Maachah . And Joseph said unto him , Abrah and he asses , and told all these things are against me . And Jacob told Rachel that he hearkened not unto you . And Sarah said , I had seen the face of the air ; for he hath broken my covenant between God and every thing that creepeth upon the man : And Eber lived after he begat Salah four hundred and thirty years , and took of every sort shalt thou be come thither .
It was the work of a moment to knock together some code that would read in all of the newspaper articles that we'd tagged as being about a particular subject, run them through a Beautiful Soup-based parser to pull out the article text, and feed that into NLTK, then to dump the results into a Wordpress blog (after a little manual polishing for readability).
Regular expressions and Resolver One column-level formulae
Recently at Resolver we've been doing a bit of analysis of the way people, parties and topics are mentioned on Twitter and in the traditional media in the run-up to the UK's next national election, on behalf of the New Statesman.
We've been collecting data, including millions of tweets and indexes to newspaper articles, in a MySQL database, using Django as an ORM-mapping tool -- sometime in the future I'll describe the system in a little more depth. However, from our perspective the most interesting thing about it is how we're doing the analysis -- in, of course, Resolver One.
Here's one little trick I've picked up; using regular expressions in column-level formulae as a way of parsing the output of MySQL queries.
Let's take a simple example. Imagine you have queried the database for the number of tweets per day about the Digital Economy Bill (or Act). It might look like this:
+------------+----------+
| Date | count(*) |
+------------+----------+
| 2010-03-30 | 99 |
| 2010-03-31 | 30 |
| 2010-04-01 | 19 |
| 2010-04-02 | 12 |
| 2010-04-03 | 2 |
| 2010-04-04 | 13 |
| 2010-04-05 | 30 |
| 2010-04-06 | 958 |
| 2010-04-07 | 1629 |
| 2010-04-08 | 1961 |
| 2010-04-09 | 4038 |
| 2010-04-10 | 2584 |
| 2010-04-11 | 1940 |
| 2010-04-12 | 3333 |
| 2010-04-13 | 2421 |
| 2010-04-14 | 1319 |
| 2010-04-15 | 1387 |
| 2010-04-16 | 3194 |
| 2010-04-17 | 860 |
| 2010-04-18 | 551 |
| 2010-04-19 | 859 |
| 2010-04-20 | 685 |
| 2010-04-21 | 528 |
| 2010-04-22 | 631 |
| 2010-04-23 | 591 |
| 2010-04-24 | 320 |
| 2010-04-25 | 363 |
| 2010-04-26 | 232 |
+------------+----------+
Now, imagine you want to get these numbers into Resolver One, and because it's a one-off job, you don't want to go to all the hassle of getting an ODBC connection working all the way to the DB server. So, first step: copy from your PuTTY window, and second step, paste it into Resolver One:
Right. Now, the top three rows are obviously useless, so let's get rid of them:
Now we need to pick apart things like | 2010-03-30 | 99 |
and turn them into separate columns. The first step is to import the Python regular expression library:
...and the next, to use it in a column-level formula in column B:
Now that we've parsed the data, we can use it in further column-level formulae to get the dates:
...and the numbers:
Finally, let's pick out the top 5 dates for tweets on this subject; we create a list
...sort it by the number of tweets in each day...
...reverse it to get the ones with the largest numbers of tweets...
...and then use the "Unpack" command (control-shift-enter) to put the first five elements into separate cells.
Now, once we've done this once, it's easy to use for other data; for example, we might want to find the fives days when Nick Clegg was mentioned most on Twitter. We just copy the same kind of numbers from MySQL, paste them into column A, and the list will automatically update:
So, a nice simple technique to create a reusable spreadsheet that parses tabular data.
OpenCL: .NET, C# and Resolver One integration -- the very beginnings
Today I wrote the code required to call part of the OpenCL API from Resolver One; just one function so far, and all it does is get some information about your hardware setup, but it was great to get it working. There are already .NET bindings for OpenCL, but I felt that it was worthwhile reinventing the wheel -- largely as a way of making sure I understood every spoke, but also because I wanted the simplest possible API, with no extra code to make it more .NETty. It should also work as an example of how you can integrate a C library into a .NET/IronPython application like Resolver One.
I'll be documenting the whole thing when it's a bit more finished, but if you want to try out the work in progress, and are willing to build the interop code, here's how:
- Make sure you have OpenCL installed -- here's the NVIDA OpenCL download page, and here's the OpenCL page for ATI. I've only tested this with NVIDIA so far, so I'm keen to hear of any incompatibilities.
- Clone the dot-net-opencl project from Resolver Systems' GitHub account.
- Load up the
DotNetOpenCL.sln
project file in the root of the project using Visual C# 2008 (here's the free "Express" version if you don't have it already). - Build the project
- To try it out from IronPython, run
ipy test_clGetPlatformIDs.py
- To try it in Resolver One, load
test_clGetPlatformIDs.rsl
That should be it! If you want to look at the code, the only important bit is in
DotNetOpenCL.cs
-- and it's simply an external method definition... the tricky
bit was in working out which OpenCL function to write an external definition for,
and what that definition should look like.
I've put a slightly tidied version of the notes I kept as I implemented this below, for posterity's sake; if you're interested in finding out how the implementation went, read on...