# Category Archives: General

Paraphernalia and chaos.

# DX hackfest: 2016 edition

By this time tomorrow, the 2016 edition of the GNOME developer experience hackfest will have started. This year, it’s in Brussels, kindly hosted by betacowork and ICAB.

We will be spending 3 days looking at a variety of things on the agenda to improve the lives of developers on GNOME, and make plans for the rest of the year. Watch out for updates on planet.gnome.org.

Thanks to the GNOME Foundation for sponsoring the travel for various people who are coming.

Collabora is sponsoring snacks throughout, and is sending 5 of us along for the hackfest. Thank you also to the other companies who are sending or letting people come — I know of Red Hat, Endless Mobile, Codethink and Canonical (please let me know if I’ve forgotten anyone!).

See people at FOSDEM afterwards?

# Checking D-Bus API stability

Announcing dbus-deviation, a small tool and set of libraries for automatically checking whether a D-Bus interface has broken API between two releases of a piece of software, developed as part of my work at Collabora.

Why?

If you have a large software project, worked on by multiple developers, it might not be clear when D-Bus interfaces change. For example, they might be pulled in from another repository, or might be accidentally changed without anyone noticing.

Breaks in the D-Bus API of a project (when it’s supposed to be stable) are potentially worse than breaks in its C API, because they can only be detected at runtime — when client applications suddenly error out half-way through an operation because they’ve called a D-Bus method with the wrong argument type. At least with C API breaks, the compiler will catch the break.

(In this respect, I guess D-Bus APIs are actually a form of ABI — a runtime interface, rather than a compile-time interface.)

How?

dbus-deviation provides a utility called dbus-interface-diff, plus some GNU Make glue to plug it into your build system. It only works with git: for each tagged release of your project, it uses git-notes to store copies of all the D-Bus interfaces you care about, in their state at the time of that release. They’re stored as introspection XML; if you have that XML committed into the repository anyway, the git-note becomes a ref to the existing file blob, and takes up virtually no space at all. The dbus-interface-diff tool then does a diff between two XML files (for example, one stored for the most recent release, and the one currently in your working tree), and flags up any forwards- or backwards-incompatibilities.

What?

A backwards-incompatibility, as far as dbus-deviation is concerned, is one where existing clients will not work against new versions of the D-Bus service, for example because a method they use has been removed.

A forwards-incompatibility is one where new versions of clients may not work against old versions of the D-Bus service, for example because they use a method which has been added in a new version of the API.

Traditionally, projects care about preventing backwards-incompatible API changes, and don’t care so much about forwards-incompatibilities. dbus-deviation lets you set your desired stability policy.

Where?

dbus-deviation has a spartan website, a git repository, and bugs are stored using Bugs Everywhere in git; contact me in the comments or by e-mail if you want to report something. API documentation is available for the Python libraries underpinning it, which provide an AST and diff methods for D-Bus APIs.

All feedback is very much welcome. One area I feel is still a little awkward is how dbus-deviation integrates with make dist — it forces use of a pre-push git hook to update the remote git-notes for the API signatures of newly pushed release tags. That needs to be set up by each developer who releases a project (using make dist) — any suggestions for improving this are welcome.

What next?

API stability checking for GIR APIs, perhaps? This one needs some more work.

# Dynamic relocs, runtime overflows and -fPIC

While merrily compiling something a little while ago, my linker threw me this gem of an error message (using GNU gold):

error: libmumble.a(libmumble.o): requires dynamic R_X86_64_PC32 reloc against 'g_strdup' which may overflow at runtime; recompile with -fPIC

or, if you’re using GNU ld (the two linkers have different error messages for the same problem):

error: mumble.o: relocation R_X86_64_PC32 against symbol g_strdup' can not be used when making a shared object; recompile with -fPIC

I recompiled everything with -fPIC, and magically the problem went away. But I didn’t understand why. I finally got a bit of time to investigate, so here we go.

