<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DUYCQ3s8cCp7ImA9WhNXEU4.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533</id><updated>2012-11-28T13:12:42.578-08:00</updated><category term="linux" /><category term="exercise" /><category term="recipe" /><category term="jobs" /><category term="ms" /><category term="research" /><category term="lifehack" /><category term="personal" /><category term="food" /><category term="thoughts" /><category term="coding" /><category term="perl" /><category term="script" /><category term="bash" /><category term="weight" /><category term="google" /><title>dedrop</title><subtitle type="html">thoughts and ideas and things</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://www.dedrop.org/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://www.dedrop.org/" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>21</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/dedrop" /><feedburner:info uri="dedrop" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;CkMHQ3wzfip7ImA9WxNQGE4.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-8674826292715771162</id><published>2009-09-24T14:55:00.000-07:00</published><updated>2009-09-24T15:13:52.286-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-24T15:13:52.286-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="personal" /><category scheme="http://www.blogger.com/atom/ns#" term="research" /><title>Dr. Dro</title><content type="html">Finally. As of about 9:00am on Tuesday, September 22nd, my doctoral thesis was deposited at the University of Wisconsin - Madison. I am now officially Dr. DeRose.
&lt;p&gt;
I look forward to having a life again.
&lt;span id="cut"&gt;
&lt;p&gt;
I won't bother with the details of the thesis, but I did want to share my Acknowledgments. They are below.
&lt;p&gt;
&lt;blockquote&gt;
This dissertation is like the final exam of a long class. And, like many finals,
it is cumulative; paraphrasing Prof. Jeff Erickson, "the final will cover
everything you have ever learned in your entire life, with a focus on what you
learn here". In this context, I have innumerable people to thank, so the ones
below are but a few highlights.
&lt;p&gt;
First, to my parents: thanks for staying in the United States, despite the
personal sacrifice. Thanks for teaching me that C's are unacceptable because I
can do better. And thanks for always supporting me, and wanting what's best for
me, especially when times got tough.
&lt;p&gt;
To my father, special thanks for sparking my interest in programming. I don't
remember how young I was when he gave me the Commodore 64. I know I was 11 when,
as I started to play computer games, he handed me "The C Programming Language"
and told me to stop playing and start making. To him I owe the epiphany of "so
&lt;i&gt;that's&lt;/i&gt; why pointers are useful!" If not for these things, I don't know
where I'd be now.
&lt;p&gt;
Thanks also to Joseph Smarr and Steve Severinghaus. They turned a coding hobby
into a love of computers and computer science. They taught me, through practice,
example, and critique ("line after line of ugly, ugly code"), that software
can solve real problems.
&lt;p&gt;
Many thanks to Phil Bohannon for teaching me that people live in different
worlds. He showed me that so much of collaboration is discovering the benefits
of other people's worlds, and sometimes leaving yours to live in theirs.
&lt;p&gt;
Finally, I'd like to thank my advisors, AnHai Doan and Raghu Ramakrishnan. They
imparted to me their passion for data management. They also put up with me long
enough to teach me immeasurably about how to think and how to communicate.
These lessons will be priceless anywhere I go from here.
&lt;/blockquote&gt;
&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/2dFrLsMdLnU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/8674826292715771162/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=8674826292715771162" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/8674826292715771162?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/8674826292715771162?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/2dFrLsMdLnU/dr-dro.html" title="Dr. Dro" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.dedrop.org/2009/09/dr-dro.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk8CQno6cSp7ImA9WxNSEk4.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-2647706580453973341</id><published>2009-08-25T14:10:00.001-07:00</published><updated>2009-08-25T14:14:23.419-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-25T14:14:23.419-07:00</app:edited><title>Five-Minute Ph.D.</title><content type="html">Okay, I lied, both about how often I'd start posting, and about the content of the next post. Briefly put, finishing a thesis and preparing for a defense while working a full-time job is both painful and time consuming. My defense is September 18th, after which there will be much rejoicing, and possibly more consistent posting.
&lt;p&gt;
Until then, here's a cross-post from my &lt;a href="http://learningpm.dedrop.org"&gt;other blog&lt;/a&gt;. I'm behind on that one, too, but since it's a work commitment, I write there before I write here.

&lt;span id="cut"&gt;
&lt;hr&gt;
As my Ph.D. defense nears, I'm thinking a lot about the most important lessons:
&lt;ul&gt;
&lt;li&gt;Don't look for reasons to fail; find ways to succeed. If something should or must be done, find a way to do it.
&lt;li&gt;First figure out the right thing to do. Only then think about implementation, and see how close you can come. Even if you can't reach the ideal, at least you'll be pushing in the right direction.
&lt;li&gt;Any good problem solver can hack a good solution quickly. What's more valuable is identifying the underlying problem, and how it relates to other problems. This tells you if something is a true solution, and helps discover other opportunities.
&lt;li&gt;Think in a structured, disciplined way. First, separate out orthogonal issues. Then, solve them incrementally and iteratively. Don't try to attack the whole mess at once.
&lt;li&gt;Finally, when communicating with others, try to tell a story. Start with something familiar, then make sure your ideas flow.
&lt;/ul&gt;
&lt;p&gt;
Those are the big ones. The gems of a Ph.D. education, in five easy minutes. Interestingly, none of these are particularly technical. But deeply technical things are limited in application. I think that's the real secret: the &lt;i&gt;work&lt;/i&gt; you do in a Ph.D. is technical, but a good Ph.D. is about becoming a better thinker and communicator.
&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/4XOpqPVJM0I" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/2647706580453973341/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=2647706580453973341" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/2647706580453973341?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/2647706580453973341?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/4XOpqPVJM0I/five-minute-phd.html" title="Five-Minute Ph.D." /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.dedrop.org/2009/08/five-minute-phd.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0EBQXY-fip7ImA9WxJWF0Q.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-954255680233365901</id><published>2009-06-23T15:14:00.001-07:00</published><updated>2009-06-23T15:20:50.856-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-23T15:20:50.856-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="jobs" /><category scheme="http://www.blogger.com/atom/ns#" term="ms" /><title>Program Manager Blog</title><content type="html">I should also mention that I've started a new, more work-related blog called &lt;a href="http://learningpm.dedrop.org/"&gt;Learning Program Management&lt;/a&gt;. It's primarily about what I've been picking up in my new role at Microsoft. 
&lt;p&gt;
The division between the two blogs is simple: if it deals with Program Management, Microsoft, or SQL Server, it'll go to Learning PM. Anything else I think worth sharing will go here.&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/ktuoY_Swecg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/954255680233365901/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=954255680233365901" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/954255680233365901?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/954255680233365901?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/ktuoY_Swecg/program-manager-blog.html" title="Program Manager Blog" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>4</thr:total><feedburner:origLink>http://www.dedrop.org/2009/06/program-manager-blog.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0AERnY7eSp7ImA9WxJWF0Q.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-5293263443279905251</id><published>2009-06-23T08:37:00.000-07:00</published><updated>2009-06-23T15:21:47.801-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-23T15:21:47.801-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="personal" /><title>Back on Earth Again</title><content type="html">It's been almost a year since my last post, which is very poor of me. I don't know how it works for others, but when I make major life changes, I cocoon for a while.
&lt;span id="cut"&gt;
&lt;p&gt;
Since my last post, I have gotten &lt;a href="http://sarahsam.livejournal.com/294943.html"&gt;married&lt;/a&gt;, &lt;a href="http://sarahsam.livejournal.com/295631.html"&gt;honeymooned&lt;/a&gt; in &lt;a href="http://www.flickr.com/photos/sarahsam/collections/72157614633423003/"&gt;New Zealand&lt;/a&gt;, visited &lt;a href="http://www.flickr.com/photos/sarahsam/collections/72157616969342726/"&gt;Brazil&lt;/a&gt;, &lt;a href="http://sarahsam.livejournal.com/297817.html"&gt;moved to Seattle&lt;/a&gt;, started my new job, and bought a &lt;a href="http://www.flickr.com/photos/sarahsam/sets/72157612840028952/"&gt;house&lt;/a&gt; (as you can see, Sarah has been much better than I about staying in touch). One important item not on the list is "defended my thesis", so there are more big changes to come. Nevertheless, I've mostly gotten my feet under me again, so it's time to come out of hibernation. Also, to mix as many metaphors as I can in one post, apparently.
&lt;p&gt;
So, if there's anyone still following this out there, apologies, and hello again. If you'd like to get in touch, my old email, IM, and phone number are all the same. All that's changed is my address:
&lt;p&gt;
&lt;b&gt;
Pedro DeRose&lt;br&gt;
6704 E Crest View Loop SE&lt;br&gt;
Snoqualmie, WA 98065&lt;br&gt;
&lt;/b&gt;
&lt;p&gt;
Now that I've poked my head back out, I'm going to try and be better about posting periodically. Next time: what I learned (or at least remember from what I learned) about buying a house.
&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/urcMZE_zYVQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/5293263443279905251/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=5293263443279905251" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/5293263443279905251?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/5293263443279905251?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/urcMZE_zYVQ/back-on-earth-again.html" title="Back on Earth Again" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.dedrop.org/2009/06/back-on-earth-again.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ACSXg4fSp7ImA9WxJWF0o.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-3520170009078407060</id><published>2008-08-18T17:58:00.002-07:00</published><updated>2009-06-23T09:49:28.635-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-23T09:49:28.635-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="personal" /><title>New Phone Number</title><content type="html">My phone bricked. I'll expand this post with details later, but for now, what's important is that my new number is 217-369-6980 until further notice.

&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; My number is back to 217-898-9662. Been that way for a while, actually. However, what with major life events (marriage, honeymoon, visiting family in Brazil, and moving to Seattle), I haven't had time to post updates. I'll try to be better about it in the upcoming weeks.&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/Ef_kzrrqLUc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/3520170009078407060/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=3520170009078407060" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/3520170009078407060?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/3520170009078407060?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/Ef_kzrrqLUc/new-phone-number.html" title="New Phone Number" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://www.dedrop.org/2008/08/new-phone-number.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk8HRX87fCp7ImA9WxdVFko.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-5991063477938290143</id><published>2008-07-18T14:25:00.011-07:00</published><updated>2008-07-21T14:13:54.104-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-21T14:13:54.104-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="perl" /><category scheme="http://www.blogger.com/atom/ns#" term="coding" /><title>Restricting method access in Perl objects</title><content type="html">&lt;p&gt;This a geeks-only entry in the "Perl: Handy, but Ugly" series...&lt;/p&gt;

&lt;p&gt;I often want to restrict access to certain methods in a class. One classic example is public and private methods. As another, I've written a class for data storage with both read and write methods, and sometimes I want an instance to be read-only, and other times write-only. I could implement this with an internal read/write flag. However, while I want that flag to be flippable, I don't want just anyone flipping it. That sort of thing is hard to do in Perl because it doesn't believe in enforced privacy.&lt;/p&gt;

&lt;p&gt;Fortunately, Perl &lt;i&gt;does&lt;/i&gt; believe in being powerful and flexible. So I've found a neat way of wrapping object instances in what I call &lt;i&gt;adapters&lt;/i&gt;, which expose only a subset of the object's methods.&lt;/p&gt;

&lt;span id="cut"&gt;

&lt;p&gt;
The basic desiderata are as follows:
&lt;ol&gt;
&lt;li&gt;The adapter should be an object wrapping another object.&lt;/li&gt;
&lt;li&gt;It should only define the methods it exposes, so that the wrapped object's unexposed methods aren't even there&lt;/li&gt;
&lt;li&gt;There should be no way of getting to the wrapped object through the adapter (otherwise, you can get to the unexposed methods)&lt;/li&gt;
&lt;li&gt;Finally, I don't want to write a new adapter for every class I want to wrap, or every subset of methods I want to expose&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;

&lt;p&gt;Wait a second, you say. I want adapters to be classes defining a custom set of methods, but I don't want to write a new adapter each time? Yes. And because Perl is "Handy, but Ugly", I can do it.&lt;/p&gt;

