sn.printf.net

2009-06-30

It started with a bug report that had been around since Ubuntu got started: Gnometris had a big Gnome foot logo on it, and most of our users didn’t know what that was.  The suggestion was simple: replace it with a stylized Ubuntu logo, patch it in, and go on our merry way.  A community member even volunteered a fantastic piece of art to go in its place.  Simple, right?

Except, unfortunately, it wasn’t.  You see, some people at Ubuntu are worried about derivatives: those Ubuntu-based distributions that use our code but aren’t actually Ubuntu.  By putting a branded image in that derivatives have to remove, we make extra work for them.

So nothing happened.  For years.  We still had that ugly foot logo that had nothing to do with the game you were playing, and it was one of the first things users saw.  But it wasn’t just Gnometris - it was solitaire too.  Millions of hours of user time have been spent playing solitaire and staring at the ugly feet on the card backs.  People would boot the Ubuntu LiveCD and feel like our games came straight out of 1995.

This bothered me.  It was ugly, but even worse we were throwing away useful contributions.  How much other useful stuff might we be throwing out, or even worse not making in the first place?

Enter UDS

The Ubuntu Developer Summit is a fantastic place for brainstorming ideas.  You’re constantly surrounded by smart, passionate people.  People who want to work with you on any and all things Ubuntu, from the moment you walk out of your hotel room for breakfast to the late hour you finally trudge off to sleep.

I think the branding-ubuntu package was my idea.  I can never be sure, since I owe so much to the creative environment around me.  I shouldn’t offend anyone by taking credit though; as you’ll see, my original design was stupid.

The overall idea seemed solid: put Ubuntu-branded replacement artwork, generated by the community, into a single branding-ubuntu package.  Installing it would change the artwork, removing it would leave everything as before.

The original design required each branded application to have a small patch causing it to look for the branded artwork first (and prefer it.)  This required modifying every program that we wanted to brand.  All I had to do was dump a bunch of artwork in some folder, and then hope other people would change their applications to take advantage of it.  Trivial for me, work for them - perhaps it wasn’t so stupid after all.

Community Leadership

Other than my three year old Gnometris background, I didn’t have any actual artwork to put into the package.  We weren’t even installing Gnometris by default anymore.  I made the package anyway.  Even though it didn’t do anything, I decided to advertise and fish for community help.  If I built it, perhaps they would come.

I wrote a few emails to our developer lists, rubbed a few shoulders on IRC, and reminded some of the people who mentioned it was a great idea at UDS.  Importantly, I took charge, making it clear that all an artist had to do was make something nice and I’d handle including it personally.

Within a manner of days I had new, branded artwork for every game we ship.  Now I had a whole lot of artwork, courtesy of MadsRH.  The screenshots from a manual install were incredible - that blue foot was gone for good.  All it took was a little initiative.

Unfortunately, those patches to use the branding hadn’t yet been written, and the upstream makers of Solitaire didn’t really want to do it.  In retrospect this is completely understandable - it was their branding we were replacing, and it wasn’t clear to them why we weren’t just patching things on our end.  Why should they care about our derivative worries?

The Real Solution

The real solution, of course, meant more work for me - but work that would actually get done.  The branding package now renames existing artwork files and replaces them with symbolic links to its own (using some fancy shell scripts and the very obscure dpkg-diversions command).  In short, it works elegantly.

So, now I’ve got yet another package under my stewardship.  I started off just maintaining Wine five years ago, but now, in true open source fashion, I’ve been applying myself throughout the entire distro.  Sometimes people refer to this as “scratching your own itches”, but in truth I don’t really play solitaire or use Wine that much.  They’re not my itches - they’re the itches of millions of users.  Those are real people, and that alone is reason enough for me to make things even just a tiny bit better.

by YokoZar at 2009-06-30 21:16

2009-06-17