tl;dr: This is caused by linking a shared library (which requires position-independent code, PIC) to a static library (which has not been compiled with PIC). You need to either link the shared library against a shared version of the static code (such as is produced automatically by libtool), or re-compile the static library with PIC enabled (-fPIC or -fpic).

To understand this, we need a brief introduction to the different types of linking, and how static objects and libraries differ from shared (or dynamic) objects and libraries. Let’s run with a minimal working example: two C files, shared.c and static.c. static.c is compiled to a static archive, libstatic.a (without position-independent code, PIC), and shared.c is compiled to a shared object, libshared.so, which links against libstatic.a.

What is a static object? It’s one where all symbol references are resolved at compile time. What’s a dynamic object? One where symbol references can be resolved at runtime. This means that dynamic objects have to have relocations performed as they’re loaded, which incurs a load-time penalty, but allows for shared libraries and symbol interpositing.

It is these relocations which cause the problem hinted at by the error message above. Each relocation is effectively a note to the runtime loader instructing it to replace a symbol reference in the dynamic object being loaded, with an address calculated at load time.

There are various types of relocations, defined by the platform ABI, as they are specific to the processor’s instruction set. For a more in-depth account of them, see Relocations, Relocations by Michael Guyver. In this case, the R_X86_64_PC32 relocation was chosen by the compiler, which is defined by the AMD64 ABI (Table 4.10). What does that mean? Each relocation type is essentially a mathematical function to define the address of a relocated symbol, given the information in various symbol, section and relocation tables in the dynamic object. The ABI defines R_X86_64_PC32 as . Less succinctly, it is the offset of the referenced symbol, plus a constant adjustment (the addend) minus the offset of the relocation. This is all explained brilliantly by Michael Guyver on his blog.

So, with our example, we get the error:

$make libshared.so cc -Wall -c -o shared.o shared.c cc -Wall -c -o static.o static.c ar rcs libstatic.a static.o cc -shared -o libshared.so shared.o libstatic.a /usr/bin/ld: error: shared.o: requires dynamic R_X86_64_PC32 reloc against 'my_static_function' which may overflow at runtime; recompile with -fPIC collect2: error: ld returned 1 exit status make: *** [libshared.so] Error 1 If we look at the disassembly of the shared object: $ objdump -d shared.o

shared.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <my_shared_function>:
0:    55                       push   %rbp
1:    48 89 e5                 mov    %rsp,%rbp
4:    e8 00 00 00 00           callq  9 <my_shared_function+0x9>
9:    5d                       pop    %rbp
a:    c3                       retq

we can see at offset 4 that the callq instruction (calling my_static_function()) leaves 4 bytes for the address of the function to call (actually, callq is instruction-pointer-relative, so the 4 bytes are for the offset of the function from the RIP register).

As the code in libstatic.a is not PIC, it has to be loaded at a fixed offset in a process’ address space. The shared library, libshared.so, must be capable of being loaded anywhere in an address space. This would be fine if the callq instruction could take an absolute address to call, as the linker could substitute in the absolute address of my_static_function() (as is done on 32-bit systems). However, it cannot – it only has 4 bytes of operand to play with, rather than the 8 needed for a 64-bit address – so linking has to fail. And that’s why we get an error which talks about overflow.

What happens if libstatic.a is compiled with PIC enabled? Not a whole lot changes, actually. The disassembly of libstatic.a remains unchanged. shared.o gains a global object table (GOT) section and its relocation for the my_static_function() call changes from R_X86_64_PC32 to R_X86_64_PLT32 — a procedure linkage table (PLT) relocation using the GOT. We can see that in action in the disassembly of the successfully-linked libshared.so (with irrelevant bits omitted):

$objdump --disassemble libshared.so libshared.so: file format elf64-x86-64 Disassembly of section .plt: 00000000000005f0 <my_static_function@plt>: 5f0: ff 25 fa 13 00 00 jmpq *0x13fa(%rip) # 19f0 <_GLOBAL_OFFSET_TABLE_+0x28> 5f6: 68 02 00 00 00 pushq$0x2
5fb:    e9 c0 ff ff ff           jmpq   5c0 <_init+0x20>