&lt;p&gt;The trick is that Perl gives you direct access to the symbol table: that magical hash that knows what reference you mean when you use a variable or subroutine name in your code. And since a class is just a set of symbols, it's possible to create a class entirely on the fly just by &lt;a href="http://www.perl.com/pub/a/2005/03/17/symtables.html"&gt;inserting the proper subroutine references into the symbol table&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With that, I present my AdapterFactory perl module. It's fairly well commented, so I'll leave groking it as an exercise for the reader. A couple of hints:
&lt;ul&gt;
&lt;li&gt;With &lt;code&gt;no strict&lt;/code&gt;, a string can be dereferenced as if it were a reference to the variable whose name is the string's value. This works only for non-lexical variables (i.e., those not defined with "my"). For instance, &lt;code&gt;$h = "hash"; %$h&lt;/code&gt; is equivalent to &lt;code&gt;$h = \%hash; %$h&lt;/code&gt;, or &lt;code&gt;%hash&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;For some reason, even with &lt;code&gt;use strict&lt;/code&gt;, strings on either side of the arrow operator can be dereferenced to the package or method whose name is the string value. For instance, &lt;code&gt;$p = "Package"; $m = "new"; $p-&gt;$m()&lt;/code&gt; is equivalent to &lt;code&gt;Package-&gt;new()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The symbols for a package are kept in a hash with the name of the package plus "::". Thus, symbols for package "foo" are kept in hash &lt;code&gt;%foo::&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The * sigil is used to set values in the &lt;a href="http://www.perl.com/pub/a/2005/03/17/symtables.html"&gt;symbol table&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="filename"&gt;AdapterFactory.pm&lt;/div&gt;
&lt;pre class="code"
&gt;###
# Author: Pedro DeRose
# Creates adapters, or objects that wrap another object, but expose only a
# subset of its methods. Useful for separating public/private methods, or
# restricting functionality. Does not provide any handle to the object itself.
#
# Usage example:
#
#     use AdapterFactory qw(defineAdapter adapt)
#
#     defineAdapter('Foo::Public', [ qw(get set print) ]);
#     my $fooAdapter = AdapterFactory::Foo::Public-&gt;new($fooObj);
#     my $barAdapter = adapt('Foo::Public', $barObj);
#     
#     defineAdapter('Foo::Private', { secret =&gt; [ 'default' ] });
#   
#   Defines the AdapterFactory::Foo::Public adapter exposing the get(), set(),
#   and print() methods, then creates adapters wrapping $fooObj and $barObj.
#   Finally, defines the AdapterFactory::Foo::Private adapter exposing the
#   secret() method, and specifies that "default" should always be passed to it.
###   
package AdapterFactory;
use Exporter 'import';
@EXPORT_OK = qw(defineAdapter adapterDefined adapt);

use strict;

# Keep map of adapter to object as a lexical variable so that adapter objects
# don't store the object themselves, where other code can get to it.
my %adapterToObj;

###
# Defines a new adapter class whose name is the name of this class, plus "::"
# then the given name appended (e.g., given name "Foo::Bar", the name is
# "AdapterFactory::Foo::Bar"). It wraps the object passed to its new()
# constructor, exposing the specified methods. Methods can be specified in two
# ways. When an array reference of method names, they are called directly. When
# a map from method name to an array reference of arguments, the adapter's
# methods call the wrapped object's methods with the given arguments always
# appended. See the usage example above for how to use the adapter.
#   name: the name of the adapter class
#   methods_r: reference to methods to expose
#   returns true if the definition was successful, false otherwise
###
sub defineAdapter {
    my ($name, $methods_r) = @_;
    $name or die "Missing name";
    ref($methods_r) eq 'HASH' or ref($methods_r) eq 'ARRAY' or die "Bad methods";

    if(adapterDefined($name)) {
        warn "Adapter $name already exists.";
        return undef;
    }

    # Lots of symbol table manipulation, so stop yer whining
    no strict;

    # Compose the adapter class name
    my $class = __PACKAGE__."\::$name";

    # Turn method array ref into method hash ref with no method arguments
    if(ref($methods_r) eq 'ARRAY') { $methods_r = { map { ($_ =&gt; []) } @$methods_r }; }

    # Directly create symbol table entry for each exposed method.
    foreach my $method (keys %$methods_r) {
        my @args = defined($methods_r-&gt;{$method})? @{$methods_r-&gt;{$method}} : ();
        *{"$class\::$method"} = sub {
            # Look up object using adapter's reference, then call the method
            my $self = shift;
            return $adapterToObj{$self}-&gt;$method(@_, @args)
        };
    }

    # Create the constructor last, so it clobbers any "new" method in methods_r
    *{"$class\::new"} = sub {
        my ($class, $obj_r) = @_;

        # Map the given obj to this adapter
        my $self = {};
        bless($self, $class);
        $adapterToObj{$self} = $obj_r;

        return $self;
    };

    return 1;
}

###
# Returns whether an adapter with the given name is already defined
#   name: the name of the adapter class
#   returns true if an adapter with the name is defined, false otherwise
###
sub adapterDefined {
    my ($name) = @_;
    no strict;
    return scalar(%{__PACKAGE__."\::$name\::"});
}

###
# Creates and returns an adapter for a given object. Equivalent to calling the
# new() constructor on the adapter created with the given name, and passing the
# given object.
#   name: the name of the adapter class
#   obj_r: reference to the object being wrapped
###
sub adapt {
    my ($name, $obj_r) = @_;
    $name or die "Missing name";
    UNIVERSAL::isa($obj_r, 'UNIVERSAL') or die "Object must be a blessed reference";

    # Create and return the adapter
    my $class = __PACKAGE__."\::$name";
    return $class-&gt;new($obj_r);
}


1;&lt;/pre&gt;

