tag:blogger.com,1999:blog-127297672024-03-17T01:16:50.662-07:00One for the Morning Glorydburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.comBlogger120125tag:blogger.com,1999:blog-12729767.post-55726874609474556152007-11-30T20:46:00.000-08:002008-07-10T06:23:10.747-07:00My blog has moved.My blog is now hosted over here:<br /><br /><a href="http://algebraicthunk.net/~dburrows/blog">http://algebraicthunk.net/~dburrows/blog</a>dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.comtag:blogger.com,1999:blog-12729767.post-49898560106808671402007-11-21T18:31:00.001-08:002009-12-11T03:28:11.001-08:00Facebook commentsMy blog is syndicated on <a href="http://planet.debian.org/">Planet Debian</a>, <a href="http://planet.gslug.org/">Planet GSLUG</a>, and Facebook (through their "notes" system). I occasionally get a comment about one of my posts over on Facebook, and every time I do I remember one of the reasons I avoid that site.<br /><br /><blockquote><br />[someone] made a comment about your note "note title".<br /><br />To see the comment, follow the link below:<br />[link to Facebook]<br /></blockquote><br /><br />What's missing here is of course the actual text of the comment. Blogger does this right: the actual comment is emailed to me. Not only does this impose the annoyance of having to click on the link, but I often read my email offline, and so a message like this is worse than useless for me. (worse as I have to postpone it for later, which means I need to deal with it twice) It would be even better if I didn't have to click to reply, but with a Web service you kind of expect that. (one of the reasons that I'll be setting up my own blog at some point: I can use software that actually allows me to compose replies offline)<br /><br />I don't know why Facebook does this, but my guess is that either (a) they haven't thought about it, or (b) they want to drive up page views and make it annoying for me to not use their site. If it's (b), then that apparently works for a large swathe of the population, but it makes me want to avoid them like a bad cliche.<br /><br />[EDIT] This post is attracting spam; closing comments.dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com3tag:blogger.com,1999:blog-12729767.post-60367144011673695592007-11-21T18:09:00.001-08:002010-03-04T06:39:39.916-08:00Good ideas in customer service: kill the hold periodThe lender for one of my student loans has apparently started using a rather cool system to manage incoming customer service calls. If all the call-takers are busy, then instead of forcing you to sit there listening to a call telling you how important your business is to them, they let you request a call-back. They ask you to enter a phone number where they can reach you, then give you a time window in which they'll be calling (in my case I think it was about two minutes wide). When my turn came up, they called me and I was able to speak with a human immediately.<br /><br />This is such a huge improvement over the typical call center experience that I'm amazed it hasn't caught on more broadly.<br /><br /><ul><br /><li>It's presumably good for them since they don't have to pay for a long incoming toll-free call, particularly when most of the call is just muzak.<br /></li><li>It's great for me, because instead of sitting by the phone like a hawk in case I miss the customer service rep, I can go do something useful for a few minutes until the time the call is scheduled for.<br /></li></ul><br /><br />I'm guessing that this option will be available in more and more places as companies computerize their telephone systems. Another nice twist, if there are any telephony guys reading this, would be to allow me to request the customer service call from a Web page, eliminating the toll-free call altogether and presumably saving some expense for the company.<br /><br />An interesting question for me is how they generate those estimates of when they'll be able to help you. I'm guessing that they use some <a href="http://en.wikipedia.org/wiki/Queueing_Theory">queueing theory</a> to estimate the most likely wait time for the next incoming customer, but this is something I have only a fuzzy awareness of. However they did it, the estimate seemed accurate enough to me.dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com5tag:blogger.com,1999:blog-12729767.post-73869950568381241052007-11-20T21:28:00.000-08:002009-12-11T03:31:53.714-08:00cwidget gets a Web pageI spent some time last weekend putting together the infrastructure to generate a basic <a href="http://cwidget.alioth.debian.org/">Web page</a> for cwidget. The Web page is generated by <a href="http://ikiwiki.info/">Ikiwiki</a> (thanks to the incomparable Joey Hess for a really nice piece of code there) and doubles as the cwidget documentation; it will be included in the next upload of libcwidget-doc. It can be found in the source tree under doc/ikiwiki.<br /><br />It's currently a bit skeletal: in particular, it really needs some tutorial/HOWTO material for new users. But it at least has all the basic information that I personally expect from a project Web site.<br /><br /><br />I was playing with ikiwiki for a week or so prior to setting this Web site up, and the more I use it the more impressed I am. When I get my new Slicehost instance set up (probably next weekend), this blog will probably migrate to an ikiwiki installation over there. Being able to edit my posts offline (about half my hacking time is offline), being able to expose a change history for posts, and not having to maintain an installation of a monster PHP program (as the docs put it, if you don't run the CGI then ikiwiki has the security implications of cat(1)), are all absolutely killer features for me, and I look forward to expanding my use of this tool. Joey has struck gold yet again.<br /><br />[UPDATE] This post is attracting spam and no real comments. Closing comments.dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com2tag:blogger.com,1999:blog-12729767.post-52154777270669477682007-11-11T18:41:00.000-08:002007-11-11T19:10:08.171-08:00ANNOUNCE: cwidgetI've just uploaded the first release of libcwidget to Alioth and NEW. libcwidget is a high-level C++ library for developing user interfaces that run in a terminal using curses as the display and input layer. It uses widget abstractions similar (but of course not identical) to those found in GTK+ and Qt, with signals and slots provided by <a href="http://libsigc.sourceforge.net">libsigc++</a>.<br /><br /><h2>Background</h2><br /><br />Back when I started writing aptitude, I had one general goal:<br /><br /><blockquote>Just because it runs in a terminal doesn't mean it has to suck.</blockquote><br /><br />I tried to apply this in the user interface, but I also applied it internally. The curses programs I looked at before writing aptitude all had very ad-hoc UIs. In many cases the code was structured with each "view" that appeared mapped to a custom C function call; if the author was feeling ambitious, similar-looking screens might be abstracted into a single function call, but the basic structure of the interface still reflected the call graph of the program.<br /><br />aptitude had a primitive interface abstraction layer from the get-go; over the years, I borrowed ideas from GTK+ and restructured this layer into a full widget set. libcwidget is this code, disentangled from the guts of aptitude and slightly cleaned up. Because of its history, it is missing widgets that aptitude doesn't need (like a multi-line text editor), but it provides an extensible base that you can build upon.<br /><br /><h2>Getting cwidget</h2><br /><br />The cwidget library is available (both as source and as an i386 .deb) from the <a href="http://alioth.debian.org/frs/?group_id=100001">cwidget Alioth releases page</a>. There is also <a href="http://alioth.debian.org/~dburrows/cwidget-docs/">API documentation automatically generated from the upstream repository</a>, which, while it is woefully incomplete, should provide some information: I've tried to write Doxygen tags into most of the code I've added in the last 4 years or so.<br /><br />The upstream code repository is in git (because what fun is a new project if you don't learn a new VCS?) and available <a href="http://git.debian.org/?p=cwidget/head/.git;a=summary">here</a>. To retrieve a copy of the repository for yourself, run this command:<br /><br /><blockquote>git clone git://git.debian.org/git/cwidget/head cwidget</blockquote>dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com8tag:blogger.com,1999:blog-12729767.post-65882391136414373382007-11-05T19:20:00.000-08:002007-11-05T19:36:58.925-08:00Building railsIn the 1860s, in the middle of one of the largest wars America has ever been involved in, a 690-mile <a href="http://en.wikipedia.org/wiki/First_Transcontinental_Railroad">railroad</a> was built in a period of seven to nine years (depending on how you count), a rate of about five days per mile of track. Now, it's certainly true that this was accomplished through labor practices that were, by today's standards, more than a little bit questionable. However, I still am amazed that it's apparently going to take us <a href="http://seattletimes.nwsource.com/html/opinion/2003905815_ronsims27.html">twenty years</a> to construct <a href="http://seattlepi.nwsource.com/opinion/335171_countycouncil12.html">fifty miles</a> of track in the Seattle area. By my count, that's <b>a hundred and forty six days per mile of track</b>. And I haven't even mentioned the harsh environmental conditions the transcontinental line faced, which a line in the Seattle metro area by and large does not.<br /><br />I haven't decided how or whether to vote in the election tomorrow, but the timescale they're projecting is ... astonishing.dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com3tag:blogger.com,1999:blog-12729767.post-66522265769288760192007-11-04T11:58:00.000-08:002007-11-04T12:54:35.879-08:00Lessig at the University of WashingtonOn Friday 2007-11-02, I watched <a href="http://www.lessig.org">Larry Lessig</a> give a presentation at the University of Washington entitled <q>Is Google (2008) Microsoft (1998)</q>? Since it was Lessig, the talk was articulate and thought-provoking, and he used his slides very well (unlike many presenters who just read bullet points).<br /><br />The argument he made is that Google is like Microsoft in some ways (and so are other companies like Facebook). In his analysis, the problem with Microsoft was that so many companies made themselves Microsoft-dependent, which both forced other companies to follow suit (due to network effects) and gave Microsoft leverage they could use against everyone in their ecosystem (e.g., Netscape). According to Lessig, Microsoft was not evil to use this leverage, but you have to recognize that Microsoft will do what is best for Microsoft, and this may not be what is best for you. He then suggested that we should be aware of the potential for the same thing to happen; in support of this point, he quoted excerpts from the terms of service from the APIs of Google and Facebook, which contain typical statements like <q>we reserve the right to terminate your use of this service for any reason or for no reason</q>, and asked: <q>What if Microsoft had written this license agreement?</q><br /><br />But it seemed to me that this wasn't his main point. He was using this observation as a springboard to talk about issues revolving around competition and public policy. Specifically, he feels that we should work towards a more just model of interaction between companies and users whose work makes the company more valuable (by contributing to a software ecosystem, by posting content on the Web site, etc). But the correct way to do this (he says) is not via competition, after-the-fact litigation, or voluntary codes of conduct: competition may not be around to enforce good behavior (as we've seen with Microsoft), litigation may be too late and ineffective (again, see Microsoft), and voluntary codes of conduct will disappear as soon as they get in the way of the bottom line. The correct approach, he argued, is across-the-board regulation so that all the companies have to play by the same rules.<br /><br />From there he went on to talk about governmental corruption. He said (quoting Robert Reich's book <q>Supercapitalism</q>) that the reason we consistently look for solutions in the market and in voluntary compliance is that our governmental system is broken and does not effectively regulate corporations in the public interest. But Lessig is optimistic that we can change things (he joked that his publisher was unhappy with this point of view, because his <q>brand</q> has been built on pessimism). In his view, the politicians in Washington, by and large, want to be honest and do good, but they aren't able to within the current political system. For instance, on the few occassions that he managed to get access to lawmakers to discuss copyright issues, it was often the first time they had heard that there was more than one side to the argument. He thinks we need a national political movement that will shame politicians into being less corrupt.<br /><br />This is all a simplification of what he said, of course; unfortunately, I wasn't able to find a recording of this talk on Lessig's <a href="http://www.lessig.org">Web site</a>, or I'd point you at primary source material. I don't know if this is because he chose not to post it, or because it just hasn't been made available yet.<br /><br /><h2>My view</h2><br /><br />In general, I thought that the speech was very interesting and well thought out. But as much as I'd like to buy into his optimism that we can fix our system, I don't think it's well-founded, for two reasons.<br /><br />First, he argued that competition will resolve some of these problems (that was before and after he said we can't rely on competition, which I found confusing and may indicate that I misunderstood something). His evidence for this seemed to be that when Microsoft was dominating the world, users responded by reducing their dependence on Microsoft products and by switching to alternatives such as Linux. But, in fact, although more people may be using Linux than in the past, virtually everyone is still only using Windows, it's still almost impossible to find a programming job that isn't Windows-only, and Microsoft is still raking in money hand over fist; indeed, they're doing so well that they're planning to <a href="http://seattletimes.nwsource.com/html/microsoft/2002796093_microsoft10.html">expand their workforce by a third</a>. To take just one data point of many: I ride the bus to Seattle and back, and I regularly see other people using laptops as they commute. Virtually all the laptops run Windows. Occasionally I'll see a Mac, and every few months I'll see a guy running Linux on his laptop; I say "a guy" because it's the same guy every single time. So by my estimation, use of Linux on laptops in buses on the 545 route from Redmond to Seattle is way below 1%, with Macintoshes somewhere around 5%.<br /><br />To broaden my point, I think Lessig has fallen into a trap that highly intelligent people, particularly those in academia, tend to fall into. In academia, you are surrounded by people who value learning and thinking deeply about the world. These are people who will give serious and unbiased consideration to questions like <q>what is the social effect of my acceptance of the Facebook Terms of Service?</q> and <q>If I become dependent on this service, will that possibly affect me in five years if the company decides to act against my interests?</q> The problem with this is that these people are not representative of the population at large. The population at large thinks <q>why is this check-box getting in the way of me sending pictures to my friends?</q> And I have no doubt that any kid who, e.g., refuses to sign up for Facebook as a protest against their TOS will be roundly mocked in their social circles for being a weird antisocial nonconformist. (of course, this may not apply to the small minority of people like myself whose social circles consist of weird antisocial nonconformists)<br /><br />Second, Lessig's optimism about the political system seemed to be based on his observation that the people in government are, by and large, not venally corrupt: they want to do good, but the system is constructed in a way that makes this impossible. To me, that's a tremendously <i>disheartening</i> statement. If our problem were simply a few, or even many, corrupt politicians, this would be a solvable problem: even nowadays, Americans have some ability to choose who gets elected, and I believe that a sufficiently well-coordinated campaign could replace bad politicians with good ones.<br /><br />But if the problem is that the system is corrupt even when the individuals are honest, it's a much deeper problem and frankly one that I don't know how to solve. While individuals have some direct control over who gets elected, we have no way to directly change the system that produces the corruption; the levers to do this are in the hands of the politicians elected through that broken system. It's unlikely that the politicians themselves will fix the problem, because they've benefited deeply from it: if the system is left as it is, well over 90% of Congress members will <a href="http://en.wikipedia.org/wiki/Congressional_stagnation_in_the_United_States">keep<br />their jobs</a> in the next election cycle, and any <b>effective</b> change seems likely (by definition) to disrupt this cushy arrangement.<br /><br />On the other hand, running new candidates for office will not fix the problem. After all, if the problem is that the system is corrupt even when the participants are honest, then putting more honest people into government will have no effect. In order to get elected, these new politicians will have to become just as corrupt as the old ones, because that's how the system is set up. So we might change the faces, but we'll have the same old problems.<br /><br />I recall two specific concrete proposals that Lessig made to make the system more responsive. First, he suggested shaming politicians who engage in corrupt behavior -- presumably taking large donations from interested parties. I don't see how this will help. Americans generally have a very low regard for the political class as it is; will pointing out particular examples of politicians taking money really make a difference when it comes to votes? And if it doesn't, will it really produce any change in their behavior? Politicians are motivated by votes the same way corporations are motivated by money; unless they stand a chance of losing their job (which is <a href="http://en.wikipedia.org/wiki/Congressional_stagnation_in_the_United_States">virtually impossible</a> in any event), there's no reason for them to change how they behave.<br /><br />His second proposal was for a system of contributions where it's impossible for any individual to prove they had donated a particular amount of money to a particular candidate. Even assuming it could be implemented perfectly, I don't think this will really solve the problem, for two reasons. First, it's not generally a secret what moneyed interests want. Politicians who want to attract large <q>donations</q> can just take positions that they know will appeal to donors of that sort. The donors themselves can make this easier on the candidates by, e.g., posting public position statements on issues of the day. Secondly, and this is far more insidious, <i>even if politicians honestly represent their positions</i>, then because success in running for office is so tied to the amount of money the candidate can raise, only candidates who hold opinions favorable to large corporations and wealthy individuals will be able to get elected. In fact, for all I know this is what happens already!<br /><br />But with all that said, it was a really interesting talk and Lessig tied together some things you might not think would go together. If a video or Flash presentation becomes available, I would recommend watching through it. And hopefully my pessimistic predictions will be wrong; it's certainly <a href="http://arstechnica.com/journals/linux.ars/2007/09/05/amd-to-deliver-better-ati-drivers-open-specifications">happened before</a>.dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com12tag:blogger.com,1999:blog-12729767.post-66592102233486828962007-10-31T05:57:00.000-07:002007-10-31T20:08:33.251-07:00MailAmusing tidbits you pick up in the mailing industry...<br /><br />No, you can't <a href="http://xkcd.com/96/">mail running chainsaws</a>. At least I'm pretty sure about that; I don't know a specific regulation against them, but USPS takes a dim view of anything that puts its employees and machinery at risk.<br /><br />On the other hand, you can mail live scorpions if you <a href="http://pe.usps.gov/Archive/Html/DMMArchive1209/C022.htm">package them appropriately</a>. Note that, however, that this is limited to the US; apparently doing so in Australia is <a href="http://www.abc.net.au/news/stories/2007/10/12/2058033.htm">not a good idea</a>. The <a href="http://pe.usps.gov/Archive/Html/DMMArchive1209/C022.htm">same page</a> also gives the rules for mailing baby chicks (which must be not more than 24 hours old) as well as adult chickens (Express Mail only, please; and no refund if the chicken dies in transit unless the container was damaged).dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com11tag:blogger.com,1999:blog-12729767.post-70883187802942284742007-10-30T21:02:00.000-07:002007-10-30T21:07:30.506-07:00Here we go again...<pre><br />[10/30/2007]<br />Version 0.4.7 "Where did all these<br /> balloons come from?<br /> And why am I wearing<br /> a fake nose?"<br /><br />- New features:<br /><br /> * The options dialogs have been completely replaced by a new<br /> interface, based on a top-level list view. This fixes many<br /> deficiencies of the old interface: it handles long strings more<br /> gracefully, avoids many of the focus-handling bugs that the old<br /> dialogs had, and should generally be better-behaved.<br /> (Closes: #197976, #331200, #424708)<br /><br /> * Prompts that ask you to enter text will now wrap to multiple lines<br /> when the text gets long, rather than hiding parts of the string.<br /><br /> * The online help and other Help-menu itmes are now top-level views,<br /> which should make them somewhat more usable. (Closes: #434349)<br /><br /> * Support for the "Breaks" field and for trigger states (thanks to<br /> Michael Vogt and Ian Jackson for patches and prodding).<br /> (Closes: #438543)<br /><br /> * Two new styles, "PkgDowngraded" and "PkgDowngradedHighlighted",<br /> are provided to control how downgraded packages look. By default<br /> these packages look like any other installed package.<br /> (Closes: #434442)<br /><br /> * aptitude can now display homepage URLs stored in the Homepage<br /> field of packages.<br /></pre><br /><br />There are bug-fixes too, but those aren't as fun. So instead I think I'll include some diffstat output. Everyone likes diffstat!<br /><br /><pre><br />daniel@alpaca:~/programming/aptitude/head$ hg diff -r 0.4.6.1:0.4.7 | diffstat<br /> .hgtags | 1 <br /> NEWS | 92 +<br /> b/src/apt_config_treeitems.cc | 477 ++++++<br /> b/src/apt_config_treeitems.h | 156 ++<br /> b/src/generic/util/browser.h | 42 <br /> configure.ac | 20 <br /> doc/en/aptitude.xml | 187 ++<br /> help-fr.txt | 10 <br /> po/ChangeLog | 24 <br /> po/dz.po | 188 +-<br /> po/es.po | 82 -<br /> po/gl.po | 19 <br /> po/ne.po | 1277 +++++++++--------<br /> po/pt.po | 20 <br /> po/ru.po | 97 -<br /> po/sv.po | 1854 ++++++++++++--------------<br /> po/zh_CN.po | 23 <br /> src/Makefile.am | 2 <br /> src/apt_info_tree.cc | 4 <br /> src/apt_options.cc | 598 +++++---<br /> src/apt_options.h | 12 <br /> src/cmdline/cmdline_action.cc | 6 <br /> src/cmdline/cmdline_check_resolver.cc | 2 <br /> src/cmdline/cmdline_do_action.cc | 134 +<br /> src/cmdline/cmdline_prompt.cc | 124 -<br /> src/cmdline/cmdline_search.cc | 4 <br /> src/cmdline/cmdline_show.cc | 20 <br /> src/cmdline/cmdline_why.cc | 64 <br /> src/defaults.cc | 4 <br /> src/dep_item.cc | 1 <br /> src/desc_parse.cc | 2 <br /> src/generic/apt/apt.cc | 32 <br /> src/generic/apt/apt.h | 30 <br /> src/generic/apt/aptcache.cc | 54 <br /> src/generic/apt/aptcache.h | 21 <br /> src/generic/apt/aptitude_resolver_universe.cc | 28 <br /> src/generic/apt/aptitude_resolver_universe.h | 57 <br /> src/generic/apt/infer_reason.cc | 22 <br /> src/generic/apt/log.cc | 8 <br /> src/generic/apt/matchers.cc | 531 +++++--<br /> src/generic/apt/matchers.h | 28 <br /> src/load_grouppolicy.cc | 25 <br /> src/menu_tree.cc | 12 <br /> src/pkg_columnizer.cc | 19 <br /> src/pkg_grouppolicy.cc | 27 <br /> src/pkg_grouppolicy.h | 9 <br /> src/pkg_info_screen.cc | 10 <br /> src/pkg_item.cc | 31 <br /> src/pkg_item.h | 7 <br /> src/pkg_subtree.cc | 22 <br /> src/pkg_subtree.h | 12 <br /> src/pkg_tree.cc | 4 <br /> src/pkg_tree.h | 1 <br /> src/pkg_ver_item.cc | 31 <br /> src/pkg_ver_item.h | 5 <br /> src/pkg_view.cc | 24 <br /> src/reason_fragment.cc | 10 <br /> src/solution_fragment.cc | 5 <br /> src/solution_item.cc | 76 -<br /> src/solution_item.h | 14 <br /> src/ui.cc | 179 +-<br /> src/vscreen/fragment.cc | 140 +<br /> src/vscreen/fragment.h | 40 <br /> src/vscreen/ref_ptr.h | 5 <br /> src/vscreen/testvscreen.cc | 20 <br /> src/vscreen/vs_editline.cc | 310 +++-<br /> src/vscreen/vs_editline.h | 33 <br /> src/vscreen/vs_tree.cc | 113 +<br /> src/vscreen/vs_tree.h | 40 <br /> src/vscreen/vs_treeitem.cc | 4 <br /> src/vscreen/vs_treeitem.h | 21 <br /> src/vscreen/vs_util.cc | 1 <br /> 72 files changed, 4853 insertions(+), 2754 deletions(-)<br /></pre>dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com4tag:blogger.com,1999:blog-12729767.post-88123252429599289542007-10-30T20:35:00.001-07:002007-10-30T20:43:50.493-07:00Just rub it in, why don't you!One of my co-workers told us about a message he saw posted on a British message board about Royal Mail. For people whose job does not involve postal systems, Royal Mail is the semi-governmental semi-monopoly that handles mail in the UK; it's a little like the USPS in the States.<br /><br />The funny thing about the message had little to do with the mail: apparently the poster was saying that Royal Mail's standards have deteriorated because he can no longer pick up his mail at 9:30 AM, <i>before he goes to work</i>. Dude! You don't even have to <i>leave</i> for work until 9:30 and you're complaining about when your mail comes?<br /><br />I bet he gets four weeks of paid vacation, too, and then complains about how that isn't enough.dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com5tag:blogger.com,1999:blog-12729767.post-17975835146183540382007-10-13T19:50:00.001-07:002007-10-13T20:04:22.537-07:00Mercurial repositories for the aptitude Debian tree now publically accessibleSince I switched the aptitude repositories over to Mercurial, I've been using <a href="http://hg.complete.org/hg-buildpackage">hg-buildpackage</a> to produce Debian packages. I wasn't sure at first if it would work out, so I didn't publish the repositories, and then I got swamped with work. But I've had good luck so far with hg-buildpackage, so I've uploaded the Mercurial trees to Alioth. You can find the upstream branch here:<br /><br /><a href="http://hg.debian.org/hg/aptitude/debian-upstream">http://hg.debian.org/hg/aptitude/debian-upstream</a><br /><br />and the Debian branch here:<br /><br /><a href="http://hg.debian.org/hg/aptitude/debian">http://hg.debian.org/hg/aptitude/debian</a>dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com15tag:blogger.com,1999:blog-12729767.post-55442021068951186992007-10-13T14:16:00.000-07:002007-10-13T15:04:54.276-07:00Monad.ReaderThe Reader monad is a simple and easy-to-use structure from the Haskell library that solves a common problem.<br /><br />Very often, it's the case that you have a lot of functions that all need to use the same values. For instance, you might be laying out some text on a page, and you need to keep the details of the page size around in all your layout algorithms. Typically, you handle this situation by adding a new parameter to all your functions which represents the state. So,<br /><br /><code><br />layoutPage :: Text -> Page<br /></code><br /><br />becomes<br /><br /><code><br />layoutPage :: PageLayoutParams -> Text -> Page<br /></code><br /><br />This works just fine, but it can get really ugly. Every single function gets a new parameter, which must be threaded through to every related function that it ever calls. This causes visual clutter, particularly for functions that don't actually use the parameter themselves but just pass it on.<br /><br />A function written in the Reader monad is augmented with a hidden parameter. For the hypothetical example above, we would write:<br /><br /><code><br />import Control.Monad.Reader<br />type LayoutFunc = Reader PageLayoutParams<br /><br />layoutPage :: Text -> LayoutFunc Page<br /></code><br /><br />Note that the Reader monad is partially applied here. The result, LayoutFunc, is a new monad that adds a parameter of type PageLayoutParams to any code that runs inside it.<br /><br />So, now that we have this monad, how do we use it? The "ask" operation retrieves the parameter that's hidden in the monad:<br /><br /><code><br />ask :: Reader a a<br /></code><br /><br />or, specialized to LayoutFunc:<br /><br /><code><br />ask :: LayoutFunc PageLayoutParams<br /></code><br /><br />In order to remain close to the example in question, I will provide specialized type signatures for the rest of the library functions. You can find the generic type signatures in <a href="http://www.haskell.org/ghc/docs/latest/html/libraries/mtl/Control-Monad-Reader-Class.html">the Haskell library documentation for Control.Monad.Reader</a>.<br /><br />Suppose that layoutPage started out like this before it was moved into the monad:<br /><br /><code><br />layoutPage st txt =<br /> let width = pageWidth st<br /> ...<br /></code><br /><br />In the Reader monad, this becomes:<br /><br /><code><br />layoutPage txt =<br /> do st <- ask<br /> let width = pageWidth st<br /> ...<br /></code><br /><br />As you can see, we've gone from one line of code to two. As this is clearly unacceptable for a clutter-reducing device, the Reader module provides a convenience function encapsulating the above pattern:<br /><br /><code><br />asks :: (PageLayoutParams -> a) -> PageLayoutFunc a<br /></code><br /><br />This allows us to simplify the monadic implementation to:<br /><br /><code><br />layoutPage txt =<br /> do width <- asks pageWidth<br /> ...<br /></code><br /><br />It's quite common, when multiple functions share context information, to invoke a function in an altered context. For instance, we might have a layoutSubPage routine that changes the page width:<br /><br /><code><br />layoutSubPage st newWidth txt =<br /> doLayout (st {pageWidth = newWidth} txt)<br /></code><br /><br />The Reader equivalent of this idiom is the function "local":<br /><br /><code><br />local :: (PageLayoutParams -> PageLayoutParams) -> LayoutFunc a -> LayoutFunc a<br /></code><br /><br />local executes an operation in a context modified by its first parameter. For instance,<br /><br /><code><br />layoutSubPage newWidth txt =<br /> local (\st -> st { pageWidth = newWidth }) txt<br /></code><br /><br />Finally, to actually invoke a computation in the Reader monad, use runReader:<br /><br /><code><br />runReader :: LayoutFunc a -> PageLayoutParams -> a<br /><br />main = showPage (runReader defaultPageParams someText)<br /></code><br /><br />For much more information on the Reader monad, see <a href="http://www.haskell.org/all_about_monads/html/readermonad.html">All About Monads</a>, or <a href="http://www.haskell.org/ghc/docs/latest/html/libraries/mtl/Control-Monad-Reader.html">the Haskell library documentation</a>.dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com18tag:blogger.com,1999:blog-12729767.post-55845573015210561992007-10-10T18:37:00.000-07:002007-10-10T18:44:33.919-07:00Science: who does it, why?On the topic of "why so few scientists are women", I recently came across a rather thought-provoking <a href="http://philip.greenspun.com/careers/women-in-science">article</a> (thanks <a href="http://erinn.org/itis/2007/10/09#random-links">Erinn</a>). It's worth a read, especially for anyone (man or woman) that's thinking about heading into academia.dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com6tag:blogger.com,1999:blog-12729767.post-6057604211448192652007-10-03T20:40:00.000-07:002007-10-03T20:47:04.614-07:00Feline LoveCoding while a cat kneads your chest: awkward.<br /><br />Coding while a cat sleeps on your face: difficult.<br /><br />Coding while a cat nibbles on your fingers: painful.<br /><br />Coding with a cat snuggled up against your side: adorable.dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com6tag:blogger.com,1999:blog-12729767.post-2018861257362070822007-09-04T07:46:00.000-07:002007-09-04T07:55:25.199-07:00What were they thinking?If you're going to build a computer case that looks like a media player ...<br /><br />and if you're going to include a big volume control and an LCD player on the front ...<br /><br />then aren't some buttons like "play", "next", and "pause" also a good idea?<br /><br />I ask because I was browsing computer cases at the store yesterday, and apparently no-one working for the companies that design these things has thought of including some control buttons on front. To me, this seems like it would rank somewhere in the top 10 most obvious ideas ever, somewhere below "eat when you get hungry" and above "don't pick a fight with a grizzly bear", but clearly I'm missing something.dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com6tag:blogger.com,1999:blog-12729767.post-7422240336951226682007-08-30T20:31:00.000-07:002007-08-30T20:42:05.340-07:00Seattle LUG meetingThe Seattle Linux user's group has been defunct for the last two years or so, but an effort is underway to renergize it. This Saturday, the group will be <a href="http://wiki.gslug.org/index.php/Meeting_2007-09-01">meeting</a> for the first time in years. The meeting will take place at the North Seattle Community College beginning at high noon -- check the <a href="http://wiki.gslug.org/index.php/Meeting_2007-09-01#Who.27s_Coming.3F">official Web page</a> for more details. TBH, the presentations don't look that interesting to me, but it's always fascinating to meet people who actually <i>use</i> Linux...<br /><br />Yes, I'll be there, but I'm not giving any of the presentations, so please don't let that keep you away. ;-)dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com6tag:blogger.com,1999:blog-12729767.post-50315966285403798772007-07-01T18:12:00.000-07:002007-07-26T06:33:07.450-07:00Do not install aptitude 0.4.4-4b+1!Apparently someone decided to resolve the dependency problems with aptitude in unstable by doing a blind recompile and NMU of the package, presumably because of my horrible laziness in not doing an upload to unstable yet. The problem, as I wrote in the bug reports regarding the need for a recompile, is that this produces a package that's totally unusable, which is why I didn't do it myself. If you are running unstable, you should either not upgrade the apt system, or install the experimental aptitude (either using "apt-get install aptitude/experimental" or by going <a href="http://packages.debian.org/experimental/admin/aptitude">here</a>). These packages are not perfectly stable, but they also aren't totally unusable.<br /><br />I apologize for the inconvenience -- if I can get some time this evening I'll rebuild the aptitude in experimental and throw it kicking and screaming into unstable.dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com1tag:blogger.com,1999:blog-12729767.post-70433543174933914912007-06-21T22:30:00.001-07:002007-06-24T08:01:10.326-07:00JealousyI've been suffering for a while from mild jealousy of the people who have a spare week of vacation time to make it to Edinburgh for <a href="http://www.debconf.org/">DebConf</a>. (is there a support group for this? :) ) But now I read that some people apparently have so much time off that they travelled to Edinburgh a full <a href="http://layer-acht.org/blog/debian/#1-111">week</a> ahead of time, just because, y'know, they could. Darn Europeans.<br /><br />But then, I only have to work for another year and a half before I qualify for another whole week of vacation time, raising the total to three weeks off per year. Maybe I can make DebConf 2009, assuming that President Hillary doesn't <a href="http://techhouse.brown.edu/cgi-bin/fluble/vault.pl?date=19971023">invade Luxembourg</a> or something...dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com2tag:blogger.com,1999:blog-12729767.post-26965244217260787892007-06-19T20:31:00.001-07:002007-06-19T21:45:57.034-07:00Fun with FunctionsPete Nuttall <a href="http://www.lupin.org.uk/blog/computing/haskell/fnreduce.html">writes</a> about the fnreduce function:<br /><br /><pre>fnreduce :: [(a->a)]->a->a<br />fnreduce [] value = value<br />fnreduce (a:as) value = freduce as $ a value</pre><br /><br />A shorter, although not necessarily clearer, expression of this function would be<br /><br /><pre>fnreduce as value = (foldr (flip (.)) id as) value</pre><br /><br />This just says that to apply a list of functions to a value, we first compose all the functions by folding down the list, then apply the result to the value. The important thing here is (flip (.)), which says to compose backwards; it means that fnreduce [f, g, h] returns (h . g . f . id) instead of (f . g . h . id). An interesting side note is that it doesn't matter (from a semantic point of view) whether I use foldl or foldr, since function composition is associative:<br /><br /><pre>f . (g . (h . id)) = ((id . f) . g) . h</pre><br /><br />But "flip" here feels a little confusing. A clearer approach would be to reverse the list instead of reversing the operator:<br /><br /><pre>fnreduce as value = foldr (.) id (reverse as) value</pre><br /><br />This might be less efficient, but it says in a much clearer way what I'm doing.<br /><br />Yet another option is to eschew the use of function composition:<br /><br /><pre>fnreduce as value = foldl (flip ($)) value as</pre><br /><br />Here ($) is the application function; (f$x) applies f to x. So if we reverse it (call this $$), we get (x$$f) applies f to x. Folding this from the left down the list [f, g, h] gives us (((value$$f)$$g)$$h), which is exactly what the original fnreduce did.<br /><br />I think this is maybe the best fold-based solution to the original problem, because it models what's happening (repeatedly transforming a value with a series of functions) directly. To use a right-fold, you have to remove the flip and reverse as (the reason this is necessary is left as an exercise to the reader).<br /><br /><hr/><br /><br />Pete also asks whether this can be done for heterogenous lists in a type-safe manner. The core problem is, what is the type of our list? It can't actually be a list: in order to check that it's OK to combine the output of one function with the input of another, we would need the elements of the list to have different types. You can't do this in Haskell, even a crazy ghc-extended Haskell.<br /><br />So, we could try something like this:<br /><br /><pre>module Test where<br /><br />data TransformList a b where<br /> Nil :: TransformList a a<br /> Cons :: (a -> b) -> TransformList b c -> TransformList a c<br /><br />apply :: TransformList a b -> a -> b<br />apply Nil = id<br />apply (Cons f fs) = (apply fs) . f</pre><br /><br />This lets us do stuff like<br /><br /><pre>> apply (Cons (\x -> x + 1) (Cons (\x -> show x) Nil)) 5<br />"6"</pre><br /><br />This is cute, but I don't know that it's really that useful. After all, how is it any better than the following?<br /><br /><pre>> ((\x -> show x) . (\x -> x + 1)) 5<br />"6"</pre><br /><br />Everything the above code lets you do with TransformList could just as well be done with the humble compose operator. The only benefit would be if we could somehow do "list-like" stuff with a transform list. For instance, say we want to write the following function:<br /><br /><pre><br />traceIntermediates Nil x = (x, [])<br />traceIntermediates (Cons f l) x = let x' = f x<br /> (x'', ss) = traceIntermediates l x'<br /> in<br /> (x'', (show x'):ss)</pre><br /><br />This won't compile, because we don't know that x' is a member of the Show typeclass. And <i>there is no way to fix this</i> in a reusable way using any technique that relies on building a type parameterized on the input and output types: the problem is that we need to say something about the types of the intermediate values, but their type variables are inaccessible.<br /><br />In other words, there isn't any way to write down a constraint on the type "TransformList a b" that constrains the intermediates. So I've just wasted a lot of typing duplicating the compose operator. Yay.<br /><br />On the other hand, it's entirely possible to do this if you don't mind some boilerplate code.<br /><br /><pre>data ShowTransformList a b where<br /> Nil :: (Show a) => ShowTransformList a a<br /> Cons :: (Show a, Show b, Show c) => (a -> b) -> ShowTransformList b c -> ShowTransformList a c<br /><br />traceIntermediates :: ShowTransformList a b -> a -> (b, [String])<br />traceIntermediates Nil x = (x, [])<br />traceIntermediates (Cons f l) x = let x' = f x<br /> (x'', ss) = traceIntermediates l x'<br /> in<br /> (x'', (show x'):ss)<br /><br />apply :: ShowTransformList a b -> a -> b<br />apply Nil = id<br />apply (Cons f fs) = (apply fs) . f</pre><br /><br />Now I can do this:<br /><br /><pre>> traceIntermediates<br /> (Cons (\x -> x + 1)<br /> (Cons (\x -> x * 2)<br /> (Cons (\x -> x - 5)<br /> (Cons show<br /> (Cons (read :: String -> Double)<br /> Nil))))) 5<br />(7.0,["6","12","7","\"7\"","7.0"])</pre>dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com2tag:blogger.com,1999:blog-12729767.post-6108483309575055042007-06-17T21:53:00.000-07:002007-06-17T21:54:02.792-07:00Freudian slips in commit messages<blockquote><br />changeset: 700:d8308a89c519<br /><br />user: Daniel Burrows <dburrows@debian.org><br /><br />date: Sun Jun 17 16:22:43 2007 -0700<br /><br />summary: Call pre_package_state_changed() before undoing, to resent the dependency resolver; call package_state_changed() after an undo if necessary.<br /></blockquote>dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com2tag:blogger.com,1999:blog-12729767.post-34410317635867504012007-06-16T21:51:00.000-07:002007-06-16T22:16:35.895-07:00aptitude development moves to Mercurial, back to AliothShort version: the aptitude development tree is now maintained using Mercurial, go <a href="http://hg.debian.org/hg/aptitude/head">here</a> to fetch it.<br /><br />aptitude development has been using darcs as a version control system for the last two years. Darcs is a distributed version control system with many great concepts -- but it has one huge, glaring, enormous flaw, which is that innocuous operations, like merging one branch into another, can require practically unbounded amounts of time and space. And once two branches get screwed up in this way, there is nothing, nothing at all, that you can do to get yourself unwedged; the cause is a design flaw in darcs that no-one seems to know how to fix or work around.<br /><br />Recently, I made the mistake of changing some files in both the Debian branch of aptitude and the head branch, and when I tried to merge the two branches to upload a new upstream release, darcs went off into la-la land. So, I figured that it was probably time to switch version control systems.<br /><br />I'd like to say that I did extensive research on the matter, but the truth is that I chose Mercurial based on the fact that (A) a lot of ex-darcs users have written nice things about it, (B) git and arch-derived systems always feel ugly to me, and (C) John Goerzen implemented support for mercurial on Alioth. Yes, I am so a follower.<br /><br />So if you want the up-to-date aptitude source, you should go to <a href="http://hg.debian.org/hg/aptitude/head">http://hg.debian.org/hg/aptitude/head</a>. You can also fetch an RSS feed from http://hg.debian.org/hg/aptitude/head?style=rss.<br /><br />You can fetch a copy of the repository with "hg clone http://hg.debian.org/hg/aptitude/head aptitude-head". To update, I recommend putting the following lines in ~/.hgrc to enable the "fetch" extension:<br /><br /><blockquote><br />[extensions]<br />hgext.fetch =<br /></blockquote><br /><br />Once you've done this, just run "hg fetch" and it should download and merge the latest code. You may want to install kdiff3 to get a better merge tool as well.<br /><br />To commit a patch locally, run "hg commit". Unfortunately, there doesn't seem to be any easy way for people to send patches back within the VCS like there is for darcs (one of many nice features I had to give up in favor of being able to actually get work done -- what, me bitter?), but it looks like you can get somewhere with "hg bundle <file>", then mailing the resulting file off.dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com34tag:blogger.com,1999:blog-12729767.post-31477086327478110162007-06-10T21:33:00.000-07:002007-06-10T21:42:31.452-07:00Dear Lazyweb: Mercurial Python APISo, in the midst of trying to convert some Darcs repositories to Mercurial repositories (see <a href="http://www.darcs.net/DarcsWiki/ConflictMisery">here</a> for the reason), I hit an "interesting" bug: tailor processes "rename" patches by deleting the renamed file. A little debugging later, I get to this simulation of what tailor does:<br /><br /><pre><br />>>> from mercurial import hg,ui<br />>>> uio = ui.ui(debug=True,verbose=True)<br />>>> r = hg.repository(ui=uio, path='.', create=True)<br />>>> f = file('A', 'w')<br />>>> f.write('Some data\n')<br />>>> f.close()<br />>>> r.add('A')<br />>>> r.commit(text='Add A')<br />A<br />'i\xe9\xb4\xc8\x9d\xb8\xeb<\xbe\xb1k\xae\xb1\x182\xa9ao\x80\xd0'<br />>>> r.copy('A', 'B')<br />B does not exist!<br /></pre><br /><br />Huh? Of course B doesn't exist, that's why I want to create it! So, we look at the code in localrepo.py to handle copying...<br /><br /><pre><br /> def copy(self, source, dest, wlock=None):<br /> p = self.wjoin(dest)<br /> if not os.path.exists(p):<br /> self.ui.warn(_("%s does not exist!\n") % dest)<br /> elif not os.path.isfile(p):<br /> self.ui.warn(_("copy failed: %s is not a file\n") % dest)<br /> else:<br /> if not wlock:<br /> wlock = self.wlock()<br /> if self.dirstate.state(dest) == '?':<br /> self.dirstate.update([dest], "a")<br /> self.dirstate.copy(source, dest)<br /></pre><br /><br />Double huh?<br /><br /><ol><br /><li>Why is this method checking whether the destination exists before it does anything? It appears to me that this is actually necessary; just disabling this test leads to a crash later.<br /><li>How does mercurial work at all with such huge breakage in its core code? Does /usr/bin/hg use a different implementation of the repository code than mercurial.hg?<br /><li>Why, in the name of $DEITY, is this a warning and not a fatal exception? One example of what happens when you don't signal to your users that you're ignoring them is this bug: tailor happily goes ahead and removes the original file, safe in the knowledge that mercurial has copied it to the new location. Except, of course, that mercurial <i>hasn't</i> actually copied it. Whoops.<br /></ol><br /><br />I'm hoping that someone will tell me that it's just too late at night for me and I'm being an idiot. Please tell me this. It would make me very sad if code like that was in my VCS.<br /><br /><br /> :-( <--- sad Danieldburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com11tag:blogger.com,1999:blog-12729767.post-49652198769338765612007-06-10T11:11:00.000-07:002007-06-10T11:32:23.867-07:00Closing bugs just because they're old is not coolTwo bug reports that I wrote were recently closed with the following explanation:<br /><br /><blockquote>Last message was posted nearly three years ago. Considering abandoned and closing.</blockquote><br /><br />Whoops, I thought, I must have missed a request for more information. So I went to the bug page and, nope, the only message on the bug was my initial report.<br /><br />Let me repeat that: the total sequence of interactions on these bugs was:<br /><br /><ol><br /><li>I report a bug in 2004<br /><li>Someone closes it in 2007 because it's "too old".<br /></ol><br /><br />Now, there are times when it's at least somewhat excusable to close old bugs without verifying that they're fixed (or even knowing that they might not be). When a package has hundreds of bug reports, closing old bugs that can't be reproduced can be a good thing: even if the reports are valid, keeping reports that can't contribute towards a fix around is arguably less useful than cleaning out the bug list so it's usable.<br /><br />In my case, though, the package in question has only 20 or so bug reports, an easily managed number. Worse, both bugs I reported could be trivially reproduced. One of them was arguably not a bug, but the guy who closed my bugs did not argue that; as far as I can tell, he didn't even <i>look</i> at my bug report.<br /><br /><br />Notice that I haven't mentioned the maintainer of the package? That's because he didn't close the bug. In fact, the person who closed the bug is not a member of Debian, nor is he in the NM process. Evidently he's just a random user who decided that old bugs offend him, so they should be closed.<br /><br />So please, everyone, exercise a modicum of common sense when it comes to closing bug reports. This will keep the BTS useful for all of us and keep blood pressures at a reasonable level. :)dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com4tag:blogger.com,1999:blog-12729767.post-210876802543272482007-06-08T21:01:00.000-07:002007-06-08T21:03:56.835-07:00Blogger annoyingnessTwo days ago, I noticed that a post from last year about my wallet getting stolen had attracted over 60 spams. So I went in, deleted all of them individually (because I can't select multiple comments to delete in Blogger), then closed comments on the post.<br /><br />This morning, I caught up on my Planet Debian email, and discovered that Blogger had decided to make that post "new", so it showed up on Planet again! Argh!<br /><br />So don't worry, I didn't lose my wallet again. Blogger is just nuts.dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com3tag:blogger.com,1999:blog-12729767.post-89051883960171273142007-05-23T20:41:00.000-07:002011-06-19T12:05:34.726-07:00The virtues of limited terminal widthI've noticed that a great benefit of reading mail in an 80-column X terminal is that it acts as a simple filter: if a thread drifts so far to the right that I can no longer read the Subject: line, it's probably not worth my time to read it and I can kill the whole thing.<br /><br />I wonder what sorts of gains in free time and productivity I could realize by shrinking my terminals to widths of 70, 60, or even 40 characters wide?dburrowshttp://www.blogger.com/profile/16310501949675761069noreply@blogger.com1