Disassembly of section .text:

00000000000006e8 <my_shared_function>:
6e8:    55                       push   %rbp
6e9:    48 89 e5                 mov    %rsp,%rbp
6ec:    e8 ff fe ff ff           callq  5f0 <my_static_function@plt>
6f1:    5d                       pop    %rbp
6f2:    c3                       retq
6f3:    90                       nop

00000000000006f4 <my_static_function>:
6f4:    55                       push   %rbp
6f5:    48 89 e5                 mov    %rsp,%rbp
6f8:    5d                       pop    %rbp
6f9:    c3                       retq
6fa:    66 90                    xchg   %ax,%ax

Firstly, the callq instruction in my_shared_function() has acquired a non-zero operand. This is a constant offset from the instruction pointer at that instruction which references the entry for my_static_function() in the PLT, which we can see as my_static_function@plt in the .plt section. Rather than being the code for the my_static_function(), this is actually a ‘trampoline’ which loads the address of my_static_function() from the GOT, then jumps to it. The GOT is set up by the runtime loader, and allows for the address of my_static_function() to be changed; for example when relocating it, or when interpositing a different version using LD_PRELOAD. By default, the GOT entry for my_static_function() will point to the implementation in the .text section, as linked in from libstatic.a.

This trampolining through a PLT and GOT is the standard solution for producing position independent code, and demonstrates three things:

• Exported functions incur a runtime cost (in the PLT) on every call. This can be eliminated for private symbols (or internal calls to public symbols, with -Bsymbolic), but not (easily) for public ones, as explained by Ian Lance Taylor. This cost is only three instructions; as they change control flow, they could be relatively expensive, but are probably also catered specifically for in modern superscalar 64-bit processors, as the majority of the code they execute will do indirect function calls this way. So the cost can be safely ignored for all but rather specific use cases.
• Position independent code is easy to achieve, and the indirection it requires brings other benefits like the ever-useful LD_PRELOAD, used by developer tools everywhere.
• Marking internal functions as static is important, because ELF exports functions by default, so internal function calls end up being indirected through the PLT if you omit the static modifier. (Though note that none of the functions here could have been marked as such, as they were all in different compilation units.)

So in summary:

• The “requires dynamic R_X86_64_PC32 reloc against ‘mumble’ which may overflow at runtime; recompile with -fPIC” error is caused by attempting to link a shared library against a static object.
• One solution is to compile a position-independent version of the static object. libtool does this automatically, so why aren’t you using libtool?
• Another (highly related) solution is to link against a shared version of the static object.
• This isn’t an issue on 32-bit systems because PIC is possible by default on those systems, since instruction operands are wide enough to contain absolute symbol addresses .
• Compiling with position independent code introduces a procedure linkage table (PLT) and global offset table (GOT) for each object file, which are very hard to eliminate if you want to avoid the (small) function call overhead they introduce.
• So you should avoid PIC if compiling for constrained targets like embedded devices.
• But use it otherwise (e.g. on desktop systems) for the flexibility (the use of shared libraries!) and security (address space layout randomisation) it affords.

Source code for the example here is available on gitorious in the public domain.

# Travelling in Honduras

Having just spent 7 weeks in Honduras, working and travelling, I thought it might be useful to document some of the things I’ve learned about the country.

In my experience, Honduras has three distinct areas: the north (Caribbean) side where English is spoken moderately commonly, and many people go to learn to dive (especially on the Bay Islands); the three major cities (Tegucigalpa, San Pedro Sula and La Ceiba) where tourism infrastructure is practically non-existent, pollution is high and crime is high; and the rest of the countryside, which is pleasant, safe (for the most part) and has little tourism infrastructure.

I spent 5 weeks in the capital (Tegucigalpa) and saw the bad side of Honduras. It is not a safe city to walk around, even in the richer areas, so you have to drive everywhere. I hadn’t previously realised how much I value being able to walk the streets and go where I please without probability of being robbed at gunpoint. Despite its security problems, Tegus was a reasonable-ish place to be. It has all the amenities of a big city — clubbing, for example, there is just as grim as in England, except with more Latin music. There is nothing for tourists to see, and they should only use it as a transport hub (since it has one of the country’s two major airports, and is a major bus terminal) or as a base to explore the much-nicer Valle de Ángeles, La Tigra national park, and Comayagua nearby.