&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/wC4g0zuyWsM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/5991063477938290143/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=5991063477938290143" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/5991063477938290143?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/5991063477938290143?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/wC4g0zuyWsM/restricting-method-access-in-perl.html" title="Restricting method access in Perl objects" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://www.dedrop.org/2008/07/restricting-method-access-in-perl.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0AFSXw-cSp7ImA9WxdWEEQ.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-8496865577896908184</id><published>2008-07-03T06:32:00.002-07:00</published><updated>2008-07-03T07:35:18.259-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-03T07:35:18.259-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="perl" /><category scheme="http://www.blogger.com/atom/ns#" term="coding" /><title>Perl: Handy, but Ugly</title><content type="html">&lt;p&gt;In what will probably be a many-part series, here's an oddity of Perl that had me tearing out my hair for a couple of hours...&lt;/p&gt;
&lt;span id="cut"&gt;
&lt;p&gt;If you know Perl well, feel free to skip this paragraph. Perl has a handy but ugly notion of &lt;i&gt;context&lt;/i&gt;. Specifically, code execute in either a &lt;i&gt;scalar&lt;/i&gt; or a &lt;i&gt;list&lt;/i&gt; context: if a single value is expected, the code executes in scalar context; if a list of values is expected, it executes in list context (that's vague, but good enough for now). Then, code behaves differently depending on the context.&lt;/p&gt;

&lt;p&gt;One example of context is getting the length of a list. Given a list &lt;code&gt;@foo = ('a', 'b', 'c')&lt;/code&gt;, then &lt;code&gt;@foo&lt;/code&gt; in scalar context is the length of &lt;code&gt;@foo&lt;/code&gt;. Thus, &lt;code&gt;$x = @foo&lt;/code&gt; sets the single value &lt;code&gt;$x&lt;/code&gt; to 3 (the code executes in scalar context because &lt;code&gt;$x&lt;/code&gt; is a single value, so Perl expects a single value assigned to it).&lt;/p&gt;

&lt;p&gt;Now for a pop quiz. If &lt;code&gt;@foo = ('a', 'b', 'c'); $x = @foo&lt;/code&gt; sets &lt;code&gt;$x&lt;/code&gt; to 3, what does &lt;code&gt;$x = ('a', 'b', 'c')&lt;/code&gt; do? Turns out it sets &lt;code&gt;$x&lt;/code&gt; to &lt;code&gt;c&lt;/code&gt;. Fascinating, isn't it?&lt;/p&gt;

&lt;p&gt;The reason is that the comma does different things in list and scalar contexts. In a list context, comma is the list building operator. Thus, &lt;code&gt;('a', 'b', 'c')&lt;/code&gt; in list context (such as when assigned to the list variable &lt;code&gt;@foo&lt;/code&gt;) returns a list with three items. However, in scalar context, comma is like C's comma: it executes both its left and right operands, then returns the result of the right. For instance, &lt;code&gt;'a', 'b'&lt;/code&gt; returns &lt;code&gt;b&lt;/code&gt;, and &lt;code&gt;'a', 'b', 'c'&lt;/code&gt; returns &lt;code&gt;c&lt;/code&gt;. Thus, when we assign &lt;code&gt;('a', 'b', 'c')&lt;/code&gt; to a single value, the code executes in scalar context, returning &lt;code&gt;c&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Of course, I wasn't lucky enough to have this bite me in such a simple form. Instead, consider this (still heavily simplified) example:
&lt;pre class="code"&gt;
sub foo {
    $a = "hello";
    $b = "world";
    return ($a, $b);
}

print join(" ", foo()) . "\n";
print scalar(foo()) . "\n";
&lt;/pre&gt;
I naively thought this would print &lt;code&gt;hello world&lt;/code&gt; then 2. Instead, we get &lt;code&gt;hello world&lt;/code&gt; then &lt;code&gt;world&lt;/code&gt;. Today's lesson, then: when returning lists from functions, assign them to a list variable first.
&lt;/p&gt;

&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/JdC3bgqMH-Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/8496865577896908184/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=8496865577896908184" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/8496865577896908184?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/8496865577896908184?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/JdC3bgqMH-Y/perl-handy-but-ugly.html" title="Perl: Handy, but Ugly" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.dedrop.org/2008/07/perl-handy-but-ugly.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkABQnw4fyp7ImA9WxdXFU0.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-8939413634577712867</id><published>2008-06-26T08:30:00.006-07:00</published><updated>2008-06-26T12:32:33.237-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-26T12:32:33.237-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="lifehack" /><title>Project Note Taking System</title><content type="html">&lt;p&gt;A while ago, I went looking for a good note taking system. Notes, as in on paper. I work on a lot of projects, and since I grok things better when I write them down, I needed a way to organize ideas, meeting minutes, tasks, and progress.&lt;/p&gt;

&lt;span id="cut"&gt;

&lt;p&gt;I found &lt;a href="http://gatheringinlight.com/2007/02/06/create-a-moleskine-pda-the-student-gtd-hack/"&gt;several&lt;/a&gt; &lt;a href="http://gtde.blogspot.com/2006/09/yet-another-gtd-moleskine-hack.html"&gt;hacks&lt;/a&gt; to turn my preferred notebook, a &lt;a href="http://www.moleskine.com"&gt;Moleskine&lt;/a&gt; into a full-fledged PDA replacement using 
&lt;a href="http://en.wikipedia.org/wiki/Getting_Things_Done"&gt;GTD&lt;/a&gt;. However, I didn't want a PDA replacement. I wanted a simple way to organize project ideas.

&lt;p&gt;I also found a lot of good &lt;a href="http://sas.calpoly.edu/asc/ssl/notetaking.systems.html"&gt;note-taking systems&lt;/a&gt;. Of these, the &lt;a href="http://en.wikipedia.org/wiki/Cornell_Notes"&gt;Cornell system&lt;/a&gt; was closest to what I wanted. I liked the idea of taking notes, then adding higher-level comments off to one side. Unfortunately, page division doesn't work well in a small notebook, and the system isn't very project-oriented.&lt;/p&gt;

&lt;p&gt;Thus, after some trial and error, I've mostly settled on something that works well for me. I begin with a &lt;a href="http://www.moleskineus.com/largesquared.html"&gt;large, graph paper Moleskine&lt;/a&gt;, though any notebook should work. Next, I take notes on the right-hand page, then write higher-level comments on the left page. That's the gist. The fun part is the details.&lt;/p&gt;

&lt;p&gt;On the right-hand page, I always first write the date in the upper-right-hand corner. This makes finding old notes a lot easier. After that, I take notes however I like &amp;mdash; outlines, drawings, mindmaps, whatever.&lt;/p&gt;

&lt;p&gt;Then, both while writing notes and when reviewing them, I write higher-level comments on the left page. I find it useful to vertically align them with the part of the notes they comment on. Each comment is labeled, in the form &lt;i&gt;Label: comment&lt;/i&gt;, so that I can immediately tell what kind of comment it is. I use five labels:
&lt;dl&gt;
&lt;dt&gt;Topic&lt;/dt&gt;
&lt;dd&gt;Every left-hand page has a single Topic comment first thing on the page. It's short phrases or keywords to remind me what the notes are about. By using only one per page and putting it at the top, it's easy to flip through the notebook and find notes about particular topics.&lt;/dd&gt;

&lt;dt&gt;Thought&lt;/dt&gt;
&lt;dd&gt;These are interesting thoughts about the notes, such as summarizations, ideas, etc.&lt;/dd&gt;

&lt;dt&gt;Tip&lt;/dt&gt;
&lt;dd&gt;Often my notes include good lessons, so Tips are things I want to do differently in the future.&lt;/dd&gt;

&lt;dt&gt;Task&lt;/dt&gt;
&lt;dd&gt;These are things that I need to do based on the notes. As I do them (or move them to a better task management system), I check them off.&lt;/dd&gt;

&lt;dt&gt;Tack/Tank&lt;/dt&gt;
&lt;dd&gt;This pair of labels keeps track of tacks we've taken in the project, and why we've decided to tank them. I use them because I found that projects often cycle back to old ideas without remembering the very good reasons they were killed in the first place. To illustrate their use, suppose we have a project meeting on Monday and decide to use MySQL. My notes on the right-hand page contain our reasoning, and I add "Tack: use MySQL" to the left-hand page, leaving some space underneath. On Tuesday, we change our minds, and decide to use SQLite instead. So now I add "Tack: use SQLite" to Tuesday's left-hand page. Then, I go back to Monday's page, and under the "Tack: use MySQL" comment, I add a Tank comment explaining why we're no longer using MySQL.&lt;/dd&gt;
&lt;/dl&gt;
&lt;/p&gt;

&lt;p&gt;That's it. Fairly easy to use and well organized, and relatively easy to find information later. Of course, it's not ideal. What I really want is a lightweight tablet PC, about the size of my Moleskine but all screen, with a swivel keyboard, and nice note software with tags, tree-structure organization, and handwriting search. But before saying &lt;a href="http://www.tabletpc2.com/Review-Fujitsu_Lifebook_T4220_Tablet_PC-Article7002.html"&gt;such things exist&lt;/a&gt;, I also want it to be affordable. Good luck to me. Until then, I'll keep buying Moleskines.&lt;/p&gt;

&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/tlwCdlgVa0Q" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/8939413634577712867/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=8939413634577712867" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/8939413634577712867?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/8939413634577712867?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/tlwCdlgVa0Q/project-note-taking-system.html" title="Project Note Taking System" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.dedrop.org/2008/06/project-note-taking-system.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08BSH48fSp7ImA9WxdQF04.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-1901473461090968148</id><published>2008-05-29T14:28:00.003-07:00</published><updated>2008-06-17T12:44:19.075-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-17T12:44:19.075-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="thoughts" /><category scheme="http://www.blogger.com/atom/ns#" term="research" /><category scheme="http://www.blogger.com/atom/ns#" term="jobs" /><title>Industry vs. Research</title><content type="html">&lt;p&gt;As a graduate student looking for jobs, a common question I heard was "Industry or research?" Industry jobs include developers, technical managers, and even applied researchers to a large degree. Fundamental research jobs are professors and research scientists at industrial labs, such as Microsoft Research and Yahoo! Research. The definitions are somewhat fuzzy (applied research is industry? industrial labs are research?), but a generally distinguishing characteristic is whether publishing papers is a primary aspect of the job.&lt;/p&gt;

&lt;p&gt;It was this characteristic that made me realize the fundamental difference between industry and research. It's one I wish I had known when I started graduate school. In short,&lt;/p&gt;

&lt;p style='text-align: center; font-style: italic; margin: 0 1em;'&gt; Industry is primarily about selling products, while research is primarily about selling stories &lt;/p&gt;

&lt;span id="cut"&gt;
&lt;p&gt;This is why publishing papers is telling: papers are a medium for selling stories. Of course, a good story helps sell a product, and a working product helps sell a story. So there is definite overlap. However, it's telling how well the pros and cons of industry and research derive from this basic difference.&lt;/p&gt;

&lt;p&gt;To illustrate, consider some classic pros and cons. In industry, since you sell products, your work has direct impact on people that use the product. Since people will typically pay for this impact, the product itself is the source of funding. And if your product is sufficiently impactful, it is the source of a lot of funding, and you get rich. However, this means it's critical to quickly and consistently create marketable products. The result is a dampening effect on the problems targeted by industry: they are dictated by the market, and typically have shorter-term visions with fewer (or at least more calculated) risks.&lt;/p&gt;

&lt;p&gt;In contrast, research has significantly more freedom in the problems it tackles. They are often longer-term, riskier visions. Research can do this because it only has to sell stories describing core ideas, not fully working products. Thus, it can focus on interesting technical problems. However, "selling" a story does not usually mean for money, but rather convincing people that it describes a good idea (e.g., getting a paper accepted to a conference). Since neither the story nor the idea generates money directly, researchers must seek out external funding such as grants, or, in industrial labs, income from products (which, to be fair, often contain the final fruits of research).&lt;/p&gt;

&lt;p&gt;Given such pros and cons, the distinction of product vs. story seems obvious in hindsight. However, what made me first realize it was a more subtle situation. My advisor asked me to devise a data model for the system we're building. I came back with two options: a very common model, and a novel model that was simpler and more expressive. I favored the novel model, but my advisor said we should use the common one. His reason was that the data model was not our primary contribution, and papers with too many innovations can confuse readers. And he was right. Even though the novel model would make for a better system, the common model makes for a better story &amp;mdash; and I'm currently in the business of selling stories. At some later date, after we sell our current story, we may sell another story that focuses on a new data model.&lt;/p&gt;

&lt;p&gt;To conclude, I want to say that this isn't meant to promote either industry or research. In my particular case, I've found that I lean more towards selling products than stories. However, I've spoken with both developers and researchers, and both agree with the product vs. story differentiation, and each prefers their side. Of course, I'd love to hear from anyone else on the topic. I just think that understanding this difference is vital to making an informed decision about graduate school, and life afterwards.&lt;/p&gt;
&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/b3D2W8GZzwk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/1901473461090968148/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=1901473461090968148" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/1901473461090968148?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/1901473461090968148?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/b3D2W8GZzwk/industry-vs-research.html" title="Industry vs. Research" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>4</thr:total><feedburner:origLink>http://www.dedrop.org/2008/05/industry-vs-research.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUcGQ387fCp7ImA9WxdREEQ.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-4712280228653195306</id><published>2008-05-24T22:26:00.002-07:00</published><updated>2008-05-29T14:37:02.104-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-29T14:37:02.104-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="jobs" /><category scheme="http://www.blogger.com/atom/ns#" term="ms" /><title>Job Decision</title><content type="html">&lt;p&gt;It's finally official. After nearly two months of applications, interviews, travel, negotiation, introspection, and extremely hard thinking, I've made a job decision. Come January next year, I'll start as a Program Manager in Microsoft's SQL Server team.&lt;/p&gt;

&lt;p&gt;This was a very difficult decision, as I had to choose between five compelling offers. In the end, there were two primary considerations: location, and how I want to contribute to my field.&lt;/p&gt;

&lt;span id="cut"&gt;
&lt;p&gt;My offers spanned two locations: Microsoft in Seattle, and the others in Silicon Valley. I characterized my options as better quality of life in Seattle vs. proximity to networking and friends in Silicon Valley. Seattle's quality of life is better due to lower cost of living, much cheaper housing (I can actually afford a nice house my first year), and significantly nearer mountains. It also feels more laid-back. On the other hand, Silicon Valley hosts constant interaction between innumerable tech companies, providing excellent networking opportunities and mobility. Also, several of my friends live there.&lt;/p&gt;

&lt;p&gt;For me, Seattle and Silicon Valley were effectively tied. However, this was a two-person decision, so Sarah joined me in visiting both places. She met and loved my Silicon Valley friends, and received a great tour of Seattle courtesy of Microsoft. Sarah sees locations differently than I do. I pick a job, and that decides the location; Sarah picks a location, then finds a job. Location is part of how she defines where she wants her life headed. As it happens, before we were engaged, she was already looking to move to the Pacific Northwest. Thus, though she liked California, and especially my friends, Washington is closer to where she wants to be. This was one consideration.&lt;/p&gt;

&lt;p&gt;The other strong consideration clarified after many conversations with mentors. The key question is how I want to contribute to my field. One path is as a technical luminary, with primarily technical contributions. This path includes god-like developers, researchers, and other deeply technical people. My offers at IBM, Oracle, and Yahoo! followed this path. Another path is as a technical manager, with primarily leadership and strategic contributions. This path includes general managers, CEOs, and other big-picture people. My offers at Google and Microsoft followed this path. I've spent most of my life as a deep techie. However, due to some eye-opening experiences and a lot of introspection, I've decided that, at least currently, my calling is management and leadership. &lt;/p&gt;

&lt;p&gt;Neither of these considerations alone decided me. But due to both together, plus several others secondary, I've accepted the Microsoft offer. A couple things in particular really impressed me about the position. First, I got to meet several team members, including my future boss, and they're all amazing. Second, Microsoft is very serious about investing in people and building careers, so the opportunities for mentorship and advancement are fantastic. I'm extremely excited, and really looking forward to starting. All that's left is to finish my doctorate!&lt;/p&gt;

&lt;p&gt;Finally, to wrap up, I want to very sincerely thank everyone who helped me throughout this process. All of my mentors for their advice; all of my friends for their time, love, connections, and support; and all of my family for putting up with weeks of waffling (individuals may fall into more than one category). I know not everyone will be happy with my decision, but I hope you will all be happy for me. Of course, feel free to send along any particularly strong variations on "You fool!". I promise no hard feelings.&lt;/p&gt;
&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/loBjebBMqTk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/4712280228653195306/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=4712280228653195306" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/4712280228653195306?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/4712280228653195306?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/loBjebBMqTk/job-decision.html" title="Job Decision" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>3</thr:total><feedburner:origLink>http://www.dedrop.org/2008/05/job-decision.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUcMRX84fyp7ImA9WxZVGU8.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-4186878614768090459</id><published>2008-03-30T16:53:00.012-07:00</published><updated>2008-03-30T17:24:44.137-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-30T17:24:44.137-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="research" /><category scheme="http://www.blogger.com/atom/ns#" term="jobs" /><title>Interviews and Conference and Travel, Oh My!</title><content type="html">&lt;p&gt;The last few weeks have been insane, and the next few weeks promise to be just as crazy. I've started my job search, which includes a lot of interviews. I've already interviewed on-site at Microsoft for two positions, and received offers from both. On Monday, I have two phone interviews with Google, again for two positions. Then, in the upcoming weeks, I have on-site interviews at &lt;a href="http://www.rapleaf.com/"&gt;Rapleaf&lt;/a&gt;, &lt;a href="http://www.oracle.com/index.html"&gt;Oracle&lt;/a&gt;, &lt;a href="http://www.almaden.ibm.com/asr/projects/biw/"&gt;IBM Almaden&lt;/a&gt;, and &lt;a href="http://research.yahoo.com/Community_Systems"&gt;Yahoo! Research.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just interviewing involves a lot of travelling. However, as added fun, I'll also be in Cancun for &lt;a href="http://www.icde2008.org/"&gt;ICDE 2008&lt;/a&gt;, where I'll be presenting one of my &lt;a href="http://dedrop.org/papers/madwiki-icde08.pdf"&gt;papers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So between interviews, the conference, and associated travelling, there's basically no time for posting. However, once all is over, I'll share interview resources, conference tidbits, and maybe details about the work I'm presenting. At any rate, just didn't want everyone to think I'd given up on blogging.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/mbQtkzqficI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/4186878614768090459/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=4186878614768090459" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/4186878614768090459?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/4186878614768090459?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/mbQtkzqficI/interviews-and-conference-and-travel-oh.html" title="Interviews and Conference and Travel, Oh My!" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://www.dedrop.org/2008/03/interviews-and-conference-and-travel-oh.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkMGRX44fSp7ImA9WxZVFEo.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-2508208210092578319</id><published>2008-03-12T17:32:00.021-07:00</published><updated>2008-03-25T11:40:24.035-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-25T11:40:24.035-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="recipe" /><category scheme="http://www.blogger.com/atom/ns#" term="food" /><title>Tasty Favorites: Pedro Pasta</title><content type="html">&lt;p&gt;At the urging of a couple &lt;a href="http://flickr.com/photos/sarahsam/"&gt;persuasive&lt;/a&gt; &lt;a href="http://severinghaus.org/"&gt;friends&lt;/a&gt;, I'd like to start sharing the results of one of my pastimes: cooking. Though I enjoy making somewhat involved meals, I also like coming up with tasty foods that encourage me to eat at home. This means quick, cheap, and with minimal clean-up.&lt;/p&gt;

&lt;p&gt;One favorite is what &lt;a href="http://flickr.com/photos/sarahsam/"&gt;Sarah&lt;/a&gt; calls "Pedro Pasta". It's simple, delicious, and (not counting the time to boil water) takes about five minutes.&lt;/p&gt;

&lt;table cellpadding="0" cellspacing="0"&gt;
&lt;tbody&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://flickr.com/photos/sarahsam/299184451/"&gt;&lt;img style="cursor: pointer; border: 0px;" src="http://farm1.static.flickr.com/118/299184451_9b2229f3cf_m.jpg" alt="" id="BLOGGER_PHOTO_ID_5160311237044417618" border="0" /&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://flickr.com/photos/sarahsam/1228717694/"&gt;&lt;img style="cursor: pointer; border: 0px;" src="http://farm2.static.flickr.com/1370/1228717694_6ee935feda_m.jpg" alt="" id="BLOGGER_PHOTO_ID_5160311374483371106" border="0" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan="2" class="caption"&gt;Photos courtesy of Sarah&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;span id="cut"&gt;

&lt;p&gt;First, an aside: I'm a huge fan of Michael Chu's &lt;a href="http://www.cookingforengineers.com/"&gt;Cooking for Engineers&lt;/a&gt;, especially his tabular recipe notation. It's an extremely elegant and concise way of displaying recipes, so I'm borrowing it for these posts.&lt;/p&gt;

&lt;p&gt;For this recipe, I'm not too picky about quantities. The recipe is simple enough that it's easy to pick appropriate quantities based on how many people you're serving, and taste.&lt;/p&gt;

&lt;table class="recipe"&gt;
   &lt;caption&gt;Pedro Pasta&lt;/caption&gt;
   &lt;tbody&gt;
   &lt;tr&gt;
       &lt;td class="ingred"&gt;Water&lt;/td&gt;
       &lt;td&gt;Boil&lt;/td&gt;
       &lt;td rowspan="2"&gt;Cook&lt;/td&gt;
       &lt;td rowspan="2"&gt;Drain&lt;/td&gt;
       &lt;td rowspan="7"&gt;Toss&lt;/td&gt;
       &lt;td rowspan="7"&gt;Let sit&lt;br /&gt;5 min.&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
       &lt;td class="ingred"&gt;Pasta&lt;/td&gt;
       &lt;td class="righthide"&gt;&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
       &lt;td class="ingred"&gt;Cherry Tomatoes&lt;/td&gt;
       &lt;td&gt;Cut half in half&lt;/td&gt;
       &lt;td rowspan="2"&gt;Combine&lt;br /&gt;(squeeze cut)&lt;/td&gt;
       &lt;td rowspan="5"&gt;Stir&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
       &lt;td class="ingred"&gt;Olive Oil&lt;/td&gt;
       &lt;td colspan="2"&gt;&lt;/td&gt; &lt;!--Needed for firefox bug--&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
       &lt;td class="ingred"&gt;Garlic&lt;/td&gt;
       &lt;td&gt;Mince&lt;/td&gt;
       &lt;td class="righthide" rowspan="3"&gt;&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
        &lt;td class="ingred"&gt;Italian Seasoning&lt;/td&gt;
        &lt;td class="righthide" rowspan="2"&gt;&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
        &lt;td class="ingred"&gt;Salt&lt;/td&gt;
   &lt;/tr&gt;
   &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3&gt;Steps:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Boil water for pasta. I generally add salt to the water to flavor the pasta and help cook it (salt water boils hotter).&lt;/li&gt;
&lt;li&gt;While the water boils, prepare the other ingredients: cut about half of the cherry tomatoes in half, and mince the garlic. If you're using fresh herbs instead of the dried "Italian Seasoning" mix (basil, oregano, rosemary, etc.), chop up the herbs as well.&lt;/li&gt;
&lt;li&gt;Add pasta to the boiling water. I like spaghetti or angel hair, but any pasta works fine.&lt;/li&gt;
&lt;li&gt;While the pasta cooks, prepare the sauce: put olive oil in a large bowl, and squeeze into it the cherry tomatoes you cut in half. Then stir in the tomatoes (both squeezed and whole), garlic, herbs, and salt to taste. You'll want enough olive oil/tomato mixture to coat the pasta, but this is also largely a matter of taste.&lt;/li&gt;
&lt;li&gt;Once the pasta has finished cooking, put it into the bowl with the sauce, and toss it.&lt;/li&gt;
&lt;li&gt;Finally, let sit for five minutes or so. The heat from the pasta will cook the garlic, and generally help spread the flavors around.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that's it. Serve with some grated Parmesan cheese, and you have a quick and tasty meal. Of course, some may complain that it's lacking in protein. To address this, I make an accompaniment:&lt;/p&gt;

&lt;table class="recipe"&gt;
    &lt;caption&gt;Pedro Pasta Accompaniment&lt;/caption&gt;
    &lt;tr&gt;
        &lt;td class="ingred"&gt;Garlic Olive Oil&lt;/td&gt;
        &lt;td&gt;Heat (med-low)&lt;/td&gt;
        &lt;td rowspan="3"&gt;Lightly&lt;br /&gt;sautee&lt;/td&gt;
        &lt;td rowspan="6"&gt;Sautee&lt;/td&gt;
        &lt;td rowspan="7"&gt;Cook (med)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td class="ingred"&gt;Extra Firm Tofu&lt;/td&gt;
        &lt;td&gt;Cube&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td class="ingred"&gt;Garlic&lt;/td&gt;
        &lt;td&gt;Mince&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td class="ingred"&gt;Salt&lt;/td&gt;
        &lt;td class="righthide" rowspan="3" colspan="2"&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td class="ingred"&gt;Italian Seasoning&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td class="ingred"&gt;Lemon Pepper&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td class="ingred"&gt;Red Wine&lt;/td&gt;
        &lt;td class="righthide" colspan="2"&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;

&lt;h3&gt;Steps:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Heat some garlic olive oil over medium-low heat (regular olive oil works fine if you don't have the garlicky variety).&lt;/li&gt;
&lt;li&gt;Add cubed extra firm tofu and minced garlic, then sautee lightly, just until the tofu starts to get a bit golden.&lt;/li&gt;
&lt;li&gt;Add salt, Italian seasoning, and lemon pepper to taste (you can buy lemon pepper at just about any grocery store). Continue sauteeing until the tofu is nice and golden.&lt;/li&gt;
&lt;li&gt;Add a splash of red wine, then turn the heat up to medium and cook until the tofu browns (or however you like it).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once finished, just throw it in with the Pedro Pasta.&lt;/p&gt;

&lt;p&gt;If you're not vegetarian (Sarah is, but I'm not), you can use chicken instead of tofu. The steps are the same, except replace tofu with chicken, and red wine with white. Also, make sure the chicken cooks thoroughly, which may require a slightly higher temperature in the early steps.&lt;/p&gt;

&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/KiFI-eljL0k" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/2508208210092578319/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=2508208210092578319" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/2508208210092578319?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/2508208210092578319?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/KiFI-eljL0k/tasty-favorites-pedro-pasta.html" title="Tasty Favorites: Pedro Pasta" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://farm1.static.flickr.com/118/299184451_9b2229f3cf_t.jpg" height="72" width="72" /><thr:total>3</thr:total><feedburner:origLink>http://www.dedrop.org/2008/03/tasty-favorites-pedro-pasta.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0IGQ307eip7ImA9WxZWE0U.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-2516470289114960505</id><published>2008-02-28T09:02:00.016-08:00</published><updated>2008-03-12T22:18:42.302-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-12T22:18:42.302-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="thoughts" /><category scheme="http://www.blogger.com/atom/ns#" term="research" /><category scheme="http://www.blogger.com/atom/ns#" term="ms" /><category scheme="http://www.blogger.com/atom/ns#" term="google" /><title>Google Sites, MS SharePoint...Creating Communities</title><content type="html">&lt;p&gt;Google recently announced a new product, called &lt;a href="http://sites.google.com/"&gt;Google Sites&lt;/a&gt;.  The basic idea is that it lets you gather and share data (e.g., Google Apps documents, files, free-form wiki-style pages) pertaining to a particular purpose (e.g., business, team, project). Inevitably, Sites is being compared to Microsoft &lt;a href="http://www.microsoft.com/sharepoint/default.mspx"&gt;SharePoint&lt;/a&gt;, which addresses a similar need.&lt;/p&gt;

&lt;p&gt;What's fascinating to me about Sites and SharePoint are how they relate to my research on community information management. Briefly, a community has a shared topic or purpose on which they have data, such as web sites, mailing lists, and documents. This data is often unstructured. I research systems that process this unstructured community data to extract structured information about entities and relationships, then provide structured services beyond keyword search (e.g., querying, browsing, monitoring). I've built a very alpha prototype system, &lt;a href="http://dblife.cs.wisc.edu"&gt;DBLife&lt;/a&gt;, for the database research community, and also published some &lt;a href="http://www.informatik.uni-trier.de/~ley/db/indices/a-tree/d/DeRose:Pedro.html"&gt;papers&lt;/a&gt; on the topic.&lt;/p&gt;

&lt;p&gt;How Sites and SharePoint relate is very exciting: they build communities. Currently, my research helps builders select web pages and other data sources. However, by integrating with a Microsoft SharePoint installation or a Google Site, the data is already there. And the benefits to users is palpable. Instead of only keyword search, users would have powerful structured access methods, making the application much more useful. Truly, it'd be very exciting to see something like that happen.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/iF_Iiv2wcCo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/2516470289114960505/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=2516470289114960505" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/2516470289114960505?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/2516470289114960505?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/iF_Iiv2wcCo/google-sites-ms-sharepointcreating.html" title="Google Sites, MS SharePoint...Creating Communities" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.dedrop.org/2008/02/google-sites-ms-sharepointcreating.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MNSXg9fCp7ImA9WxdWEEQ.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-4011733399524989015</id><published>2008-02-27T20:00:00.012-08:00</published><updated>2008-07-03T07:31:38.664-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-03T07:31:38.664-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="bash" /><category scheme="http://www.blogger.com/atom/ns#" term="coding" /><title>Bash Command-line Programming: Flow Control</title><content type="html">&lt;p&gt;Time for another post on handy techniques for command-line bash programming. This post covers some useful command-line techniques for flow control.&lt;/p&gt;

&lt;span id="cut"&gt;

&lt;p&gt;Even when writing quick programs on the command-line, I often need to branch or loop. Especially loop, as I often need to do something over every file in a directory, or every line in a file. Below are some techniques I commonly use. For more neat bash-isms, check out the &lt;a href="http://wooledge.org:8000/BashFAQ"&gt;Bash FAQ&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;cmd &amp;amp;&amp;amp; trueCmd || falseCmd&lt;/strong&gt;&lt;/code&gt;: if &lt;code&gt;cmd&lt;/code&gt; executes successfully, run &lt;code&gt;trueCmd&lt;/code&gt;, else run &lt;code&gt;falseCmd&lt;/code&gt;. This is a pithy version of
&lt;pre class="code"&gt;if cmd; then trueCmd; else falseCmd; fi&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;while cmd; do stuff; done&lt;/strong&gt;&lt;/code&gt;: execute &lt;code&gt;stuff&lt;/code&gt; while &lt;code&gt;cmd&lt;/code&gt; executes successfully. Use
&lt;pre class="code"&gt;while true; do stuff; done&lt;/pre&gt;
for an infinite loop.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;for W in words; do stuff; done&lt;/strong&gt;&lt;/code&gt;: sets the variable &lt;code&gt;$W&lt;/code&gt; to each word in &lt;code&gt;words&lt;/code&gt;, then executes &lt;code&gt;stuff&lt;/code&gt;. For instance, to run &lt;code&gt;foo&lt;/code&gt; on every text file in a directory tree, use
&lt;pre class="code"&gt;for W in $(find . -name '*.txt'); do foo "$W"; done&lt;/pre&gt;
Note that &lt;code&gt;words&lt;/code&gt; are split automatically based on whitespace. This means that filenames with spaces will be split into multiple words (I know &lt;code&gt;find&lt;/code&gt; has the -exec option, but it can be cumbersome, and this is just an example). To avoid splitting on whitespace, see the next tip.
&lt;div class="edit"&gt;&lt;strong&gt;Edit:&lt;/strong&gt; Originally, my example used &lt;code&gt;/bin/ls *.txt&lt;/code&gt; rather than &lt;code&gt;find&lt;/code&gt;. However, as &lt;a href="http://severinghaus.org"&gt;HorsePunchKid&lt;/a&gt; points out,
&lt;pre class="code"&gt;for W in *.txt; do foo "$W"; done&lt;/pre&gt;
works on filenames with whitespace (and is also cleaner). This is an excellent point, but the &lt;em&gt;only&lt;/em&gt; expansion done after word splitting is pathname expansion, so it applies only to file globs. If you're processing the output of a command, or the contents of an environment variable, then you'll still have a word splitting problem.&lt;/div&gt;&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;while read L; do stuff; done&lt;/strong&gt;&lt;/code&gt;: sets the variable &lt;code&gt;$L&lt;/code&gt; to each line in stdin, then executes &lt;code&gt;stuff&lt;/code&gt;. Use this to handle input with spaces. For example, to run foo on every text file in a directory tree, including those with spaces, use &lt;pre class="code"&gt;find . -name '*.txt' | while read L; do foo "$L"; done&lt;/pre&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The last tip has a caveat: a piped command executes in a subshell with its own scope. Thus, if I use &lt;code&gt;cmd | while read L; do stuff; done&lt;/code&gt;, variables set in &lt;code&gt;stuff&lt;/code&gt; are not available outside of the loop. For example, if I want to run &lt;code&gt;foo&lt;/code&gt; on every text file, then print how many times &lt;code&gt;foo&lt;/code&gt; succeeded, I could try this:&lt;/p&gt;
&lt;pre class="code"&gt;
I=0
find . -name '*.txt' | while read L; do foo "$L" &amp;amp;&amp;amp; let I++; done
echo $I
&lt;/pre&gt;
&lt;p&gt;However, this prints &lt;code&gt;0&lt;/code&gt;. The reason is because &lt;code&gt;$I&lt;/code&gt; outside the pipe is a different variable than &lt;code&gt;$I&lt;/code&gt; inside the pipe. To fix this, avoid a pipe using a trick from my &lt;a href="http://blog.dedrop.org/2008/02/bash-command-line-programming.html"&gt;earlier post&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="code"&gt;
I=0
while read L; do foo "$L" &amp;amp;&amp;amp; let I++; done &amp;lt; &amp;lt;(find . -name '*.txt')
echo $I
&lt;/pre&gt;
&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/3QeDGP10zL4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/4011733399524989015/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=4011733399524989015" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/4011733399524989015?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/4011733399524989015?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/3QeDGP10zL4/bash-command-line-programming-flow.html" title="Bash Command-line Programming: Flow Control" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>6</thr:total><feedburner:origLink>http://www.dedrop.org/2008/02/bash-command-line-programming-flow.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QCQHk_eyp7ImA9WxZWE0U.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-9164235078959070349</id><published>2008-02-22T13:26:00.023-08:00</published><updated>2008-03-12T22:16:01.743-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-12T22:16:01.743-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="research" /><category scheme="http://www.blogger.com/atom/ns#" term="lifehack" /><title>Managing papers with GMail</title><content type="html">&lt;p&gt;As a graduate student, I read a lot of papers. Then, I often want to write notes about these papers, categorize them, find them quickly, etc. However, despite being a common problem for graduate students (or anyone else keeping track of documents), there are few free solutions that are any good. Thus, I rolled my own using &lt;a href="http://mail.google.com/"&gt;GMail&lt;/a&gt;.&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cIG3mHzb9ek/R787jpR9e8I/AAAAAAAAACc/JlHESDm7WBA/s1600-h/gmail-papers-list.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/R787jpR9e8I/AAAAAAAAACc/JlHESDm7WBA/s400/gmail-papers-list.png" alt="" id="BLOGGER_PHOTO_ID_5169916380807265218" border="0" /&gt;&lt;/a&gt;

&lt;span id="cut"&gt;

&lt;h2&gt;Available Solutions are Limited&lt;/h2&gt;
&lt;p&gt;Unfortunately, there aren't many free solutions for managing papers. In fact, the only decent one I've found is Richard Cameron's &lt;a href="http://www.citeulike.org/"&gt;CiteULike&lt;/a&gt;. CiteULike provides all the necessities: online storage, tagging, metadata search, and note taking. It also has two other draws: one-click paper bookmarking from supported sites, and social features for sharing and collaboration.&lt;/p&gt;

&lt;p&gt;However, CiteULike has a deal-breaker for me: its search capabilities are very limited. It provides keyword search only over paper titles, author last names, venues, and a part of the abstract (to the best of my knowledge, since it doesn't list what it searches). It does not search the paper's full text, or even your notes. This can make finding papers based on vaguely remembered information very difficult.&lt;/p&gt;

&lt;h2&gt;Using GMail to Manage Papers&lt;/h2&gt;

&lt;p&gt;To address CiteULike's limited search, I decided to manage papers with GMail. The basic idea is that I keep each paper and its notes in an email thread. Then, further notes are replies to the thread. This supports writing richly formatted notes, as well as GMail's search over each paper's full text and any notes I've written.&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cIG3mHzb9ek/R79BP5R9e_I/AAAAAAAAADY/N7cKQf9VFvU/s1600-h/gmail-thread.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_cIG3mHzb9ek/R79BP5R9e_I/AAAAAAAAADY/N7cKQf9VFvU/s400/gmail-thread.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5169922638574615538" /&gt;&lt;/a&gt;

&lt;p&gt;Below, I describe the steps to set up the solution, add a new paper, take notes on a paper, and find a paper I've read. Finally, I compare the advantages of using this solution to using CiteULike.&lt;/p&gt;

&lt;h3&gt;Setup&lt;/h3&gt;

&lt;p&gt;Setup is trivial, consisting of creating a new gmail account for storing papers. I'll refer to this account as &lt;em&gt;papers@gmail.com&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;Adding a New Paper&lt;/h3&gt;
&lt;p&gt;After creating the account, I add new papers by sending email to papers@gmail.com. To ease finding the paper later, I use the following steps, which take only a minute or so:&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cIG3mHzb9ek/R7871JR9e-I/AAAAAAAAACs/xvJ52SEo3JI/s1600-h/gmail-new-paper.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://3.bp.blogspot.com/_cIG3mHzb9ek/R7871JR9e-I/AAAAAAAAACs/xvJ52SEo3JI/s200/gmail-new-paper.png" alt="" id="BLOGGER_PHOTO_ID_5169916681454975970" border="0" /&gt;&lt;/a&gt;

&lt;ol&gt;
&lt;li&gt;Start a new email to papers@gmail.com. Then, fill in the paper information. The key is to put the paper title as the subject, and include the author name, venue, and any other metadata you may want to search for later. The image to the right is an example (click to enlarge).&lt;/li&gt;
&lt;li&gt;Attach the PDF or PS file of the paper to the email.&lt;/li&gt;
&lt;li&gt;Send the email. Since it's to me, it will appear in my inbox.&lt;/li&gt;
&lt;li&gt;Respond to the email with the full text of the paper (if necessary, delete any other text first). To get the text from the PS or PDF file, I use the &lt;a href="http://pages.cs.wisc.edu/%7Eghost/doc/pstotext.htm"&gt;pstotext&lt;/a&gt; or &lt;a href="http://www.linuxcommand.org/man_pages/ps2ascii1.html"&gt;ps2ascii&lt;/a&gt; Linux programs. The &lt;a href="http://freshmeat.net/projects/xclip/"&gt;xclip&lt;/a&gt; program is handy for putting the text in the clipboard, from which I paste it into the response.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These steps accomplish three things. First, they store the PDF or PS of the paper in GMail. Second, they make the paper's full text searchable. Finally, they put the paper's author, venue, year, and other important data in an email with an attachment. This last is important because it lets me search over just this information by restricting the search to emails with attachments (see the section on finding papers below).&lt;/p&gt;

&lt;h3&gt;Taking Notes&lt;/h3&gt;

&lt;p&gt;Papers I have added but not finished reading are in my inbox. As I read a paper, I add notes by replying to the conversation from within GMail (first deleting the quoted text). Thus, my notes can use GMail's rich text features, such as lists and bolding.&lt;/p&gt;

&lt;p&gt;Once I finish reading a paper, I tag the conversation with appropriate tags. Finally, I archive the conversation.&lt;/p&gt;

&lt;h3&gt;Finding a Paper&lt;/h3&gt;

&lt;p&gt;To find a paper, I use GMail's search functionality. This searches the full paper text and all notes, and supports searching on tags and dates. Furthermore, due to how I add papers, I can find paper titles by restricting the search to email subjects, or restrict it to emails with attachments to find author names, venues, and other information in the first email of each paper.&lt;/p&gt;

&lt;h2&gt;Comparing Solutions&lt;/h2&gt;

&lt;p&gt;Given the above procedure, GMail can compete with CiteULike as a system for managing papers. However, though better in some ways, it is also limited in others.&lt;/p&gt;

&lt;p&gt;Specifically, my solution has these limitations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No one-click adding of papers from supported sites.&lt;/li&gt;
&lt;li&gt;No automatic BibTex generation. However, though not quite as good, BibTex entries from &lt;a href="http://citeseer.ist.psu.edu/"&gt;Citeseer&lt;/a&gt;, &lt;a href="http://scholar.google.com/"&gt;Google Scholar&lt;/a&gt;, or other sites can still be saved as notes.&lt;/li&gt;
&lt;li&gt;Can't easily edit existing notes. Instead, must copy and paste the old note into a new note, then delete the original.&lt;/li&gt;
&lt;li&gt;No social or community features, such as sharing papers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, my solution has these advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can search the full text of papers and notes.&lt;/li&gt;
&lt;li&gt;Supports more sophisticated searches, including dates.&lt;/li&gt;
&lt;li&gt;Richly formatted notes, and a nice interface for writing and reading them.&lt;/li&gt;
&lt;li&gt;Can easily print or forward one or all notes about a paper (tip: before printing/forwarding all notes, delete the note containing the full paper text, then restore it afterwards).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Depending on what advantages are more important to you, it may be worth giving this a try.&lt;/p&gt;

&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/r3H5UbQhqKE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/9164235078959070349/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=9164235078959070349" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/9164235078959070349?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/9164235078959070349?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/r3H5UbQhqKE/managing-papers-with-gmail.html" title="Managing papers with GMail" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_cIG3mHzb9ek/R787jpR9e8I/AAAAAAAAACc/JlHESDm7WBA/s72-c/gmail-papers-list.png" height="72" width="72" /><thr:total>6</thr:total><feedburner:origLink>http://www.dedrop.org/2008/02/managing-papers-with-gmail.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0IGQX8_fip7ImA9WxdWEEQ.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-4706713693285842591</id><published>2008-02-11T13:22:00.002-08:00</published><updated>2008-07-03T07:32:00.146-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-03T07:32:00.146-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="bash" /><category scheme="http://www.blogger.com/atom/ns#" term="coding" /><title>Bash Command-line Programming: Redirection</title><content type="html">&lt;p&gt;The bash shell is also a pretty handy programming language. One way to use this is writing scripts. However, another use is writing ad-hoc, one-time-use programs, for very specific tasks, right on the command line. I do this a lot, and find myself using the same techniques over and over.&lt;/p&gt;

&lt;p&gt;In this post, I'll share some useful command-line techniques for redirection.&lt;/p&gt;

&lt;span id="cut"&gt;

&lt;p&gt;There are many ways other than pipes for redirecting stdin and stdout:&lt;/p&gt;
&lt;ul&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;cmd &amp;amp;&amp;gt;file&lt;/strong&gt;&lt;/code&gt;: send both stdout and stderr of &lt;code&gt;cmd&lt;/code&gt; to &lt;code&gt;file&lt;/code&gt;. Equivalent to &lt;code&gt;cmd &gt;file 2&amp;gt;&amp;amp;1&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;cmd &amp;lt;file&lt;/strong&gt;&lt;/code&gt;: pipes the contents of &lt;code&gt;file&lt;/code&gt; into &lt;code&gt;cmd&lt;/code&gt;. Similar to &lt;code&gt;cat file | cmd&lt;/code&gt;, except that while pipes execute in a subshell with their own scope, this keeps everything in the same scope.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;cmd &amp;lt;&amp;lt;&amp;lt;word&lt;/strong&gt;&lt;/code&gt;: expands &lt;code&gt;word&lt;/code&gt; and pipes it into &lt;code&gt;cmd&lt;/code&gt;. &lt;code&gt;word&lt;/code&gt; can be anything you'd type as a program argument. For example, &lt;code&gt;cmd &amp;lt;&amp;lt;&amp;lt;$VAR&lt;/code&gt; pipes the value of &lt;code&gt;$VAR&lt;/code&gt; into &lt;code&gt;cmd&lt;/code&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Also, sometimes programs need arguments on the command line, rather than through stdin:&lt;/p&gt;
&lt;ul&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;cmd $(&amp;lt;file)&lt;/strong&gt;&lt;/code&gt;: expands the contents of &lt;code&gt;file&lt;/code&gt; as arguments to &lt;code&gt;cmd&lt;/code&gt;. For example, if the file &lt;code&gt;toRemove&lt;/code&gt; contains a list of files, &lt;code&gt;rm $(&amp;lt;toRemove)&lt;/code&gt; removes those files.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;cmd1 &amp;lt;(cmd2)&lt;/strong&gt;&lt;/code&gt;: creates a temporary file containing the output of &lt;code&gt;cmd2&lt;/code&gt;, then puts the name of that file as an argument to &lt;code&gt;cmd1&lt;/code&gt;. This is handy when &lt;code&gt;cmd1&lt;/code&gt; expects filename arguments. For example, to see the difference between the contents of directories &lt;code&gt;dir1&lt;/code&gt; and &lt;code&gt;dir2&lt;/code&gt;, use &lt;code&gt;diff &amp;lt;(ls dir1) &amp;lt;(ls dir2)&lt;/code&gt;. This is conceptually equivalent to
&lt;pre class="code"&gt;
ls dir1 &gt;/tmp/contentsDir1
ls dir2 &gt;/tmp/contentsDir2
diff /tmp/contentsDir1 /tmp/contentsDir2
rm /tmp/contentsDir1 /tmp/contentsDir2
&lt;/pre&gt;
(only conceptually, though, since it actually uses &lt;a href="http://www.linuxjournal.com/article/2156"&gt;fifos&lt;/a&gt;). For another handy command for this, check out &lt;a href="http://unixhelp.ed.ac.uk/CGI/man-cgi?comm"&gt;comm&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, you sometimes want to redirect to and from multiple programs at once:&lt;/p&gt;
&lt;ul&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;{cmd1; cmd2; cmd3;} | cmd&lt;/strong&gt;&lt;/code&gt;: pipes output of &lt;code&gt;cmd1&lt;/code&gt;, &lt;code&gt;cmd2&lt;/code&gt;, and &lt;code&gt;cmd3&lt;/code&gt; to &lt;code&gt;cmd&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;&lt;code&gt;&lt;strong&gt;cmd | tee &amp;gt;(cmd1) &amp;gt;(cmd2) &amp;gt;(cmd3) &amp;gt;/dev/null&lt;/strong&gt;&lt;/code&gt;: pipes output of &lt;code&gt;cmd&lt;/code&gt; to &lt;code&gt;cmd1&lt;/code&gt;, &lt;code&gt;cmd2&lt;/code&gt;, and &lt;code&gt;cmd3&lt;/code&gt; in parallel. This trick is a tweak on that &lt;a href="http://www.linuxjournal.com/article/2156"&gt;here&lt;/a&gt;. In the same way &lt;code&gt;&amp;lt;(cmd)&lt;/code&gt; is replaced with a file containing the stdout of &lt;code&gt;cmd&lt;/code&gt;, &lt;code&gt;&amp;gt;(cmd)&lt;/code&gt; is replaced with a file that becomes the stdin of &lt;code&gt;cmd&lt;/code&gt;. Since &lt;code&gt;tee&lt;/code&gt; writes its stdin to each given file, you can combine it with &lt;code&gt;&amp;gt;(cmd)&lt;/code&gt; to send the output of one command to the stdin of many. The final &lt;code&gt;&amp;gt;/dev/null&lt;/code&gt; discards the stdout of tee, which we no longer need. Doesn't come up too often, but it's certainly neat.&lt;/li&gt;

&lt;/ul&gt;

&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/9Szwr_vGTJk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/4706713693285842591/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=4706713693285842591" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/4706713693285842591?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/4706713693285842591?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/9Szwr_vGTJk/bash-command-line-programming.html" title="Bash Command-line Programming: Redirection" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.dedrop.org/2008/02/bash-command-line-programming.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QESX8yfyp7ImA9WxZWE0U.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-5721887766795691426</id><published>2008-01-28T11:59:00.004-08:00</published><updated>2008-03-12T22:15:08.197-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-12T22:15:08.197-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="exercise" /><category scheme="http://www.blogger.com/atom/ns#" term="lifehack" /><category scheme="http://www.blogger.com/atom/ns#" term="weight" /><title>A new lifestyle: losing 85 lbs in 7 months</title><content type="html">&lt;p&gt;Back in late June/early July, I found that I weighed 300 lbs. For the first time, I had to buy a pair of pants at a "big men" store: size 46 waist. I'm a big guy. I'm almost 6'3", and have broad shoulders. But this was ridiculous. I decided to do something.&lt;/p&gt;

&lt;p&gt;I had already tried &lt;a href="http://www.bodyforlife.com/"&gt;Body for Life&lt;/a&gt;, with which I lost (then regained) 30lbs a couple of times. I also ran into some &lt;a href="http://www.fourhourworkweek.com/blog/2007/04/06/how-to-lose-20-lbs-of-fat-in-30-days-without-doing-any-exercise/"&gt;blog&lt;/a&gt; &lt;a href="http://www.fourhourworkweek.com/blog/2007/04/29/from-geek-to-freak-how-i-gained-34-lbs-of-muscle-in-4-weeks/"&gt;posts&lt;/a&gt; by &lt;a href="http://www.fourhourworkweek.com/blog/"&gt;Tim Ferris&lt;/a&gt;. These shared much with Body for Life, but were new enough that I tried them for a few weeks. Unfortunately, they didn't work well for me. The problem was that I was on a diet, and what I really needed was a new lifestyle.&lt;/p&gt;

&lt;table cellpadding="0" cellspacing="0"&gt;
&lt;tbody&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cIG3mHzb9ek/R50busZ9NFI/AAAAAAAAABQ/kk9hKgkRv0k/s1600-h/P10204991.JPG"&gt;&lt;img style="cursor: pointer; border: 0px;" src="http://3.bp.blogspot.com/_cIG3mHzb9ek/R50busZ9NFI/AAAAAAAAABQ/kk9hKgkRv0k/s320/P10204991.JPG" alt="" id="BLOGGER_PHOTO_ID_5160311237044417618" border="0" /&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cIG3mHzb9ek/R50b2sZ9NGI/AAAAAAAAABY/ydtQNsmkJPs/s1600-h/p10403821.jpg"&gt;&lt;img style="cursor: pointer; border: 0px;" src="http://3.bp.blogspot.com/_cIG3mHzb9ek/R50b2sZ9NGI/AAAAAAAAABY/ydtQNsmkJPs/s320/p10403821.jpg" alt="" id="BLOGGER_PHOTO_ID_5160311374483371106" border="0" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan="2" class="caption"&gt;7 months: -85lbs, -10 inches, same jeans&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;span id="cut"&gt;

&lt;p&gt;For me, the difference between a diet and a lifestyle is that a diet is temporary, while a lifestyle is something you can continue forever. A diet is something you can't wait to be done with, while a lifestyle is your daily routine.&lt;/p&gt;

&lt;p&gt;I learned two key lessons while finding a good lifestyle:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;You must want to be fit more than you want to binge or not sweat&lt;/em&gt;. A healthy lifestyle will involve some moderation in eating, and some exercise. So, if binging and not sweating are more important to you than being fit, you'll have a hard time even starting.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;You can't resent your lifestyle&lt;/em&gt;. This is crucial, even if it means a lifestyle that's somewhat less effective. Simply put, if you resent it, eventually you won't do it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Since I quite love stuffing myself, and I hate exercise, one would think I'd resent any lifestyle that required differently. However, I found that if I keep such sacrifices reasonable, the resulting weight loss makes up for them. In other words, I don't resent moderate exercise so much when the pounds are coming off.&lt;/p&gt;

&lt;p&gt;Now I'll describe the lifestyle I settled on after a few weeks of experimentation. I've maintained it with little effort for 7 months, during which I've gone from 300 lbs and size 46 pants to 215 lbs and size 36 (the pictures above show me then and now, wearing the same jeans). Most importantly, it's easy enough to maintain that I see no reason to ever stop. It comprises two aspects: eating right and exercising.&lt;/p&gt;

&lt;h2&gt;Eating Right&lt;/h2&gt;

&lt;p&gt;My goal is to keep my metabolism high, and avoid foods that quickly become fat. Thus, I follow these guidelines:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Eat four to six small meals a day, every 3 to 4 hours (I try to leave feeling slightly hungry; I'll eat again soon enough)&lt;/li&gt;
&lt;li&gt;Eat more protein than carbohydrates.&lt;/li&gt;
&lt;li&gt;Drink lots of water (I drink multiple cups with each meal, and between meals).&lt;/li&gt;
&lt;li&gt;Avoid carbohydrates after lunch.&lt;/li&gt;
&lt;li&gt;Avoid fatty foods, such as dairy, certain cuts of meat, etc.&lt;/li&gt;
&lt;li&gt;No empty calories, such as desserts or non-diet soda.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, there's the two most important guidelines of all:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Once a week, eat whatever and however much you want&lt;/em&gt;. Indian buffets, pizza, ice cream, pasta...anything. Partly, this actually helps you lose weight because it convinces your body there's no famine. But more importantly, it lets you address any cravings that build during the week. My free day is Saturday, and I look forward to it all week.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;If a rare opportunity for food comes along, it's okay to take it&lt;/em&gt;. Opportunities like parties, or travel (I feasted for a whole week while in Vienna). And don't feel bad, or give up your weekly binge for it. Sure, it's sub-optimal. But what's even less optimal is feeling so restricted you give up on your lifestyle entirely. Just make sure it happens rarely. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These last two are the most important guidelines because they keep away that fatal resentment.&lt;/p&gt;

&lt;p&gt;Given these guidelines, my typical meals are as follows:&lt;/p&gt;

&lt;h3&gt;Breakfast: 9:00am&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;1/4 cup low fat cottage cheese, &lt;em&gt;or&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;1 egg, fried in olive oil or hard-boiled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I prefer quick breakfasts, and I'm not hungry in the morning. Thus, a typical breakfast is 1/4 cup of low fat cottage cheese (0.75g saturated fat, 2.5g carbs, 6g protein), with some freshly ground black pepper for seasoning. Another option is an egg fried in olive oil, or hard-boiled.&lt;/p&gt;

&lt;h3&gt;Lunch: 12:30pm&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Moderate portion at restaurant, with vegetables and as much protein as carbs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since it's still early in the day and my metabolism is going, I eat more for lunch than other meals, including more carbs. This makes lunch my most free meal. Anything with moderate portions, vegetables, and low-fat carbs and protein is good. The key is to eat as much protein as carbs, and to leave a bit hungry.&lt;/p&gt;

&lt;div class="captionedImage"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cIG3mHzb9ek/R50218Z9NHI/AAAAAAAAABg/KkH0mTTCre0/s1600-h/200801241233_000561.jpg"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_cIG3mHzb9ek/R50218Z9NHI/AAAAAAAAABg/KkH0mTTCre0/s200/200801241233_000561.jpg" alt="" id="BLOGGER_PHOTO_ID_5160341048412419186" border="0" /&gt;&lt;/a&gt;
&lt;div class="caption"&gt;Typical lunch, from a Peruvian restaurant&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;There are several restaurants near my workplace that I frequent for lunch. I like almost any special at a nearby Chinese restaurant, though I eat only half the rice. There are Peruvian, Korean, and African restaurants with perfect meals (Madison is great for restaurants). There's also a sports bar with a good chicken salad, and a burger joint with lean bison and ostrich burgers. Again, the key is low fat, as much protein as carbs, and leaving a bit hungry. Given this, it's easy to find good lunches almost anywhere.&lt;/p&gt;

&lt;h3&gt;Snack: 4:00pm&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;3 or 4 pieces of beef jerky, &lt;em&gt;or&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;1/3 of a high protein meal replacement bar&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="captionedImage" style="float:left;"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cIG3mHzb9ek/R503BMZ9NJI/AAAAAAAAABw/tb6SJ_UhEqs/s1600-h/200801250226_000711.jpg"&gt;&lt;img style="cursor: pointer;" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/R503BMZ9NJI/AAAAAAAAABw/tb6SJ_UhEqs/s200/200801250226_000711.jpg" alt="" id="BLOGGER_PHOTO_ID_5160341241685947538" border="0" /&gt;&lt;/a&gt;
&lt;div class="caption"&gt;1/3 of a high-protein meal replacement bar for a snack&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Three or four hours later, I have a snack. This is a very light meal, about 100 calories, and protein-heavy. One good snack is three or four pieces of beef jerky (0g saturated fat, 5g carbs, 11g protein). Since I get tired of jerky, I've started alternating with high-protein meal replacement bars from nutrition stores like GNC. I look for low fat and few net carbs, then eat about a third of a bar (1/3 of a Myoplex Carb Control bar is 90 calories, 1.5g saturated fat, 1.3g net carbs, 8.3g protein). The bars aren't as ideal as jerky, but they're nice variety and sweet, which helps to avoid resentment.&lt;/p&gt;

&lt;h3&gt;Dinner: 7:30pm&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;1 cup of mixed vegetables and protein&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I eat dinner after getting home and exercising. Dinner isn't as light as my breakfast or snack, but it's much lighter than lunch. I typically have 1 cup of mixed vegetables and protein. For example, my last few dinners were tofu stir-fry. Other common dinners are seasoned ground beef with peas or broccoli, or leftovers from a Mexican restaurant (no carbs, so a meat dish in sauce, like pollo ranchero or steak in green chile sauce)&lt;/p&gt;

&lt;div class="captionedImage"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cIG3mHzb9ek/R50278Z9NII/AAAAAAAAABo/f2PJ5W5YCGs/s1600-h/200801242014_000651.jpg"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_cIG3mHzb9ek/R50278Z9NII/AAAAAAAAABo/f2PJ5W5YCGs/s200/200801242014_000651.jpg" alt="" id="BLOGGER_PHOTO_ID_5160341151491634306" border="0" /&gt;&lt;/a&gt;
&lt;div class="caption"&gt;Light dinner: tofu stir fry&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Since dinner is small, I typically cook a large portion, then have a little each evening. This applies equally well to take-out: a dinner portion at a Mexican restaurant serves for three or four dinners.&lt;/p&gt;

&lt;p&gt;Dinner is usually my last meal. However, if I'm going to be up past midnight, I sometimes have another snack around 11:00pm.&lt;/p&gt;

&lt;h2&gt;Exercising&lt;/h2&gt;

&lt;p&gt;I detest exercising. I hate it beforehand, during, and afterwards. Thus, to keep resentment low, I minimize exercise time: 20-30 minutes per day, 5-6 days a week. I don't exercise on Saturday, my free day, and I only exercise on Sunday if I feel inspired. However, when I exercise, it's with high intensity.&lt;/p&gt;

&lt;p&gt;I do both cardio and resistance training: on Mondays, Wednesdays, and Thursdays, I use a stationary bike or run; on Tuesdays and Thursdays, I lift weights. Since I hate exercising, if I have an excuse, I'll eventually take it. To combat this, I bought a stationary bicycle, a weight bench, and a dumbbell set. This minimizes time overhead, since I can exercise at home.&lt;/p&gt;

&lt;p&gt;Below I describe my typical workouts. They're all short, but high-intensity.&lt;/p&gt;

&lt;h3&gt;Cardio: Stationary Bike&lt;/h3&gt;

&lt;p&gt;I use a stationary bicycle for cardio, largely because they're relatively inexpensive and fit easily in my apartment. However, my workout works well with any aerobic exercise with variable intensity. It is a variation on the Body for Life cardio workout.&lt;/p&gt;

&lt;p&gt;The workout comprises four parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Low intensity warm-up: 1 minute&lt;/li&gt;
&lt;li&gt;3 sets of&lt;/li&gt;
&lt;ul&gt;
  &lt;li&gt;Mid intensity: 3 minutes&lt;/li&gt;
  &lt;li&gt;High intensity: 3 minutes&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Very high intensity sprint: 1 minute&lt;/li&gt;
&lt;li&gt;Low intensity cool-down: 1 minute&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a tougher workout than it sounds. I push so that I don't think I'll be able to finish the last set. Then, when I do, I push one more minute of all-out sprinting. I am definitely sweaty and exhausted by the end. However, since it only lasts 21 minutes, it's over quickly.&lt;/p&gt;

&lt;h3&gt;Resistance: Bench and Dumbbells&lt;/h3&gt;

&lt;p&gt;Muscle burns fat, so more muscle burns more fat. It also makes you stronger and look better. Thus, resistance training is just as important as cardio. It doesn't take much equipment, either: my whole workout uses only one pair of dumbbells with changeable weights, and a weight bench.&lt;/p&gt;

&lt;p&gt;For each muscle group I exercise, I do three sets of six repetitions, with 30-60 seconds of rest between sets. Then, without rest after the third set, I do a fourth set of six reps, but of a different exercise for the same muscle. For instance, for pectorals, I might do a set of fly, rest, another fly set, rest, a third fly set, and immediately after a set of bench press. The key is to exhaust the muscle; if I can finish the fourth set a couple workouts in a row, then I increase the weight.&lt;/p&gt;

&lt;p&gt;I concentrate on my upper body. I know this is sub-optimal, since it ignores the big muscles in my legs. However, I really don't like lower body exercises, and they were making me dread my workout. Thus, to minimize resentment, I left my lower body to the stationary bicycle.&lt;/p&gt;

&lt;p&gt;I exercise four muscle groups: chest, biceps, triceps, and shoulders. For each group, I pick a primary and secondary exercise, then swap every few months. These are the exercises I like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chest: &lt;a href="http://www.exrx.net/WeightExercises/PectoralSternal/DBBenchPress.html"&gt;bench press&lt;/a&gt;, &lt;a href="http://www.exrx.net/WeightExercises/PectoralSternal/DBFly.html"&gt;fly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Bicep: &lt;a href="http://www.exrx.net/WeightExercises/Biceps/DBCurl.html"&gt;curl&lt;/a&gt;, &lt;a href="http://www.exrx.net/WeightExercises/Brachioradialis/DBHammerCurl.html"&gt;hammer curl&lt;/a&gt; (technically not bicep, but an accessory muscle)&lt;/li&gt;
&lt;li&gt;Tricep: &lt;a href="http://www.exrx.net/WeightExercises/Triceps/DBTriExt.html"&gt;extension&lt;/a&gt;, &lt;a href="http://www.exrx.net/WeightExercises/Triceps/DBLyingTriExt.html"&gt;lying extension&lt;/a&gt;, &lt;a href="http://www.exrx.net/WeightExercises/Triceps/DBOneArmTriExt.html"&gt;one-arm extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Shoulders: &lt;a href="http://www.exrx.net/WeightExercises/DeltoidAnterior/DBShoulderPress.html"&gt;press&lt;/a&gt;, &lt;a href="http://www.exrx.net/WeightExercises/DeltoidLateral/DBRaises.html"&gt;raise&lt;/a&gt;, &lt;a href="http://www.exrx.net/WeightExercises/DeltoidLateral/DBLateralRaise.html"&gt;lateral raise&lt;/a&gt;, &lt;a href="http://www.exrx.net/WeightExercises/DeltoidAnterior/DBFrontRaise.html"&gt;front raise&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Results&lt;/h2&gt;

&lt;p&gt;So far, I've stuck to my new lifestyle for 7 months, without much effort. I've lost 85 pounds, and 10 inches off my waist. I've also gained noticeable muscle. I feel much healthier: I've got more energy, and can participate in many more activities. I've been told I even move much differently. Given all this, I'd say my new lifestyle is a success, and I plan to continue it indefinitely.&lt;/p&gt;

&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/2UHiH6u9SM4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/5721887766795691426/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=5721887766795691426" title="7 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/5721887766795691426?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/5721887766795691426?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/2UHiH6u9SM4/new-lifestyle-losing-85-lbs-in-7-months.html" title="A new lifestyle: losing 85 lbs in 7 months" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_cIG3mHzb9ek/R50busZ9NFI/AAAAAAAAABQ/kk9hKgkRv0k/s72-c/P10204991.JPG" height="72" width="72" /><thr:total>7</thr:total><feedburner:origLink>http://www.dedrop.org/2008/01/new-lifestyle-losing-85-lbs-in-7-months.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkUNQnc5eyp7ImA9WxZRF0s.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-1876229595705931234</id><published>2008-01-23T14:30:00.000-08:00</published><updated>2008-02-11T13:11:33.923-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-02-11T13:11:33.923-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="script" /><title>Dotfile replication with subversion</title><content type="html">&lt;p&gt;Whenever I got a new *nix account, the first thing I did was copy over dotfiles (.bashrc, .vimrc, .screenrc, etc.). Managing these copies was a pain, since I had to manually replicate changes. For example, if I thought of something clever to add to .vimrc, I had to manually add it to .vimrc on every account. Of course, this meant my dotfiles got hopelessly out of sync. This in turn made copying dotfiles to a new account even more painful, since I had to remember which copies were the latest.&lt;/p&gt;

&lt;p&gt;To address this annoyance, I now keep all my dotfiles in a &lt;a href="http://subversion.tigris.org/"&gt;subversion&lt;/a&gt; repository. I assume by now everyone knows of subversion. If not, in short, it's a version control system, like CVS. If you don't know what that is either, chances are you're not worried about managing dotfiles.&lt;/p&gt;

&lt;span id="cut"&gt;

&lt;p&gt;The process was actually pretty simple, comprising only four steps (I'll assume basic familiarity with subversion, or at least a willingness to read the subversion handbook):&lt;/p&gt;

&lt;h2&gt;1. Create the subversion repository&lt;/h2&gt;
&lt;p&gt;See &lt;a href="http://svnbook.red-bean.com/en/1.4/svn.reposadmin.create.html"&gt;here&lt;/a&gt; for creating subversion repositories, and &lt;a href="http://svnbook.red-bean.com/en/1.4/svn.serverconfig.html"&gt;here&lt;/a&gt; for serving them. I called my repository "dotfiles".&lt;/p&gt;

&lt;h2&gt;2. Create the .dotfiles/ directory&lt;/h2&gt;
&lt;p&gt;I'll assume your most recent dotfiles are all on one account. First, on this account, create a .dotfiles/ directory in your home directory. Then, copy the following shell script to .dotfiles/linkToDotFiles.sh:&lt;/p&gt;

&lt;div class="filename"&gt;~/.dotfiles/linkToDotFiles.sh&lt;/div&gt;
&lt;pre class="code"
&gt;#!/bin/sh

SCRIPT_DIR=$(echo $0 | sed -e 's/\(.*\)\/.*/\1/')
SCRIPT_FILE=$(echo $0 | sed -e 's/.*\///')
[ "$SCRIPT_DIR" = "." ] &amp;amp;&amp;amp; SCRIPT_DIR=$(pwd)

for F in $(/bin/ls $SCRIPT_DIR | grep -v $SCRIPT_FILE)
do
   echo -n "$SCRIPT_DIR/$F: "
   if [ -e "$HOME/.$F" ]; then
       echo "~/.$F already exists, skipping."
   else
       if ln -s "$SCRIPT_DIR/$F" "$HOME/.$F"; then
           echo "linked to ~/.$F."
       fi
   fi
done
&lt;/pre&gt;

&lt;p&gt;We'll use this script shortly to create symlinks (i.e., shortcuts) from your home directory to dotfiles in the .dotfiles/.&lt;/p&gt;

&lt;p&gt;Finally, &lt;a href="http://svnbook.red-bean.com/en/1.4/svn.tour.importing.html"&gt;import&lt;/a&gt; .dotfiles/ to your subversion repository&lt;/p&gt;

&lt;h2&gt;3. Add dotfiles to .dotfiles/ and the repository&lt;/h2&gt;
&lt;p&gt;First, copy any dotfile you want to replicate to other accounts into .dotfiles/, but renaming them to remove the leading dot. For example, copy .vimrc to .dotfiles/vimrc. You can do the same for configuration directories, like .vim/. Then, &lt;a href="http://svnbook.red-bean.com/en/1.4/svn.ref.svn.c.add.html"&gt;add&lt;/a&gt; and &lt;a href="http://svnbook.red-bean.com/en/1.4/svn.ref.svn.c.commit.html"&gt;commit&lt;/a&gt; these additions to the repository.&lt;/p&gt;

&lt;h2&gt;4. Replicate dotfiles to a new account&lt;/h2&gt;
&lt;p&gt;First, in the home directory of a new account (not the one where you created the .dotfiles/), &lt;a href="http://svnbook.red-bean.com/en/1.4/svn.tour.initial.html"&gt;checkout&lt;/a&gt; your repository. This will create a .dotfiles/ directory in the new account.&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;Then, run the linkToDotfiles.sh script by using this command from your home directory: &lt;code&gt;bash .dotfiles/linkToDotfiles.sh&lt;/code&gt;. This creates symlinks in your home directory to files in .dotfiles/. For instance, it will create a symlink from ~/.vimrc to ~/.dotfiles/vimrc.&lt;/p&gt;



&lt;p&gt;That's pretty much it. You can add new dotfiles by repeating step 3, and you can &lt;a href="http://svnbook.red-bean.com/en/1.4/svn.tour.cycle.html"&gt;modify&lt;/a&gt; existing dotfiles and &lt;a href="http://svnbook.red-bean.com/en/1.4/svn.tour.cycle.html#svn.tour.cycle.commit"&gt;commit&lt;/a&gt; them from within .dotfiles/. If you commit changes, you can &lt;a href="http://svnbook.red-bean.com/en/1.4/svn.tour.cycle.html#svn.tour.cycle.update"&gt;update&lt;/a&gt; .dotfiles/ in each account, which will &lt;a href="http://svnbook.red-bean.com/en/1.4/svn.tour.cycle.html#svn.tour.cycle.resolve"&gt;preserve&lt;/a&gt; local, uncommitted modifications.&lt;/p&gt;

&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/u5J4_vmzpWQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/1876229595705931234/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=1876229595705931234" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/1876229595705931234?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/1876229595705931234?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/u5J4_vmzpWQ/dotfile-replication-with-subversion.html" title="Dotfile replication with subversion" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.dedrop.org/2008/01/dotfile-replication-with-subversion.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUcCQn49fyp7ImA9WxZWE04.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-4675725153358732476</id><published>2008-01-18T19:55:00.001-08:00</published><updated>2008-03-12T08:51:03.067-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-12T08:51:03.067-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="script" /><title>mediactrl: controlling laptop media buttons</title><content type="html">My laptop media buttons don't do quite what I want. Specifically, I want
&lt;ul&gt;
&lt;li&gt;Volume changes to affect multiple channels.&lt;/li&gt;
&lt;li&gt;A sound to play when I change volume.&lt;/li&gt;
&lt;li&gt;Play/pause, forward, rewind, and stop to control whatever application I'm using, not just always the same one (e.g., pause the video if I'm watching a video, but the music if I'm listening to music).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I first wrote a script for volume changing and media control, then told KDE to call it when I press media buttons.

&lt;span id="cut"&gt;

&lt;p&gt;Modifying multiple channels and playing a sound on volume changes is trivial. Controlling multiple media players is trickier. A heuristic that works well is to have a list of players that are controlled in order. In my case, I first list my video players, kaffeine and kplayer, then my music player, amarok. Thus, since amarok is always running, the media buttons control it by default. However, when I watch a video with kplayer, the media buttons control it instead because I listed it before amarok.

&lt;p&gt;The player list, and other parameters, are in a config file:&lt;/p&gt;

&lt;div class="filename"&gt;/etc/mediactrl.conf&lt;/div&gt;
&lt;pre class="code"
&gt;################################################################################
# Volume settings
################################################################################

# What percent to step on volume up/down
VOL_STEP_PERCENT=5

# The sound to play when volume is changed
VOL_NOTIFICATION_SOUND="/usr/share/sounds/KDE_Click.wav"

# The player to use when volume is changed (default is /usr/bin/aplay)
#VOL_NOTIFICATION_PLAYER="/usr/bin/artsplay"

# Comma-separated list of channels to alter (default is "PCM")
VOL_CHANNELS="Master, Master Mono, Headphone, PCM"


################################################################################
# Media player settings
################################################################################

# Comma-separated list of media players in the order in which they should be
# checked. (these need to be the actual command name). For each of these, the
# command to be run when play/pause, stop, prev, and next are pressed should be
# specified. Examples are below.
MEDIA_PLAYERS="kaffeine, kplayer, amarok"

kaffeine_playpause='dcop kaffeine KaffeineIface pause'
kaffeine_stop="dcop kaffeine KaffeineIface stop"
kaffeine_prev="dcop kaffeine KaffeineIface posMinus"
kaffeine_next="dcop kaffeine KaffeineIface posPlus"

kplayer_playpause="dcop kplayer kplayer-mainwindow#1 activateAction player_pause"
kplayer_stop="dcop kplayer kplayer-mainwindow#1 activateAction player_stop"
kplayer_prev="dcop kplayer kplayer-mainwindow#1 activateAction player_backward"
kplayer_next="dcop kplayer kplayer-mainwindow#1 activateAction player_forward"

amarok_playpause="dcop amarok player playPause"
amarok_stop="dcop amarok player stop"
amarok_prev="dcop amarok player prev"
amarok_next="dcop amarok player next"&lt;/pre&gt;

&lt;p&gt;For each player, the config specifies commands to execute for each media button. Since I happen to use all KDE apps, these commands are calls to &lt;a href="http://en.wikipedia.org/wiki/DCOP"&gt;dcop&lt;/a&gt;. The config should be placed in /etc/mediacntrl.conf.

&lt;p&gt;The script itself is below:&lt;/p&gt;

&lt;div class="filename"&gt;mediactrl&lt;/div&gt;
&lt;pre class="code"
&gt;#!/bin/bash

function usage() {
  echo "Usage: mediactrl &lt;playpause|stop|prev|next|volume&gt;"
  echo "  playpause    - toggles play/pause on active media player"
  echo "  stop         - stops play on active media player"
  echo "  prev         - goes to previous on active media player"
  echo "  next         - goes to next on active media player"
  echo "  volume &lt;cmd&gt; - alters volume. &lt;cmd&gt; is up, down, mute, unmute, or toggle"
  exit
}

if [ ! -f /etc/mediactrl.conf -o ! -r /etc/mediactrl.conf ]; then
   echo "Cannot read /etc/mediactrl.conf!" &gt;&amp;amp;2
   exit 1
fi
. /etc/mediactrl.conf

case "$1" in
   playpause|stop|prev|next)
       echo $MEDIA_PLAYERS | perl -ne 's/,\s*/\n/g; print' | while read PLAYER; do
           if pgrep -u "$USER" "$PLAYER" &gt; /dev/null; then
               eval CMD="\${${PLAYER}_${1}}"
               [ -n "$CMD" ] &amp;amp;&amp;amp; eval "$CMD"
               break
           fi
       done
       ;;
   volume)
       case "$2" in
           up|down)
               echo ${VOL_CHANNELS:=PCM} | perl -ne 's/,/\n/g; print' | while read CHANNEL; do
                   if [ -z "$VOL" ]; then
                       VOL=$(amixer get "$CHANNEL" | grep % | head -n 1 | sed -e 's/.*\[\(.*\)%\].*/\1/')
                       PLUS_MINUS=$(if [ "$2" = "up" ]; then echo "+"; else echo "-"; fi)
                       VOL=$((VOL $PLUS_MINUS ${VOL_STEP_PERCENT:=5}))
                       [ $VOL -lt 0 ] &amp;&amp; VOL=0
                       amixer set "$CHANNEL" "$VOL%" &gt; /dev/null
                       dcop kded kmilod displayProgress "Volume " "$VOL"
                   else
                       amixer set "$CHANNEL" "$VOL%" &gt; /dev/null
                   fi
               done
               ;;
           mute|unmute|toggle)
               echo ${VOL_CHANNELS:=PCM} | perl -ne 's/,/\n/g; print' | while read CHANNEL; do
                   amixer set "$CHANNEL" "$2" &gt; /dev/null
               done

               CHANNEL=$(echo $VOL_CHANNELS | sed -e 's/,.*$//')
               MUTE=$(amixer get "$CHANNEL" | grep % | head -n 1 | sed -e 's/.*\[\(.*\)\]/\1/')
               dcop kded kmilod displayText "Sound $MUTE"
               ;;
           *) usage;;
       esac

       [ -n "$VOL_NOTIFICATION_SOUND" ] &amp;amp;&amp;amp; eval "${VOL_NOTIFICATION_PLAYER:=/usr/bin/aplay}" "$VOL_NOTIFICATION_SOUND" 1&gt;/dev/null 2&gt;&amp;amp;1
       ;;
   *) usage ;;
