2013 Charitable Giving

I’ve got an amazing job. I get paid lots of money to do challenging work that I feel good about.  Its a great life!

The downside, for me, of programming and of the high tech world in general, is that it is so easy to get sucked into the marvels of it all, and spend all of my time immersed in code. So at this time of year, I try to force myself to look away from the beautiful devices and apps I work on and remember that most people do not live in the same shiny world that I do, and that for many of them, the world can actually be pretty sucky.

This year, I’m reminding myself of this out loud in case anyone else needs or wants the same reminder: those of us blessed enough to be in a position to help others ought to at least make the time to write some checks.

It is only in recent years that I’ve started being even semi-serious about charitable giving.  It never really occurred to me to give very much before. I guess I thought that giving was something for people who owned tuxedos and went to benefit galas and operas and stuff. I’ve learned, though, that donating a day’s salary to a local charity will put me on their list of big ticket donors and get me a personal thank you note from the executive director. Its not much to me, but it makes a huge difference to these organizations and the people tey serve.  And I don’t have to buy a tuxedo!

This year, about 2/3rds of my giving is to to be in my home town, divided between the food bank, an organization that is part of the Waterkeeper Alliance and is fighting against a proposed coal export terminal and two smaller non-profits that work with the victims of domestic violence and child abuse.

I’ve picked national and international charities for the remaining third. This year’s picks:

  • Feeding America: Hunger is one of my pet peeves, so this donation goes along with my donation to my local food bank.  Feeding America is a national clearinghouse for food donations that are then distributed to a national network of local food banks.  If you look Feeding America up on Charity Navigator you’ll see that they have a huge budget with very low overhead and an insanely high percentage going to program services.  I suspect this is because so much of their income is in the form of food donations from corporate food manufacturers.  They send me way too many solicitations (though this year’s donation form has an opt out check box, which is nice). And their executive director is paid $400k a year, which seems excessive.  But they serve a unique niche and if they were not around, I suspect that hunger would be a much bigger problem than it already is in communities all around the country.
  • 350.org: This organization was founded by Bill McKibben who started sounding the climate change alarm a long time ago with the publication of his book The End of Nature. The “350” in the name refers to their goal of reducing carbon dioxide in the atmosphere to 350 parts per million. The seem to be doing really innovative work and are spearheading fossil fuel divestment campaigns on university campuses, in churches, and even in local governments.  This is the first time I’ve given to 350.org and I don’t know what has taken me so long. The fossil fuel divestment movement reminds me my own university activism for South African divestment, so maybe it is Nelson Mandela’s death that has spurred me to donate.
  • Heifer International: this is a great organization that combats malnutrition and poverty in the developing world by giving livestock (like Heifers and dairy goats) to needy families, and backing the gifts up with appropriate training in caring for the animals.  The bonus here is that kids love it. We’re going to let our kids choose what kind of animal to give with their share of the donation.

There are so many good causes out there. I wish I was also giving for civil liberties, peace, reforestation, disaster relief and more.

Comments welcome. Feel free to share links to your favorite charities!

Custom Ringtones for FirefoxOS

In FirefoxOS versions 1.0 and 1.1 the Settings app handles ringtone selection and the user’s choices are hard-coded into that app.  In version 1.2, I’ve changed the Settings app to use Web Activities instead.  Instead of displaying ringtone choices directly to the user, Settings now initiates a “pick” activity for type=”ringtone”.  A new System Ringtones app (which you can see in the apps/ringtones/ directory of the Gaia repo) now handles ringtone display and selection.  System Ringtones has a manifest file that says it knows how to handle “pick” requests for ringtones, so when Settings starts the pick activity, FirefoxOS launches System Ringtones.

What the user sees has hardly changed at all, but under the covers there is a new app running.  System Ringtones let’s the user select and listen to ringtones. When she chooses one she likes and taps Done, System Ringtones returns the ringtone audio file (as a Blob) and ringtone name back to the Settings app by calling the postResult() method of the Activity object. The Settings app verifies that it can actually play the audio file and saves it to the settings database, where it is ready for use when a call is received.