Tegucigalpa demonstrates the two major problems which Honduras suffers from: a huge imbalance in the distribution of wealth, and endemic corruption in government and the police force. These have knock-on effects on everything else. The rich live in enclosed neighbourhoods with high walls, barbed wire, electric fences, and armed private security. They drive luxury 4×4s and have lives which would be considered privileged in Europe. The poor live in shacks which line the roads and are stacked up the hillsides. There is a huge amount of gang crime: it seems that most of the drugs passing from South America to the USA come through Honduras. This gang crime contributes hugely to Honduras’ murder rate, making it officially one of the most dangerous countries in the world — although if you’re not involved in a gang, you’re as safe as in other Central American countries. A lot of this crime goes unpunished, both because the police are unable to tackle the gangs, and also because they’re corrupt. It is the army which enforces the law here.

The Bay Islands are completely different. I spent a week on Utila, and it was a safe, friendly place, quite different from Tegucigalpa. Its summer climate is hot (30?) and humid (up to 80% relative humidity, with very little wind), which I found unbearable at times. Still, it is easy to get to, has excellent diving opportunities, and caters well for someone who wants to party every night. It’s quite drug-friendly.

The rest of the country is mostly small villages and farmland. There isn’t much tourism infrastructure, but travel is easy and cheap on ‘collectivo’ and chicken buses (old, reappropriated US school buses; less gaudily decorated than in Guatemala). Most villages don’t have much to offer other than colonial architecture and old churches (and a lot of auto repair shops). A few are more popular: Gracias, Lempira; and Copán Ruinas.

Gracias has more quaint architecture than most places, and is next to Celaque national park, home of Honduras’ tallest mountain (Cerro Las Minas). Worth a visit if you like cloud forests, bird watching or hiking in general. Summitting Cerro Las Minas normally takes two days, but an experienced (and fit — it’s a steep mountain) hiker can do it in 7 hours.

Copán Ruinas is the gateway to the country’s Mayan ruins, which are definitely worth a visit. Very well preserved hieroglyphics, and lots of wildlife (including a Macaw breeding programme). If you visit Copán Ruinas, seeing the ruins will take half a day, and there is little else to do in the town unless you plan in advance with a local tour company to do a trek or horse ride. I didn’t, so I don’t know what they’re like.

Infrastructure is what Honduras lacks. Its roads are full of potholes (leading to its infamous crazy driving), there are frequent (roughly once a week) power outages and internet outages. None of the tap water is potable and drainage often runs straight onto the street (which in turn expedites damage to the roads). Building and maintaining infrastructure in such a mountainous country is tricky, but it’s necessary.

With the benefit of hindsight, there are a few things I would do differently if I came to Honduras again. Quite a few of them are the standard recommendations for travelling in Central/South America anyway:

• If you can afford it, hire a car or motorbike (the latter are incredibly popular here). Having your own transport gives you a lot of freedom and safety. Get a vehicle suited to off-road driving: even if you don’t end up on a dirt track (which is quite possible if one of the few major roads is closed due to landslides), there are nasty speed bumps throughout the country which chew up cars with low ground clearance.
• If you can’t, use collectivo buses, which are safe and, while the routes aren’t listed anywhere online or on paper, generally follow major roads. Any local will know about them. They run very frequently.
• Find out which areas of a city are considered safe, and which aren’t. If you stick to the safe areas and use common sense, everything will be fine. If you go to an unsafe area, you’re likely to be robbed or kidnapped. For example, even the locals in Tegus don’t venture to Comayaguela. The hotels aren’t always in the safe areas, especially in Tegucigalpa — definitely avoid anything in the Comayaguela area.
• Don’t plan to do much hiking. It’s not a particularly popular pastime here, so while there are many ‘national parks’, they mostly exist to protect the cloud forests. There are some nice trails in some (for example, La Tigra and Celaque), but don’t expect too much. If you’re interested in birds, however, Honduras is supposed to be pretty good; there are hotels dedicated to bird watching around La Ceiba.
• If you go to the Bay Islands to dive, have a contingency plan in case of illness (which would prevent you from diving). When I was there, several people I knew got colds and ended up doing absolutely nothing for a week until they got better.
• Don’t try and plan a tight itinerary in advance, as unexpected transport problems might throw it off. Internet access is easy to come by in Honduras (especially 3G), so make things up as you go along. Factor in plenty of time for making travel connections, as few of the bus times are synchronised.
• Aside from touristy places (like Copán Ruinas), Honduras doesn’t do European-style hostels. You’re going to have to look at hotels, but there are cheap ones.
• Similarly, don’t expect to send any postcards. In my experience, they’re hard to find, and harder to send. Post offices are like gold dust.
• Don’t trust the websites describing most bus routes in Honduras (apart from the huge companies like Hedman Alas). Even medium-sized Honduran companies don’t do websites well, or keep them updated. Phone the bus company up instead, or ask a local.

# A summer with XOs in Honduras

One of the main streets in Valle de Ángeles, a village near Tegucigalpa, the capital.

I’ve been lucky this summer to spend 7 weeks in Honduras, working on the OLPC deployment for primary school kids here. I’ve been training the local team (part of Educatrachos, a government- and IADB-funded education project in Honduras): teaching them Python, how to create activities for Sugar, and some Unix server administration magic.

The deployment itself is impressive. Over the past two years, they’ve delivered 40?000 laptops to 400 schools. A lot of the work has been in providing infrastructure (power and internet): this is tricky given Honduras’ hugely irregular terrain. A lot of the schools are using satellite internet, which is inherently affected by the weather. Despite these obstacles, the infrastructure has been in place for a while and is working nicely.

Showing a hint about which cells to sum in Pascal’s triangle.

The focus is now moving towards producing and updating educational resources for the laptops. That means creating new Sugar activities and refreshing and redeploying existing resource collections. This is what the bulk of my time has been spent on: training the team here in how to create activities and collections, starting from basic Python and working upwards. It’s been tricky (because of my poor Spanish if nothing else) but the team have tackled the learning with enthusiasm. I hope to see new Sugar activities on the Educatrachos gitorious page soon! So far, we’ve produced one new Sugar activity: a Pascal’s triangle game. We’ve also published the training materials I used for teaching Python and Sugar. They’re available in English and Spanish, although the Spanish translation is pretty patchy (my fault!).

What remains to be seen is how the project will evolve after the change of government from the upcoming Honduran elections.

Tomorrow is my final day in Tegucigalpa: on Friday I leave for two weeks of time off, travelling around the country to end a fun summer of travelling to celebrate graduating from university after four years.

Thanks to Raúl Segales, Walter Bender, Daniel Drake and Martin Abente for answering my silly questions as I dived into Sugar!

# Marin Bobcat Trail bike maintenance

I just spent a few days overhauling my aging mountain bike. It was an interesting (and at times frustrating) process, partly due to this being the first time I’ve done anything like it, and partly due to the apparent lack of maintenance manuals for the bike or many of its components. I thought it might be useful to put together a brief Marin Bobcat Trail maintenance manual, in the hope it’s useful to someone else who owns the 2008 or 2009 edition of the bike. I’m new to this, so it’s probably a laughable effort in cycling circles, but it’ll be useful to me next time I overhaul the bike anyway. Feedback welcome at the address given in the document!

# Weston frame buffer backend

Just over a week ago everyone’s favourite Xorg replacement, Weston, gained a frame buffer backend I put together as part of some university work. It was remarkably easy to write, since almost all of the code already existed in the DRM and RPI backends; I just needed to hook pixman up to /dev/fb0 and everything worked!