esac&lt;/cmd&gt;&lt;/cmd&gt;&lt;/playpause|stop|prev|next|volume&gt;&lt;/pre&gt;

&lt;p&gt;The bit of craziness with setting volumes ensures all channels are truly set to the same level.

&lt;p&gt;Note that this script was written for a laptop running Kubuntu, and may need tweaking for other settings. For example, it uses kmilo to display a volume bar, which will not work unless the kmilo service is running.

&lt;p&gt;Once this script is executable (&lt;code&gt;chmod u+x mediactrl&lt;/code&gt;), I map it to the laptop media buttons through the KDE Accessibility settings (K Menu -&gt; System Settings -&gt; Accessibility -&gt; Input Actions). Voila! More intelligent media buttons.

&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/30ECj_7jqKE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/4675725153358732476/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=4675725153358732476" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/4675725153358732476?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/4675725153358732476?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/30ECj_7jqKE/mediactrl-controlling-laptop-media.html" title="mediactrl: controlling laptop media buttons" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>8</thr:total><feedburner:origLink>http://www.dedrop.org/2008/01/mediactrl-controlling-laptop-media.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUcAQnk7cCp7ImA9WxZWE04.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-8425709588202736974</id><published>2008-01-14T14:44:00.001-08:00</published><updated>2008-03-12T08:50:43.708-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-12T08:50:43.708-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="thoughts" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><title>Gentoo to Ubuntu, or bottom-up to top-down</title><content type="html">&lt;p&gt;After many years of using and proselytizing to others about &lt;a href="http://www.gentoo.org"&gt;Gentoo&lt;/a&gt;, last week, I converted to &lt;a href="http://www.ubuntu.com"&gt;Ubuntu&lt;/a&gt; (&lt;a href="http://www.kubuntu.com"&gt;Kubuntu&lt;/a&gt;, to be precise).