For the first time, I have my own idiotic app review rejection story.  I have to say, until now I've been one of the lucky ones.  My developer app was approved in days, and every app and update I've put through has been approved with no hassles (save for the ...

2009-06-17 18:30

2009-06-14

A stunning update to Lock ‘n’ Roll 1.0.1, this version includes the following changes:

  • New: LNR restores statuses that it replaces when the workstation locks
  • Bugfix: LNR no longer replaces Unavailable, Offline, or Invisible statuses
  • Misc: Documented the source code
  • Misc: Updated URLs to point to the specific LNR category at my site

Thanks to O. D. for submitting a patch to accomplish the new feature and the bugfix!

Download locknroll-1.1.zip, source and binary included. To install, copy “locknroll.dll” to the Pidgin plugins directory. To activate it, restart Pidgin and go to the Tools menu, select Plugins, and tick the checkbox next to “Lock ‘n’ Roll”

by Chris at 2009-06-14 20:41

2009-06-12

One of the reasons entrenched Windows users find switching to the Mac unappealing is that the interface is so different.  Different can be better. But in my opinion, after 6 months developing on the Mac, different is definitely NOT better.  I consider myself fairly used to the Mac interface and ...

2009-06-12 18:30

Alight, I haven’t posted in awhile and it’s time for an update about what’s going on. School’s out for the summer, so I’ll have time now to finish up Default Programs Editor v2 in the next couple weeks. In truth, it’s been pretty much done since the middle of April but it’s missing a couple features I want in before I lay this project to rest and move on to other things. Of course I’ll still welcome user feedback, and I expect there will probably be a spike in interest for the new version. Those new user experience reports may require some updates like I put out for v1.0. I’ve also been planning some additional internal refactoring of the library on which the program is based, as well as substantial documentation, so that I can finally publicly release the source and not be horribly embarrassed about it.

Editing an Autoplay Handler:

04-apr-09-autoplay-handler-page-3

The high points of v2.0 include

    Installation as a Control Panel applet, which means instant integration with Vista/Win7 start search
    Hugely simplified UI which breaks down the complexity through the use of an Aero Wizard interface
    Full Windows Vista and Windows 7 support (and limited legacy XP support as well)
    New, dedicated website at http://defaultprogramseditor.com, which will launch along with v2.0 in a couple weeks

While I get work on that done, I’m also in the prep stages for possibly my next summer project, which will kick off with a short series of posts on the use of COM interop in C# to create an Aero compatible DeskBand UI. Stay tuned, it’s going to be a fun summer!

by Factor Mystic at 2009-06-12 05:56

Everyone knows by now that iPhone developers must submit their apps to Apple for approval before they make it to the app store.  And by now, almost everyone knows how irritating the whole process has been for developers.  Personally, I don't have a huge problem with it.  Approvals take about ...

2009-06-12 04:30

2009-06-11

It needs to be easier for community contributors to find out how they can help. We’ve had this discussion in Ubuntu before at past developer summits, and the ideas were generally things like “improve the participate link on the ubuntu.com front page.” Sorry, no one’s clicking that link anyway, and even if we did create an elaborate AI-powered survey system behind it we couldn’t possibly do better than an actual human providing an encouraging suggestion about what’s really needed.

Human responses

Over the past few months, at least five separate people have reached out to me personally asking about specific ways they could help. I’m happy to answer, of course, but this tells me that it’s not at all obvious for them to figure out on their own. Likely, there’s five more who never emailed me since it was too much of a hassle to talk to an internet stranger, even a blogger who IMs more than a 13 year old girl.

What’s needed, then, is just a simple encouragement of human interaction. The open source community is a strange concept to newcomers, even the computer-savvy. You really can just dive right in and start offering help wherever you’re useful, and developers will just treat it like it’s the most natural thing. Maybe you’re from another project, or deploying the software in a business, or just bored around the house. There’s no such thing as an imposter in open source.

Many people who aren’t used to this kind of openness find it intimidating - there are too many people, so it’s not obvious who to go to for help getting started. We try to have mentoring programs and the like, but these are for people who want to be serious developers solving big problems. Small problems don’t need serious developers - they need a serious amount of small help.

Practical things for getting small help

At the Developer Summit, we discussed the idea of using more helpful bug tags to help contributors find where they can help. Our goal isn’t to sort half a million launchpad bugs into forty tiers of type, importance, and difficulty - our goal is to get them fixed.

So, here are the brand new bug tags, based on a simple discussion from the developer summit:

Most bug trackers don’t really use tags like this because the system is obvious - if you’re looking at Wine’s bugzilla, then pretty much every bug in there really could be tagged “needs-coding-c”. Launchpad is different: we’ve got a whole mess of bugs, and half of them aren’t even in the code.

Now we’ve got a real answer to the question “I want to help, what can I do?” We just tag some bugs and say click the link: Launchpad will instantly tell them dozens of places where they’ll be useful. That’s important, as they’ll not only be able to help, but they’ll also see that they can fill a real need and feel good about themselves. Make contributing simple and rewarding, and users will do so eagerly.

by YokoZar at 2009-06-11 12:32

2009-06-08

Here's a short, but nifty, addition to your ~/.vimrc that'll make copying to your Mac's clipboard a little easier:
map cc :w !pbcopy
Typing 'cc' in command mode will put the entire current buffer into the clipboard. If you type 'cc' while you have lines selected in visual mode, it'll only copy those lines.

Woo!

by GT_Onizuka (noreply@blogger.com) at 2009-06-08 17:34

2009-06-05

As many of you will know, Google recently hosted their I/O sessions in San Francisco. Unfortunately not all of us could be there - but the good news is that all the sessions are now up and available for you to view and download.

by Tane Piper at 2009-06-05 09:26

2009-06-03

A couple weeks ago I thoroughly bummed out a lot of iPhone developers with real, hard numbers from the app store.  Selling apps is a ridiculous gamble, but free is still on the table.  Today I'll talk about some free app strategies, for those who haven't abandoned the app store ...

2009-06-03 23:30

2009-06-01

I’ve just come back from the Ubuntu Developer Summit for 9.10, so I’ve got a flurry of things to do and follow up on.  The first priority is to put together the community based on ideas generated during the sessions.

Ubuntu developer Facebook group:

Since it’s so easy to do, I just went ahead and made it myself.  If you’re an Ubuntu developer, and you’re on Facebook, please go ahead and join.  It should make networking easier than talking to a blank IRC channel or trolling Jorge Castro’s friend list.

Planet Feeds by Language rather than country:

This was an idea I had and brought up with Jorge in a hallway conversation.  In Spanish, for example, there are separate Planet Ubuntu feeds for Argentina, Ecuador, Chile, and Colombia.  Doubtlessly some content that users would like to read is being missed.  Similarly, the guy who translates the Ubuntu news into Spanish doesn’t have a specific “all Spanish feeds” place to post it, so it ends up going into the main (otherwise English) feed.

Things get even dicier with mixed languages.  Interesting English content published to the country feeds is often missing from the main feed.  More worrisome, a multilingual country may have to be split into separate language-based content feeds anyway.

I understand the concept behind country-based planet feeds.  There will likely still be a demand for local content anyway, so perhaps they shouldn’t go away.  But language based feeds are still better - they should even be displayed in a list above the country-specific feeds. We are, after all, a global project.

I love Ubuntu video:

Jono Bacon suggested it would be nice if we had members from the community each submit small bits of content that could be compiled artistically into a kickass promotional video.  One idea was to get a whole bunch of people in front of their webcams saying “I Love Ubuntu”.  As soon as I figure out the best standard way to do this (cheese?), I’ll take the initiative and submit my version.

Bonus Karaoke:

Traditionally, the final night of the Ubuntu Developer Summit includes a party.  This one featured Karaoke combined with barroom accoustics, tinny speakers, a cheap microphone, and cell phone video recordings.  Combined, these should render this presentation by Canonical’s community organizers appropriately awful:

I did three renditions myself.  I’m not a horrible singer when playing Rock Band, mainly due to practice.  Still, you don’t want to watch this video.

aside: The bumper sticker above came from the 2008 US Presidential Elections, where Republicans supporting Governor Palin mocked Senator Obama’s experience as a community organizer.

aside to the aside: There was an even better looking bumper sticker that I would have shown and linked, however the website selling it went to very elaborate lengths using javascript and embedded flash to try and prevent me from copying the image.  In other words, they paid a web developer a thousands of dollars to build a system that makes me give someone else free advertising.

by YokoZar at 2009-06-01 01:49

2009-05-31

A couple of things in tech:

Wolfram Alpha has launched, in an attempt to distribute a know it all to the masses, but unfortunately the one we have recieved is autistic.

It is meant to answer questions - like a calculator is a tool for answering mathematical problems, this is a calculator for facts and data.
The attempt to encompass this is a lot of natural language processing, and the solution entails building something bigger than Wolfram's Ego.

The examples work but the web is now littered with counterexamples.


Microsoft have amalgamated their search offerings together under a new brand and direction. Presenting 'Bing' - A 'decision engine' apparently.
It isn't here yet but there is an annoying video which shows the perfect consumer tool. Want to buy stuff find stuff to buy.

It isn't anything new beyond better integration of existing components, geared towards purchasing things.


Google on the other hand have come up with something novel - a wave. A numver of simple extentions to existing instant messaging systems to add significant features - real time editing and collaboration, and structured content containing widgets and media.

On top of this they've developed a highly integrated web app that looks like gmail, but interacts with the desktop (drag and drop), with a lot of well thought out features.

They are releasing the client and the server openly - unlike the highly centralised models of interaction like twitter and facebook - this is more like a new version of jabber/google chat.

In fact, the protocol itself is just an extention to XMPP.

Unlike the last two efforts above, this is achieving something new on top of existing protocols and standards.

And what it is trying to achieve is a federated real time collaborative conversation and content tool.

Which is pretty awesome.

I can see it easily replacing email, forums and instant messaging - even livejounal for me.

As well as replacing bug tracking for work.

It's a great step forward that builds on the present rather than abandoning it. They demonstrated integration with existing apps and keeping most of the features.


I think I should mention again the whole open nature and federated thing - this is not an attempt to build a great tool, but to give everyone a great tool to use.

2009-05-31 03:17

2009-05-26


Yeah, I haven’t posted in awhile - since pycon I’ve been sick off an on, working my butt off at the place which allows me to purchase ice cream for my kid, and so on. Busy busy. Not to mention, I’ve been suffering a slight case of burnout - long story.

That all being said, I think it was last week when I twittered a minor philosophical point which was picked up and ran with by pydanny. The little point I made was something like:

I don’t think it’s unreasonable to be able to name at least 5 things you don’t like/would change about something you love. Implementation details are fair game too

stop-whining.jpg
Now, before I delve into my personal list, I want to provide some context to this comment. It actually has some history, and it’s not an original thought - I think Titus Brown started a meme around this last year. In his case, it was purely based around python.

In my case, I’ve long maintained that if you can not name things you would change, irk you or generally dislike about something (not just a language) you supposedly love, whether it be a tool, a language, an OS, etc - then it shows you have a certain lack of self-awareness or pragmatism (there is another word I’m grasping for here, but it escapes me).

Historically, I’ll ask this in interview situations whether I’m speaking with someone who is a test engineer (name and explain 5 things you love/hate about automated testing?) a programmer (name and explain 5 things you love/hate about language $FOO) - generally speaking, this is great discussion fodder, and allows you to probe the thought process of the candidate.

For example, if someone says “I hate Python’s whitespace” and they’re interviewing for a Python coding position, I think it fair game to dig into that a bit and see if its rational, and ultimately ask the question: If you hate something so fundamental, why do you use it/why do you want to program in it for the foreseeable future?

In any case, I promised a few people I’d give them the shortlist of nits (I don’t hate these things, I simply dislike them) I have with Python. It’s important to remember that:

  1. I contribute work to python-core (see the multiprocessing module)
  2. I program in Python daily for work, and in my free time too.
  3. I participate (when I’m not on a self imposed exile) on the mailing lists and discussions (see Python-dev, etc.
  4. I too, am a strong believer in “put up or shut up”

Now, part of me is sad that I have to preface me being critical with a disclaimer like the above; but alas - some people, especially those on the internet, thrive on controversy and fail to read more than 5 or 6 words before posting some half-witted response, or worse yet, someone skims to the gripes I have, finds one they want to take me to task about and says “SUBMIT A PATCH !!!11″.

I do contribute back, so you can avoid telling me to submit a patch, ok?

That all being said, here’s my list:

  1. Concurrency: This is actually a love/hate topic for me. Obviously, I’m the maintainer of the multiprocessing module, which sidesteps the GIL, but the GIL is still an irritant for me (given I do write a lot of threaded code). A lot of people are very familiar with the fact I am a proponent of threads and processes/IPC, as both serve different (yet overlapping) purposes. There is room for both. Hopefully unladen-swallow will be able to get rid of the GIL, and then we can all move on with our lives: So long as in killing it, we don’t hose the ecosystem of C extensions.
    • Additionally, I would love to see a decent coroutine implementation included in the standard library, once PEP 380 is done and in the bag, if you need justification, see David Beazley’s coroutine talk. Again, while people might disagree with this, saying that coroutines/processes/threads all “do the same thing” and would violate “TIOWTDI” (There’s Only One Way To Do It) I would strongly disagree with them. In the case of concurrency, different solutions fit different problems. We do not have a grand unified theory of concurrency within python.
    • Also in the concurrency vein, I would like to see a cross language messaging/serialization system/format eventually come in. Right now, we have pickle; most recently, JSON - and JSON might be the final answer in this regard, but something akin to protocol buffers has also piqued my interest. Given we have JSON, I’m not terribly hot on this one.
    • Finally, I’d like to see more of the java.util.concurrent abstractions migrated in. I mean, using python threads isn’t hard, seriously, but more/better abstractions make things nicer for everyone.

  2. The Standard Library: This, again, is a love/hate thing - I love the standard library, and I will gladly argue with anyone who suggests getting rid of it. However, that said - I would like to see the entire thing get a much better documentation treatment, the docs while good, could be 1000x better, more clear/etc. I would also make every single module in there PEP 8 compliant. I know that sounds like a style-nazi thing, but if that’s the style we’re to use, I think the first thing to adhere to that is the standard lib.
    • It’s also disorganized. While flat is better than nested, I’m sorry - but I think making it deeper and putting all the things like one another into the same namespaces does make sense.
    • I would also break out the stdlib from core. This idea was discussed at the python language summit, and I think almost everyone there was in agreement. The idea would be to separate out the stdlib into it’s own path inside the repo, and other python implementations (such as Jython/etc) could use that copy as their copy of the stdlib modules. Anything which was CPython specific (such as multiprocessing) would stay with core/be marked as CPython only.
    • Taking this concept of breaking out the standard library a little further: I would begin to evolve it a little more quickly. There’s a strong difference between changes to the language, and changes to the standard library. In the case of the former; it should evolve slowly, and carefully. In the case of the latter (the stdlib) I think it could - and possibly should, evolve more quickly. By evolve, I mean “get cleaned up, have things removed/added” more quickly. I do not, however, mean with less thought. There’s obviously a lot of “buts” and other concerns with this idea, but it’s just a thought. I think compartmentalizing this into python-core and python-stdlib meshes with how a lot of people think about things.

  3. The Docs: I touched on this in the stdlib one, but the standard library documentation, as well as rich examples for a lot of the core features are lacking. Many of them focus on syntax and not necessarily on use. For example, I would gladly integrate all of Doug Hellmann’s Python Module of the Week posts into the standard library documentation tomorrow, and wholesale if I could - his examples are much more rich than those we find in the current docs.
    Many people, including myself, have been working on making these better - in my case, I need to overhaul the multiprocessing docs when I have a chance.
    • Don’t get me wrong - I actually appreciate the docs we have, they keep me sane, but they can be better, more clear and in some cases, more practical. One or two examples for usage just doesn’t cut it.
  • update see: http://tosh.pl/gminick/gsoc/sphinx/
  • cosmic-rex-excuse-me-wtf-r-u-doin.jpg

  • Packaging: Ahhhhh! I’m not going to go too deep into this rabbit hole, especially given I know Tarek is hacking away at making python packaging a much better animal, but the entire setuptools/eggs/distutils/etc pile is well, frustrating. I just want a clean, standard way of packaging my packages, built into core, that doesn’t force me into install into the global site-packages directory. Also, uninstall, dammit. I know setuptools and easy_install and eggs were designed to scratch an itch: and I do use easy_install, but the entire pile of things need to be made into a standard, implemented in core and we need to move on.
    • However, as I pointed out during the language summit - I don’t think something like easy_install belongs in core, instead I think core should make what easy_install does (to a certain extent) easier and standard, so people can use whatever tools/scripts/etc they want. One ring to bind them!

  • Linting: Ok, face it, if you’re on a big enough team, you need to have a pre commit hook for your VCS that lints the code, and yacks if it doesn’t conform. I would love for one to be built into the stdlib, but something like pylint is too big, pychecker is too simple, and I haven’t used pyflakes recently enough to comment. There was a thread on python-ideas about this recently - and maybe Jeremy Hylton is right, and it doesn’t belong in core, but if that’s the case, we need to pick one to “endorse” on the python doc website. Maybe in a “getting started with developing python” document, which is linked in size 30 font, and links to a linter, maybe the pep8.py and reindent.py scripts, etc. It should be painfully obvious where to get and how to use these tools. Yeah, I know “waaaaah why didn’t they link to mine” - well, because we liked this one over here more. QQ.
    • As it stands, I can not count the number of times I’ve been asked about linters and style checkers for python code. Maybe we make three packages: python-core, python-stdlib and python-tools.

  • Optional Static Typing: This one doesn’t make me feel like I’ll make any friends, but I would love to have pre-runtime, static typing as an option to python - maybe as a –anal-types flag. Guido has discussed (part 2) the difficulties of this before, so I don’t think this will ever come (the closest we get to “type safety” is function annotations, which make me feel funny in sensitive places). The biggest reason I have for static typing of any flavor, is that I would prefer to have the ability to catch some errors prior to runtime. That’s all. On a big enough team, all hacking on the same (massive) python code base, I’ve found you do want the ability to turn something like this on - it helps you with a (small) class of very annoying bugs.
    • I do love me the dynamic/late typing system of python, and I use it to my advantage as much as possible. So, I wouldn’t trade the dynamism of Python for static types, it’s just an nit I have. Of course, maybe something like interfaces (as Jacob points out in his list) might solve some of the issues I have (mainly bad people doing silly things). The rest of the stuff is why I write unit tests and actually run the damned code.
    • Yes, I know the drawbacks of something like this; I also don’t have some sort of magic solution to be able to wave a wand and do this. Nor do I have a concrete proposal, otherwise you’d see an email on python-dev. Other people much smarter than me have pointed out the sheer enormity and numerous drawbacks to something like this. No, I don’t expect magic fairy dusty to suddenly appear and just “make this work”.

  • Standard Library Part II: Yeah, you might notice a lot of my gripes are around the stdlib - but in particular, I want to point out the state of XML handling in the standard library is about as clear as wearing glasses made of meat. Additionally, the httplib/urllib/urllib2 thing? Yeah. No.
    • While I’m harping on this stuff, get rid of the commands module, anything that is not in subprocess should be put there. Since I mentioned subprocess, needs more documentation also, non blocking asynchronous input/output/handling of subprocess data should be easy, and built in. There’s a GSoC project around this spinning up, so we’ll see.
  • That all being said, would I trade python for something else? Not right now. Most of my nits are exactly that: nits, and most of all, they’re not impossible to change or resolve (given enough time, and resources).

    I can make a similar list for OS/X, Linux and other things I use day in and day out - hell, I can make one for myself (ask my wife about me griping about me sometime). I can probably make a list like this for every single thing I’ve written, tools, scripts, apps, etc.

    Like I said, being aware of, and trying to overcome your own shortcomings is how we all improve. In the case of a language, you can’t just keep adding things into a standard library and call it “better” - you have to take a constant look at what you’ve done to date with a critical eye, and ask yourself “what can we do better”.


    by jesse at 2009-05-26 17:43

    2009-05-24

    The hype surrounding the iPhone App Store continues to persist.  It's been called a gold rush, and stories of one man teams making hundreds of thousands of dollars almost overnight abound.  But what does that mean for you, if you want to get into the game?  Let's look at the ...

    2009-05-24 18:30

    2009-05-21

    There’s an argument about to occur at the Ubuntu Developer Summit.  It’s come up before, it’s coming up now, and it will come up again later.  This argument, cliched as it is, is about security vs usability.

    Imagine you’re a user.  One who just happens to have Wine installed on your system.  And you double click an executable file.  What happens?

    You might expect it to open.  That’s what Windows did.  But then people ended up running programs they didn’t actually want to run - they were surprised when Olson_Twins_Nude.jpg.exe wasn’t a picture at all, and even more surprised to discover their computer could be more accurately described as on loan from Vlad the hackpaler’s discount botnet.

    It wasn’t long before third party security software and, ultimately, Windows Vista started giving prompts to the user.  Even Firefox felt the need to warn you that the movie you just downloaded was actually a program.

    The unix approach to this was to require the user to give explicit permission for programs to run by embedding it into the filesystem - the execute bit.  No one complained, mainly because there weren’t many programs to download and run outside of a command line.

    Two things have since happened.  First, we wrote an awful lot of interpreters that don’t care about the execute bit, like Java and Wine.  More importantly, we finally made a Linux desktop that doesn’t suck.  Now people actually want to download things, and they want to run them without having to open that shortcut to the terminal.  So the debate is back.  Now we have to figure out what to do when you click on those pesky .exe and .jar files.

    For Wine, the issue was “solved” for 8.10 and 9.04 by making double clicking on a .exe file flat out broken - Ubuntu will try to open your program in Archive Manager, hit you with a shovel, and then give you a mysterious error about the shovel blade being the wrong curvature.

    Well, that solution wasn’t good enough for me.  I wanted to make Wine open the executables on double click since, well, that’s how you open executables.  But the security guys, understandably, want to be really sure that a user actually meant to open the executable.  This means some sort of dialog has to happen between the computer and the user when you double click the .exe file.

    I figured that, since I know something about user interface design, I may as well design the dialog myself and minimize the damage.  Here’s my second attempt:

    Ok, that sucked.  I said it was my second attempt, because my first attempt was to go with something a little more direct.

    I stared at my pen board for a good 10 minutes.  As it turns out, it’s a bit difficult to design a dialog that conforms to user expectations when you’re deliberately ignoring what they just told you.

    That’s a bit better. We’ll skip the obvious question of why we didn’t do what we were asked, and instead act like it just has to be this way.  Any explanation would take up a bunch of words users won’t read anyway, so let them mindlessly click on launch application and maybe we can hope they’ll forgive us when their computer blows up because they gave it permission to.

    Or, we can remember that the whole point of this message is to remind the user that this is a program they’re launching.  Let’s start by putting a Wine icon there instead of that generic warning label.

    You might be wondering what that “Wine preferences” button’s doing there at the bottom.  That was me thinking ahead a bit - maybe a user will want to disable this behavior somewhere, so maybe we’ll need to have a preference setting for that, and we might as well help them get there as soon as they’re frustrated enough to fix it.  But now we’ve made three buttons, and the user has to make a decision and think a bit. Worse, if they actually used the middle button, they’d have to dig through a bunch of unrelated Wine preferences before finding what they want.

    Here, we give them exactly what they want right there in the dialog.  We act like it’s some sort of preference they had set, so now instead of wondering why the computer didn’t do what you wanted until you told it twice, you at least know this annoyance can be prevented in the future by simply unchecking the magic box.

    But that sentence says something else too, more than the button ever could: it has the phrase “new applications” in it.  It means we’re only showing this dialog for programs you’ve just downloaded.  If you’ve already run them before, the damage is done, so we may as well just launch without asking the second time.  And, get this, we can keep track of it all by using that silly execute bit.  Turns out it’s useful after all.

    But there’s one more major improvement we can make.  Did you catch it?

    That’s right. It’s a very slight difference in wording. Without thinking about it, we wrote the original dialog like a programmer, using programmer jargon.  Prompting is exactly what we’re doing here, and it’s the exact word I’d use to describe this dialog in a spec, and it’s exactly the most inhuman thing to say.  Two words turn this dialog into something an actual human being might enjoy - now, instead of ignoring their double clicking due to these wonky default preference settings, the computer is doing the user a favor.  We’ve turned a robotic vending machine into a bellhop who asks, “sir, did you mean to leave this dollar here?” whenever you try to tip him.

    So, now I’ve got a rough design for a dialog.  It’s the least bad I can think of.  But it’s better the damage came from me than the security team.

    by YokoZar at 2009-05-21 13:12

    2009-05-20

    I had a couple hours to kill downtown, so I wandered into the bookstore.  After futzing about with popular economics and romance novels, I decided to go check out the various Ubuntu books on offer.  I ended up looking through the index and sorting them into two piles.

    Two piles of books at Borders

    So, what’s the difference between the left and the right pile?  The books on the left, despite some of them being much thicker, make absolutely zero mention of Wine or running Windows applications.  Not even a cursory mention of how it’s possible, or a small paragraph suggesting users go look it up themselves - these books don’t even list Windows applications or Wine in the Index.

    I’m sorry, but if your book is in the left pile, it’s crap.  At best, it’s written for an audience in some alternate reality. 90 percent of computer users run Windows; about half of all Ubuntu users have installed Wine, and an untold number more would like to if they could get it to work. And these books, on the left, pretend that they simply don’t exist.  It’s like making a tourist guide and forgetting to mention the majority of cabdrivers will kidnap you unless you tip in advance.

    Concern for at least one Windows application is a use case so common that it could be fairly described as the main barrier for human beings running Ubuntu.  Maybe they don’t need to run their application since there’s a good Ubuntu equivalent.  Maybe their application works without fuss in Wine.  Maybe it doesn’t work at all.  It’s a question users have, and it’s a question that needs to be answered - even a short “no, don’t bother with Wine” is better than pretending this question doesn’t exist.

    Fortunately, most users don’t read books, and they shouldn’t have to.  If we’re smart about it, we can convey the information missing from these books through the operating system itself.  I shouldn’t have to look in a book to find out what Wine is, how it may or may not work with Windows applications, and how to install it - that information should be given to me as soon as the computer can figure out I’m interested.  That is, as soon as I double click on a Windows application.

    A dialog more valuable than any book (pen board draft)

    This is just one dialog, but it can convey information more valuable than any book, to millions more people.  That kind of small change having a big impact is exactly the reason I get excited about developing for Ubuntu.

    UPDATE: Apparently Hacking Ubuntu does mention Wine, it’s just that Wine and Windows applications aren’t in the index because the author didn’t write that part.

    by YokoZar at 2009-05-20 00:34

    2009-05-05

    Ubuntu 9.04 is here, and work continues

    Ubuntu 9.04 was released just over a week ago.  A release represents the public distribution of six months of serious work, a chance to show the world what we’ve been doing and how good it is.  It seems like a time to celebrate.  For me, it’s just as busy as ever.

    The very next day I spent the greater part of the day putting out the new Wine release for beta testing.  It’s become a bit of a routine of mine every other Friday - wake up, download the new tarball, test build it, update the package, push it to the Wine team PPA for building, redownload it from there and put it on the budget dedicated server.  Then I’ll go read the Digg article and see people post how Wine is getting better all the time.  Every now and again I’ll have to do something special - this release, for instance, included the new icons I found.

    I’m still not done with them though.  Nothing’s ever done, of course, but some days you spend 4 hours going over redesigns with another volunteer who probably wouldn’t be there without you.  This past week has given me a few more of those days.

    I volunteered to teach an online class for Ubuntu Open Week on Friday.  I teach in real life professionally, however the experience on a muted IRC channel is quite different.  There’s absolutely no continuous feedback; no students slightly nodding their head or twisting it in confusion - just empty channel.

    At first I thought I wouldn’t have much to talk about, but after taking a few questions I found myself running out of time.  I didn’t even get to talk much about some of the games projects I’ve been working on - people always have many questions about Wine.  They are, of course, completely right to do so.  You can read the session here.

    Anyway, it’s getting late so I’ll make this brief: I spent the past week also catching up on 5-a-day bugs; the Wine package now ranks very highly on the list of packages with good bug reports (upstream percentage).  I’ve got about 5 different major Wine package changes around the corner, and I’ve decided to move forward with Wine beta releases in Karmic even though I can’t be 100% sure that Wine 1.2 will be released on time.

    by YokoZar at 2009-05-05 11:02

    2009-05-03

    So it's been a few weeks since I've updated the site. In that time a lot has been going on in my personal life - but now things are starting to get better and back on track.

    by Tane Piper at 2009-05-03 11:18

    2009-05-02

    Females have long been an untapped market when it comes to tech and software.  Game publishers know this better than anyone, but nearly every corner of entertainment software would like to attract more female customers.  Glowdot Productions "Zen Jar" app for the iPhone seems to have accidentally stumbled onto the ...

    2009-05-02 07:30

    2009-05-01

    For a project I'm currently working on, I wanted to parse input strings looking for URLs and convert them to shortened URLs.  The best service to do this in is CR.AM, which is like competing URL shortening services but with some extra features like phishing/spam protection, Twitter integration, and more.  ...

    2009-05-01 18:30

    2009-04-22

    It started with a bug report.  The problem was the icon. Here is Wine’s current icon:

    The Wine icon is old.  It’s ugly.  It looks like it was made for Windows 95 (it was).  All this is enough reason to change it to something, but what does a good icon actually look like?  The Tango project has an answer to this question.

    A good icon is intuitive

    They’ve defined a set of standards for icons.  Usability is improved when these standards are followed - a user can easily pick out the icon and, if a good metaphor is possible, have a reasonable guess as to what it means.  The two playing cards next to eachother hint as to what Applications->Games has inside of it, even before you read the text.

    When a good metaphor isn’t possible, your best bet is to have an easy to recognize logo.  Since a “program for running Windows applications” doesn’t lend itself to any obvious metaphor, a logo suggesting the name Wine is our best bet.1

    A good icon is easy to recognize

    Enter the Wine glass.  To an English speaker, it’s very easy to create a mental connection between “wine glass” and “Wine program”.  If you don’t know what “Wine” is, at the very least you can recognize the wine glass as something rather unlike any other icon on the system.

    We also benefit from using the same Wine icon everywhere the user interacts with Wine itself.  Applications->Wine should have the main Wine logo.  Browse C:\ Drive should have a folder icon with a Wine logo on it, since it’s both a folder and has a lot to do with Wine.

    A good icon is consistent with the rest of the system

    The Tango project gives simple standards for visibility and usability, however they also give helpful standards for design.  Icons are generally three dimensional and, importantly, from the same perspective with the same lighting.  It looks very off when you jam a 2D, backwards tilted, viewed and lit from the bottom wine glass onto a menu full of 3D, front-viewed, lit from the top objects.

    Selecting the Wine glass

    The bug report was helpful enough to include a link to a Tango-compliant Wine icon that someone had made over 3 years ago.  It looked like this:

    I appreciated it, since it certainly was consistent with the other system icons, however something was off.  It looked like a wine glass, but a strange one.  Not being a drinker, my closest encounters with real life wine glasses all involved sparkling cider or rubbing my finger around the rim to make a humming sound.  I turned to Wikipedia.

    As it turns out, some real life wine drinkers really care about what kind of glass they use.  I learned that for all these years we’ve been committing the horrible sin of using a white wine glass for red wine.  That’s why the tango icon looked different - red wine glasses are supposed to be fatter.  But they vary on this too: as I learned from the internet, burgundy-style glasses are a bit fatter, and bordeaux-style glasses are a bit thinner.

    I also discovered a whole lot of websites use the same public domain wine glass clipart images:

    My uncultured user expectation

    So, that’s why the tango icon looked off.  It was violating my intuition of what a wine glass should look like - I hadn’t seen many fat glasses, and was expecting a thin wine glass.  The author of the icon was probably expecting wine to be in a burgundy glass.  Maybe he’s Burgundian.

    Being an uncultured American prone to these kinds of things, I decided the typical user was more like me.  I figured the best compromise was an actual red wine glass, but not one as fat as the icon provided.  I sent off emails to the wine devel list and posted on web forums discussing the situation, hoping someone might appear out of nowhere to make the perfect icon for me.

    YOSPOS, Bitch!

    The most helpful answer came from the Something Awful “Your OS is a POS” forum.  It’s a forum designed for nonsense so users of the “Serious Hardware/Software Crap” forum can blow off some steam.  In practice it’s a much more casual place to talk about nerd stuff where you don’t have to be burdened by making an effortpost.2

    Apparently, the work I was looking for was already done, and even put into an Ubuntu package.  Specifically, the ubuntustudio-icon-themes package, which has an icon for Wine that looks like this:

    It was everything I wanted.  They even had sub icons made for the Wine-related programs like notepad.  After a quick consensus from the Wine-devel mailing list, I’ll be bundling the icons into the next beta package.  Most users won’t see the new look until the upcoming Wine 1.2 release makes its way into Ubuntu 9.10.  There’s a nice coincidence there, because a slick new look tends to increase users expectations about an application, and Wine has vastly improved since 1.0.

    1: A Windows logo might seem like a good icon to use here, however that could create confusion as to what Wine is actually doing.  It’s very easy to think Wine might be opening some sort of virtual machine if you’ve never used it before.

    2: Actually, I find myself reading/posting almost exclusively in YOSPOS now instead of the serious forum.  It’s just more enjoyable somehow.  The catchphrase “YOSPOS, bitch!” is, of course, repeated widely in users signatures.

    by YokoZar at 2009-04-22 09:42

    2009-04-21

    I wrote some horrible C to do co-routines using the labels as values in gnu c or c99(?)

    http://pastebin.ca/1397932

    2009-04-21 03:11

    2009-04-18

    A while back I found myself facing the question of when we could expect Wine to get substantially better.  Wine has been in development for 16 years, and while it has millions of users there are still a great deal who are unhappy with it.  This is completely understandable - Wine doesn’t yet work perfectly with all their applications, and they shouldn’t be happy until it does.

    So, I decided to make a model of Wine development.  That way I could figure out if we were doing something wrong, or if it even mattered which bugs we were solving as long as we were working.

    Modelling Wine development and user happiness

    Let’s define the Wine project as a set of 10,000 or so bugs yet to be solved.  Maybe these represent API functions, or usability issues, or performance problems - whatever.  Some of these bugs may be harder to solve than others, so we’ll give each one a difficulty rating in terms of time.

    Now let’s define an application as some subset of these bugs.  A working application is one that has all its bugs solved.  We can also give each bug a different relative probability of affecting an application - maybe bug x is 10 times more likely to affect an application than bug y.

    A user is then defined as a set of applications he needs.  A “happy user” is one who has all his applications working.  Just like with the applications, we can assign relative probabilities to reflect the real world - World of Warcraft is 60 times more likely than CuteCatExploderPro.

    Finally, we need some strategy for solving the bugs.  We’ll get to 100% bugs solved in the same amount of time regardless, but the order we do them in will matter.  I was able to come up with about a dozen or so strategies, such as “pick a random unhappy user and solve a random bug in one of his applications”.  I picked the most realistic of these, and told the simulation to alternate between them.

    I then turned this all into a python script and combed it with the cairoplot chart generator, generating a picture like this:

    Model of Wine development

    Output of wine-model with 10,000 bugs, 500 users, and 500 applications simulated

    You can download the script and play with it yourself - much of it is easily customizable

    Surprising things learned from the model:

    • The strategy we use - the order we tackle various bugs - really does matter.  Every strategy gets to the perfect 100% end after solving all the bugs, but some get you 10 times as many happy users when you’re only half done.  In practice, having far more users likely translates into extra developers and a much faster rate of development.
    • Varying the difficulty of individual bugs didn’t matter much.  The pictures came out pretty much the same
    • Prioritizing the last few bugs in apps that are almost done is one of the most productive ways to increase happy users - in the simulations I ran it even outperformed working on the most popular application.  Unfortunately in the real world it can sometimes be difficult to tell if an application “almost works” in Wine.
    • Similarly, “almost happy users” are the easiest to satisfy.  When we have many to choose from, picking one arbitrarily and ensuring he was happy before moving on to the next user significantly outperformed trying to satisfy almost happy users at random.
    • Instances of “collateral damage” - the fixing of one application causing another application to start working without any extra effort - are rather uncommon until most applications are almost working.  The wintrust API is needed by both Steam and iTunes, however when enough of wintrust was implemented to make Steam work there were still many unrelated bugs causing iTunes to remain broken.
    • Just about every reasonable way of generating bug difficulty, relative bug probability, applications, and users that I could think of lead to the same general picture: something that looks roughly linear for most of it before taking a very sharp upward turn near the very end.  In other words, the model tells us that we should expect to be pleasantly surprised.  At some point, Wine will get very good very fast.

    So, when will that point of sudden very rapid growth begin in the real world?  No one can really know - even analyzing statistics like the growth of platinum ratings on AppDB would only give us information after the fact. 

    Modeling Linux adoption

    We can make a similar model for Linux adoption itself.  Just imagine a few well-known barriers to entry, like driver support and compatibility with existing applications.  Now suppose that a particular barrier affects some large percentage of potential users.

    If 80% of users can’t switch until they have working drivers, 80% can’t switch because of some existing Windows application, and 80% can’t switch because they haven’t heard of Ubuntu, then that means we can only expect to get 0.8% of the users.  This is, incidentally, about as many as we have.  As Joel on Software* puts it:

    Think of these barriers as an obstacle course that people have to run before you can count them as your customers. If you start out with a field of 1000 runners, about half of them will trip on the tires; half of the survivors won’t be strong enough to jump the wall; half of those survivors will fall off the rope ladder into the mud, and so on, until only 1 or 2 people actually overcome all the hurdles.

    So what’s our best strategy then?  Eliminating these barriers to entry - turning the rope ladder into an elevator - is the only way to get new users.  If we fix the driver problem, and the driver problem affects 80% of our would-be users, then we can quintuple our user base.  If we fix the Windows application problem, and make Wine work well, then we can quintuple usage again.

    Full article by Joel on Software

    by YokoZar at 2009-04-18 00:25

    2009-04-16

    Since shaim is over, I’ve found myself with rather a glut of time on my hands. I’ve been reading a lot more (alternating between the Dune series and the Dresden Files series) but I still have the desire to work on programming stuff in my spare time. This time around I’ve decided to combine my love of strange books with my interests in linguistics and computational analysis.

    I’m guessing that aren’t many people reading this who know what the Codex Seraphinianus is. From Wikipedia:

    The Codex Seraphinianus is a book written and illustrated by the Italian artist, architect and industrial designer Luigi Serafini during thirty months, from 1976 to 1978. The book is approximately 360 pages long (depending on edition), and appears to be a visual encyclopedia of an unknown world, written in one of its languages, a thus-far undeciphered alphabetic writing.

    It’s rather rare (read: expensive) and isn’t currently published in the US, but I happened to get a hold of a copy via Courtney’s connection to the library at the University of Illinois. The art is beautiful, and the language intrigues me. Linguists have worked at figuring out this language since the book was first published - for all anyone knows, it’s complete nonsense. I’m not vain or stupid enough to think that I can succeed where trained linguists have not, but I decided I’d try my hand at learning about image processing and give the deciphering a crack myself. What can it hurt?

    The first step to all of this ballyhoo is to extract words from the book. Recently I came across some fairly high-quality scans of the Codex. Here’s an example of the writing:
    Writing from the Codex Seraphinianus
    Writing from the Codex Seraphinianus

    The scans are full-color and you can see where images on the opposing page have shown through. The first thing I did was write a quick program to convert the images to black-and-white. This removes a lot of the noise, smallerizes the image files, and gives analysis algorithms an easier time of figuring out what’s where.

    The same paragraph in 2-color format
    The same paragraph in 2-color format

    The next step is to figure out where words are on the page. I’ve implemented a connected components algorithm that identifies connected regions on an image.

    The same paragraph with connected regions colored
    The same paragraph with connected regions colored

    That’s all my progress as of last night. The algorithm isn’t perfect yet, I’ll have to tweak its performance to find regions that should be connected but aren’t because of quality issues in the black-and-white format. You can also see that diacritic marks aren’t grouped to the word that they belong to, so the next phase of processing will involve grouping regions that fall within a bounding area.

    I’m not entirely sure what comes next, at least as far as extracting the text goes. This is a learning experience for me. Further bulletins as events warrant :)

    by Chris at 2009-04-16 15:10

    The even-stunninger conclusion to I’m All Up Outta Here parts one and two!

    I’m just going to come out and say it: I’m burned out on shaim. As of right about now, I’ve been developing some incarnation of shaim for four years. I really enjoyed the experience that it netted me, as well as the satisfaction of helping loyal users as they reported bugs and endeavored to help me make it better, but now enough is enough. The site will remain up as long as Greg sees fit to leave it up; if it ever goes down, I’ll transition the codebase to another host so that anyone who wants to use any part of it may do so.

    Thanks go out to everyone who’s contributed code, resources, or general support over the years. In no particular order:

    • Greg
    • CheeToS
    • saiyr
    • Joy
    • Andrew
    • The group from Western Washington University who contributed to shaim for their senior project
    • The dozens of people who’ve contributed bug reports and kudos

    PEACE OUT

    by Chris at 2009-04-16 14:35

    2009-04-15

    Act One: The Code and The Motivation

    Here’s the first player, our code.

        % ls Repository/trunk/clementine/interfaces/gesture
        CLGestureCue.cxx           CLGestureCueAppearance.h   CLGestureListener.cxx      CLGestureParser.h
        CLGestureCue.h             CLGestureInterface.cxx     CLGestureListener.h        CLGestureTrainer.cxx
        CLGestureCueAppearance.cxx CLGestureInterface.h       CLGestureParser.cxx        CLGestureTrainer.h
    
        % cat CLGestureListener.h
        #ifndef __CLEMENTINE_INTERFACES_GESTURE_CLGESTURELISTENER_H__
        #define __CLEMENTINE_INTERFACES_GESTURE_CLGESTURELISTENER_H__
    
        #include "CLGestureParser.h"
        #include <string>
    
        /**
         * CLGestureListener is responsible for listening on the CLGestureInterface
         * for a single gesture type.
         */
        class CLGestureListener
        {
                public:
                        /**
                         * Instantiate the listener.
                         * @param gestureName the name of the gesture
                         * (and consequently, the filename to parse) that this object is created to listen for.
                         */
                        CLGestureListener(std::string gestureName);
        ... etc
    

    It’s a whole bunch of header and implementation files for a C++ project I’m involved with. This project requires the use of thorough documentation, but our design documents are hundreds of revisions behind our code. While it’s important to have gone through initial designs, our code at this point is miles removed from those designs. It would be nice to be able to automagically update our design document to be kept current on what is occurring in the code. This will not make up our entire design document. It is meant to be used in conjunction with manual, hand-written and hand-proofed analysis of the larger architecture.

    The second player is AsciiDoc, a wonderful formatting and markup system. You may know it from the Git User’s Manual. AsciiDoc affords us several advantages.

    • It is in plain text, which means it can sit in source control, right alongside our code, and diffs are easily viewable.
    • It is a templating language, which allows output into HTML, PDF, you name it. With enough hacking, you can produce really distinct output for webpages and PDF readers.
    • It allows division of sections into different files, so authors can focus on the sections that concern them without being overwhelmed by the text they’re editing.

    Act Two: The Tools

    We want the comments in our code to be part of the documentation, but that’s not all. Since UML is the standard when it comes to software engineering description, it would be nice to have UML diagrams in our output as well. The ubiquitous free diagramming tool Dia provides, with its invocation, command line arguments to convert Dia diagrams into images. It goes like this, where you wish the output to be image_name.png:

        dia -t png -e image_name.png diagram_name.dia
    

    So this part will be simple. Generating the Dia diagrams from code is already taken care of for us. Aaron Trevena has written an excellent script called AutoDia which provides this functionality. All we need to do is put these pieces together, along with writing the functionality to extract the comments we want to become documentation.

    Act Three: The Program

    I am calling it Amorfus, because I think client-side applications should start getting into the Web 2.0 naming crazes.

    How do you use it?

    1. Create a new CommentDocParser, with these parameters: a string pointing to the subdirectory of your trunk that you wish to document, a string containing the conceptual name of the code in that directory, and a string containing your trunk directory. You can leave this last one out, and it will default to '.'.
    2. Run #parse on that parser.
    3. Create a file handle, and output the return value of #to_asciidoc to that file.
    4. That’s it!

    Here’s an example:

    	require 'amorfus'
    	DIRECTORY_HEADER_LEVEL = 1 # This will become the section depth, in AsciiDoc, for each individual class we find
    	r = CommentDocParser.new 'interfaces/gesture', 'Gesture Interface', 'Repository/trunk'
    	r.parse
    	t = File.new('output.txt', 'w')
    	t.write r.to_asciidoc
    	t.close

    What does it do in the background?

    1. It uses a dumb regex based heurestic to determine if a comment has value.
    2. It classifies methods by what it can find of their name.
    3. It generates Dia diagrams whenever it can find an object.
    4. When generating images, it parses Dia diagrams using Nokogiri and removes irrelevant objects from that diagram, so that only the featured object shows up in the image.

    Finally, we’ll need to make a small patch to AutoDia to make it recognize structs as equally valid objects. This is extremely hackish (see the Epilogue), but it manages to work for now.

    --- Autodia-2.03/lib/Autodia/Handler/Cpp.pm     2009-04-15 01:10:46.000000000 -0400
    +++ Autodia-2.03.orig/lib/Autodia/Handler/Cpp.pm        2005-04-15 08:02:49.000000000 -0400
    @@ -72,7 +72,7 @@
              $i++;
     
              # check for class declaration
    -         if ($line =~ m/^\s*(?:class|struct)\s+(\w+)/)
    +         if ($line =~ m/^\s*class\s+(\w+)/)
                {
     
     #            print "found class : $line \n";

    Act Four: The Results

    The resultant HTML looks like this:

    Example of Amorfus-generated documentation

    From our previous example, this can be generated on the command line like so:

        % asciidoc --unsafe -e data-uri output.txt
    

    The --unsafe and -e data-uri allows AsciiDoc to embed the images you’ve created directly into the HTML, instead of referencing them externally. This makes the document self-contained, in a sense. You can ignore these flags if you wish. In that case, standard <img> tags will be generated.

    Epilogue: Warnings

    This functionality was hacked together in about two hours. It does horrible things to Dia’s XML documents, it guesses at what the current spec for AsciiDoc is, and requires a hastily applied patch to a third party tool, AutoDia, in order to accomplish its goals. Because of it’s nature, I can’t make any guarantees as to how effectively it will work, what circumstances it will work under, and the like. If you have any suggestions or improvements, I implore you to fork the code (currently hosted at this Gist) and see what you can come up with. For example:

    • I don’t even think it recognizes variables correctly. You might want to fix this.
    • It ignores public:, private:, and protected:. You might want to fix this, but it is meant for design documents, so all methods should be documented.
    • If a class has more than one constructor, only one will be displayed in the documentation. You might want to fix this.

    by Ardekantur at 2009-04-15 20:09

    2009-04-14

    If you’re one of the 130,000 or so people who have been using Wine beta releases, then at some point you’ve probably run into a regression.  Version 1.1.12 ran TerroristExploderPro fairly well, so you upgraded to Wine 1.1.13 only to find that it functions worse than TerroristExploder Home Edition.  This is a regression.

    Regressions are best caught quickly.  When we have a regression, it means some “improvement” we made is actually very wrong, and the longer we go without realizing there’s a problem the harder it is to figure out which change actually caused it.  This was the main reason why Wine first built an extensive Applications Database - not so users could find out if their application worked, but so developers could find out when it stopped working.

    An example regression

    Suppose we have an incomplete “stub” function in Wine for telling the time that just returns a blinking 12:00.  This could be good enough; rather than crashing outright when Photoshop asks for the time, instead the wrong time is printed in some log file the user never sees.

    Now, suppose a Wine developer comes along and sees that some other application, Baby’s First Clock, doesn’t work because a blinking 12:00 isn’t good enough.  So that Wine developer tries to implement the time function.  He can’t, however, be exactly sure how to do it since Microsoft’s documentation is often inaccurate or even nonexistant.

    So, he makes his best guess, and tells the function to return 6:00 PM when it’s dinnertime.  He tests Baby’s First Clock and it seems to work, so the patch gets committed and a new version of Wine is released touting advanced Baby’s First Clock support.  By doing this, however, we may have broke Photoshop: because it expected 24-hour time, Photoshop now crashes whenever it sees 6:00 PM instead of 1800.

    Preventing regressions with an automated test suite

    Preventing regressions has become an important part of Wine development, however we’re still pretty bad at it.  One approach that’s had partial success is to write a big automated test suite. In theory, if we had a magic way of running Photoshop every patch then regressions like this wouldn’t happen.  Currently, Wine’s test suite, while very large, is not very reflective of real-world applications; instead, individual functions are tested to make sure we do the same thing as Windows.

    In theory, if we had one of these individual tests for every case for every function, Wine would never have any regressions.  In practice, we miss a few, and real world applications break every now and again.  Actually, that’s not quite true - Wine would still have regressions even with a complete test suite; some tests we expect to fail because we haven’t written the functions yet, but we might be accidentally relying on broken behavior when we write another function.  It’s like painting a wall light brown to match the ugly yellow carpet - when you finally replace it with something good you may find your wall looks as ugly as it sounds.

    Regressions can also come from passing well made tests.  Performance regressions are the best example: at one point a certain direct3d shading function was “stubbed” out and did nothing.  Most gamers didn’t care, since all it meant was the color of the beards on the terrorists was a slightly duller shade of brown.  However, this stub behavior (correctly) caused a Direct3D test to fail, so the shading function was implemented and the test passed.  Unfortunately, the implementation was very slow and now instead of seeing 50 dull beards per second gamers were seeing 5 shiny beards per second, making the game an unplayable albeit beardy slideshow.

    Wine’s test suite grows as Wine development progresses.  In many ways, having a “complete” test suite is almost the same thing as having a complete Wine - once we know exactly what to test for we also know how to write our implementation.

    A test suite, however, can only get you so far.  Until we have a nearly complete test suite that can expose all the subtle problems in partially broken applications, we’re still going to run into periodic regressions.  For that, we need another tool - users need to actually play the shiny beard game.

    Preventing regressions with stable releases

    The most effective way to prevent regressions is done by all serious projects: the stable release process.  The process starts with a feature freeze: no new code features are done, and all those “implement this” regressions just can’t happen.  Baby’s First Clock stays broken, but Photoshop won’t break either.  We stay in this freeze until we’re confident enough that anything that ever worked in Wine still works in Wine - that is, we fix Photoshop.

    That’s what Wine 1.0 was about: it was the first release that actually made that promise.  It took 15 years, but this made a certain amount of sense given how visibly incomplete Wine was - there was always some new feature about to go in, and so many applications were “almost” working.  A year and a half later, they’re still almost working.

    Wine 1.0 came out shortly after Ubuntu Hardy (8.04), so I had to ship a Wine beta version and then later replace it with a stable release update.  As a distribution meant for human users, Ubuntu tries to only ship stable software in its releases; this way, end users don’t have to worry so much about regressions.  Attracting new users with features is important, but not scaring off our existing users is important too - that’s the kind of innovation that gets it right.

    This need for stable releases is why Jaunty (9.04) will still have Wine 1.0.1, and it’s why I’ve been secretly lobbying for speeding up the next stable Wine release for over a year now.  “If Wine 1.2 can come out in the next six months,” I’d argue, “then we can ship it in the next Ubuntu and end users will be able to actually see some of these improvements you’ve been making.”  This is the same reason Mark Shuttleworth has been calling for more synchronous freezing of upstream projects - if everyone releases around the same predictable time, then we maximize the amount of new but stable software users actually get.

    Well, it looks like I may finally get my way in the Karmic time frame.  Wine may actually make that 1.2 release happen, even if it’s not as “complete” as the project’s leader originally envisioned.  So look forward to Wine and Ubuntu being particularly powerful come 9.10, and I’ll do my part to help it along the way.

    by YokoZar at 2009-04-14 21:58

    Can you make an iPhone game using only the interface builder and no additional libraries? Yes, and I'll show you how.

    2009-04-14 19:30

    2009-04-13

    When someone says “pick a markup language,” most people would immediately respond with “XML!”, but there’s an alternative out there. YAML is human-readable, easy to use, and overall quite fantastic.

    This is a reprint of an article I wrote for Python Magazine as a Completely Different column that was published in the December 2008 issue. I have republished this in its original form, bugs and all


    I hate markup languages. There, I said it. The first time I had the pleasure of “using” (being abused by) XML, I said to myself “there has got to be a better way of doing this.” Well, after years of sticking with plain text ini files and custom syntaxes based off of using ”eval()”, I’ve come to not only use, but love, YAML.

    YAML, or “YAML Ain’t Markup Language”, is “a human friendly data serialization standard for all programming languages.” It has the advantage of leaning towards dynamic languages a la Python, Ruby, etc.

    It is important to note that friendliness and readability are very core to the design of YAML. The number of format characters is very low and, like Python, YAML’s markup can use whitespace to indicate scoping of items. Tabs are not allowed, so there is no chance for confusion about indention level. Additionally, the constructs within YAML such as mappings, sequences, and scalars all mesh nicely with existing Python data types like dictionaries, lists, strings, and integers. It’s also fully unicode-enabled, which should make happy a lot of people who are normally worried about UTF-8.

    What really attracted me to YAML are some of the key things that drew me to Python: cleanliness and approachability. Too often, I’ve had to deal with monstrous XML files for data passing or — worse yet — configuration and sometimes ini-style configuration files that simply don’t scale, or communicate enough information. So far, I’ve used YAML in about six different projects with great success and found that it scales quite well while staying human-readable.

    Syntax is Key

    YAML, on its face, is amazingly simple. Take the code below, for example. Run through the pyyaml load function (more on PyYAML in a moment):

     # YAML
    name: Jesse
    

    This YAML will get the following Python dictionary:

    ?View Code PYTHON
    1
    2
    3
    4
    5
    6
    7
    
    >>> import yaml
    >>> yaml.load("""
    ...  # YAML
    ... name: Jesse
    ... """)
    {'name': 'Jesse'}
    >>>

    This is a simple example. Line 1 of the YAML file, or document, is a simple comment. Note that there is a space character right before that # sign. The next line is a simple key value pair which, after being parsed, gets returned to us in a Python dictionary. Simple as pie!

    A simple name-value pair is easy to do. Here is a document with some additional structures and details to try:

     # YAML
    object:
        attributes:
            - attr1
            - attr2
            - attr3
        methods: [ getter, setter ]
    

    Here, we have defined a top-level entity named “object”. This object has two block mappings related to it, ”attributes” and ”methods”. The ”attributes” mapping uses the more verbose YAML syntax for a list, in this case:

    attributes:
        - attr1
        - attr2
        - attr3
    

    In this case the YAML represents a key with a name of ”attributes” while each item underneath it, prefaced with a “”-””, represents an item that will appear in a list as a value for that key. Here it is printed after a load:

    ?View Code PYTHON
    1
    
    {'object': {'attributes': ['attr1', 'attr2', 'attr3'], ...

    The ”methods” key uses YAML shorthand to accomplish the same thing. In my experience, non-programmers tend to understand the first method, “”-”” prefacing, a bit more than the second method. Both parse to Python lists:

    ?View Code PYTHON
    1
    2
    3
    
    {'object': {'attributes': ['attr1', 'attr2',
                               'attr3'],
                'methods': ['getter', 'setter']}}

    I included both examples to illustrate a point. Most of YAML’s syntax has two ways of achieving the same intended goal. There is the verbose, multi-line method, and the more compact method. Both methods are human-readable, so choosing one is a matter of personal preference.

    As you can see, the most basic syntax is as follows:

    dicts/hashes: key, value separated by a colon and space, e.g. ”key: value”; additionally, you can use ”{key: value}”

    lists: dash followed by a space then the item, e.g. ”- item”; additionally, you can use ”[item, item, item]”

    Strings do not require quotation. You can preserve line breaks with the ”|” character; for example:

     # YAML
    sonnet: |
        I wish I could
        write a poem
        but I can't
    

    This would parse to:

    ?View Code PYTHON
    1
    
    {'sonnet': "I wish I could\nwrite a poem\nbut I can't\n"}

    Trailing and preceding whitespace is trimmed out in the basic use case of ”|”. See the “Scalar indicators” section of the compact cheat sheet for modifiers to the ”|” character.

    Core to YAML is the concept of documents. A document is not just a separate file in this case. Instead, think of a document as just a chunk of YAML. You can have multiple documents in a single stream of YAML, if each one is separated by ”—”, like:

     # YAML
    ---
    document: this is doc 1
    ---
    document: this is doc 2
    ...
    

    Using an ellipsis explicitly ends a document. The nice thing about documents is you can treat them as different entities. Let’s say, “people” and “cars” are in the same file. You can use them for a bunch of entities that look alike, e.g.:

    name: SomeObject
    attributes:
        - attr1
        - attr2
        - attr3
    methods: [ getter, setter ]
    ---
    name: MyPrettyObject
    attributes:
        - attr1
        - attr2
        - attr3
    methods: [ getter, setter ]
    

    which parses to:

    ?View Code PYTHON
    1
    2
    3
    4
    5
    6
    
    {'attributes': ['attr1', 'attr2', 'attr3'],
     'methods': ['getter', 'setter'],
     'name': 'SomeObject'}
    {'attributes': ['attr1', 'attr2', 'attr3'],
     'methods': ['getter', 'setter'],
     'name': 'MyPrettyObject'}

    YAML also supports variables, or repeated nodes, which at first didn’t click for me. The simplest explanation is that you define something as a variable by preceding it with ”&NAME value” and you can refer to it with ”*NAME” e.g.:

     # YAML
    some_thing: &NAME foobar
    other_thing: *NAME
    

    Parses to:

    ?View Code PYTHON
    1
    
    {'other_thing': 'foobar', 'some_thing': 'foobar'}

    As you can see, the syntax is pretty simple. It’s easy to represent information in a way that is both clear, concise and, well… fun. What’s really cool is the fact it meshes so well with Python!

    Note that fans of JSON (JavaScript Object Notation) will quickly realize that the concise-version of the syntax (e.g. using ”[value, value]”) looks a lot like JSON. In fact, for the most part, JSON is a subset of YAML syntax. With a little bit of additional pre-processing you should be able to pass your JSON off as YAML and vice-versa.

    And with that, PyYAML

    After reading the basic of the syntax, you’re jazzed to get started with YAML, right? Well, getting started with YAML is only a single ”easy_install” away. The **PyYAML** module is pretty much the de-facto parser and emitter for YAML. The core of the module is written in pure Python, but, as of version 3.0.4, it also supports binding to the high-speed LibYAML implementation written in C.

    PyYAML is blindingly simple to use for most cases. To generate all of the output I’ve used in the article so far, all I used was:

    ?View Code PYTHON
    1
    2
    3
    4
    
    import yaml
    import pprint
    for project in yaml.load_all(open('test.yaml')):
        pprint.pprint(project)

    The ”load_all()” function goes back to the “multiple documents within a stream” concept. In the case above I am assuming that there won’t be just a single document. I am using ”yaml.load_all()”, rather than ”load()”, then iterating over the results. ”yaml.load_all()” returns a generator yielding each document in the stream. The ”yaml.load()” function accepts a string (Unicode or otherwise), or an open file object.

    For many cases, you’ll be loading a single document. You might use it for configuration loading:

    ?View Code PYTHON
    1
    
    configuration = yaml.load(open('test.yaml').read())

    Of course, one of the other aspects to PyYAML is dumping Python data structures to a YAML file. Take, for example, Listing 1:

    ?View Code PYTHON
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    #!/usr/bin/python
     
    import yaml
     
    mydata = {'person' : 'jesse',
              'hobby' : 'python',
              'employed' : True,
              'limbs': {'arms' : 2, 'legs' : 2},
              'family' : ['wife', 'toddler']}
     
    print yaml.dump(mydata)

    In this case, I am constructing a dictionary containing all of the data I want to include in the YAML file. Then I simply call ”yaml.dump()” and the output of Listing 1 looks like well-formed YAML:

    ?View Code PYTHON
    1
    2
    3
    4
    5
    6
    
    $ python Listing1.py
    employed: true
    family: [wife, toddler]
    hobby: python
    limbs: {arms: 2, legs: 2}
    person: jesse

    Additionally, PyYAML includes ”yaml.dump_all()”. It accepts a list of objects to serialize and writes to the target stream. Let’s make Listing 1 handle a series of objects:

    ?View Code PYTHON
    1
    2
    
    mydata = [ mydata for i in range(2) ]
    print yaml.dump_all(mydata, explicit_start=True)

    And our output is fairly obvious:

    ---
    employed: true
    family: [wife, toddler]
    hobby: python
    limbs: {arms: 2, legs: 2}
    person: jesse
    ---
    employed: true
    family: [wife, toddler]
    hobby: python
    limbs: {arms: 2, legs: 2}
    person: jesse
    

    By default, you don’t need to pass additional arguments to ”yaml.dump()” or ”yaml.dump_all()”, as you can see above. In the ”dump_all()” example, I added the ”explicit_start” argument. The dump functions support this flag, along with some others that you should know about, to control formatting.

    The ”explicit_start” argument adds the “—” string prior to the data structure being dumped. This allows you to dump multiple objects/documents to the same stream, say, an open file handle, without worrying about the document separators yourself.

    Adding the ”default_flow_style” argument changes the output from the default compact style of output, to the more verbose, “humane” output:

    ?View Code PYTHON
    1
    
    print yaml.dump(mydata, default_flow_style=False)

    And the output:

    ?View Code PYTHON
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    employed: true
    family:
    - wife
    - toddler
    hobby: python
    limbs:
      arms: 2
      legs: 2
    person: jesse

    You can also control indenting, width, and so on. You can also switch it to canonical mode, which explicitly defines the type of the value within the YAML:

    ?View Code PYTHON
    1
    
    print yaml.dump(mydata, canonical=True)

    And the matching output:

    !!map {
      ? !!str "employed"
      : !!bool "true",
      ? !!str "family"
      : !!seq [
        !!str "wife",
        !!str "toddler",
      ],
      ? !!str "hobby"
      : !!str "python",
      ? !!str "limbs"
      : !!map {
        ? !!str "arms"
        : !!int "2",
        ? !!str "legs"
        : !!int "2",
      },
      ? !!str "person"
      : !!str "jesse",
    }
    

    Yes, I just jumped the tracks on that last one. YAML and PyYAML both support explicit type declaration within the YAML documents. This is obviously handy for inter-language data exchange, but, as you can see in the output, is not so good on the side of readability if you’re a non-programmer. On the other hand, it allows for a nice segue!

    =h=Turning the Awesome Up=h=

    We have covered the basics of YAML and, by extension, PyYAML, but PyYAML offers some additional niceties for Python users. Obviously, these advanced features start to edge out approachability, but they are actually really useful.

    In the last example of the last section, we turned on the ”canonical” flag to the ”dump” function, which caused it to spit out explicitly typed YAML. Each type was in the format of

    ''!!''

    . These are standard YAML tags, and they’re fully covered in the spec.

    Internally, PyYAML converts these tags to the expected Python types. ”!!null” is ”None”, ”!!timestamp” is ”datetime.datetime”, ”!!seq” is ”list”, and so on. You don’t need to explicitly put these in your YAML documents. In most cases the types are inferred from the document, but being able to explicitly define them is handy.

    PyYAML can take the ”!!” syntax a bit further though, and adds a series of Python-specific tags which are exceedingly useful. Each one of the Python-specific tags is prefaced with

    ''!!python/''

    . PyYAML defines explicit Python types such as ”float”, ”complex”, ”list”, ”tuple” and ”dict”. In my opinion, the ”tuple” and the ”integer” ones are more useful simply due to the fact that ”dicts” and ”lists” can be derived from the YAML file itself.

    However, PyYAML also offers “non-type” ”!!python” extensions. These are referred to as “Complex Python Tags” and they allow you to add things to your YAML document such as Python modules, packages, class instances, and the output of a method call with a passed-in variable.

    Say we wanted to have a YAML file which defined some number of variables, but then passed one or more of them to a given module’s method. I wanted something to list the contents of my home directory on parsing:

     # YAML
    directory: &DIRECTORY /Users/jesse
    contents: !!python/object/apply:os.listdir [*DIRECTORY]
    

    And the abbreviated output:

    ?View Code PYTHON
    1
    2
    3
    4
    
    {'contents': ['.bash_history',
                  '.bash_profile',
                  'todo.txt'],
     'directory': '/Users/jesse'}

    Virtually any function can be called this way. You can also pass in keyword arguments and other data as required. Calling a function, though, is rather easy. Here’s an example YAML file which uses the PyYAML ”new:module.class” tag to create a ”Queue.Queue” at load-time with a defined max size:

    qsize: &SIZE 10
    queue: !!python/object/new:Queue.Queue {maxsize: *SIZE}
    

    Which, of course, passes you back the correct class instance:

    ?View Code PYTHON
    1
    
    {'qsize': 10, 'queue': <Queue.Queue instance at 0x292fa8>}

    In theory, and in my rather abusive practice, this would allow you to define a very rich configuration which constructed all of the relevant objects at parse-time to significantly alter the behavior of the application (or in my case, test) to which the YAML file was passed. One catch when you are using the ”!!python/object/*” tag(s) is that the objects you are creating must be pickle-compatible.

    For example, if you tried this:

     # YAML
    threadpool:
     - !!python/object/new:threading.Thread
      target: myapp.myfunction
    

    It would fail with an assertion error:

    ?View Code PYTHON
    1
    
    AssertionError: Thread.__init__() was not called

    PyYAML is not calling ”__init__()” when creating the object. Both ”yaml.load()” and ”yaml.dump()” are designed to work exactly like ”pickle.load()” and ”pickle.dump()”. Objects must implement the pickle protocol.

    Conclusion

    YAML and, by extension, PyYAML, are incredibly useful if you want something easy on the eyes, easy to understand, and easy to use in a markup language. It’s straightforward to customize, it’s cross-language, and fundamentally simple. YAML is popping up in all sorts of places, such as the configuration settings for Google’s AppEngine, and in Django, where it is used for a serialization format and to load data fixtures.

    Obviously some of the advanced features of PyYAML are Python-specific, but the fundamentals make it an easy win for cross-language communication. Sure, XML does this, too, and there’s support in every known language for XML parsing (including the stuff toddlers speak), but how readable is XML, seriously?

    I do hope more and more people adopt this user-friendly format. It’s simply great as a configuration language, and if you need to expose anything to humans and later serialize and deserialize it, just say “no” to XML.

    The revolution will be readable.

    Requirements:

    Related Links


    by jesse at 2009-04-13 15:28