Weston’s code base was a pleasure to work on. Hopefully someone stuck on a frame buffer somewhere finds this work useful. Since I did this work, I also got the frame buffer backend working on FreeBSD (as part of the same university project), but haven’t had time to update, tidy up and submit my patches yet. They’re pretty hacky in (many) places.

Without further ado, a gratuitous flowery screenshot (taken using fbcat):

Weston running on a Linux frame buffer, taken on 2013-01-15.

As part of some university coursework, I’ve recently been playing around with an Atmel 8-bit microcontroller in a quest to build a data logger for home brewing. The aim is to log various sensor readings over the course of primary fermentation of a batch of beer to see how it’s progressing without having to disturb the brew.

While working with hardware is fun, it has the downside that you’re working with hardware. Things break as much as they do in software, but are harder to debug. A nice solution to this is to use a simulator to test the software, rather than using the hardware itself. I’ve been using the simavr simulator. It’s got all the right features, but more importantly its code is easy to understand and extend. In fact, most of the simulator is written as a library which one can build a simulated circuit board around.

I’ve built simulations of several of the components used in the brewing logger now, including an SD card and a flash memory. The code isn’t brilliant, but they’re working well enough to get my firmware booting. Hopefully they might be useful to other people too — hence the code is on gitorious. The SD card simulator is for a generic SDv2 card. The flash memory is for an ST M25P16 (but should support any of the M25P family, with a little work). The serial LCD is for a custom LCD daughter board provided by my university, so that’s probably not so useful. The RHT03 temperature/humidity sensor is general purpose; as is the DS3231 real-time clock.

Put together, and with a little extra work, these will allow closed loop testing of the microcontroller firmware — without ever having to go near the hardware itself. Bliss. (This is all under the misguided assumption that the simulations are sound and complete, but they’ll get there eventually.)

As an example of how easy simavr makes this, take a look at the code needed to instantiate and hook up the humidity sensor simulation:

/* Create the sensor. */
rht03_t rht03;
rht03_init (avr, &rht03);