&lt;p&gt;This transition has made me think about how I use computers. Thanks to years of *nixes before user-friendly distros like Ubuntu, my understanding is bottom-up: I start with low-level functionality, then build higher-level abstractions. This is in contrast to most users' top-down understanding: start with provided high-level abstractions, then dig deeper if necessary.

&lt;span id="cut"&gt;
&lt;p&gt;To illustrate the difference, consider connecting to a wireless network. I know that I first bring up the network interface with ifconfig, then assign an ESSID and WEP key with iwconfig, then finally get an IP address with dhcpcd. I can execute these low-level steps by hand. However, to make life easier, I create a script to execute them. I can then extend this script to pick one of a set of networks, run a VPN program after connecting to a particular network, etc. This script is a higher-level abstraction that hides low-level details.

&lt;p&gt;In contrast, a typical user has a top-down understanding; they start with the high-level abstraction. For example, in Kubuntu, the knetworkmanager program puts a nice icon in the system tray from which users manage their networks. The user never needs to know about ifconfig, iwconfig, or dhcpcd. Until something breaks and they have to dig deeper, anyway.

&lt;p&gt;The top-down approach is vital to making computers usable to laymen. For years, Linux effectively required a bottom-up approach, which is one reason it was so inaccessible. This is why it's good to see new distros, like Ubuntu, moving toward a top-down approach.