The cool thing about switching to Activities for ringtone selection is that other apps can implement the pick activity for ringtones.  If more than one app is registered to handle an activity, FirefoxOS asks the user to choose which one she wants to use:

More than one app can provide ringtones

The My Ringtones app is a proof-of-concept I developed (the ringtones themselves were composed by my son, however).  If the user selects it, she sees these custom ringtone choices:

A demo app that offers custom ringtones

Tapping on a ringtone name plays the ringtone, and tapping Set passes the ringtone Blob back to the Settings app.

If you have a FirefoxOS device running version 1.2, you can try it out:

  1. In the FirefoxOS Browser app, visit http://git.io/djf
  2. Click on the Install button you see there
  3. Wait for the app to be installed
  4. Open the Settings app, tap on Sound, and then select a new ringtone. You should see “My Ringtones” as a choice along with “System Ringtones”
  5. To uninstall this app, use Settings -> App Permissions -> My Ringtones

The code for the My Ringtones app is available on GitHub and shows you how all this is done. If you’ve got ringtones that you’d like to sell (or distribute for free) through the FirefoxOS Marketplace, you can fork that app, change its name, fix up the visual design, add your new audio files, package it up and submit it to the Firefox Marketplace. Remember, though, that this only works in version 1.2 and later, and devices running version 1.2 are not yet commercially available.

Here are some final notes:

  • Wallpaper selection is handled by pick activity, too, and has been since version 1.0, so you can write custom wallpaper apps right away.  See the Gaia wallpaper app (in the apps/wallpaper/ directory) to see how it is done.  In version 1.0 and 1.1, the Settings app picks wallpaper by making a pick request for type “image/jpeg”.  In version 1.2, it also adds the type “wallpaper”.
  • I have a patch pending review that will add a “Set Ringtone” app to Gaia. If this lands, then when apps use a “share” activity to share audio files, one of the choices the user will see is to use the shared audio as a ringtone. This will allow us to use songs from the Music app as ringtones.
  • Apps that implement the pick activity may not be the official way to customize FirefoxOS. We have UX designers thinking about customization and theming. And we have other designers thinking about ways to enable the download and installation of new system ringtones.  So it may be that releases after version 1.2 will support custom ringtones in some other way.

Update: this is what I was referring to when I tweeted that FirefoxOS was the “grassrootable” phone. Creating a custom ringtone and wallpaper apps is easy enough that we hope FirefoxOS users will have many deep customization options that arise from “the grassroots”.

BinaryStringView.js

For my work on FirefoxOS, I recently had to use XMLHttpRequest to download binary content in multipart/mixed encoding, like the encoding used for attachments to email messages. I wanted the binary file in the middle, but first had to strip away the ASCII boundary strings before and after it. To make things more complicated, the server was not correctly sending the boundary string as part of the Content-Type header, so I had to actually parse the file to determine the correct boundary string.

Because simple parsing and other string manipulation was involved, the easiest way to do what I needed was to use binary strings. That is, I used code like this:

xhr.responseType = 'string';
xhr.overrideMimeType('text\/plain; charset=x-user-defined');

This is, of course, a horrible thing to do, now that XHR supports array buffers. (Read more about this at MDN.) When we use binary strings, each byte of the binary content is expanded to a two-byte JavaScript character. Yuck. These files I was dealing with have the potential to be megabytes long, and this is for a mobile device, so I really need to pay attention to memory consumption. But I needed string methods like trim(), slice(), indexOf() and lastIndexOf(). So I ignored my better judgement and went with binary strings.

Today, I came up with an alternative: my code now downloads the file as an array buffer, and then I wrap the ArrayBuffer with a custom BinaryStringView class (modeled after other ArrayBufferView types) that implements the String methods I need on top of Uint8Array. I had to write indexOf() and lastIndexOf() by hand, but I get the string-manipulation methods I need and each character only occupies a byte of memory. I’m probably trading off performance for memory here, but for mobile, it is worth it.

I’ve seen a lot of legacy code using binary strings, and this BinaryStringView wrapper seems like it could be a generally-useful class to help migrate that code, so I’ve put it on github. The caveat is that I’ve only implemented a few string methods. Maybe someone will fork this and finish it for me!