/* Connect its bidirectional data pin to pin D3 on the microcontroller. */
avr_connect_irq (avr_io_getirq (avr, AVR_IOCTL_IOPORT_GETIRQ ('D'), 3), rht03.irq + IRQ_RHT03_DATA);
avr_connect_irq (rht03.irq + IRQ_RHT03_DATA, avr_io_getirq (avr, AVR_IOCTL_IOPORT_GETIRQ ('D'), 3));`

# Interaction in team projects

I had an interesting experience over the summer, working in a small but diverse team on a single project for several months. I was contracted to design and maintain the build system, and so ended up getting involved in all areas of the project. As a result, I came across many of the problems which my team mates were having. A lot of these problems were my fault, some were my team mates’ faults; but a lot of the problems were a result of bad communication.

While this all occurred in a (unfortunately) closed source project, I’ve seen similar things happen in open source. I thought I’d come up with a list of suggestions for people starting out in the open source world, to try and help them understand the best way to interact with other people on the same project, or with their mentors in GSoC (for example). None of this is targeted at anyone in particular (especially not the GSoC students I had the pleasure of interacting with this summer)!

Thinking about this has been useful to me; hopefully I won’t do any of these things in future (because I certainly have in the past). I just hope it’s useful to someone, somewhere.

• Don’t spam chats with half-written messages. Take your time and formulate your thoughts properly in a full sentence. Spamming messages just means the other conversant has to sit there and wait for the rest of the sentence, rather than getting on with something else.
• Don’t join a chat, say “hi” or “someone please help” or “ping” and then sit there without giving more information. This just introduces an extraneous round trip in communication, since someone has to then ask what the problem is before they can start to help. Conversely, if someone joins a chat and says “someone please help”, don’t lecture them about it. Be patient, and help them as much as you can.
• After asking a question in a chat, wait patiently for the answer to the question. Although they’d love to help, developers are not constantly looking at their chat client. If you leave a fully-formed question in the chat and then wait, a developer should answer in their own time.
• If you encounter an error or warning (e.g. from a compiler or program) and want help with it, always provide the full error message and some context. The person who’s helping you isn’t psychic.
• Always give context and be careful of over-using pronouns. “It’s running awfully slow” is not specific enough. What is ‘it’? What were you doing with ‘it’ when things slowed down?
• Look at man pages and --help output before asking people. Documentation for established software (e.g. SVN) is generally quite good. The person who’s helping you will probably just look at the man page anyway.
• Read VCS commit logs. Ideally, people will explain and justify all of their work in their commit messages, and mention things which you should be aware of. Reading the logs may well save you debugging later.
• Use the correct terminology as much as possible, and don’t use that terminology in other contexts where it could confuse matters. Communication is a lot faster if a common vocabulary is used.
• Learn your version control system and learn it well. It’s a tool you’ll be using every day, and making mistakes with it can be costly for your (uncommitted) work and/or for other people’s productivity. Always check the changes you’re about to commit, especially if conflicts have occurred. People will not take kindly to their work being overwritten because you’ve made a mistake, especially if it happens regularly.
• If you’re making use of someone else’s code/APIs and you have a problem or can’t get it working, double check (against the documentation which they have written) that you’re using the code correctly. In many cases, the problem might be the way you’re invoking/using that code, not the work itself (thought such problems do suggest a lack of user friendliness in the work which could be fixed).
• Always check to see if the code at least compiles before committing it to VCS. Committing something which doesn’t compile due to a trivial error shows a complete lack of testing or care. Compile it using the build system which everyone else uses, too. Manually invoking the compiler doesn’t count.

# More festive drinks

It turns out that stuffing my failure of an apricot liqueur full of spices has worked, and I now have a bottle of tasty festive spicy apricot vodka. Here's the recipe in full:

## Ingredients

• 300g dried apricots
• 700ml vodka
• 1 large cinnamon stick
• Rind of 1 orange
• 4 cloves
• 8 juniper berries
• ~200g granulated sugar

## Method

1. Submerge the dried apricots in boiling water and leave them overnight to re-inflate. I had to do this because I could only buy dried apricots, but I guess an equivalent mass of fresh apricots would work.
2. Split the apricots into halves and put them into a 1.5l plastic bottle (an empty water bottle is perfect) with a cinnamon stick and the vodka. It's better to put the apricots in first so that they don't splash.
3. Seal the bottle well and shake it.
4. Leave the bottle in a cool, dark place for around four weeks, shaking it every day. The precise amount of time you leave the mixture to infuse doesn’t really matter, as long as it’s more than about three weeks. Try to avoid opening the bottle during this time, as that’ll introduce contaminants.
5. After the mixture has infused for a suitable amount of time, filter it out into another bottle. This might take a day or longer, depending on your filter paper. Use fine filter paper (coffee filter papers worked well for me), and be prepared to use several filter papers, as they will get clogged up. Keep the apricots!
6. Once filtering is complete, add sugar to the filtered liquid to taste. 200g should be about right (I used 225g this time, and it was a little too sweet). Add the cinnamon stick again (or use a fresh one), and the orange rind, mace blades, cloves and juniper berries. Seal the bottle up again and leave it for at least another two weeks, shaking it daily.
7. After at least two weeks, filter it again. This should take a lot less time, as most of the fine sediment will have been removed during the first filtration.
8. Drink and enjoy! The recipe produces about 700ml of spiced apricot vodka. The apricots left over from filtration are nice in a pie, though they will have lost a lot of their flavour (more so than the raspberries).

I'm sure it would be quite possible to infuse the vodka with the apricots and spices at the same time, but I didn't try this, so I can't be sure. Another thing I probably should've done is added the sugar after infusing the vodka with the spices, as that would've allowed it to be added to taste. As it was, I added what I guessed was the right amount and fortunately it turned out well.

While not busy playing around with drinks, I've got around to finishing off and releasing libgdata 0.8.0. This vastly improves upload and downloads via streaming I/O, as well as fixing a lot of race conditions, leaks and cancellation problems. This release doesn't introduce much new functionality, but breaks a lot of API, hopefully for the better.