&lt;p&gt;In keeping with this spirit, I'm trying to use Ubuntu in a top-down manner. In other words, I'm trying to use only the high-level abstractions it provides, without digging into low-level programs and configuration files to build my own. This has worked well enough that I'm recommending Ubuntu to my non-Linux friends. Still, I miss the power and configurability of the bottom-up approach. Which is why you'll periodically see some of my nicer abstractions on this blog.
&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/vMtLwmpiwzw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/8425709588202736974/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=8425709588202736974" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/8425709588202736974?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/8425709588202736974?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/vMtLwmpiwzw/gentoo-to-ubuntu-or-bottom-up-to-top.html" title="Gentoo to Ubuntu, or bottom-up to top-down" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.dedrop.org/2008/01/gentoo-to-ubuntu-or-bottom-up-to-top.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkEESXg9fSp7ImA9WxZTE0o.&quot;"><id>tag:blogger.com,1999:blog-1536634109450452533.post-8568926671835759821</id><published>2008-01-14T12:46:00.000-08:00</published><updated>2008-01-14T21:23:28.665-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-01-14T21:23:28.665-08:00</app:edited><title>And so it begins</title><content type="html">&lt;p&gt;A conversation at Del's with friends &lt;a href="http://severinghaus.org"&gt;Steve&lt;/a&gt; and Jay convinced me to find a place to collect and share random thoughts, ideas, and things. Here it is.

&lt;p&gt;I've got a few things saved up, which I'll post by and by.

&lt;p&gt;Also, as a side note: don't expect this blog to look pretty, barring someone else's template. I'm very left-brained, and though I can recognize prettiness, I have a hard time creating it.&lt;img src="http://feeds.feedburner.com/~r/dedrop/~4/dmlQI9kkRRA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.dedrop.org/feeds/8568926671835759821/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=1536634109450452533&amp;postID=8568926671835759821" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/8568926671835759821?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1536634109450452533/posts/default/8568926671835759821?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/dedrop/~3/dmlQI9kkRRA/and-so-it-begins.html" title="And so it begins" /><author><name>Pedro DeRose</name><uri>http://www.blogger.com/profile/14833075200638108981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://1.bp.blogspot.com/_cIG3mHzb9ek/ShHeiW2gIII/AAAAAAAAAEQ/W1bji7WabVQ/S220/pedrod.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.dedrop.org/2008/01/and-so-it-begins.html</feedburner:origLink></entry></feed>
