<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-27488238</id><updated>2012-01-30T15:50:51.333+01:00</updated><category term='barcamp'/><category term='jrpg'/><category term='lasik'/><category term='fish'/><category term='erlang'/><category term='movies'/><category term='gentoo'/><category term='books'/><category term='gadgets'/><category term='audible'/><category term='elections'/><category term='poland'/><category term='royal mail'/><category term='regexp'/><category term='redcar'/><category term='game theory'/><category term='bioinformatics'/><category term='war'/><category term='firefox'/><category term='css'/><category term='git'/><category term='greece'/><category term='web 2.0'/><category term='dentistry'/><category term='iraq'/><category term='sansa'/><category term='unicode'/><category term='israel'/><category term='dating'/><category term='pagerank'/><category term='greasemonkey'/><category term='reading'/><category term='oil'/><category term='genetics'/><category term='java'/><category term='muhammad'/><category term='video games'/><category term='crackpot'/><category term='security'/><category term='economy'/><category term='graphics'/><category term='textmate'/><category term='medieval 2 total war'/><category term='gaming'/><category term='gui'/><category term='oracle'/><category term='c'/><category term='diet'/><category term='gmp'/><category term='libertarian'/><category term='mac'/><category term='webcomics'/><category term='mp3'/><category term='ubuntu'/><category term='magic the gathering'/><category term='blogging'/><category term='google'/><category term='ruby'/><category term='cooking'/><category term='korea'/><category term='javascript'/><category term='democracy'/><category term='ddr'/><category term='comics'/><category term='perl'/><category term='status'/><category term='hacking'/><category term='military'/><category term='osx'/><category term='market failure'/><category term='evolution'/><category term='climate'/><category term='gnome'/><category term='biology'/><category term='python'/><category term='amazon'/><category term='overcoming bias'/><category term='internet'/><category term='empire total war'/><category term='london'/><category term='blinkenlights'/><category term='usability'/><category term='hardware'/><category term='science'/><category term='arduino'/><category term='linux'/><category term='gtd'/><category term='islam'/><category term='personal'/><category term='kubuntu'/><category term='politics'/><category term='programming'/><category term='dvcs'/><category term='culture'/><category term='startup'/><category term='wii'/><category term='ssh'/><category term='games'/><category term='24c3'/><category term='death penalty'/><category term='go'/><category term='kde'/><category term='stepmania'/><category term='asm'/><category term='seo'/><category term='cool'/><category term='wikipedia'/><category term='ruby on rails'/><category term='ycombinator'/><category term='energy'/><category term='ipod'/><category term='unix'/><category term='audiobooks'/><category term='healthcare'/><category term='rlisp'/><category term='history'/><category term='religion'/><category term='ocaml'/><category term='steam'/><category term='rome total war'/><category term='mercurial'/><category term='health'/><title type='text'>taw's blog</title><subtitle type='html'>The best kittens, technology, and video games blog in the world.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default?start-index=101&amp;max-results=100'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>305</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-27488238.post-5555802646374655918</id><published>2011-05-01T11:26:00.000+02:00</published><updated>2011-05-01T11:26:59.119+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><category scheme='http://www.blogger.com/atom/ns#' term='magic the gathering'/><title type='text'>Friday Night Magic - Red Deck Wins</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-_O2jK0QKxr4/Tb0me1TPtcI/AAAAAAAABBI/rrE28TMkLm8/s1600/ad4ad51a_529b_486a.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="443" src="http://3.bp.blogspot.com/-_O2jK0QKxr4/Tb0me1TPtcI/AAAAAAAABBI/rrE28TMkLm8/s640/ad4ad51a_529b_486a.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;On Friday (that would be 2011-04-29) I took part in my first Magic: The Gathering tournament ever, and I ended up winning it. I never drafted before so I made some notes afterwards and here they are.&lt;br /&gt;&lt;h3&gt;Draft&lt;/h3&gt;&lt;br /&gt;The draft was one Mirrodin Besieged booster, and two Scars of Mirrodin boosters.&lt;br /&gt;&lt;br /&gt;In case you haven't been following Magic, both sets are full of artifacts, almost purely monocolor, have moderate amount of infect, and use metalcraft mechanic, where various cards get significant bonuses if you control 3 or more artifacts.&lt;br /&gt;&lt;br /&gt;In three boosters you'll see - 3 rares/mythics, 9 uncommons, 30 commons, plus as many basic lands as you want, so the deck of 40 cards you need to build will be based on mostly crap commons and crap uncommons. This is far worse than even 100% common Pauper format - there you at least get to choose any commons you want. In booster draft it's mostly commons others didn't want.&lt;br /&gt;&lt;br /&gt;Power creep took place primarily on rare and mythic rare levels, so unlike with constructed, limited's power levels are very low. Majority of the cards will be stuff considered unplayable elsewhere, and the few "playable" cards will lack any consistency or synergy you'd normally expect if you could build the deck from larger set of cards.&lt;br /&gt;&lt;br /&gt;The way draft works, everybody opens one booster, picks one card, then passes the rest to the person on the left, and it continues until all cards have been used. Then second booster goes to the right, and finally third again to the left.&lt;br /&gt;&lt;br /&gt;This introduces a lot of luck into the process. Obviously people will take the best cards in their first few picks, so the first few cards are the most important. The only reason they would not take a great card if it was incompatible (most likely of wrong color) with the deck they got so far. &lt;br /&gt;&lt;br /&gt;So if you're trying to build a deck very similar to what people next to you are making, they'll take all the good cards, and you're screwed.&amp;nbsp; On the other hand if they build something in a completely different color, you'll get a lot of great&lt;br /&gt;cards you can use. Where you sit decides a lot.&lt;br /&gt;&lt;br /&gt;In Mirrodin Besieged booster draft you get to make three big decisions:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;which colors to use&lt;/li&gt;&lt;li&gt;use a lot of artifacts and try to get metalcraft bonuses or not?&lt;/li&gt;&lt;li&gt;use infect or not?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;My constructed experience of playing multicolor decks without dual lands and other solid mana fixing told me to never do that again. In constructed, multicolor requires expensive mana base, and that's the end of it.&lt;br /&gt;&lt;br /&gt;I was quite strongly determined to go monocolor even with crap cards, or at worst mainly monocolor with just a splash of a second color but only if I really really have to. At least due to lack of any dual lands whatsoever it wouldn't matter if it's ally or enemy color.&lt;br /&gt;&lt;br /&gt;Because I wanted monocolor and I couldn't really count on having enough cards of one color - artifact-heavy metalcraft deck was a totally obvious choice. I didn't want to use infect as infect is an all or nothing choice - and with red having so few decent infect cards that wasn't even much of a choice.&lt;br /&gt;&lt;br /&gt;By the way after the tournament I found out I had the only monocolored deck of all players.&lt;br /&gt;&lt;h3&gt;Deck&lt;/h3&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-dk-qDnc5_co/Tb0ms23LkaI/AAAAAAAABBM/-V1V8pv6vkc/s1600/2000913673688669733_rs.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="640" src="http://4.bp.blogspot.com/-dk-qDnc5_co/Tb0ms23LkaI/AAAAAAAABBM/-V1V8pv6vkc/s640/2000913673688669733_rs.jpg" width="448" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;So here's my deck:&lt;br /&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Memnite"&gt;Memnite&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Iron+Myr"&gt;Iron Myr&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Blisterstick+Shaman"&gt;Blisterstick Shaman&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21"&gt;Koth's Courier&lt;/a&gt;&lt;br /&gt;2x &lt;a href="http://magiccards.info/query?q=%21Snapsail+Glider"&gt;Snapsail Glider&lt;/a&gt;&lt;br /&gt;2x &lt;a href="http://magiccards.info/query?q=%21Blade-Tribe+Berserkers"&gt;Blade-Tribe Berserkers&lt;/a&gt;&lt;br /&gt;2x &lt;a href="http://magiccards.info/query?q=%21Ogre+Resister"&gt;Ogre Resister&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Oxidda+Scrapmelter"&gt;Oxidda Scrapmelter&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Flameborn+Hellion"&gt;Flameborn Hellion&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Galvanic+Blast"&gt;Galvanic Blast&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Rally+the+Forces"&gt;Rally the Forces&lt;/a&gt;&lt;br /&gt;2x &lt;a href="http://magiccards.info/query?q=%21Assault+Strobe"&gt;Assault Strobe&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Metallic+Mastery"&gt;Metallic Mastery&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Slagstorm"&gt;Slagstorm&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Golden+Urn"&gt;Golden Urn&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Infiltration+Lens"&gt;Infiltration Lens&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Panic+Spellbomb"&gt;Panic Spellbomb&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Golem%27s+Heart"&gt;Golem's Heart&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Trigon+of+Rage"&gt;Trigon of Rage&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Necrogen+Censer"&gt;Necrogen Censer&lt;/a&gt;&lt;br /&gt;1x &lt;a href="http://magiccards.info/query?q=%21Semblance+Anvil"&gt;Semblance Anvil&lt;/a&gt;&lt;br /&gt;15x &lt;a href="http://magiccards.info/query?q=%21Mountain"&gt;Mountain&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;At first, I even wanted to go with 14 lands - 1/3 lands is entirely reasonable in constructed, right? Especially monocolor. Double especially monored.&lt;br /&gt;&lt;br /&gt;But such low land counts rely purely on abundance of 1-drops and 2-drops, and here there are very few. Most people had 16-18 lands as far as I can tell and that's far more reasonable.&lt;br /&gt;&lt;br /&gt;Very early I got rid of one card - Semblance Anvil - and replaced it with 16th mountain. Together with Iron Myr that increased count of mana sources to 17, which was totally reasonable.&lt;br /&gt;&lt;br /&gt;I had no idea how bad Semblance Anvil would be. I had it three times in my hand, and every single time it was a dead card. It costs you two cards (a huge cost) for some mana savings, and it is only useful if vast majority of your spells have the same type. Mostly artifacts, or mostly creatures, or maybe some tribal tricks. This just never ever happens in draft. Even if I had two creatures and Semblance Anvil in my hand, I would have to exile one of them and waste a turn just to cast the second one more cheaply the next turn. In almost every case an extra Mountain instead would let me cast it turn earlier, and without wasting the other guy. Usually it was even worse.&lt;br /&gt;&lt;br /&gt;I didn't do any other sideboarding - I simply had no red left, nor artifact cards that weren't total garbage.&lt;br /&gt;&lt;h3&gt;Games&lt;/h3&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-SPW2wB4YBwg/Tb0nJ7Ddb3I/AAAAAAAABBU/i4feQ8gz9MM/s1600/TokenRed1-2LolCat.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="522" src="http://4.bp.blogspot.com/-SPW2wB4YBwg/Tb0nJ7Ddb3I/AAAAAAAABBU/i4feQ8gz9MM/s640/TokenRed1-2LolCat.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;There were four rounds. My record was:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;2-0 against Blue-Black&lt;/li&gt;&lt;li&gt;2-0 against Red-Green-Blue&lt;/li&gt;&lt;li&gt;2-1 against Green-White&lt;/li&gt;&lt;li&gt;2-0 against Red-White&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;I also played two more games outside the tournament with this deck, losing one and winning the other. I only had to mulligan in one game, down to 5 cards. I had some not terribly good cards, but I went ahead with them as draft doesn't need to worry about opponent winning on turn 3-4 the way constructed has.&lt;br /&gt;&lt;br /&gt;Many of the games were very close.&lt;br /&gt;&lt;br /&gt;Some of the decks I played against had much better cards, whet considered individually. &lt;a href="http://magiccards.info/query?q=%21Sword+of+Body+and+Mind"&gt;Sword of Body and Mind&lt;/a&gt; and &lt;a href="http://magiccards.info/query?q=%21Thrun,%20the%20Last%20Troll"&gt;Thrun, the Last Troll&lt;/a&gt; have hit the board, but in both cases their timing was too late and they couldn't do much. Even many less powerful card were simply better than anything I had.&lt;br /&gt;&lt;br /&gt;I think all decks I played against - and probably most of those I haven't - suffered from more or less serious consistency problems. Many times I won thanks to my opponent being color screwed. Quite a few times they were mana screwed or mana flooded, and their curve didn't work too well with what they got.&lt;br /&gt;&lt;br /&gt;Many people have splashed some infect. I understand why they did it, as individually they were good cards, and there's only so much you get to work with, but most cards which are good in infect decks, are bad in decks which just splash infect.&lt;br /&gt;&lt;br /&gt;In all games I wasn't countered even once, I had my cards removed in various ways quite often. Some of my opponents tried to get metalcraft as well, but they seemed to have harder time doing this, probably they simply had fewer artifacts.&lt;br /&gt;&lt;br /&gt;At least that's my theory. It's entirely possible that I'm wrong and I simply got lucky this time ;-)&lt;br /&gt;&lt;h3&gt;Cards&lt;/h3&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/--fiYeNbe5TE/Tb0m52HWisI/AAAAAAAABBQ/8P98u9ARuBs/s1600/Cotinia.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="522" src="http://2.bp.blogspot.com/--fiYeNbe5TE/Tb0m52HWisI/AAAAAAAABBQ/8P98u9ARuBs/s640/Cotinia.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Now I'll talk about all cards individually. I'll order the cards from the best to the worst.&lt;br /&gt;&lt;br /&gt;The best card was my only rare &lt;a href="http://magiccards.info/query?q=%21Slagstorm"&gt;Slagstorm&lt;/a&gt;. It saved the game when I used it to clean the board when I was behind. Once I attacked with everything, the opponent let some damage through, and then I cleaned the board of everything. It won the game a few times - people defend their last point of life with everything they got but it's much easier to get them down to 3, and then it's over.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Oxidda+Scrapmelter"&gt;Oxidda Scrapmelter&lt;/a&gt; was really awesome in this deck, as pretty much everyone played with some artifacts. And 3/3 for 4 mana in this format is good.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Iron+Myr"&gt;Iron Myr&lt;/a&gt; generates mana, metalcrafts, and has 1/1 body which can be surprisingly useful.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Infiltration+Lens"&gt;Infiltration Lens&lt;/a&gt; is normally a really good card, but when it doubles as metalcraft pumper it's just amazing.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Blisterstick+Shaman"&gt;Blisterstick Shaman&lt;/a&gt; was usually 2-for-1, but at the very least it damaged the opponent one life.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Flameborn+Hellion"&gt;Flameborn Hellion&lt;/a&gt; - 5/4 with haste and totally irrelevant downside for 6cmc - was my most common wincon. It often got 5 damage the turn it entered the battlefield, and then the opponent would get desperate, stop their attacks, and squandered their resources on chump blocking while my side of the board got bigger and bigger. When I managed to equip it with &lt;a href="http://magiccards.info/query?q=%21Infiltration+Lens"&gt;Infiltration Lens&lt;/a&gt; it was game over same turn.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Koth%27s+Courier"&gt;Koth's Courier&lt;/a&gt; was just amazing as long as my opponent played green. 2 damage per turn means 10 turn clock, and it doesn't really matter on its own. But its presence on the board made every other threat at least twice as thretening, and the opponent would desperately throw all their resources at doing something at least about the other one - even at very unfavourable exchange, and that loss of resources would lose them the game.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Blade-Tribe+Berserkers"&gt;Blade-Tribe Berserkers&lt;/a&gt; were really awesome as long as I had metalcraft - but more often than not I was out of luck here and I missed an artifact or two. With metalcraft it's essentially 4cmc 3/3, opponent sacrifices a creature or gets 6 damage. Almost as good as Oxidda Scrapmelter if it was only more consistent.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Golem%27s+Heart"&gt;Golem's Heart&lt;/a&gt; was very good. As both me and the opponent had plenty of artifacts, it would usually get me enough life to win aggro race while pumping metalcraft. It was the target of opponent's removal spells more often than any other card, including my biggest threats.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Galvanic+Blast"&gt;Galvanic Blast&lt;/a&gt; was able to get rid of pretty big creatures if I had metalcraft. I had to use it without metalcraft once, but then the creature I wanted to get rid of was something small, so it didn't really matter.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Necrogen+Censer"&gt;Necrogen Censer&lt;/a&gt; is 4 damage to player for 3 mana. Normally it would be somewhat too slow, but here it helps with metalcraft.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Ogre+Resister"&gt;Ogre Resister&lt;/a&gt; was a decent early fattie, unplayable in constructed but pretty good in draft.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Memnite"&gt;Memnite&lt;/a&gt; mostly pumped metalcraft, I didn't have many other uses for it, and I rarely even wanted to exchange it for another 1/1 or I'd lose metalcraft bonus. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Snapsail+Glider"&gt;Snapsail Glider&lt;/a&gt; was only OK because it pumped its metalcraft, so its chances of gaining flying were higher than usual. In constructed it would be a crap card - even 2/2 unconditional flier for 3cmc would be highly unimpressive.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Metallic+Mastery"&gt;Metallic Mastery&lt;/a&gt; is an artifact version of Act of Treason, but I'd rather have Act of Treason. I only used it once to steal &lt;a href="http://magiccards.info/query?q=Myr+Propagator"&gt;Myr Propagator&lt;/a&gt; for a turn and use it to make&lt;br /&gt;myself a copy. For the rest of the game we kept creating and wasting Myr Propagators. There aren't really that many non-creature artifacts I could steal, and those I could for example sac for good effect would get prematurely sacced in response to my Metallic Mastery anyway, so it would be a waste.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Trigon+of+Rage"&gt;Trigon of Rage&lt;/a&gt; was very hard to use well. Mostly metalcraft pumping.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Golden+Urn"&gt;Golden Urn&lt;/a&gt; was slower lifegain than Golem's Heart. Mostly metalcraft pumping.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Rally+the+Forces"&gt;Rally the Forces&lt;/a&gt; looks like a very nice card, but in all my games I never had a good opportunity to use it.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Panic+Spellbomb"&gt;Panic Spellbomb&lt;/a&gt; only served to boost metalcraft, or as emergency card draw.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://magiccards.info/query?q=%21Assault+Strobe"&gt;Assault Strobe&lt;/a&gt; was so often &lt;b&gt;almost&lt;/b&gt; what I needed, except I couldn't use it because of its sorcery speed.&lt;br /&gt;&lt;br /&gt;The single biggest disappointment was Semblance Anvil, as I mentioned before.&lt;br /&gt;&lt;h3&gt;Future&lt;/h3&gt;&lt;br /&gt;Is my booster draft experience normal? I'd have expected a lot more monocolored decks, but I had the only one. We just had two sets with plenty of artifacts, now we'll get one with easily splashable phyrexian mana. Shouldn't more people try to build consistent monocolor decks?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-5555802646374655918?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/5555802646374655918/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=5555802646374655918' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/5555802646374655918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/5555802646374655918'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2011/05/friday-night-magic-red-deck-wins.html' title='Friday Night Magic - Red Deck Wins'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-_O2jK0QKxr4/Tb0me1TPtcI/AAAAAAAABBI/rrE28TMkLm8/s72-c/ad4ad51a_529b_486a.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-290094604142127433</id><published>2010-12-10T10:16:00.002+01:00</published><updated>2010-12-10T22:40:48.612+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='redcar'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='osx'/><category scheme='http://www.blogger.com/atom/ns#' term='kde'/><category scheme='http://www.blogger.com/atom/ns#' term='textmate'/><category scheme='http://www.blogger.com/atom/ns#' term='kubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='gnome'/><title type='text'>My Christmas wishlist - redcar and desktop Linux</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/TQHgOIrFXwI/AAAAAAAABAE/qoTdOqlMvq0/s1600/and_we_are_back_by_fofurasfelinas_from_flickr_cc_nc_nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="And we are back by fofurasfelinas from flickr (CC-NC-ND)"&gt;&lt;img alt="And we are back by fofurasfelinas from flickr (CC-NC-ND)" border="0" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/TQHgOIrFXwI/AAAAAAAABAE/qoTdOqlMvq0/s1600/and_we_are_back_by_fofurasfelinas_from_flickr_cc_nc_nd.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Who would have thought my blog would be so high on &lt;a href="http://t-a-w.blogspot.com/2010/04/osx-vs-linux.html"&gt;OSX vs Linux&lt;/a&gt;. Well, this subject never gets old, so here's another instalment.&lt;br /&gt;&lt;br /&gt;For personal reasons which Facebook aptly calls "It's complicated" I haven't had much time to update this blog recently.&lt;br /&gt;&lt;br /&gt;I have so many things I'd like to write about - but &lt;a href="http://en.wikipedia.org/wiki/Marginal_utility"&gt;marginal utility of time&lt;/a&gt; keeps getting in a way - with a lot of my previously free time no longer available, I have to make decisions which of too many things I'd like to do I should drop or postpone, hopefully starting from the least important of them.&lt;br /&gt;&lt;br /&gt;And just like nearly everybody else, I keep &lt;a href="http://en.wikipedia.org/wiki/First_Things_First_%28book%29"&gt;confusing &lt;b&gt;important&lt;/b&gt; with &lt;b&gt;urgent&lt;/b&gt;&lt;/a&gt; - this blog is never really urgent - no cat will die if I leave writing for another day or week - but it surely is not the least important of all things I could be doing, or have been doing in the last month or so. So quadrant two, here I come! &lt;br /&gt;&lt;h3&gt;Macs suck&lt;/h3&gt;GPU in my MacBookPro failed, so I'm temporarily back on Linux, on a desktop box which I was using mostly for gaming.&lt;br /&gt;&lt;br /&gt;I will probably stay on Linux for quite some time, even after I get my laptop back. And they're really slow with repairs - I will forgive them only if they keep my hard drive undisturbed like they promised - my backups were not terribly up to date (about a month old) and what's worse - didn't include everything (just imagine - I don't have kitten picture downloader compatible with the most recent flickr API and I have to download kittens manually!). Now I backup everything to two independent external USB disks just to be sure, so I was prepared for this kind of backup failure, but I don't backup as often as I should - mostly because dual backup is such a pain.&lt;br /&gt;&lt;br /&gt;Anyway, all cost of switching from one system to another must be paid up front - all the time necessary to setup and upgrade the new system, to change my habits and so on. Once the cost is paid (and with this post it will mostly be so), I can as well continue using it - so I might very well wipe out OSX and install Ubuntu on the laptop once I get it - I haven't decided it yet.&lt;br /&gt;&lt;br /&gt;Well, first here's the list of the most important things how Linux (kUbuntu, old install upgraded to 10.4) is way better than OSX:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Polish Dvorak keyboard, thanks to divide. I kept meaning to write one for OSX, but never quite did it. You can write keyboard layouts for OSX as XMLs these days, but sadly there seems to be no way to get XMLs of existing layouts as starting point.&lt;/li&gt;&lt;li&gt;apt-get. Seriously, MacPorts is such a pile of fail compared to apt-get, it's just ridiculous. Imagine that - with apt-get you can upgrade system without breaking anything. It just works! I know, it's crazy!&lt;/li&gt;&lt;li&gt;I mostly develop for EC2, so quite a few things are easier on Linux than on OSX.&lt;/li&gt;&lt;li&gt;konsole and virtual desktops completely destroy Terminal.app and Spaces.&lt;/li&gt;&lt;/ul&gt;Sadly from this point it only gets worse.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/TQHumxnrIdI/AAAAAAAABAI/8h5NvGAAXCw/s1600/rum_tum_tugger_by_trish_hamme_from_flickr_cc_nc_nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Rum Tum Tugger by Trish Hamme from flickr (CC-NC-ND)"&gt;&lt;img alt="Rum Tum Tugger by Trish Hamme from flickr (CC-NC-ND)" border="0" height="628" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/TQHumxnrIdI/AAAAAAAABAI/8h5NvGAAXCw/s640/rum_tum_tugger_by_trish_hamme_from_flickr_cc_nc_nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h3&gt;Desktop Linux sucks&lt;/h3&gt;&lt;br /&gt;When you keep using the same system for long, you stop noticing some problems - you just get used to them, just like Congolese got used to malaria.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And this is actually a big fucking deal. People "in charge" of desktop Linux - be in GNOME, KDE, or whatever - are mostly old-timers. They got so used to all the fail present in desktop Linux, it doesn't seem like a big deal to them.&lt;br /&gt;&lt;br /&gt;The last non-Linux system they used regularly is probably Windows XP or something even older - they have only very faint idea what progress the closed source world have made with OSX and even Windows 7. Did I ever mention I sort of like Windows 7? Not for development of course, but you just don't see fail jumping at you all the time like it used to be on XP and Vista.&lt;br /&gt;&lt;br /&gt;Anyway, the first impression I had once I switched from OSX to KDE was:&lt;br /&gt;&lt;blockquote style="font-size: 120%; font-style: italic;"&gt;Are they fucking trying to reimplement Windows XP here?&lt;/blockquote&gt;&lt;br /&gt;I am deeply disturbed by what I've seen. KDE not only lacks all the awesome new stuff you get in OSX, it also lacks all the awesome old Unix stuff you get in OSX.&lt;br /&gt;&lt;br /&gt;Let's start with the basics - a text editor. Control-A and Control-E don't work. A shortcut as convenient as Control-A instead does something as incredibly useless as selecting entire document. Control-E seems to do nothing. Just like Control-D. Control-K deletes entire line, which is broken, but at least only halfway so.&lt;br /&gt;&lt;br /&gt;Fine, whatever, I thought - Windows noobs also use KDE, and if they want such broken shortcuts it's their problem - I'll just go to keyboard settings and switch to Emacs mode.&lt;br /&gt;&lt;br /&gt;It's such a shame I haven't been recording myself, as the very moment I realized they removed Emacs mode I produced such an awasome stream of Polish and English swear-words that you could write a research paper about bilingual cursing based on it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And amazingly, even mcedit lacks Emacs keybindings these days. How is it even possible that even the supposedly most noob-friendly operating system OSX has standard Emacs keybindings, but Linux doesn't even support them as an option any more? It doesn't even seem possible to set them up shortcut by shortcut.&lt;br /&gt;&lt;br /&gt;At least they still work in konsole+bash, and in gtk-based programs if you add &lt;tt&gt;gtk-key-theme-name = "Emacs"&lt;/tt&gt; to your &lt;tt&gt;~/.gtkrc-2.0&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;Unfortunately even that much barely works. In some contexts Control-F means forward, in some it means search. Control-W changes meaning between close tab and delete previous word - it's an unreliable mess.&lt;br /&gt;&lt;br /&gt;They way OSX does it is simple - one modifier key (Control) is used for text editing, another (Command) for application control. I understand Linux cannot really follow this way, but would it really be that difficult to have a single global mapping between key presses and actions?&lt;br /&gt;&lt;br /&gt;When you think about it most programs use the same shortcuts:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; text editing (control-A, control-E, ...)&lt;/li&gt;&lt;li&gt;copy&amp;amp;paste (command-C, command-V, command-X) &lt;/li&gt;&lt;li&gt;undo stack control (command-Z, command-Y) &lt;/li&gt;&lt;li&gt;document/tab control - save (command-S), load (command-L), close document/tab/window (command-W), new (command-N) etc.&lt;/li&gt;&lt;li&gt;switching between tabs - command-1/2/3/..., control-pageup/pagedown etc.&lt;/li&gt;&lt;li&gt;application control - let's not get into application/window/sdi/mdi mess, there's time for everything and it isn't now - mostly quit (command-Q)&lt;/li&gt;&lt;li&gt;window control - maximize, minimize etc. &lt;/li&gt;&lt;li&gt;system control - like switching between windows/applications, making screenshots, locking screen, some dashboard, start menu, volume up/down/mute - the list is pretty long, but they're global by definition&lt;/li&gt;&lt;/ul&gt;There are very few applications that really need more than a few important shortcuts to this list. Some of them are important applications (Office, Photoshop, Emacs), but you'll be mostly using these anyway.&lt;br /&gt;&lt;br /&gt;I would be surprised if GNOME/KDE lacked infrastructure for this (what's gtk-key-theme if not half of this?) - it just that nobody bothered doing this consistently. Or if they did, their efforts were blocked by some old-timer whose last recollections of life outside desktop Linux is Windows 3.11.&lt;br /&gt;&lt;blockquote style="font-size: 120%; font-style: italic; font-weight: bold;"&gt;My Christmas wish: Good keybindings for Linux that won't make me miss OSX, or Linux from a decade ago.&lt;/blockquote&gt;&lt;br /&gt;It cannot be that hard, as Linux used to have those before losing them very recently.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/TQHvZfeT42I/AAAAAAAABAM/bLds9oj_gaw/s1600/kocka_z_mincovni_by_abejorro34_from_flickr_cc_nc.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Kočka z Mincovní by abejorro34 from flickr (CC-NC)"&gt;&lt;img alt="Kočka z Mincovní by abejorro34 from flickr (CC-NC)" border="0" height="480" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/TQHvZfeT42I/AAAAAAAABAM/bLds9oj_gaw/s640/kocka_z_mincovni_by_abejorro34_from_flickr_cc_nc.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h3&gt;Redcar&lt;/h3&gt;Let's continue the story. Kate and gedit were various levels of unusable due to keybindings, as was mcedit in Emacs mode which I mostly use over ssh instead of real Emacs. I could try the actual Emacs, but after a few years of TextMate it just isn't the same. Not even close.&lt;br /&gt;&lt;br /&gt;Fortunately the totally awesome &lt;a href="http://danlucraft.com/"&gt;Daniel Lucraft&lt;/a&gt; wrote a TextMate-like editor in JRuby &lt;a href="http://redcareditor.com/"&gt;redcar&lt;/a&gt;. Every time I check it it gets more and more awesome, and it's safe to say it's already far better than any other editor you can get on Linux. &lt;br /&gt;&lt;br /&gt;Of course I wouldn't be myself if I didn't start bitching. So here's my quick list of easy improvements to redcar.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Any of these will make a great Christmas gift for me&lt;/b&gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Context menu absolutely needs TextMate-like "&lt;a href="http://brandonmathis.com/blog/2010/06/08/quicktip-textmates-filter-through-command/"&gt;Filter through command&lt;/a&gt;" features and all its options (mostly "input selection / output selection", "input selection / output create new document", and "input document / output create new document", but others are occasionally useful as well). This is easily one of top five most useful  features of TextMate ever and it's really not that hard.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Getting a lot of common bundles/plugins/snippets/whatever-else-it-is-using with a single command. Batteries included you know.&lt;/li&gt;&lt;li&gt;Tab size control really needs to be visible by default. I'm sure this is one of the first thing requested by half of the redcar users, so why not just do it?&lt;/li&gt;&lt;li&gt;Support for Control-A and Control-E, seriously. &lt;b&gt;Patch on github&lt;/b&gt;.&lt;/li&gt;&lt;li&gt;Syntax highlighting often breaks. Now making it unbreakable would require massive architectural charget, but can we at least get easy refresh shortcut, or refresh on switching tabs (if edited since last switch)? Most documents are not that huge, so it shouldn't be a major performance problem, right?&lt;/li&gt;&lt;li&gt;Does it really need to create .redcar directories everywhere? It creates ~/.redcar/ already, won't that be enough?&lt;/li&gt;&lt;li&gt;Unixy interface like &lt;tt&gt;mate&lt;/tt&gt; command. Right now starting &lt;tt&gt;redcar ~/some/dir&lt;/tt&gt; from console makes it stay there and keep producing &lt;tt&gt;java.lang.IllegalArgumentException&lt;/tt&gt; stack traces. It's definitely a good thing for developing redcar, but would it be possible to get some command line switches to make &lt;tt&gt;redcar&lt;/tt&gt; fork away like &lt;tt&gt;mate&lt;/tt&gt; command does?&lt;/li&gt;&lt;li&gt;TextMate-compatible Control-K - it should delete everything between cursor and end of line (right), or delete linebreak if cursor is already at end of line. Right now in redcar pressing Control-K multiple times doesn't do anything useful. &lt;b&gt;Patch on github&lt;/b&gt;.&lt;/li&gt;&lt;li&gt;Can we get some sort of 2D selections? Even Firefox has them for tables with control-mouse. I understand they might be too hard architecturally, but it would be pretty awesome. &lt;b&gt;Ctrl+B does exactly that already&lt;/b&gt;.&lt;/li&gt;&lt;li&gt;Control-T (search file) should ignore spaces like in TextMate. I know this behaviour is irregular, but it just makes so much more sense to me to search for "login ctr test" like in TextMate than for "loginctrtest" redcar wants. By the way history for Control-T is pretty awesome.&lt;b&gt;Patch on github&lt;/b&gt;.&lt;/li&gt;&lt;li&gt;Search and replace within selection.&lt;/li&gt;&lt;li&gt;Not in TextMate but would be awesome: support for filtering by full path with Control-T, like &lt;tt&gt;login/index&lt;/tt&gt;.&lt;/li&gt;&lt;/ul&gt;That was a lot of bitching - but then isn't this exactly what this blog is made for?&lt;br /&gt;&lt;br /&gt;Yes, I'm aware of &lt;a href="https://github.com/redcar/redcar/wiki/WishList"&gt;official redcar wishlist&lt;/a&gt; and I might convert some of this bitching to requests and maybe even - imagine that - patches (I've been doing quite a lot of JRuby lately, so I'm no longer scared of JVM). Just not now. Marginal utility of time, "it's complicated", &lt;a href="http://en.wikipedia.org/wiki/Getting_Things_Done"&gt;delegate if possible&lt;/a&gt; and so on... You know, the usual excuses for not contributing.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;EDIT: &lt;a href="https://github.com/taw/redcar"&gt;I fixed a few easy ones at github&lt;/a&gt;.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;I'm not done yet&lt;/h3&gt;&lt;br /&gt;Silly me, I thought I would be able to include my Ruby standard library wishlish in this post - this will have to wait, there are two weeks left so I might find an evening for that as well - and that will be a ridiculously long list - and judging from &lt;a href="http://t-a-w.blogspot.com/2010/07/we-need-syntax-for-talking-about-ruby.html"&gt;reactions to my preliminary post about Ruby stdlib&lt;/a&gt; it will make everybody hate me even more than they hate me now.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;So just a few minor additions to my Christmas wishlish, just in case robot Santa or spirit of Kwanzaa or your personification of gift giving of choice happens to be deluded enough to think I was nice enough that my wishlist so far is somehow not yet long enough&lt;/b&gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Is there anything like OmniFocus for Linux?&lt;/li&gt;&lt;li&gt;Sound system on Linux is still broken in 2010. Skype mysteriously cannot find my microphone, even after spending far too much time trying various alsamixer and Skype options. Rebooting to Windows on same hardware - zero problems, works out of the box. Can we please get this?&lt;/li&gt;&lt;li&gt;System settings are just dreadful. Why cannot we have everything in one place, instead of some options in General, some in Advanced, some inside various programs, and some who knows where. This has always been a big weakness of Linux, but total lack of progress is disturbing. Even something as simple as telling Linux to automatically mount an external disk is nontrivial - in dolphin there's nothing like it in context either on disk icon on sidebar, or disk mountpoint directory in /media. Searching "usb" or "external" in system settings also returned nothing. It turns out I need to switch to "Advanced" tab and search for "removable". I seem to recall this used to work far better than that, but maybe that was GNOME. Is anybody working to improve this situation?&lt;/li&gt;&lt;/ul&gt;By the way is there any major reason for using KDE versus GNOME these days? It used to be so that GNOME had much worse Windows-itis and hypernoobemia than KDE, but these days I'm getting the impression that noobness rankings changed from Mac &amp;gt; Windows &amp;gt; GNOME &amp;gt; KDE to Mac &amp;gt; Windows &amp;gt; KDE = GNOME &amp;gt; Mac. Yes - somehow Macs dominate both total noob and expert user part of the spectrum.&lt;br /&gt;&lt;br /&gt;Or actually - the person who does the most to fulfil my wishlist gets to decide KDE vs GNOME for me.&lt;br /&gt;&lt;ul&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-290094604142127433?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/290094604142127433/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=290094604142127433' title='33 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/290094604142127433'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/290094604142127433'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/12/my-christmas-wishlist-redcar-and.html' title='My Christmas wishlist - redcar and desktop Linux'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_IYGc_MWwkfw/TQHgOIrFXwI/AAAAAAAABAE/qoTdOqlMvq0/s72-c/and_we_are_back_by_fofurasfelinas_from_flickr_cc_nc_nd.jpg' height='72' width='72'/><thr:total>33</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-6747122240757844768</id><published>2010-10-12T22:48:00.002+02:00</published><updated>2010-10-13T06:16:03.631+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='science'/><title type='text'>Blogging about Robin Hanson is not about blogging about Robin Hanson</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/TLTIe1EJxQI/AAAAAAAAA_4/6GTA7f_hxkA/s1600/fancy_snug_in_my_bed_by_hairlover_from_flickr_cc-by.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Fancy, snug in my bed by Hairlover from flickr (CC-BY)"&gt;&lt;img alt="Fancy, snug in my bed by Hairlover from flickr (CC-BY)" border="0" height="481" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/TLTIe1EJxQI/AAAAAAAAA_4/6GTA7f_hxkA/s640/fancy_snug_in_my_bed_by_hairlover_from_flickr_cc-by.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;This post is a semi-confession, and the difference between "I find X" statements and "X" statements is significant.&lt;br /&gt;&lt;br /&gt;When I don't like something, I can of course come with some reasonable-sounding arguments specific to the particular subject, but usually "X is not really about X, it's just status seeking game gone awry" has no trouble getting onto such list. Sometimes high, sometimes not, but it's rarely missing.&lt;br /&gt;&lt;br /&gt;When I like something, I tend to believe "X is not about X" type of arguments don't really apply - maybe there's some status seeking involved, but it surely cannot be that significant.&lt;br /&gt;&lt;br /&gt;So here's my main point - &lt;b&gt;"X is not about X" is not about X not being about X&lt;/b&gt;. It is a cheap and hard to refute shot at X to lower its status - essentially "X is not about X" argument is really about raising speaker's status relative to X.&lt;br /&gt;&lt;h3&gt;Science is not about science&lt;/h3&gt;&lt;br /&gt;For example I find it intuitively obvious that academic science is mostly silly status game, with just tiny fraction of effort directed towards seeking important truth about reality.&lt;br /&gt;&lt;br /&gt;How else can you explain:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;persistent disregard for statistics, reliance on cargo cult statistics like p-values and PCA&lt;/li&gt;&lt;li&gt;vast majority of papers not getting even a single replication attempt&lt;/li&gt;&lt;li&gt;most research being about irrelevant minutiae &lt;/li&gt;&lt;li&gt;nobody bothered by research results being not publicly available online&lt;/li&gt;&lt;li&gt;review by "peers", not by outsiders&lt;/li&gt;&lt;li&gt;obsession about citations&lt;/li&gt;&lt;li&gt;obsession regarding where something gets published&lt;/li&gt;&lt;li&gt;routinely shelving results you don't like&lt;/li&gt;&lt;/ul&gt;This is exactly what we'd expect if it was just one big status seeking game! Truth seeking would involve:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;everything being public from even before experiments start&lt;/li&gt;&lt;li&gt;all results being published online immediately, most likely on researcher's blog&lt;/li&gt;&lt;li&gt;results being routinely reviewed by outsiders with most clue about statistics and methodology at least as much as by insiders with domain knowledge&lt;/li&gt;&lt;li&gt;journals wouldn't exist at all&lt;/li&gt;&lt;li&gt;citations wouldn't matter much, hyperlinks work just as well - and nobody would bother with silliness like adding classics from 1980s to bibliography like it's still commonly done in many fields&lt;/li&gt;&lt;li&gt;most research focusing on the most important issues &lt;/li&gt;&lt;li&gt;vast majority of effort being put towards reproducing others' research - if it was worth studying, it's worth verifying; and if it's not worth verifying, why did anyone bothered with original research in the first place?&lt;/li&gt;&lt;li&gt;serious statistical training as part of curriculum in place of current sham in most disciplines&lt;/li&gt;&lt;/ul&gt;It's a miracle that anything ever gets discovered at all! It would be a very cheap shot, but it's really easy to finish this line of reasoning by attributing any genuine discovery as an attempt at acquiring funding from outsiders so the status game can continue. And isn't there a huge correlation between commercial funding of science and rate of discovery?&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/TLTIg36-lfI/AAAAAAAAA_8/HEkuTXw4pyI/s1600/the_notsofat_one__playing_with_water_by_jeffomatic_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="The Not-So-Fat One - playing with water by jeff-o-matic from flickr (CC-NC-ND)"&gt;&lt;img alt="The Not-So-Fat One - playing with water by jeff-o-matic from flickr (CC-NC-ND)" border="0" height="640" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/TLTIg36-lfI/AAAAAAAAA_8/HEkuTXw4pyI/s640/the_notsofat_one__playing_with_water_by_jeffomatic_from_flickr_cc-nc-nd.jpg" width="460" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Medicine is definitely about health&lt;/h3&gt;&lt;br /&gt;And here's something I like - modern medicine. It's just obvious to me it's about health and I find claims to the contrary ridiculous.&lt;br /&gt;&lt;br /&gt;Yes, plenty of medical interventions have only weak evidence behind them, but this is true about anything in the universe. Hard evidence is an exception (also see previous section) and among few things having hard evidence, medical interventions are unusually well represented.&lt;br /&gt;&lt;br /&gt;And yes, a few studies show that medical spending might not be very beneficial on the margin - mostly in short term, mostly in United States, mostly on small samples, always without replication, and I could go on like this.&lt;br /&gt;&lt;br /&gt;Anyway, modern medicine has enough defenders without me getting involved, so I'll just stop here. To me it just looks like what you'd get if it was about health, and it doesn't look like what you'd get if it was about status seeking, even if a tiny bit of it gets into it somehow.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;But notice how the argument goes. Conclusions first, and you can always fit or refute status seeking in arguments later. This bothered me until I've seen even bigger point - it all works as well when you replace "seeking status" with "making money" or any other motivator!&lt;br /&gt;&lt;br /&gt;Compare these semi-silly examples:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Writing books is not about content, it's about money &lt;/li&gt;&lt;li&gt;Writing blog posts is not about content, it's about status&lt;/li&gt;&lt;li&gt;Food industry is not really about food, it's about money&lt;/li&gt;&lt;li&gt;Organic food is not really about food, it's about status &lt;/li&gt;&lt;li&gt;Commercial software is not really about software, it's about money&lt;/li&gt;&lt;li&gt;Open Source is not really about software, it's about status&lt;/li&gt;&lt;/ul&gt;This is just universal and an argument like that can be applied to nearly everything. But in all these &lt;b&gt;money and status are only mechanisms of compensation&lt;/b&gt; - people optimize for money or status because that's what people are good at, but the only reason there's a connection between money/status and given action or product is underlying connection with desirable outcome.&lt;br /&gt;&lt;br /&gt;To pull an Inception - "X is about status, not X" is about status, not about X being about status, not X.&lt;br /&gt;&lt;br /&gt;PS. &lt;a href="http://www2.uah.es/jmc/ai53.pdf"&gt;Here's a paper claiming that 2/3 of highly cited papers had serious problems getting published at all because of peer review&lt;/a&gt;. How many breakthroughs didn't get published? How many got published and then ignored? How many people didn't even bother, limiting themselves to standard useless minutiae, or staying away from academic science entirely?&lt;br /&gt;&lt;br /&gt;PPS. Here's a few more relevant links:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Basic statistics showing &lt;a href="http://www.plosmedicine.org/article/info:doi/10.1371/journal.pmed.0020124"&gt;"Why Most Published Research Findings Are False"&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.plosmedicine.org/article/info:doi/10.1371/journal.pmed.0040028"&gt;Why replication matters and how little research survives it&lt;/a&gt;. Of over 600 published gene-disease associations claims, 6 survived replication, 160 failed replication, and for most nobody even bothered checking - not a big surprise with 1% success rate.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.overcomingbias.com/2009/04/in-the-latest-american-journal-of-economics-and-sociology-arthur-diamond-presents-a-very-disturbing-resultpolywater-one-of.html"&gt;Scientists who spend time refuting false ideas are punished&lt;/a&gt; (paper gated).&lt;/li&gt;&lt;/ul&gt;Notice how except for medicine nobody seems bothered by this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-6747122240757844768?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/6747122240757844768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=6747122240757844768' title='35 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/6747122240757844768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/6747122240757844768'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/10/blogging-about-robin-hanson-is-not.html' title='Blogging about Robin Hanson is not about blogging about Robin Hanson'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_IYGc_MWwkfw/TLTIe1EJxQI/AAAAAAAAA_4/6GTA7f_hxkA/s72-c/fancy_snug_in_my_bed_by_hairlover_from_flickr_cc-by.jpg' height='72' width='72'/><thr:total>35</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-1892522949260710159</id><published>2010-09-25T03:31:00.001+02:00</published><updated>2011-05-23T05:16:22.168+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='diet'/><title type='text'>Neolithic Counter-Revolution in Diet</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/TJ1P5QbTMSI/AAAAAAAAA_s/TF1wlb9atj4/s1600/cat_grass_om_nom_nom_by_chrisjervis_from_flickr_cc-nc.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Cat grass om nom nom by chris.jervis from flickr (CC-NC)"&gt;&lt;img alt="Cat grass om nom nom by chris.jervis from flickr (CC-NC)" border="0" height="480" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/TJ1P5QbTMSI/AAAAAAAAA_s/TF1wlb9atj4/s640/cat_grass_om_nom_nom_by_chrisjervis_from_flickr_cc-nc.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;All people have silly things to feel proud of, like their country or their soccer team - one unusual thing I feel very proud of myself is Neolithic Revolution. We fucking made it! We're the only beings in the whole damn universe who broke free from bondage of evolution, and that was the main act.&lt;br /&gt;&lt;br /&gt;Like all irrationally proud people, I get easily irritated by all misguided criticism Neolithic Revolution has been getting - by amount of pure hatred it gets you'd think it was run by Justin Bieber and involved kitten sacrifice. Not that there would be any kittens without Neolithic Revolution - it's a true fact!&lt;br /&gt;&lt;br /&gt;The most common thread of criticism is that somehow, with literally over 9000 years of lag, Neolithic food is making us unhealthy and overweight, and if only we could abandon civilization and go back to what was eaten in Paleolithic, we'd all be happy monkey once more.&lt;br /&gt;&lt;br /&gt;This is plainly ridiculous. There's not a single group anywhere in the world even remotely living Upper Paleolithic life any more - even those that get most of their food hunting and gathering have long history of contact, trade, and interbreeding with agriculturalists and pastoralists, and every time you look more closely you'll see they don't really shy away from a bit of farming here and there themselves.&lt;br /&gt;&lt;br /&gt;In other words - our knowledge of Paleolithic life and diet is about as good as our knowledge of mating habits of Hogwarts students - a lot of real fun speculation, and very little hard data.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And no matter where you look - vast majority of people have been unhealthy, with huge infant mortality, and all kinds of other severe health problems. True, cardiovascular problems and obesity are a fairly recent thing, but it is just ridiculous to focus exclusively on them and blame modern diet and lifestyle, while totally disregarding sheer count of much more debilitating diseases it saves us from.&lt;br /&gt;&lt;br /&gt;It's a lot like complaining about Internet leading to more privacy violations, while ignoring how helpful it is in fixing a far more severe problem of not having fucking Internet access in the first place. Whiners gonna whine.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/TJ1QRhkPWDI/AAAAAAAAA_0/rvuTi58zcDQ/s1600/isis_is_an_ouroboros_om_nom_nom_cat_macro_by_benchilada_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Isis is an ouroboros om nom nom cat macro by benchilada from flickr (CC-NC-SA)"&gt;&lt;img alt="Isis is an ouroboros om nom nom cat macro by benchilada from flickr (CC-NC-SA)" border="0" height="640" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/TJ1QRhkPWDI/AAAAAAAAA_0/rvuTi58zcDQ/s640/isis_is_an_ouroboros_om_nom_nom_cat_macro_by_benchilada_from_flickr_cc-nc-sa.jpg" width="584" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;center&gt;&lt;i&gt;&lt;a href="http://www.flickr.com/photos/benchilada/3211371130/"&gt;Isis as an Oroboros&lt;/a&gt;&lt;/i&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Diet by era&lt;/h3&gt;&lt;br /&gt;Getting back on track, I took FAO data, and classified all food consumed into three big groups:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Paleolithic - &lt;b&gt;vegetables, fruit (excluding wine), treenuts, meat, eggs, fish&lt;/b&gt;, seafood, other aquatic products, offal&lt;/li&gt;&lt;li&gt;Neolithic - &lt;b&gt;cereals, pulses, alcoholic beverages, milk, butter, animal fats, starchy roots&lt;/b&gt;, spices, stimulants, miscellaneous&lt;/li&gt;&lt;li&gt;Industrial - &lt;b&gt;sugar, sweeteners, sugarcrops, vegetable oils, oilcrops&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;For nitpickers who want to pick nits, &lt;a href="http://faostat.fao.org/site/655/default.aspx"&gt;here are exact definitions&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;There are a few borderline cases I'll explain before proceeding:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Sugars and sweeteners (HFCS) are undoubtedly extremely recent introduction to diet. &lt;/li&gt;&lt;li&gt;A few vegetable oils like palm kernel oil and olive oil were common in traditional Neolithic, but they're a few percent of total, which is dominated by extremely recent soy, corn, sunflower etc., and they get far far more refining including partial oxidation than they ever used to. Traditional vegetable oils exist, but it would just complicate matters without changing conclusions.&lt;/li&gt;&lt;li&gt;Starchy roots category are almost all Neolithic crops like potatoes, sweet potatoes, and so on.&lt;/li&gt;&lt;li&gt;Minor categories without bold font are rather insignificant, and only included to make percents add up nicely.&lt;/li&gt;&lt;li&gt;Fans of Paleolithic will undoubtedly whine that modern vegetable, meat, etc. are not really Paleo due to all changes in modern agriculture, but by the same logic Neolithic foods are very rapidly disappearing as well. More seriously - in the grand scheme of things an egg is an egg, a pig is a pig, and a nut is a nut. Modern pig is far closer to wild pig than it is to a can of Diet Mountain Dew.&lt;/li&gt;&lt;/ul&gt;Still with me? Can you guess what changed in our diet between 1961 and 2007?&lt;br /&gt;&lt;blockquote style="font-size: 150%;"&gt;Our diet became a lot &lt;b&gt;less Neolithic&lt;/b&gt;, a lot &lt;b&gt;more Paleolithic&lt;/b&gt;, and a lot &lt;b&gt;more Industrial&lt;/b&gt;.&lt;/blockquote&gt;Yes, we eat more Paleolithic, and we're more fatter than when we were eating Neolithic. How do you deal with that, Neolithic-haters?&lt;br /&gt;&lt;br /&gt;Here's full list of countries for which data exists for both 1961 and 2007, percents are Paleolithic:Neolithic:Industrial by calories. Sadly there's no high quality data predating 1961, and for many countries like United States that was halfway through the Neolithic Counter-Revolution in diet.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Albania - 11.75%:80.75%:7.51% - 20.52%:65.36%:14.12%&lt;/li&gt;&lt;li&gt;Algeria - 9.75%:73.61%:16.65% - 11.11%:67.83%:21.06%&lt;/li&gt;&lt;li&gt;Angola - 7.89%:79.36%:12.75% - 9.32%:69.61%:21.07%&lt;/li&gt;&lt;li&gt;Antigua and Barbuda - 15.81%:57.22%:26.96% - 31.47%:46.85%:21.67%&lt;/li&gt;&lt;li&gt;Argentina - 27.36%:54.76%:17.88% - 24.13%:47.73%:28.13%&lt;/li&gt;&lt;li&gt;Australia - 24.36%:54.1%:21.54% - 25.47%:45.74%:28.79%&lt;/li&gt;&lt;li&gt;Austria - 18.21%:63.22%:18.57% - 22.02%:50.83%:27.15%&lt;/li&gt;&lt;li&gt;Bahamas - 23.15%:61.93%:14.93% - 28.53%:50.39%:21.08%&lt;/li&gt;&lt;li&gt;Bangladesh - 3.85%:89.29%:6.86% - 4.28%:84.97%:10.74%&lt;/li&gt;&lt;li&gt;Barbados - 13.98%:60.39%:25.63% - 23.63%:46.47%:29.9%&lt;/li&gt;&lt;li&gt;Belize - 11.35%:74.1%:14.55% - 19.45%:59.28%:21.26%&lt;/li&gt;&lt;li&gt;Benin - 6.94%:81.69%:11.37% - 5.59%:79.67%:14.74%&lt;/li&gt;&lt;li&gt;Bermuda - 29.55%:49.89%:20.56% - 26.64%:47.87%:25.49%&lt;/li&gt;&lt;li&gt;Bolivia - 16.84%:69.13%:14.03% - 20.5%:63.21%:16.29%&lt;/li&gt;&lt;li&gt;Botswana - 8.12%:81.73%:10.15% - 8.33%:68.47%:23.2%&lt;/li&gt;&lt;li&gt;Brazil - 10.84%:64.72%:24.44% - 18.5%:52.16%:29.34%&lt;/li&gt;&lt;li&gt;Brunei Darussalam - 11.3%:60.84%:27.86% - 18.18%:58.17%:23.65%&lt;/li&gt;&lt;li&gt;Bulgaria - 12.09%:73.62%:14.29% - 14.32%:59.42%:26.27%&lt;/li&gt;&lt;li&gt;Burkina Faso - 5.7%:82.29%:12.0% - 4.88%:82.2%:12.92%&lt;/li&gt;&lt;li&gt;Burundi - 12.63%:86.26%:1.12% - 18.25%:76.82%:4.93%&lt;/li&gt;&lt;li&gt;Cambodia - 6.9%:85.41%:7.69% - 10.36%:78.72%:10.92%&lt;/li&gt;&lt;li&gt;Cameroon - 13.2%:77.79%:9.02% - 14.16%:69.59%:16.25%&lt;/li&gt;&lt;li&gt;Canada - 19.53%:56.58%:23.89% - 20.26%:47.84%:31.9%&lt;/li&gt;&lt;li&gt;Cape Verde - 4.7%:81.66%:13.64% - 15.5%:66.54%:17.96%&lt;/li&gt;&lt;li&gt;Central African Republic - 7.06%:78.32%:14.62% - 12.51%:62.86%:24.63%&lt;/li&gt;&lt;li&gt;Chad - 5.5%:76.12%:18.37% - 4.72%:74.52%:20.76%&lt;/li&gt;&lt;li&gt;Chile - 14.27%:69.53%:16.2% - 22.35%:55.36%:22.29%&lt;/li&gt;&lt;li&gt;China - 7.84%:85.5%:6.66% - 26.97%:60.24%:12.8%&lt;/li&gt;&lt;li&gt;Colombia - 20.28%:58.13%:21.59% - 17.96%:54.0%:28.04%&lt;/li&gt;&lt;li&gt;Comoros - 10.92%:69.45%:19.63% - 12.41%:63.33%:24.26%&lt;/li&gt;&lt;li&gt;Congo - 9.8%:78.31%:11.89% - 11.48%:65.33%:23.19%&lt;/li&gt;&lt;li&gt;Costa Rica - 12.49%:58.25%:29.25% - 13.21%:54.1%:32.69%&lt;/li&gt;&lt;li&gt;Cuba - 12.87%:56.72%:30.41% - 17.15%:59.63%:23.22%&lt;/li&gt;&lt;li&gt;Cyprus - 18.96%:55.05%:25.99% - 25.71%:44.5%:29.79%&lt;/li&gt;&lt;li&gt;Côte d'Ivoire - 22.44%:67.91%:9.65% - 12.63%:71.54%:15.84%&lt;/li&gt;&lt;li&gt;Democratic People's Republic of Korea - 10.04%:82.17%:7.78% - 14.28%:76.58%:9.14%&lt;/li&gt;&lt;li&gt;Democratic Republic of the Congo - 11.51%:77.38%:11.11% - 5.62%:80.92%:13.46%&lt;/li&gt;&lt;li&gt;Denmark - 12.89%:62.25%:24.85% - 22.85%:56.69%:20.46%&lt;/li&gt;&lt;li&gt;Djibouti - 10.02%:64.9%:25.08% - 9.22%:64.56%:26.22%&lt;/li&gt;&lt;li&gt;Dominica - 17.34%:54.38%:28.27% - 25.55%:53.08%:21.37%&lt;/li&gt;&lt;li&gt;Dominican Republic - 30.24%:50.15%:19.62% - 21.13%:45.9%:32.97%&lt;/li&gt;&lt;li&gt;Ecuador - 19.72%:57.59%:22.69% - 23.44%:50.79%:25.77%&lt;/li&gt;&lt;li&gt;Egypt - 9.99%:76.98%:13.04% - 13.53%:72.27%:14.2%&lt;/li&gt;&lt;li&gt;El Salvador - 9.57%:71.64%:18.79% - 12.95%:63.52%:23.53%&lt;/li&gt;&lt;li&gt;Fiji - 5.56%:70.69%:23.75% - 13.74%:59.49%:26.77%&lt;/li&gt;&lt;li&gt;Finland - 12.06%:71.48%:16.46% - 24.17%:57.14%:18.7%&lt;/li&gt;&lt;li&gt;France - 21.62%:63.01%:15.37% - 22.55%:52.99%:24.46%&lt;/li&gt;&lt;li&gt;French Polynesia - 14.2%:63.64%:22.16% - 25.66%:52.12%:22.22%&lt;/li&gt;&lt;li&gt;Gabon - 32.81%:60.46%:6.72% - 24.44%:58.77%:16.79%&lt;/li&gt;&lt;li&gt;Gambia - 4.72%:71.77%:23.51% - 5.43%:62.54%:32.02%&lt;/li&gt;&lt;li&gt;Germany - 17.41%:61.61%:20.98% - 19.11%:54.34%:26.55%&lt;/li&gt;&lt;li&gt;Ghana - 14.96%:70.04%:14.99% - 15.66%:68.45%:15.88%&lt;/li&gt;&lt;li&gt;Greece - 16.44%:62.54%:21.02% - 20.88%:52.17%:26.95%&lt;/li&gt;&lt;li&gt;Grenada - 19.96%:51.5%:28.54% - 22.75%:44.22%:33.03%&lt;/li&gt;&lt;li&gt;Guatemala - 7.94%:78.14%:13.92% - 11.88%:62.1%:26.03%&lt;/li&gt;&lt;li&gt;Guinea - 19.42%:66.22%:14.36% - 12.7%:65.3%:22.0%&lt;/li&gt;&lt;li&gt;Guinea-Bissau - 13.84%:66.61%:19.55% - 8.88%:72.67%:18.45%&lt;/li&gt;&lt;li&gt;Guyana - 9.91%:63.19%:26.9% - 13.37%:61.33%:25.29%&lt;/li&gt;&lt;li&gt;Haiti - 12.78%:71.19%:16.03% - 11.49%:67.65%:20.86%&lt;/li&gt;&lt;li&gt;Honduras - 14.6%:70.33%:15.06% - 14.01%:60.13%:25.86%&lt;/li&gt;&lt;li&gt;Hungary - 15.99%:73.08%:10.93% - 18.2%:54.28%:27.52%&lt;/li&gt;&lt;li&gt;Iceland - 23.18%:52.58%:24.24% - 29.86%:50.0%:20.14%&lt;/li&gt;&lt;li&gt;India - 3.91%:79.42%:16.67% - 6.05%:75.19%:18.76%&lt;/li&gt;&lt;li&gt;Indonesia - 5.01%:78.85%:16.14% - 10.06%:70.67%:19.28%&lt;/li&gt;&lt;li&gt;Iran - 13.05%:71.72%:15.22% - 19.0%:64.28%:16.72%&lt;/li&gt;&lt;li&gt;Ireland - 13.96%:68.21%:17.83% - 18.92%:57.09%:23.99%&lt;/li&gt;&lt;li&gt;Israel - 18.05%:54.71%:27.25% - 24.11%:46.88%:29.01%&lt;/li&gt;&lt;li&gt;Italy - 15.24%:65.83%:18.93% - 22.54%:50.52%:26.95%&lt;/li&gt;&lt;li&gt;Jamaica - 17.55%:52.07%:30.37% - 19.78%:50.2%:30.02%&lt;/li&gt;&lt;li&gt;Japan - 10.96%:73.67%:15.37% - 20.18%:52.37%:27.45%&lt;/li&gt;&lt;li&gt;Jordan - 15.15%:61.34%:23.52% - 11.56%:56.94%:31.51%&lt;/li&gt;&lt;li&gt;Kenya - 10.21%:81.37%:8.42% - 10.96%:71.23%:17.8%&lt;/li&gt;&lt;li&gt;Kiribati - 15.97%:36.76%:47.27% - 17.87%:41.66%:40.47%&lt;/li&gt;&lt;li&gt;Kuwait - 20.35%:53.3%:26.35% - 20.59%:55.01%:24.4%&lt;/li&gt;&lt;li&gt;Lao People's Democratic Republic - 5.7%:92.49%:1.81% - 12.54%:80.1%:7.36%&lt;/li&gt;&lt;li&gt;Lebanon - 18.25%:63.08%:18.67% - 19.77%:51.64%:28.59%&lt;/li&gt;&lt;li&gt;Lesotho - 6.41%:87.67%:5.93% - 5.42%:86.71%:7.87%&lt;/li&gt;&lt;li&gt;Liberia - 11.77%:78.59%:9.64% - 7.39%:70.14%:22.47%&lt;/li&gt;&lt;li&gt;Libyan Arab Jamahiriya - 12.64%:64.69%:22.67% - 14.19%:57.38%:28.43%&lt;/li&gt;&lt;li&gt;Madagascar - 10.93%:82.92%:6.15% - 8.59%:82.55%:8.87%&lt;/li&gt;&lt;li&gt;Malawi - 6.94%:80.3%:12.76% - 8.17%:80.37%:11.46%&lt;/li&gt;&lt;li&gt;Malaysia - 10.39%:66.13%:23.48% - 17.46%:55.23%:27.31%&lt;/li&gt;&lt;li&gt;Maldives - 11.62%:52.79%:35.59% - 31.66%:47.91%:20.43%&lt;/li&gt;&lt;li&gt;Mali - 7.59%:84.68%:7.73% - 7.61%:78.81%:13.58%&lt;/li&gt;&lt;li&gt;Malta - 11.15%:68.35%:20.5% - 20.93%:58.91%:20.16%&lt;/li&gt;&lt;li&gt;Mauritania - 12.88%:75.94%:11.18% - 8.49%:68.07%:23.43%&lt;/li&gt;&lt;li&gt;Mauritius - 3.87%:65.63%:30.5% - 11.67%:60.76%:27.58%&lt;/li&gt;&lt;li&gt;Mexico - 10.63%:71.76%:17.61% - 17.84%:57.94%:24.21%&lt;/li&gt;&lt;li&gt;Mongolia - 39.69%:58.38%:1.94% - 21.64%:66.94%:11.42%&lt;/li&gt;&lt;li&gt;Morocco - 7.48%:72.86%:19.66% - 11.14%:67.73%:21.13%&lt;/li&gt;&lt;li&gt;Mozambique - 4.49%:86.97%:8.54% - 4.86%:81.05%:14.09%&lt;/li&gt;&lt;li&gt;Myanmar - 7.85%:79.08%:13.07% - 13.94%:68.05%:18.01%&lt;/li&gt;&lt;li&gt;Namibia - 11.65%:72.43%:15.92% - 9.47%:73.61%:16.93%&lt;/li&gt;&lt;li&gt;Nepal - 2.92%:92.98%:4.1% - 6.57%:83.19%:10.24%&lt;/li&gt;&lt;li&gt;Netherlands - 15.62%:54.88%:29.5% - 23.71%:48.54%:27.75%&lt;/li&gt;&lt;li&gt;Netherlands Antilles - 22.11%:56.63%:21.26% - 19.48%:57.6%:22.92%&lt;/li&gt;&lt;li&gt;New Caledonia - 18.0%:59.27%:22.73% - 20.3%:55.11%:24.58%&lt;/li&gt;&lt;li&gt;New Zealand - 25.31%:57.12%:17.57% - 26.86%:46.42%:26.72%&lt;/li&gt;&lt;li&gt;Nicaragua - 10.28%:69.71%:20.01% - 7.62%:66.84%:25.54%&lt;/li&gt;&lt;li&gt;Niger - 6.39%:88.74%:4.87% - 8.12%:82.06%:9.82%&lt;/li&gt;&lt;li&gt;Nigeria - 10.03%:69.04%:20.93% - 8.41%:72.24%:19.35%&lt;/li&gt;&lt;li&gt;Norway - 19.78%:61.74%:18.48% - 21.85%:55.4%:22.75%&lt;/li&gt;&lt;li&gt;Pakistan - 4.75%:81.31%:13.94% - 6.8%:69.01%:24.19%&lt;/li&gt;&lt;li&gt;Panama - 15.72%:66.74%:17.54% - 16.01%:62.74%:21.24%&lt;/li&gt;&lt;li&gt;Paraguay - 23.41%:66.75%:9.83% - 16.12%:59.2%:24.68%&lt;/li&gt;&lt;li&gt;Peru - 12.89%:68.83%:18.28% - 15.12%:69.75%:15.13%&lt;/li&gt;&lt;li&gt;Philippines - 19.21%:66.67%:14.12% - 20.62%:65.71%:13.68%&lt;/li&gt;&lt;li&gt;Poland - 10.91%:76.75%:12.35% - 18.45%:60.73%:20.82%&lt;/li&gt;&lt;li&gt;Portugal - 16.91%:66.28%:16.81% - 23.23%:56.13%:20.64%&lt;/li&gt;&lt;li&gt;Republic of Korea - 5.32%:90.37%:4.32% - 22.31%:52.44%:25.25%&lt;/li&gt;&lt;li&gt;Romania - 9.45%:82.0%:8.55% - 15.07%:67.21%:17.73%&lt;/li&gt;&lt;li&gt;Rwanda - 25.5%:73.72%:0.78% - 19.72%:73.29%:6.99%&lt;/li&gt;&lt;li&gt;Saint Kitts and Nevis - 8.93%:50.93%:40.14% - 20.29%:48.07%:31.65%&lt;/li&gt;&lt;li&gt;Saint Lucia - 25.06%:50.34%:24.6% - 29.78%:51.14%:19.08%&lt;/li&gt;&lt;li&gt;Saint Vincent and the Grenadines - 9.56%:60.38%:30.06% - 21.06%:53.12%:25.82%&lt;/li&gt;&lt;li&gt;Samoa - 23.99%:36.67%:39.34% - 30.0%:36.99%:33.01%&lt;/li&gt;&lt;li&gt;Sao Tome and Principe - 8.04%:60.04%:31.92% - 16.54%:55.14%:28.31%&lt;/li&gt;&lt;li&gt;Saudi Arabia - 15.92%:75.97%:8.11% - 18.27%:59.75%:21.98%&lt;/li&gt;&lt;li&gt;Senegal - 7.95%:71.51%:20.54% - 8.12%:67.61%:24.28%&lt;/li&gt;&lt;li&gt;Seychelles - 8.56%:67.95%:23.49% - 19.51%:55.67%:24.82%&lt;/li&gt;&lt;li&gt;Sierra Leone - 8.22%:60.19%:31.59% - 7.24%:69.23%:23.53%&lt;/li&gt;&lt;li&gt;Solomon Islands - 11.34%:76.01%:12.65% - 8.8%:74.13%:17.07%&lt;/li&gt;&lt;li&gt;South Africa - 11.65%:68.29%:20.06% - 13.0%:65.02%:21.98%&lt;/li&gt;&lt;li&gt;Spain - 14.51%:65.32%:20.17% - 26.26%:44.51%:29.23%&lt;/li&gt;&lt;li&gt;Sri Lanka - 7.11%:66.81%:26.08% - 7.77%:65.04%:27.2%&lt;/li&gt;&lt;li&gt;Sudan - 12.25%:69.05%:18.7% - 8.99%:73.13%:17.88%&lt;/li&gt;&lt;li&gt;Suriname - 10.5%:62.34%:27.17% - 17.27%:50.4%:32.33%&lt;/li&gt;&lt;li&gt;Swaziland - 9.94%:72.8%:17.26% - 11.05%:66.46%:22.48%&lt;/li&gt;&lt;li&gt;Sweden - 15.71%:55.94%:28.35% - 21.33%:52.34%:26.33%&lt;/li&gt;&lt;li&gt;Switzerland - 18.89%:56.97%:24.14% - 22.51%:47.44%:30.06%&lt;/li&gt;&lt;li&gt;Syrian Arab Republic - 15.76%:64.68%:19.57% - 12.54%:59.61%:27.85%&lt;/li&gt;&lt;li&gt;Thailand - 13.35%:75.37%:11.28% - 16.74%:57.68%:25.57%&lt;/li&gt;&lt;li&gt;Timor-Leste - 24.68%:71.22%:4.09% - 9.99%:75.86%:14.15%&lt;/li&gt;&lt;li&gt;Togo - 4.07%:86.81%:9.12% - 4.06%:78.59%:17.35%&lt;/li&gt;&lt;li&gt;Trinidad and Tobago - 10.2%:63.93%:25.88% - 14.56%:53.62%:31.82%&lt;/li&gt;&lt;li&gt;Tunisia - 9.36%:70.51%:20.13% - 13.45%:62.22%:24.33%&lt;/li&gt;&lt;li&gt;Turkey - 15.4%:74.39%:10.2% - 13.6%:62.28%:24.12%&lt;/li&gt;&lt;li&gt;Uganda - 17.44%:68.31%:14.25% - 22.27%:61.07%:16.66%&lt;/li&gt;&lt;li&gt;United Arab Emirates - 17.52%:70.51%:11.98% - 23.45%:57.72%:18.82%&lt;/li&gt;&lt;li&gt;United Kingdom - 20.41%:56.05%:23.54% - 22.54%:53.49%:23.97%&lt;/li&gt;&lt;li&gt;United Republic of Tanzania - 11.34%:80.15%:8.51% - 10.55%:75.45%:14.0%&lt;/li&gt;&lt;li&gt;United States of America - 20.36%:50.72%:28.92% - 20.51%:43.43%:36.06%&lt;/li&gt;&lt;li&gt;Uruguay - 28.54%:52.68%:18.78% - 15.05%:62.14%:22.82%&lt;/li&gt;&lt;li&gt;Vanuatu - 19.77%:57.07%:23.16% - 17.79%:52.8%:29.41%&lt;/li&gt;&lt;li&gt;Venezuela - 18.93%:54.48%:26.59% - 17.04%:53.45%:29.51%&lt;/li&gt;&lt;li&gt;Viet Nam - 10.49%:85.45%:4.06% - 19.59%:70.94%:9.46%&lt;/li&gt;&lt;li&gt;Yemen - 7.35%:85.13%:7.53% - 8.83%:69.29%:21.88%&lt;/li&gt;&lt;li&gt;Zambia - 6.0%:85.56%:8.44% - 5.53%:80.41%:14.05%&lt;/li&gt;&lt;li&gt;Zimbabwe - 5.85%:83.99%:10.16% - 5.64%:69.28%:25.07%&lt;/li&gt;&lt;/ul&gt;Almost universally, good old Neolithic foods that served us so well for entire history of human civilization are abandoned. And two primary foods of industrial era - sugar and vegetable oil - become the new basis of diet. What people rarely mention is how at the same time Paleolithic food - meat, fish, fruit, vegetables and so on - doubled in popularity in so many countries. And some combination of Paleolithic and Industrial is destroying everyone's hearts, livers, thyroids, and attractiveness outside certain narrow niche.&lt;br /&gt;&lt;br /&gt;To save you some eye strain, here's the list of Top Ten Least Neolithic Countries. I don't even need to mention how it correlates with obesity rankings:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Samoa - 23.99%:36.67%:39.34% - 30.0%:36.99%:33.01%&lt;/li&gt;&lt;li&gt;Kiribati - 15.97%:36.76%:47.27% - 17.87%:41.66%:40.47%&lt;/li&gt;&lt;li&gt;United States of America - 20.36%:50.72%:28.92% - 20.51%:43.43%:36.06%&lt;/li&gt;&lt;li&gt;Grenada - 19.96%:51.5%:28.54% - 22.75%:44.22%:33.03%&lt;/li&gt;&lt;li&gt;Cyprus - 18.96%:55.05%:25.99% - 25.71%:44.5%:29.79%&lt;/li&gt;&lt;li&gt;Spain - 14.51%:65.32%:20.17% - 26.26%:44.51%:29.23%&lt;/li&gt;&lt;li&gt;Australia - 24.36%:54.1%:21.54% - 25.47%:45.74%:28.79%&lt;/li&gt;&lt;li&gt;Dominican Republic - 30.24%:50.15%:19.62% - 21.13%:45.9%:32.97%&lt;/li&gt;&lt;li&gt;New Zealand - 25.31%:57.12%:17.57% - 26.86%:46.42%:26.72%&lt;/li&gt;&lt;li&gt;Barbados - 13.98%:60.39%:25.63% - 23.63%:46.47%:29.9%&lt;/li&gt;&lt;/ol&gt;&lt;ul&gt;&lt;/ul&gt;But no worries - The Neolithic Counter-Revolution seems to be reaching everyone who can afford it, so soon the entire planet will consist of walking blobs of omega-6 PUFA.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/TJ1QEglYwmI/AAAAAAAAA_w/UqekCbOCTwQ/s1600/om_nomnomnom_nom_by_katherinea_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="OM NOMNOMNOM NOM by katherine.a from flickr (CC-NC-SA)"&gt;&lt;img alt="OM NOMNOMNOM NOM by katherine.a from flickr (CC-NC-SA)" border="0" height="466" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/TJ1QEglYwmI/AAAAAAAAA_w/UqekCbOCTwQ/s640/om_nomnomnom_nom_by_katherinea_from_flickr_cc-nc-sa.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Anonymous Heroes of Science&lt;/h3&gt;&lt;br /&gt;You might now think that I'm some ridiculous kind of ultra-Conservative, who would like to move back not just to the Founding Fathers or their local equivalent but all the way to ancient Sumer. Not at all.&lt;br /&gt;&lt;br /&gt;Food of Industrial era is mostly horrible crap, but it's also very plentiful, very cheap, and some of it is actually quite tasty. I'm sure we'll figure it out eventually - a big more Omega-3 here, a bit less Bisphenol A there - and step by step it might get just as good or even better than what farming came out with. Food eaten by early farmers was also horrible and caused severe health problems, but it was plentiful, cheap, and it took only a few millennia to figure out matters of health.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The thing is - I just don't feel particular need to be the early adopter of Industrial Diet. Early adopters are essential, as our scientific ethics committees are too chickenshit to approve genuine scientific experiments on humans, so we're doing the second best things by pretending it's all perfectly safe and letting nature run the experiment. Which trial of trans fats could even hope compete with feeding ridiculous amounts of them to hundreds of millions of people for nearly a century now? Without even telling them, to avoid placebo effect! Now that's proper science on grand scale!&lt;br /&gt;&lt;br /&gt;And so I'd like to thank all people who unlike me bravely volunteer to let food industry run scientific experiments on their bodies by purchasing industrial food, and not stopping even after suffering severe side effects including but not limited to disfiguration, heart failure, liver failure, depression, diabetes, cancer, osteoarthritis, sleep apnea, and many others.&lt;br /&gt;&lt;br /&gt;Your noble sacrifice will not be forgotten. Actually it totally will, but keep going please? The science needs you!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-1892522949260710159?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/1892522949260710159/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=1892522949260710159' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1892522949260710159'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1892522949260710159'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/09/neolithic-counter-revolution-in-diet.html' title='Neolithic Counter-Revolution in Diet'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_IYGc_MWwkfw/TJ1P5QbTMSI/AAAAAAAAA_s/TF1wlb9atj4/s72-c/cat_grass_om_nom_nom_by_chrisjervis_from_flickr_cc-nc.jpg' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-2058657459732461917</id><published>2010-07-20T13:14:00.001+02:00</published><updated>2010-07-20T19:27:33.682+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>We need syntax for talking about Ruby types</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/TEWDHlH1PMI/AAAAAAAAA_U/585PGD67q4Y/s1600/koteczek_by_kemcio_from_flickr_cc-nc.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Koteczek by kemcio from flickr (CC-NC)"&gt;&lt;img alt="Koteczek by kemcio from flickr (CC-NC)" border="0" height="480" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/TEWDHlH1PMI/AAAAAAAAA_U/585PGD67q4Y/s640/koteczek_by_kemcio_from_flickr_cc-nc.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;All this is about discussing types in blog posts, documentation etc. None of that goes anywhere near actual code (except possibly in comments). Ruby never sees that.&lt;/b&gt; &lt;br /&gt;&lt;br /&gt;Statically typed languages have all this covered, and we need it too. Not static typing of course - just an expressive way to talk about what types things are - as plain English fails here very quickly. As far as I know nothing like that exists yet, so here's my proposal.&lt;br /&gt;&lt;br /&gt;This system of type descriptions is meant for humans, not machines. It focuses on the most important distinctions, and ignores details that are not important, or very difficult to keep track of. Type descriptions should only be as specific as necessary in given context. If it makes sense, there rules should be violated.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In advance I'll say I totally ignored all the covariance / contravariance / invariance business - it's far to complicated, and getting too deeply into such issues makes little sense in a language where everything can be redefined.&lt;br /&gt;&lt;h3&gt;Basic types&lt;/h3&gt;&lt;br /&gt;Types of simple values can be described by their class name, or any of its superclasses or mixins. So some ways to describe type of &lt;tt&gt;15&lt;/tt&gt; would be &lt;tt&gt;Fixnum&lt;/tt&gt; (actual class), &lt;tt&gt;Integer&lt;/tt&gt; (superclass), &lt;tt&gt;Comparable&lt;/tt&gt; (mixin), or &lt;tt&gt;Object&lt;/tt&gt; (superclass all the way up).&lt;br /&gt;&lt;br /&gt;In context of describing types, everything is considered an &lt;tt&gt;Object&lt;/tt&gt;, and existence of &lt;tt&gt;Kernel&lt;/tt&gt;, &lt;tt&gt;BasicObject&lt;/tt&gt; etc. is ignored.&lt;br /&gt;&lt;br /&gt;So far, it should all be rather obvious. Examples:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;tt&gt;42&lt;/tt&gt; - &lt;tt&gt;Integer&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;&lt;tt&gt;Time.now&lt;/tt&gt;&amp;nbsp; - &lt;tt&gt;Time&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;&lt;tt&gt;Dir.glob("*")&lt;/tt&gt; -  &lt;tt&gt;Enumerable&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;&lt;tt&gt;STDIN&lt;/tt&gt; - &lt;tt&gt;IO&lt;/tt&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;&lt;tt&gt;nil&lt;/tt&gt; and other ignored issues&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;nil&lt;/tt&gt; will be treated specially - as if it was of every possible type. &lt;tt&gt;nil&lt;/tt&gt; means absence of value, and doesn't indicate what type the value would have if it was present. This is messy, but most explicitly typed languages follow this path.&lt;br /&gt;&lt;br /&gt;Distinction between situations that allow &lt;tt&gt;nil&lt;/tt&gt;s and those that don't will be treated as all other value range restrictions (&lt;tt&gt;Integer&lt;/tt&gt; must be posibile, &lt;tt&gt;IO&lt;/tt&gt; must be open for writing etc.) - as something outside the type system.&lt;br /&gt;&lt;br /&gt;For cases where &lt;tt&gt;nil&lt;/tt&gt; means something magical, and not just absence of value, it should probably be mentioned.&lt;br /&gt;&lt;br /&gt;Checked exceptions and related non-local exits in Ruby would be a hopeless thing to even attempt. There's syntax for exceptions and catches used as control structures if they're really necessary.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Booleans&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;We will also pretend that &lt;tt&gt;Boolean&lt;/tt&gt; is a common superclass of &lt;tt&gt;TrueClass&lt;/tt&gt; and &lt;tt&gt;FalseClass&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;We will also normally ignore distinction between situations where  real &lt;tt&gt;true&lt;/tt&gt;/&lt;tt&gt;false&lt;/tt&gt; are expected,  and situations where any object goes, but acts identically to its  boolean conversion. Any method that acts identically on &lt;tt&gt;x&lt;/tt&gt; and &lt;tt&gt;!!x&lt;/tt&gt; can be said to take &lt;tt&gt;Boolean&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;On the other hand if some values are treated differently than their double negation, that's not really &lt;tt&gt;Boolean&lt;/tt&gt; and it deserves a mention. Especially if &lt;tt&gt;nil&lt;/tt&gt; and &lt;tt&gt;false&lt;/tt&gt; are not equivalent - like in Rails's &lt;tt&gt;#in_groups_of&lt;/tt&gt; (I don't think Ruby stdlib  ever does thing like that).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Duck typing&lt;/h3&gt;&lt;br /&gt;If something quacks like a &lt;tt&gt;Duck&lt;/tt&gt; convincingly  enough, it can be said to be of type &lt;tt&gt;Duck&lt;/tt&gt;, it being  object's responsibility that its cover doesn't get blown.&lt;br /&gt;&lt;br /&gt;In particular, Ruby uses certain methods for automatic type conversion. In many contexts objects implementing &lt;tt&gt;#to_str&lt;/tt&gt; like &lt;tt&gt;Pathname&lt;/tt&gt;s will be treated as &lt;tt&gt;String&lt;/tt&gt;s, objects implementing &lt;tt&gt;#to_ary&lt;/tt&gt; as  &lt;tt&gt;Array&lt;/tt&gt;s, &lt;tt&gt;#to_hash&lt;/tt&gt; as &lt;tt&gt;Hash&lt;/tt&gt;es, and &lt;tt&gt;to_proc&lt;/tt&gt; as &lt;tt&gt;Proc&lt;/tt&gt;s - this can be used for some amazing things like &lt;tt&gt;Symbol#to_proc&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;This leads to a big complication for us - C code implementing Ruby interpreter and many libraries is normally written in a way that calls these conversion functions automatically, so in such contexts &lt;tt&gt;Symbol&lt;/tt&gt; really is a &lt;tt&gt;Proc&lt;/tt&gt;, &lt;tt&gt;Pathname&lt;/tt&gt; really is a &lt;tt&gt;String&lt;/tt&gt; and so on. On the other hand, in Ruby code these methods are not magical, and such conversions will only happen if explicitly called - for them &lt;tt&gt;Pathname&lt;/tt&gt; and &lt;tt&gt;String&lt;/tt&gt; are completely unrelated types. Unless Ruby code calls C code, which then autoconverts.&lt;br /&gt;&lt;br /&gt;Explicitly differentiating between contexts which expect a genuine &lt;tt&gt;String&lt;/tt&gt; and those which expect either that or something with a valid &lt;tt&gt;#to_str&lt;/tt&gt; method would be highly tedious, and I doubt anyone would get it exactly right.&lt;br /&gt;&lt;br /&gt;My recommendation would be to treat everything that autoconverts to something as if it subclassed it. So we'll pretend &lt;tt&gt;Pathname&lt;/tt&gt; is a subclass of &lt;tt&gt;String&lt;/tt&gt;, even though it's not really. In some cases this will be wrong, but it's not really all that different from subclassing something and then introducing incompatible changes. &lt;br /&gt;&lt;br /&gt;This all doesn't extend to &lt;tt&gt;#to_s&lt;/tt&gt;,  &lt;tt&gt;#to_a&lt;/tt&gt; etc - nothing can be described as  &lt;tt&gt;String&lt;/tt&gt; just because it has  &lt;tt&gt;to_s&lt;/tt&gt; method - every object has  &lt;tt&gt;to_s&lt;/tt&gt; but most aren't really strings.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Technical explanation of &lt;tt&gt;to_str&lt;/tt&gt; and friends&lt;/h3&gt;&lt;i&gt;This section is unrelated to post's primary subject - skip if uninterested.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Ruby uses special memory layout for basic types like strings and arrays. Performance would be abysmal if string methods had to actually call Ruby code associated with whatever &lt;tt&gt;[]&lt;/tt&gt; happened to be redefined to for every character - instead they ask for a certain C data structure, and access that directly (via some macros providing extra safety and convenience to be really exact).&lt;br /&gt;&lt;br /&gt;By the way this is a great example of C being really slow - if Ruby was implemented on a platform with really good JIT, it could plausibly have every single string function implemented in term of calls to &lt;tt&gt;[]&lt;/tt&gt;, &lt;tt&gt;[]=&lt;/tt&gt;, &lt;tt&gt;size&lt;/tt&gt;, and just a few others, with different subclasses of &lt;tt&gt;String&lt;/tt&gt; providing different implementations, and JIT compiling inlining all that to make it really fast.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It would make it really simple to create class representing a text file, and &lt;tt&gt;=~ /regexp/&lt;/tt&gt; that directly without reading anything more than required to memory, or maybe even &lt;tt&gt;gsub!&lt;/tt&gt; it in a way that would read it in small chunks, saving them to another file as soon as they're ready, and then renaming in one go. All that without regexp library knowing anything about it all. It's all just my fantasy, I'm not saying any such JIT actually exists.&lt;br /&gt;&lt;br /&gt;Anyway, strings and such are implemented specially, but we still want these types to be real objects, not like what they've done in Java. To make it work, all C functions requiring access to underlying storage call a special macro which automatically calls a method like &lt;tt&gt;to_str&lt;/tt&gt; or &lt;tt&gt;to_ary&lt;/tt&gt; if necessary - so such objects can pretend to be strings very effectively. For example if you alias method &lt;tt&gt;to_str&lt;/tt&gt; to &lt;tt&gt;path&lt;/tt&gt; on &lt;tt&gt;File&lt;/tt&gt; code like &lt;tt&gt;system File.open("/bin/hostname")&lt;/tt&gt; will suddenly start working. It really makes sense only for things which are "essentially strings" like &lt;tt&gt;Pathname&lt;/tt&gt;, &lt;tt&gt;URI&lt;/tt&gt;, Unicode-enhanced strings, proxies for strings in third party libraries like Qt etc.&lt;br /&gt;&lt;br /&gt;To complicate things further objects of all classes inheriting from &lt;tt&gt;String&lt;/tt&gt; automatically use &lt;tt&gt;String&lt;/tt&gt;'s data representation - and C code will access that, never calling &lt;tt&gt;to_str&lt;/tt&gt;. This leaves objects which duck type as &lt;tt&gt;String&lt;/tt&gt;s two choices:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Subclass &lt;tt&gt;String&lt;/tt&gt; and every time anything changes update C string data. This can be difficult - if you implement an &lt;tt&gt;URI&lt;/tt&gt; and keep query part as a hash instance variable - you need to somehow make sure that your update code gets run every time that hash changes - like by not exposing it at all and only allowing query updates via your direct methods, or wrapping it in a special object that calls you back.&lt;/li&gt;&lt;li&gt;Don't subclass &lt;tt&gt;String&lt;/tt&gt;, define &lt;tt&gt;to_str&lt;/tt&gt; the way you want. Everything works - except your class isn't technically a &lt;tt&gt;String&lt;/tt&gt; so it's not terribly pretty OO design.&lt;/li&gt;&lt;/ul&gt;You probably won't be surprised that not subclassing is the more popular choice. As it's all due to technical limitations not design choices, it makes sense to treat such objects as if they were properly subclassed.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/TEWDOvo38GI/AAAAAAAAA_c/_i25a_PeveU/s1600/pussy_by_tripleigrek_from_flickr_cc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Pussy by tripleigrek from flickr (CC-SA)"&gt;&lt;img alt="Pussy by tripleigrek from flickr (CC-SA)" border="0" height="480" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/TEWDOvo38GI/AAAAAAAAA_c/_i25a_PeveU/s640/pussy_by_tripleigrek_from_flickr_cc-sa.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Collections&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Back to the subject. For collections we often want to describe types of their elements. For simple collections yielding successive elements on &lt;tt&gt;#each&lt;/tt&gt;, syntax for type description is &lt;tt&gt;CollectionType[MemberType]&lt;/tt&gt;. Examples:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;tt&gt;[42.0, 17.5]&lt;/tt&gt; - &lt;tt&gt;Array[Float]&lt;/tt&gt; &lt;/li&gt;&lt;li&gt;&lt;tt&gt;Set["foo","bar"]&lt;/tt&gt; - &lt;tt&gt;Set[String]&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;&lt;tt&gt;5..10&lt;/tt&gt; - &lt;tt&gt;Range[Integer]&lt;/tt&gt;&lt;/li&gt;&lt;/ul&gt;When we don't care about collection type, only about element types, descriptions like &lt;tt&gt;Enumerable[ElementType]&lt;/tt&gt; will do.&lt;br /&gt;&lt;br /&gt;Syntax for types of hashtables is &lt;tt&gt;Hash[KeyType, ValueType]&lt;/tt&gt; - in general collections which yield multiple values to &lt;tt&gt;#each&lt;/tt&gt; can be described as &lt;tt&gt;CollectionType[Type1, Type2, ..., TypeN]&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;For example &lt;tt&gt;{:foo =&amp;gt; "bar"}&lt;/tt&gt; is of type &lt;tt&gt;Hash[Symbol, String]&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;This is optional - type descriptions like &lt;tt&gt;Hash&lt;/tt&gt; or  &lt;tt&gt;Enumerable&lt;/tt&gt; are perfectly valid - and often types  are unrelated, or we don't care.&lt;br /&gt;&lt;br /&gt;Not every &lt;tt&gt;Enumerable&lt;/tt&gt; should be treated as collection of members like that - &lt;tt&gt;File&lt;/tt&gt; might technically be &lt;tt&gt;File[String]&lt;/tt&gt; but it's usually pointless to describe it this way. In 1.8 &lt;tt&gt;String&lt;/tt&gt; is &lt;tt&gt;Enumerable&lt;/tt&gt;, yielding successive lines when iterated - but &lt;tt&gt;String[String]&lt;/tt&gt; make no sense (no longer a problem in 1.9).&lt;br /&gt;&lt;br /&gt;Classes other than &lt;tt&gt;Enumerable&lt;/tt&gt; like  &lt;tt&gt;Delegator&lt;/tt&gt; might need type parameters, and they should be specified with the same syntax. Their order and meaning depends on particular class, but usually should be obvious.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Literals and tuples&lt;/h3&gt;Ruby doesn't make distinction between &lt;tt&gt;Array&lt;/tt&gt;s and tuples. What I mean here is a kind of &lt;tt&gt;Array&lt;/tt&gt; which shouldn't really be treated as a collection, and in which different members have unrelated type and meaning depending on their position.&lt;br /&gt;&lt;br /&gt;Like method arguments. It really wouldn't be useful to say that every method takes &lt;tt&gt;Array[Object]&lt;/tt&gt; (and an optional &lt;tt&gt;Proc&lt;/tt&gt;) - types and meanings of elements in this array should be specified.&lt;br /&gt;&lt;br /&gt;Syntax I want for this is &lt;tt&gt;[Type1, Type2, *TypeRest]&lt;/tt&gt; - so for example &lt;tt&gt;Hash[Date, Integer]&lt;/tt&gt;'s &lt;tt&gt;#select&lt;/tt&gt; passes &lt;tt&gt;[Date, Integer]&lt;/tt&gt; to the block, which should return a &lt;tt&gt;Boolean&lt;/tt&gt; result, and then returns either &lt;tt&gt;Array[[Date, Integer]]&lt;/tt&gt; (1.8) or &lt;tt&gt;Hash[Date, Integer]&lt;/tt&gt; (1.9). Notice double &lt;tt&gt;[[]]s&lt;/tt&gt; here - it's an &lt;tt&gt;Array&lt;/tt&gt; of pairs. In many contexts Ruby automatically unpacks such tuples, so &lt;tt&gt;Array[[Date,Integer]]&lt;/tt&gt; can often be treated as &lt;tt&gt;Array[Date,Integer]&lt;/tt&gt; - but it doesn't go deeper than one level, and if you need this distinction it's available. &lt;br /&gt;&lt;br /&gt;Extra arguments can be specified with &lt;tt&gt;*Type&lt;/tt&gt; or &lt;tt&gt;...&lt;/tt&gt; which is treated here as &lt;tt&gt;*Object&lt;/tt&gt;. If you want to specify some arguments as optional suffix their types with &lt;tt&gt;?&lt;/tt&gt; (the most obvious &lt;tt&gt;[]&lt;/tt&gt; having too many uses already, and &lt;tt&gt;=&lt;/tt&gt; not really fitting right).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In this syntax &lt;tt&gt;[*Foo]&lt;/tt&gt; is pretty much equivalent to &lt;tt&gt;Array[Foo]&lt;/tt&gt;, or possibly &lt;tt&gt;Enumerable[Foo]&lt;/tt&gt; (with some duck typing) - feel free to use that if it makes things clearer.&lt;br /&gt;&lt;br /&gt;Basic literals like &lt;tt&gt;true&lt;/tt&gt;, &lt;tt&gt;false&lt;/tt&gt;, &lt;tt&gt;nil&lt;/tt&gt; stand for themselves - and for entire &lt;tt&gt;TrueClass&lt;/tt&gt;, &lt;tt&gt;FalseClass&lt;/tt&gt;,  &lt;tt&gt;NilClass&lt;/tt&gt; classes too as they're their only members. Other literals such as symbols, strings, numbers etc. can be used too when needed.&lt;br /&gt;&lt;br /&gt;To describe keyword arguments and hashes used in similar way, syntax is &lt;tt&gt;{Key1=&amp;gt;Type1, Key2=&amp;gt;Type2}&lt;/tt&gt; - specifying exact key, and type of value like &lt;tt&gt;{:noop=&amp;gt;Boolean, :force=&amp;gt;Boolean}&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;It should be assumed that keys other than those listed are ignored, cause exception, or are otherwise not supported. If they're meaningful it should be marked with &lt;tt&gt;...&lt;/tt&gt; like this &lt;tt&gt;{:query=&amp;gt;String, ...}&lt;/tt&gt;. Subclasses often add extra keyword arguments, and this issue is ignored.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Functions&lt;/h3&gt;&lt;br /&gt;Everything so far was just a prelude to the most important part of any type system - types for functions. Syntax I'd propose it: &lt;tt&gt;ArgumentTypes -&amp;gt; ReturnType&lt;/tt&gt; (&lt;tt&gt;=&amp;gt;&lt;/tt&gt; being already used by hashes).&lt;br /&gt;&lt;br /&gt;I cannot decide if blocks should be specified in Ruby-style notation or a function notation, so both&amp;nbsp; &lt;tt&gt;&amp;amp; {|BlockArgumentTypes| BlockReturnType}&lt;/tt&gt; and &lt;tt&gt;&amp;amp;(BlockArgumentTypes-&amp;gt;BlockReturnType)&lt;/tt&gt; are valid. &lt;tt&gt;&amp;amp;&lt;/tt&gt; is necessary, as block are passed separately from normal arguments, however strong the temptation to reuse &lt;tt&gt;-&amp;gt;&lt;/tt&gt; and let the context disambiguate might be.&lt;br /&gt;&lt;br /&gt;Blocks that don't take any arguments or don't return anything can drop that part, leaving only something like &lt;tt&gt;&amp;amp;{|X|}&lt;/tt&gt;, &lt;tt&gt;&amp;amp;{Y}&lt;/tt&gt;, &lt;tt&gt;&amp;amp;{}&lt;/tt&gt;, or in more functional notation &lt;tt&gt;&amp;amp;(X-&amp;gt;)&lt;/tt&gt;, &lt;tt&gt;&amp;amp;(Y)&lt;/tt&gt;, &lt;tt&gt;&amp;amp;()&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Because of all the &lt;tt&gt;[]&lt;/tt&gt; unpacking, using  &lt;tt&gt;[]&lt;/tt&gt; around arguments, tuple return values etc. is  optional - and just like in Ruby &lt;tt&gt;()&lt;/tt&gt; can be used  instead in such contexts.&lt;br /&gt;&lt;br /&gt;If function doesn't take any arguments, or returns no values, these parts can be left - leaving perhaps as little as &lt;tt&gt;-&amp;gt;&lt;/tt&gt;. &lt;br /&gt;&lt;br /&gt;Examples:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;In context of &lt;tt&gt;%w[Hello world !].group_by(&amp;amp;:size)&lt;/tt&gt; method &lt;tt&gt;#group_by&lt;/tt&gt; has type &lt;tt&gt;Array[String]&amp;amp;{|String| Integer}-&amp;gt;Hash[Integer,String]&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;&lt;tt&gt;Time.at&lt;/tt&gt; has type &lt;tt&gt;Numeric -&amp;gt; Time&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;&lt;tt&gt;String#tr&lt;/tt&gt; has type &lt;tt&gt;[String, String] -&amp;gt; String&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;On a collection of &lt;tt&gt;Float&lt;/tt&gt;s, &lt;tt&gt;#find&lt;/tt&gt; would have type &lt;tt&gt;Float?&amp;amp;(Float-&amp;gt;Boolean)-&amp;gt;Float&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;Function which takes no arguments and returns no values has type &lt;tt&gt;[]-&amp;gt;nil&lt;/tt&gt;&lt;/li&gt;&lt;/ul&gt;If you really need to specify exceptions and throws, you can add &lt;tt&gt;raises Type&lt;/tt&gt;, or &lt;tt&gt;throws :kind&lt;/tt&gt; after return value.&amp;nbsp; Use only for control structure exceptions, not for actual errors exceptions. It might actually be useful if actual data gets passed around.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;tt&gt;Find.find&lt;/tt&gt; has type &lt;tt&gt;[String*]&amp;amp;(String-&amp;gt;nil throws :prune)-&amp;gt;nil&lt;/tt&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;A standalone &lt;tt&gt;Proc&lt;/tt&gt; can be described as &lt;tt&gt;(ArgumentsTypes-&amp;gt;ReturnType)&lt;/tt&gt; just as with notation for functions. There is no ambiguity between &lt;tt&gt;Proc&lt;/tt&gt; arguments and block arguments, as blocks are always marked with &lt;tt&gt;|&lt;/tt&gt;. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Type variable and everything else&lt;/h3&gt;In addition to names of real classes, any name starting with an uppercase letter should be consider a type. Unless it's specified otherwise in context, all such unknown&amp;nbsp; names should be considered class variables with big forall quantifier in front of it all.&lt;br /&gt;&lt;br /&gt;Examples:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;tt&gt;Enumerable[A]#partition&lt;/tt&gt; has type &lt;tt&gt;&amp;amp;(B-&amp;gt;Boolean)-&amp;gt;[Array[A], Array[A]]&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;&lt;tt&gt;Hash[A,B]#merge&lt;/tt&gt; has type &lt;tt&gt;Hash[A,B]&amp;amp;(A,B,B-&amp;gt;B)-&amp;gt;Hash[A,B]&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;&lt;tt&gt;Array[A]#inject&lt;/tt&gt; has either type &lt;tt&gt;B&amp;amp;(B,A-&amp;gt;B)-&amp;gt;B&lt;/tt&gt; or &lt;tt&gt;&amp;amp;(A,A)-&amp;gt;A&lt;/tt&gt;. This isn't just a usual case of missing argument being substituted by &lt;tt&gt;nil&lt;/tt&gt; - these are two completely different functions.&lt;/li&gt;&lt;/ul&gt;To specify that multiple types are allowed (usually implying that behaviour will be different, otherwise there should be a superclass somewhere, or we could treat it as common duck typing and ignore it) join them with &lt;tt&gt;|&lt;/tt&gt;. If there's ambiguity between this use and block arguments, parenthesize. It binds more tightly than &lt;tt&gt;,&lt;/tt&gt;, so it only applies to one argument. Example:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;tt&gt;String#index&lt;/tt&gt; in 1.8 has type &lt;tt&gt;(String|Integer|Regexp, Integer?)-&amp;gt;Integer&lt;/tt&gt; (and notice how I ignored &lt;tt&gt;Fixnum&lt;/tt&gt;s here).&lt;/li&gt;&lt;/ul&gt;For functions that can be called in multiple unrelated ways, just list them separately - &lt;tt&gt;|&lt;/tt&gt; and parentheses will work, but they are usually top level, and not needed anywhere deeper.&lt;br /&gt;&lt;br /&gt;If you want to specify type of &lt;tt&gt;self&lt;/tt&gt;, prefix  function specification with &lt;tt&gt;Type#&lt;/tt&gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;tt&gt;#sort&lt;/tt&gt; has type like  &lt;tt&gt;Enumerable[A]#()&amp;amp;(A,A-&amp;gt;1|0|-1)-&amp;gt;Array[A]&lt;/tt&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;To specify that something takes range of values not really corresponding to a Ruby class, just define such extra names somewhere and then use like this:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;tt&gt;File#chown&lt;/tt&gt; has type &lt;tt&gt;(UnixUserId, UnixUserId)-&amp;gt;0&lt;/tt&gt; - with &lt;tt&gt;UnixUserId&lt;/tt&gt; being a pretend subclass of &lt;tt&gt;Integer&lt;/tt&gt;, and &lt;tt&gt;0&lt;/tt&gt; is literal value actually returned.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;To specify that something needs a particular methods just make up a pretend mixin like &lt;tt&gt;Meowable&lt;/tt&gt; for &lt;tt&gt;#meow&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;Any obvious extensions to this notation can be used, like this:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;tt&gt;Enumerable[A]#zip&lt;/tt&gt; has type &lt;tt&gt;(Enumerable[B_1], *Enumerable[B_i])-&amp;gt;Array[A, B_1, *B_i]&lt;/tt&gt; - with intention that &lt;tt&gt;B_i&lt;/tt&gt;s will be different for each argument understood from context. (I don't think any static type system handles cases like this one reasonably - most require separate case for each supported tuple length, and you cannot use arrays if you mix types. Am I missing something?)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;The End&lt;/h3&gt;&lt;br /&gt;Well, what I really wanted to do what talk about Ruby collection system, and how 1.9 doesn't go far enough in its attempts at fixing it. And without notation for types talking about high order functions that operate on collections quickly turns into a horrible mess. So I started with a brief explanation of notation I wanted to use, and then I figured out I can as well do it right and write something that will be reusable in other contexts too.&lt;br /&gt;&lt;br /&gt;Most discussion of type systems concerns issues like safety and flexibility, which don't concern me at all, and limit themselves to type systems usable by machines.&lt;br /&gt;&lt;br /&gt;I need types for something else - as statements about data flow. Type signature like &lt;tt&gt;Enumerable[A]#()&amp;amp;(A-&amp;gt;B)-&amp;gt;Hash[A,B]&lt;/tt&gt; doesn't tell you exactly what such function does but narrows set of possibilities extremely quickly. What it describes is a function which iterates over collection in order while building a &lt;tt&gt;Hash&lt;/tt&gt; to be returned, using collection's elements as keys, and values returned by the block as values. Can you guess the function I was thinking about here?&lt;br /&gt;&lt;br /&gt;Now a type like that is not a complete specification - a function that returns an empty hash fits it. As does one which skips every 5th element. And one that only keeps entries with unique block results. And for that matter also one that sends your email password to NSA - at least assuming it returns that &lt;tt&gt;Hash&lt;/tt&gt; afterwards.&lt;br /&gt;&lt;br /&gt;It was still pretty useful. How about some of those?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;tt&gt;Hash[A,B] -&amp;gt; Hash[B, Array[A]]&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;&lt;tt&gt;Hash[A,B] &amp;amp;(A,B-&amp;gt;C) -&amp;gt; Hash[A,C]&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;&lt;tt&gt;Hash[A, Hash[B,C]] -&amp;gt; Hash[[A,B], C]&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;&lt;tt&gt;Hash[A,B] &amp;amp;(A,B-&amp;gt;C) -&amp;gt; Hash[C, Hash[A,B]]&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;&lt;tt&gt;Enumerable[Hash[A,B]] &amp;amp;(A,B,B-&amp;gt;B) -&amp;gt; Hash[A,B]&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;&lt;tt&gt;Hash[A,Set[B]] -&amp;gt; Hash[Set[A], Set[B]]&lt;/tt&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Even these short snippets should give a pretty good idea what these are all about.&lt;br /&gt;&lt;br /&gt;That's it for now. Hopefully it won't be long until that promised 1.9 collections post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-2058657459732461917?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/2058657459732461917/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=2058657459732461917' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/2058657459732461917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/2058657459732461917'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/07/we-need-syntax-for-talking-about-ruby.html' title='We need syntax for talking about Ruby types'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_IYGc_MWwkfw/TEWDHlH1PMI/AAAAAAAAA_U/585PGD67q4Y/s72-c/koteczek_by_kemcio_from_flickr_cc-nc.jpg' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-6482169166654361990</id><published>2010-07-18T07:22:00.000+02:00</published><updated>2010-07-18T07:22:03.270+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>If only Ruby had macros</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/TEKOzKw02BI/AAAAAAAAA_E/fKctL2TcCHM/s1600/kicius_gustaw_czarowny_by_k0p_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Kicius Gustaw Czarowny by K0P from flickr (CC-NC-ND)"&gt;&lt;img alt="Kicius Gustaw Czarowny by K0P from flickr (CC-NC-ND)" border="0" height="640" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/TEKOzKw02BI/AAAAAAAAA_E/fKctL2TcCHM/s640/kicius_gustaw_czarowny_by_k0p_from_flickr_cc-nc-nd.jpg" width="392" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Blogger will most likely totally destroy code formatting again, sorry about that.&lt;/i&gt; &lt;br /&gt;&lt;br /&gt;Ruby annoys me a lot - the code gets so close to being Just Right, with only that last little bit of wrongness that won't go away no matter what. With everything except Ruby at least I know it will be crap no matter what, so I never get this.&lt;br /&gt;&lt;br /&gt;For example it's so easy to make a function generating successive values on each call:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;def counter(v)&lt;/pre&gt;&lt;pre&gt;return counter(v, &amp;amp;:succ) unless block_given?&lt;br /&gt;&amp;nbsp; proc{ v = yield(v) }&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But you must give it value before the first - and sometimes such a thing doesn't exist, like with generating successive labels &lt;tt&gt;"a", "b", "c" ...&lt;/tt&gt; A counter starting from the first value passed isn't exactly difficult, it just doesn't feel right:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;def counter(v)&lt;/pre&gt;&lt;pre&gt;return counter(v, &amp;amp;:succ) unless block_given?&lt;br /&gt;&amp;nbsp; proc{ old, v = v, yield(v); old }&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;Useless variables like &lt;tt&gt;old&lt;/tt&gt; that only indicate control flow just annoy me. Not to mention lack of default block argument. I'm undecided if this &lt;tt&gt;tap&lt;/tt&gt; makes things better or worse.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;def counter(v)&lt;/pre&gt;&lt;pre&gt;return counter(v, &amp;amp;:succ) unless block_given?&lt;br /&gt;&amp;nbsp; proc{v.tap{ v = yield(v) }}&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;Another example. This wrapper for Ruby executable makes rubygems and -r compatible. It's so close to being able to use &lt;tt&gt;Array#map&lt;/tt&gt;, and yet so far away:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;args = []&lt;br /&gt;while arg = ARGV.shift&lt;br /&gt;&amp;nbsp; if arg =~ /\A-r(.*)\z/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; lib = $1.empty? ? ARGV.shift : $1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; args &amp;lt;&amp;lt; "-e" &amp;lt;&amp;lt; "require 'rubygems'; require '#{lib}'"&lt;br /&gt;&amp;nbsp; else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; args &amp;lt;&amp;lt; arg&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;end&lt;br /&gt;exec "ruby", *args&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Yes, these are tiny things, but it's frustrating to get almost there. By the way, &lt;tt&gt;-r&lt;/tt&gt; should just call &lt;tt&gt;require&lt;/tt&gt;, another thing which is almost right but no.&lt;br /&gt;&lt;br /&gt;I could go on with these small examples, but I want to talk about something bigger. A very common pattern in all programming languages is something like this: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;collection.each{|item|&lt;/pre&gt;&lt;pre&gt;&amp;nbsp; if item.test_1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; item.action_1 &lt;br /&gt;&amp;nbsp; elsif item.test_2&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; item.action_2&lt;br /&gt;&amp;nbsp; elsif item.test_3&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; item.action_3&lt;br /&gt;&amp;nbsp; else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; item.otherwise&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Or a very similar:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;collection.each{|item|&lt;/pre&gt;&lt;pre&gt;case item&lt;br /&gt;&amp;nbsp; when pattern_1&lt;br /&gt; &amp;nbsp;&amp;nbsp; item.action_1 &lt;br /&gt;&amp;nbsp; when pattern_2&lt;br /&gt;    item.action_2&lt;br /&gt;&amp;nbsp; when pattern_3&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; item.action_3&lt;br /&gt;&amp;nbsp; else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; item.otherwise&lt;/pre&gt;&lt;pre&gt;end&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Tests and actions are all next to each other, where they belong. But what if instead of executing an action on a single item at a time, we wanted to do so on all matching items together?&lt;br /&gt;&lt;br /&gt;If Ruby had proper macros it would be totally trivial - unfortunately Ruby forces us to choose one of bad options. First, the most straightforward:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;yes1, no1 = collection.partition{|item| item.test_1}&lt;br /&gt;yes2, no12 = no1.partition{|item| item.test_2}&lt;br /&gt;yes3, no123 = no12.partition{|item| item.test_3}&lt;br /&gt;&lt;br /&gt;yes_1.action_1&lt;br /&gt;yes_2.action_2&lt;br /&gt;yes_3.action_3&lt;br /&gt;no123.otherwise&lt;/pre&gt;&lt;br /&gt;Rather awful. Or perhaps this?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;groups = collection.group_by{|item|&lt;/pre&gt;&lt;pre&gt;if item.test_1 then 1&lt;br /&gt;&amp;nbsp; elsif item.test_2 then 2&lt;br /&gt;&amp;nbsp; elsif item.test_3 then 3&lt;br /&gt;&amp;nbsp; else 4&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;}&lt;br /&gt;(groups[1]||[]).action_1&lt;br /&gt;(groups[2]||[]).action_2&lt;br /&gt;(groups[3]||[]).action_3&lt;br /&gt;(groups[4]||[]).otherwise&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;By the way we cannot use a series of &lt;tt&gt;select&lt;/tt&gt;s here - &lt;tt&gt;action_3&lt;/tt&gt; should apply only to items which pass &lt;tt&gt;test_3&lt;/tt&gt; but not &lt;tt&gt;test_1&lt;/tt&gt; or &lt;tt&gt;test_2&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;We can imagine adding extra methods to &lt;tt&gt;Enumerable&lt;/tt&gt; to get syntax like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;collection.run_for_each_group(&lt;/pre&gt;&lt;pre&gt;proc{|item| item.test_1}, proc{|group| group.action_1},&lt;br /&gt;&amp;nbsp; proc{|item| item.test_2}, proc{|group| group.action_2},&lt;br /&gt;&amp;nbsp; proc{|item| item.test_3}, proc{|group| group.action_3},&lt;br /&gt;&amp;nbsp;                           proc{|group| group.otherwise})&lt;/pre&gt;&lt;br /&gt;Or maybe like this (looks even worse if you need to assign groups to a variable before performing the relevant action):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;tmp = collection.dup&lt;/pre&gt;&lt;pre&gt;tmp.destructive_select!{|item| item.test_1}.action_1&lt;br /&gt;tmp.destructive_select!{|item| item.test_2}.action_2&lt;br /&gt;tmp.destructive_select!{|item| item.test_3}.action_3&lt;br /&gt;tmp.otherwise&lt;/pre&gt;&lt;br /&gt;&lt;tt&gt;#destructive_select!&lt;/tt&gt; being a method in style of Perl's &lt;tt&gt;splice&lt;/tt&gt; - removing some items from collection, and returning removed values.&lt;br /&gt;&lt;br /&gt;Possibly wrapping it in something like:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;collection.filter{|item| item.test_1}.action{|group| group.action_1}.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .filter{|item| item.test_2}.action{|group| group.action_2}.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .filter{|item| item.test_3}.action{|group| group.action_3}.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;     &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .action{|group| group.otherwise}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/TEKPEHGC7GI/AAAAAAAAA_M/PaDAc3blnbY/s1600/its_kicius_by_starlightexpress_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="It's Kicius by starlightexpress from flickr (CC-NC-ND)"&gt;&lt;img alt="It's Kicius by starlightexpress from flickr (CC-NC-ND)" border="0" height="480" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/TEKPEHGC7GI/AAAAAAAAA_M/PaDAc3blnbY/s640/its_kicius_by_starlightexpress_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;A few more bad ideas (David Allen says the way you can tell a highly creative person is that they generate bad ideas faster than anyone else). With &lt;tt&gt;instance_eval&lt;/tt&gt; we could do something like this, with &lt;tt&gt;item&lt;/tt&gt; and &lt;tt&gt;group&lt;/tt&gt; being appropriate method calls.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;collection.run_for_each_group{&lt;/pre&gt;&lt;pre&gt;&amp;nbsp; rule{ item.test_1 }&lt;br /&gt;&amp;nbsp; action{ group.action_1 }&lt;br /&gt;&lt;br /&gt;&amp;nbsp; rule{ item.test_2 }&lt;br /&gt;&amp;nbsp; action{ group.action_2 }&lt;br /&gt;&lt;br /&gt;&amp;nbsp; rule{ item.test_3 }&lt;br /&gt;&amp;nbsp; action{ group.action_3 }&lt;br /&gt;&lt;br /&gt;&amp;nbsp; action{ group.otherwise }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;It would be pretty hard to do that while still being able to have  inner blocks with your current object's context. By the way trying this  out I found out that it's impossible to call a block specifying &lt;tt&gt;self&lt;/tt&gt;,  and call a block passing arguments at the same time - it's only one or  the other - and no combination of the two makes it work. Those tiny  limitations are just infuriating.&lt;br /&gt;&lt;br /&gt;I also tried overriding &lt;tt&gt;===&lt;/tt&gt;. Now that would only work for a small subset of cases but was worth a try:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;collection.run_for_each_group{|item, group|&lt;br /&gt;&amp;nbsp; case item&lt;br /&gt;&amp;nbsp; when pattern_1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.action_1&lt;br /&gt;&amp;nbsp; when pattern_2&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.action_2&lt;br /&gt;  when pattern_3&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.action_3&lt;br /&gt;&amp;nbsp; else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.otherwise&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This item would actually be a special object, calling &lt;tt&gt;===&lt;/tt&gt; on which would callcc, partition collection in two, and resume twice modifying &lt;tt&gt;group&lt;/tt&gt; variable (initially set to the entire collection). That would be pretty cool - except Ruby doesn't use double dispatch, so &lt;tt&gt;===&lt;/tt&gt; is not a CLOS style generic function - it's a method, set on pattern objects, and while adding new pattern types is easy, making old patterns match new kinds of objects is hard. It would require manually finding out every pattern, and manually overriding it to handle our magic item type - and then a lot of hackery to make &lt;tt&gt;Regexp#===&lt;/tt&gt; work, and then it would fail anyway, as &lt;tt&gt;Range#===&lt;/tt&gt; and such seem to be handled specially by Ruby.&lt;br /&gt;&lt;br /&gt;There was a related possibility of not doing anything weird to &lt;tt&gt;item&lt;/tt&gt;, but requiring special patterns:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;collection.run_for_each_group{|item, group, all|&lt;br /&gt;&amp;nbsp; case item&lt;br /&gt;&amp;nbsp; when all[pattern_1]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.action_1&lt;br /&gt;&amp;nbsp; when all[pattern_2]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.action_2&lt;br /&gt;&amp;nbsp; when all[pattern_3]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.action_3&lt;br /&gt;&amp;nbsp; else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.otherwise&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;We're not actually using &lt;tt&gt;item&lt;/tt&gt; here all, so we don't really need to pass it:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;collection.run_for_each_group{|group, all|&lt;br /&gt;  if all[pattern_1]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.action_1&lt;br /&gt;&amp;nbsp; elsif all[pattern_2]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.action_2&lt;br /&gt;&amp;nbsp; elsif all[pattern_3]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.action_3&lt;br /&gt;&amp;nbsp; else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.otherwise&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Totally implementable, only somewhat ugly with all these &lt;tt&gt;all[]&lt;/tt&gt;s. There are two good ways to implement it - &lt;tt&gt;all&lt;/tt&gt; function would test all items, and if all returned the same value it would just return. Otherwise, it would divide the collection, and in one implementation use callcc, or in alternative implementation, throw something, and restart the whole block twice - this assumes tests are cheap and deterministic.&lt;br /&gt;&lt;br /&gt;It looks good, but it doesn't make me happy, as I want all kinds of tests, not just pattern matches. And eventually I came up with this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;collection.run_for_each_group{|item, group, all|&lt;br /&gt;  if all[item.test_1]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.action_1&lt;br /&gt;&amp;nbsp; elsif all[item.test_2]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.action_2&lt;br /&gt;&amp;nbsp; elsif all[item.test_3]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.action_3&lt;br /&gt;&amp;nbsp; else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; group.otherwise&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;This way, you can do any test on &lt;tt&gt;item&lt;/tt&gt; you want - just pass the result to &lt;tt&gt;all[]&lt;/tt&gt; before proceeding.&lt;br /&gt;&lt;br /&gt;How is it implemented? I could callcc for every element, but unlike Scheme's, Ruby's callcc is rather expensive. And not every version of Ruby has it. So it's the naive throw-and-restart-twice instead. This means tests on each item can be rerun many times, so they better be cheap. Determinism is also advised, even though my implementation caches the first value returned to avoid troubles.&lt;br /&gt;&lt;br /&gt;Well, first some usage example you can actually run:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;require "pathname"&lt;/pre&gt;&lt;pre&gt;files = Pathname("/etc").children&lt;br /&gt;files.run_for_each_group{|x,xs,all|&lt;br /&gt;&amp;nbsp; if all[x.directory?]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; puts "Subdirectories: #{xs*' '}"&lt;br /&gt;&amp;nbsp; elsif all[x.symlink?]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; puts "Symlinks: #{xs*' '}"&lt;br /&gt;&amp;nbsp; elsif all[x.size &amp;gt; 2**16]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; puts "Big files: #{xs*' '}"&lt;br /&gt;&amp;nbsp; else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; puts "The rest: #{xs.size} files"&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Doesn't it look a lot lot better than a long cascade of &lt;tt&gt;#partition&lt;/tt&gt;s?&lt;br /&gt;&lt;br /&gt;And now &lt;tt&gt;#run_for_in_group&lt;/tt&gt;:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;module Enumerable &lt;br /&gt;&amp;nbsp; def run_for_each_group(expected=[], &amp;amp;blk)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return if empty?&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; xst, xsf = [], []&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; each{|it|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; answers = expected.dup&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; catch :item_tested do&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; yield(it, self, proc{|v|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if answers.empty?&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (v ? xst : xsf) &amp;lt;&amp;lt; it&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw :item_tested&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; end&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; answers.pop&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; })&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; end&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; xst.run_for_each_group([true, *expected], &amp;amp;blk)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; xsf.run_for_each_group([false, *expected], &amp;amp;blk)&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;It shouldn't be that difficult to understand. &lt;tt&gt;expected&lt;/tt&gt; tracks the list of expected test results for all items in current collection. Now we iterate, passing each element, the entire group, and &lt;tt&gt;all&lt;/tt&gt; callback function.&lt;br /&gt;&lt;br /&gt;The first few times &lt;tt&gt;all&lt;/tt&gt; is called, it just returns recorded answers - they're the same for every element. If after all recorded answers &lt;tt&gt;all&lt;/tt&gt; is called again - we record its result, throw out of the block, and rerun it twice with expanded expectations.&lt;br /&gt;&lt;br /&gt;On the other hand if we didn't get any calls to &lt;tt&gt;all&lt;/tt&gt; other than those already recorded, it means we reached the action - &lt;tt&gt;group&lt;/tt&gt; it sees is every element with the same test history. This must only happen once for group, so we return from function.&lt;br /&gt;&lt;br /&gt;Total number of block calls is - 1x for each action, 2x for directories, 3x for symlinks, 4x for big files, and also 4x for everything else. Avoiding these reruns would be totally possible with callcc - but it's rather ugly, and often these tests aren't an issue.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So problem solved? Not really. I keep finding myself in situations where a new control structure would make a big difference, and there just doesn't seem to be any way of making it work in Ruby without enough boilerplate code to make it not worthwhile.&lt;br /&gt;&lt;br /&gt;I'll end this post with some snippets of code which are just not quite right. Any ideas for making them suck less?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;urls = Hash[file.map{|line| id, url = line.split; [id.to_i, url]}]&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;each_event{|type, *args| &lt;br /&gt;&amp;nbsp; case type&lt;br /&gt;&amp;nbsp; when :foo&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; one, two = *args&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # ...&lt;br /&gt;&amp;nbsp; when :bar&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; one, = *args&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # ...&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;if dir&lt;/pre&gt;&lt;pre&gt;Dir.chdir(dir){ yield(x) }&lt;br /&gt;else&lt;br /&gt;&amp;nbsp; yield(x)&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-6482169166654361990?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/6482169166654361990/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=6482169166654361990' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/6482169166654361990'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/6482169166654361990'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/07/if-only-ruby-had-macros.html' title='If only Ruby had macros'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_IYGc_MWwkfw/TEKOzKw02BI/AAAAAAAAA_E/fKctL2TcCHM/s72-c/kicius_gustaw_czarowny_by_k0p_from_flickr_cc-nc-nd.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-6060448889398245876</id><published>2010-07-17T21:44:00.000+02:00</published><updated>2010-07-17T21:44:35.171+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Ruby is now more popular than C++</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/TEIHxi-MUwI/AAAAAAAAA-8/FnsmfimcuQI/s1600/_by_bc_cf_from_flickr_cc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="啊？！ by bc cf from flickr (CC-ND)"&gt;&lt;img alt="啊？！ by bc cf from flickr (CC-ND)" border="0" height="428" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/TEIHxi-MUwI/AAAAAAAAA-8/FnsmfimcuQI/s640/_by_bc_cf_from_flickr_cc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;There are many ways to measure popularity, and I'll take one proposed by creator of C++  Bjarne Stroustrup. According to him there are only two kinds of languages - those that nobody uses and those  that everybody bitches about - so counting google results for "&amp;lt;language&amp;gt; sucks" is a perfectly good way of measuring popularity.&lt;br /&gt;&lt;br /&gt;I did &lt;a href="http://t-a-w.blogspot.com/2006/07/language-popularity-metrics.html"&gt;an identical experiment exactly 4 years ago&lt;/a&gt;, so it's interesting to see what changed since then.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;D 147000 - mostly bogus matches for "3D sucks" etc.&lt;/li&gt;&lt;li&gt;Java 56300&lt;/li&gt;&lt;li&gt;C 48900 - possibly also many bogus matches&lt;/li&gt;&lt;li&gt;PHP 34500&lt;/li&gt;&lt;li&gt;Ruby 25900&lt;/li&gt;&lt;li&gt;Ruby on Rails 18100 - included for comparison only&lt;/li&gt;&lt;li&gt;Scheme 14900 - &lt;a href="http://t-a-w.blogspot.com/2006/07/list-of-things-that-suck-in-scheme.html"&gt;my blog is #1&lt;/a&gt;, also many bogus matches &lt;/li&gt;&lt;li&gt;C++ 14000&lt;/li&gt;&lt;li&gt;Visual Basic 11600&lt;/li&gt;&lt;li&gt;Python 8930&amp;nbsp;&lt;/li&gt;&lt;li&gt;Perl 5450&lt;/li&gt;&lt;li&gt;Lisp 3510&lt;/li&gt;&lt;li&gt;C# 3310&lt;/li&gt;&lt;li&gt;Ada 1240&lt;/li&gt;&lt;li&gt;OCaml 1070&lt;/li&gt;&lt;li&gt;SML 784&lt;/li&gt;&lt;li&gt;Erlang 750&lt;/li&gt;&lt;li&gt;Cobol 641&lt;/li&gt;&lt;li&gt;Fortran 476&lt;/li&gt;&lt;li&gt;Haskell 416&lt;/li&gt;&lt;li&gt;Smalltalk 176&lt;/li&gt;&lt;li&gt;Prolog 161 &lt;/li&gt;&lt;/ul&gt;Some things just don't change. Ignoring queries with too many false positives, the list is dominated by  Java and PHP, just as four years ago - with Java lead now being a lot stronger. Most niche languages like OCaml, Smalltalk, and Prolog are still niche languages - although many get a lot of bitching these days (like OCaml's 17x increase).&lt;br /&gt;&lt;br /&gt;On the other hand some things changed. Perl used to be very high in the sucking charts - at about 15x as many sucks as Ruby and Python, but isn't anywhere close to the top now, losing almost half of the sucks in that time, as old ones die in link rot, and new ones stop being generated.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The second biggest success story is Python, which sucks 12x as much now, finally overtaking Perl.&lt;br /&gt;&lt;br /&gt;But the biggest success is a spectacular explosion of popularity of Ruby. My first list was released only half a year after Rails 1.0, when many people were intrigued by Ruby, but few were actually using it. In those four years Ruby suckiness levels exploded 43x - not even counting Rails bitching, a lot of which is as much about Ruby as about Rails themselves.&lt;br /&gt;&lt;br /&gt;Ruby is now a lot more popular than C++ - according to the very metric endorsed by C++ creator. What alternative explanation is there? That C++ is used a lot, it just happens to suck less? Come on.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;People complaining about scientific validity of this post are &lt;a href="http://t-a-w.blogspot.com/2010/04/boobquake-experiment-is-bad-science.html"&gt;sent here&lt;/a&gt;.&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-6060448889398245876?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/6060448889398245876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=6060448889398245876' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/6060448889398245876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/6060448889398245876'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/07/ruby-is-now-more-popular-than-c.html' title='Ruby is now more popular than C++'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_IYGc_MWwkfw/TEIHxi-MUwI/AAAAAAAAA-8/FnsmfimcuQI/s72-c/_by_bc_cf_from_flickr_cc-nd.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-1605732407967845478</id><published>2010-07-17T20:22:00.000+02:00</published><updated>2010-07-17T20:22:58.293+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Another example of Ruby being awesome - %W</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/TEHzuMAUuiI/AAAAAAAAA-0/7rgc_hdm1ao/s1600/cuteness_by_sparkleice_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="cuteness by sparkleice from flickr (CC-NC-ND)"&gt;&lt;img alt="cuteness by sparkleice from flickr (CC-NC-ND)" border="0" height="640" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/TEHzuMAUuiI/AAAAAAAAA-0/7rgc_hdm1ao/s640/cuteness_by_sparkleice_from_flickr_cc-nc-nd.jpg" width="480" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;And there I was thinking I knew everything about Ruby, at least as far as its syntax goes...&lt;br /&gt;&lt;br /&gt;As you might have figured out from my previous posts, I'm totally obsessed about string escaping hygiene - I would never send &lt;tt&gt;"SELECT * FROM reasons_why_mysql_sucks WHERE reason_id = #{id}"&lt;/tt&gt; to an sql server even if I was absolutely totally certain that &lt;tt&gt;id&lt;/tt&gt; is a valid integer and nothing can possibly go wrong here. Sure, I might be right 99% of time, but it only takes a single such mistake to screw up the system. And not only with SQL - it's the same with generated HTML, generated shell commands and so on.&lt;br /&gt;&lt;br /&gt;And speaking of shell commands - &lt;tt&gt;system&lt;/tt&gt; function accepts either a string which it then evaluates according to shell rules (big red flag), or a list of arguments which it uses to fork+exec right away. Of course we want to do that - except it's really goddamn ugly. Faced with a choice between this insecure but reasonably looking way of starting MongoDB shard servers:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;system "mongod --shardsvr --port '#{port}' --fork --dbpath '#{data_dir}' \&lt;/pre&gt;&lt;pre&gt;--logappend --logpath '#{logpath}' --directoryperdb"&lt;/pre&gt;&lt;br /&gt;And this secure but godawful (&lt;tt&gt;to_s&lt;/tt&gt; is necessary as &lt;tt&gt;port&lt;/tt&gt; is an integer, and &lt;tt&gt;system&lt;/tt&gt; won't take that):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;system *["mongod", "--shardsvr", "--port", port, "--fork",&lt;/pre&gt;&lt;pre&gt;"--dbpath", data_dir, "--logappend",&lt;/pre&gt;&lt;pre&gt;"--logpath", logpath, "--directoryperdb"].map(&amp;amp;:to_s)&lt;/pre&gt;&lt;br /&gt;Even I have my doubts.&lt;br /&gt;&lt;br /&gt;And then I found something really cool in Ruby syntax that totally solves the problem. Now I was totally aware of &lt;tt&gt;%w[foo bar]&lt;/tt&gt; syntax Ruby copied from Perl's &lt;tt&gt;qw[foo bar]&lt;/tt&gt;, and while useful occasionally, is really little more than constructing a string, and then calling &lt;tt&gt;#split&lt;/tt&gt; on that.&lt;br /&gt;&lt;br /&gt;And I though I was also aware of &lt;tt&gt;%W&lt;/tt&gt; - which obviously would work just like &lt;tt&gt;%w&lt;/tt&gt; except evaluating code inside. Except that's not what it does! &lt;tt&gt;%W[foo #{bar}]&lt;/tt&gt; is not &lt;tt&gt;"foo #{bar}".split&lt;/tt&gt; - it's &lt;tt&gt;["foo", "#{bar}"]&lt;/tt&gt;! And using a real parser of course, so you can use as many spaces inside that code block as you want.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;system *%W[mongod --shardsvr --port #{port} --fork --dbpath #{data_dir}&lt;/pre&gt;&lt;pre&gt;--logappend --logpath #{logpath} --directoryperdb]&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;There's nothing in Perl able to do that. Not only it's totally secure, it looks every better than the original insecure version as you don't need to insert all those &lt;tt&gt;'&lt;/tt&gt;s around arguments (which only half-protected them anyway, but were better than nothing), and you can break it into multiple lines without &lt;tt&gt;\&lt;/tt&gt;s.&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;%W&lt;/tt&gt; always does the right thing - &lt;tt&gt;%W[scp #{local_path} #{user}@#{host}:#{remote_path}]&lt;/tt&gt; will keep the whole remote address together - and if the code block returns an empty string or nil, you'll get an empty string there in the resulting array. I sort of wish there was some way of adding extra arguments with &lt;tt&gt;*args&lt;/tt&gt;-like syntax like in other contexts, but &lt;tt&gt;%W[...] + args&lt;/tt&gt; does exactly that, so it's not a big deal.&lt;br /&gt;&lt;br /&gt;By the way, it seems to me that all &lt;tt&gt;%&lt;/tt&gt; constructors undeservingly get a really bad reputation as some sort of ugly Perl leftover in Ruby community. This is so wrong - what's ugly is excessive escaping with &lt;tt&gt;\&lt;/tt&gt; which they help avoid. Which regexp for Ruby executables looks less bad, the one with way too many &lt;tt&gt;\/&lt;/tt&gt;s - &lt;tt&gt;/\A(\/usr|\/usr\/local|\/opt|)\/bin\/j?ruby[\d.]*\z/&lt;/tt&gt;, or one which avoids them all thanks to &lt;tt&gt;%r&lt;/tt&gt; - &lt;tt&gt;%r[\A(/usr|/usr/local|/opt|)/bin/j?ruby[\d.]*\z]&lt;/tt&gt;?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;By the way - yes I used &lt;tt&gt;[]&lt;/tt&gt;s inside even though they were the big demarcator. That's another great beauty of &lt;tt&gt;%&lt;/tt&gt; constructions - if you demarcate with some sort of braces like &lt;tt&gt;[]&lt;/tt&gt;, &lt;tt&gt;()&lt;/tt&gt;, &lt;tt&gt;&amp;lt;&amp;gt;&lt;/tt&gt;, or &lt;tt&gt;{}&lt;/tt&gt; - it will only close once every matched pair inside is closed - so unlike traditional singly and doubly quoted strings &lt;tt&gt;%&lt;/tt&gt; can be nested infinitely deep without a single escape character! (Perl could do that one as well)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And speaking of things that Ruby copied from Perl, and then made them much more awesome, here's a one-liner to truncate a bunch of files after 10 lines, with optional backups. Which language gets even close to matching that? (&lt;tt&gt;$.&lt;/tt&gt; in both Perl and Ruby will keep increasing from file to file, so you cannot use that)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;ruby -i.bak -ple 'ARGF.skip if ARGF.file.lineno &amp;gt; 10' files*.txt&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-1605732407967845478?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/1605732407967845478/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=1605732407967845478' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1605732407967845478'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1605732407967845478'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/07/another-example-of-ruby-being-awesome-w.html' title='Another example of Ruby being awesome - %W'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_IYGc_MWwkfw/TEHzuMAUuiI/AAAAAAAAA-0/7rgc_hdm1ao/s72-c/cuteness_by_sparkleice_from_flickr_cc-nc-nd.jpg' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-3764195014101625516</id><published>2010-07-16T07:44:00.000+02:00</published><updated>2010-07-16T07:44:37.494+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Arrays are not integer-indexed Hashes</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/TD_xlLnppyI/AAAAAAAAA-s/K9FVpY-ze_8/s1600/cabooki_by_elycefeliz_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Cabooki by elycefeliz from flickr (CC-NC-ND)"&gt;&lt;img alt="Cabooki by elycefeliz from flickr (CC-NC-ND)" border="0" height="640" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/TD_xlLnppyI/AAAAAAAAA-s/K9FVpY-ze_8/s640/cabooki_by_elycefeliz_from_flickr_cc-nc-nd.jpg" width="606" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;We use a separate &lt;tt&gt;Array&lt;/tt&gt; type even though Ruby &lt;tt&gt;Hash&lt;/tt&gt;es can be indexed by integers perfectly well (unlike Perl hashes which implicitly convert all hash keys to strings, and array keys to integers). Hypothetically, we could get rid of them altogether and treat &lt;tt&gt;["foo", "bar"]&lt;/tt&gt; as syntactic sugar for &lt;tt&gt;{0=&amp;gt;"foo", 1=&amp;gt;"bar"}&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;Now there are obviously some performance reasons for this - &lt;a href="http://judy.sourceforge.net/"&gt;these are mostly fixable and a single data structure can perform well in both roles&lt;/a&gt;. And it would break backwards compatibility rather drastically, but let's ignore all that and imagine we're designing a completely fresh language which simply looks a lot like Ruby.&lt;br /&gt;&lt;h3&gt;What would work&lt;/h3&gt;&lt;br /&gt;First, a lot of things work right away like &lt;tt&gt;[]&lt;/tt&gt;,  &lt;tt&gt;[]=&lt;/tt&gt;, &lt;tt&gt;==&lt;/tt&gt;, &lt;tt&gt;size&lt;/tt&gt;, &lt;tt&gt;clear&lt;/tt&gt;, &lt;tt&gt;replace&lt;/tt&gt;, and &lt;tt&gt;zip&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The first incompatibility is with &lt;tt&gt;each&lt;/tt&gt; - for hashes it yields both keys and values, for arrays only values, and we'd need to decide one way or the other - I think yielding both makes more sense, but then there are all those non-indexable enumerables which won't be able to follow this change, so there are good reasons to only yield values as well. In any case, &lt;tt&gt;each_pair&lt;/tt&gt;, &lt;tt&gt;each_key&lt;/tt&gt;, and &lt;tt&gt;each_value&lt;/tt&gt; would be available.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Either way, one more change would be necessary here - &lt;tt&gt;each&lt;/tt&gt; and everything else would need to yield elements sorted by key. There are performance implications, but they're not so bad, and it would be nicer API.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Hash's methods &lt;tt&gt;keys&lt;/tt&gt;, &lt;tt&gt;values&lt;/tt&gt;, &lt;tt&gt;invert&lt;/tt&gt;, and &lt;tt&gt;update&lt;/tt&gt; all make perfect sense for Arrays. With keys sorted, &lt;tt&gt;first&lt;/tt&gt;, &lt;tt&gt;last&lt;/tt&gt;, and &lt;tt&gt;pop&lt;/tt&gt; would work quite well. &lt;tt&gt;push&lt;/tt&gt;/&lt;tt&gt;&amp;lt;&amp;lt;&lt;/tt&gt; would be slightly nontrivial - but making it add &lt;tt&gt;#succ&lt;/tt&gt; of the last key (or 0 for empty hashes) would work well enough.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Collection tests like &lt;tt&gt;any?&lt;/tt&gt;, &lt;tt&gt;all?&lt;/tt&gt;, &lt;tt&gt;one?&lt;/tt&gt;, &lt;tt&gt;none?&lt;/tt&gt; are obvious once we decide &lt;tt&gt;each&lt;/tt&gt;, and so is &lt;tt&gt;count&lt;/tt&gt;. &lt;tt&gt;map&lt;/tt&gt;/&lt;tt&gt;collect&lt;/tt&gt; adapts to hashes well enough (yielding both key and value, and returning new value).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Array methods like &lt;tt&gt;shuffle&lt;/tt&gt;, &lt;tt&gt;sort&lt;/tt&gt;, &lt;tt&gt;sample&lt;/tt&gt;, &lt;tt&gt;uniq&lt;/tt&gt;, and &lt;tt&gt;flatten&lt;/tt&gt; which ignore indexes (but not their relative positions) would do likewise for hashes, so flattening &lt;tt&gt;{"a"=&amp;gt;[10,20], "b"=&amp;gt;30}&lt;/tt&gt; would result in &lt;tt&gt;[10,20,30]&lt;/tt&gt; (&lt;tt&gt;"a"&lt;/tt&gt; yields before &lt;tt&gt;"b"&lt;/tt&gt;).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Enumerable methods like &lt;tt&gt;min&lt;/tt&gt;/&lt;tt&gt;max&lt;/tt&gt;/&lt;tt&gt;min_by&lt;/tt&gt;/&lt;tt&gt;max_by&lt;/tt&gt;, &lt;tt&gt;find&lt;/tt&gt;, &lt;tt&gt;find_index&lt;/tt&gt;, &lt;tt&gt;inject&lt;/tt&gt; would do likewise.&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;include?&lt;/tt&gt; checks values for Arrays and keys for hashes - we can throw that one out (or decide one way or the other, values make more sense to me), and use &lt;tt&gt;has_key?&lt;/tt&gt;/&lt;tt&gt;has_value?&lt;/tt&gt; when it matters.&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;reverse&lt;/tt&gt; should just return values, but &lt;tt&gt;reverse_each&lt;/tt&gt; should yield real keys.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I could go on like this. My point is - a lot of this stuff can be made to work really well. Usually there's a single behavior sensible for both Arrays, and Hashes, and if you really need something different then &lt;tt&gt;keys&lt;/tt&gt;, &lt;tt&gt;values&lt;/tt&gt;, or &lt;tt&gt;pairs&lt;/tt&gt; would usually be a suitable solution.&lt;br /&gt;&lt;h3&gt;What doesn't work&lt;/h3&gt;&lt;br /&gt;Unfortunately some things cannot be made to work. Consider this - what should be the return value of &lt;tt&gt;{0 =&amp;gt; "zero", 1 =&amp;gt; "one"}.select{|k,v| v == "one"}&lt;/tt&gt;?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If we treat it as a hash - let's say a mapping of numbers to their English names, there is only one correct answer, and everything else is completely wrong - &lt;tt&gt;{1=&amp;gt;"one"}&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;On the other hand if we treat it as an array - just an ordered list of words -  there is also only one correct answer, and everything else is completely wrong - &lt;tt&gt;{0=&amp;gt;"one"}&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;These two are of course totally incompatible. And an identical problem affects a lot of essential methods. Deleting an element renumbers items for an array, but not for a hash. &lt;tt&gt;shift&lt;/tt&gt;/&lt;tt&gt;unshift&lt;/tt&gt;/&lt;tt&gt;drop&lt;/tt&gt;/&lt;tt&gt;insert&lt;/tt&gt;/&lt;tt&gt;slice&lt;/tt&gt; make so sense for hashes, and methods like &lt;tt&gt;group_by&lt;/tt&gt; and &lt;tt&gt;partition&lt;/tt&gt; have two valid and conflicting interpretations. It is, pretty much, unfixable.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So what went wrong? Thinking that Arrays are indexed by integers was wrong!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In &lt;tt&gt;{0=&amp;gt;"zero",1=&amp;gt;"one"}&lt;/tt&gt; association between keys and values is extremely strong - key &lt;tt&gt;0&lt;/tt&gt; is associated with value &lt;tt&gt;"zero"&lt;/tt&gt;, and key &lt;tt&gt;1&lt;/tt&gt; with value &lt;tt&gt;"one"&lt;/tt&gt;. They exist as a pair and everything that happens to the hash happens to pairs, not to keys or values separately - there are no operations like &lt;tt&gt;insert_value&lt;/tt&gt;, &lt;tt&gt;delete_value&lt;/tt&gt; which would just shift remaining values around from one key to another. This is the nature of hashes.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Arrays are not at all like that. In &lt;tt&gt;["zero", "one"]&lt;/tt&gt; association between &lt;tt&gt;0&lt;/tt&gt; and &lt;tt&gt;"zero"&lt;/tt&gt; is very weak. The real keys are not &lt;tt&gt;0&lt;/tt&gt;, and &lt;tt&gt;1&lt;/tt&gt; - they're two objects devoid of any external meaning, whose only property is their relative partial order.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To implement array semantics on top of hashes, we need a class like &lt;tt&gt;Index.new(greater_that=nil, less_than=nil)&lt;/tt&gt;. Then a construction like this would have semantics we desire.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;arr = {}&lt;br /&gt;&lt;br /&gt;arr[Index.new(arr.last_key, nil)] = "zero"&lt;br /&gt;&lt;br /&gt;arr[Index.new(arr.last_key, nil)] = "one"&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If we use these instead of integers, hashes can perform all array operations correctly.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;# shift&lt;br /&gt;&lt;br /&gt;arr.delete(arr.first_key)&lt;br /&gt;&lt;br /&gt;# unshift&lt;br /&gt;&lt;br /&gt;arr[Index.new(nil, arr.first_key)] = "minus one"&lt;br /&gt;&lt;br /&gt;# select - indexes for "zero" and "two" in result have correct order&lt;br /&gt;&lt;br /&gt;["zero", "one", "two"].select{|key, value| value != "one"}&lt;br /&gt;&lt;br /&gt;# insert - nth_key only needs each&lt;br /&gt;&lt;br /&gt;arr[Index.new(arr.nth_key(0), arr.nth_key(1))] = "one and half"&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And so the theory is satisfied. We have a working solution, even if highly impractical one. Of course all these &lt;tt&gt;Index&lt;/tt&gt; objects are rather hard to use, so the first thing we'd do is subclassing &lt;tt&gt;Hash&lt;/tt&gt; so that &lt;tt&gt;arr[i]&lt;/tt&gt; would really mean &lt;tt&gt;arr[arr.nth_key(i)]&lt;/tt&gt; and so on, and there's really no point yielding them in &lt;tt&gt;#each&lt;/tt&gt; and friends... oh wait, that's exactly where we started.&lt;br /&gt;&lt;br /&gt;In other words, unification of arrays and hashes is impossible - at least unless you're willing to accept a monstrosity like PHP where numerical and non-numerical indexes are treated differently, and half of array functions accept a boolean flag asking if you'd rather have it behave like an array or like a hash.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-3764195014101625516?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/3764195014101625516/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=3764195014101625516' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/3764195014101625516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/3764195014101625516'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/07/arrays-are-not-integer-indexed-hashes.html' title='Arrays are not integer-indexed Hashes'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_IYGc_MWwkfw/TD_xlLnppyI/AAAAAAAAA-s/K9FVpY-ze_8/s72-c/cabooki_by_elycefeliz_from_flickr_cc-nc-nd.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-7311156327634736459</id><published>2010-07-16T03:23:00.000+02:00</published><updated>2010-07-16T03:23:29.996+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Random sampling or processing data streams in Ruby</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/TD-zxYV6vbI/AAAAAAAAA-c/I8qGqy6Oxjo/s1600/7_14_10_by_bernieg10_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="7 14 10 by BernieG10 from flickr (CC-NC-ND)"&gt;&lt;img alt="7 14 10 by BernieG10 from flickr (CC-NC-ND)" border="0" height="480" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/TD-zxYV6vbI/AAAAAAAAA-c/I8qGqy6Oxjo/s640/7_14_10_by_bernieg10_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;It might sound like I'm tackling a long solved problem here - &lt;tt&gt;sort_by{rand}[0, n]&lt;/tt&gt; is a well known idiom, and in more recent versions of Ruby you can use even simpler &lt;tt&gt;shuffle[0, n]&lt;/tt&gt; or &lt;tt&gt;sample(n)&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;They all suffer from two problems. The minor one is that quite often I want elements in the sample to be in the same relative order as in the original collection (this in no way implies sorted) - what can be dealt with by a &lt;a href="http://en.wikipedia.org/wiki/Schwartzian_transform"&gt;Schwartzian transform&lt;/a&gt; to &lt;tt&gt;[index, item]&lt;/tt&gt; space, sampling that, sorting results, and transforming out to just &lt;tt&gt;item&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;The major problem is far worse - for any of these to work, the entire collection must be loaded to memory, and if that was possible, why even bother with random sampling? More often than not, the collection I'm interested in sampling is something disk-based that I can iterate only once with &lt;tt&gt;#each&lt;/tt&gt; (or twice if I really really have to), and I'm lucky if I even know its &lt;tt&gt;#size&lt;/tt&gt; in advance.&lt;br /&gt;&lt;br /&gt;By the way - this is totally unrelated, but I really hate &lt;tt&gt;#length&lt;/tt&gt; method with passion - collections have sizes, not "lengths" - for a few kinds of collections we can imagine them arranged in a neat ordered line, and so their size is also length, but it's really lame to name a method after special case instead of far more general "size" - hashtables have sizes not lengths, sets have sizes not lengths, and so on - &lt;tt&gt;#length&lt;/tt&gt; should die in fire!&lt;br /&gt;&lt;h3&gt;When size is known&lt;/h3&gt;&lt;br /&gt;So we have a collection we can only iterate once - for now let's assume we're really lucky and we know exactly how many elements it has - this isn't all that common, but it happens every now and then. As we want &lt;tt&gt;n&lt;/tt&gt; elements out of &lt;tt&gt;size&lt;/tt&gt;, probability of each element being included is &lt;tt&gt;n/size&lt;/tt&gt;, and so &lt;tt&gt;select{ n &amp;gt; rand(size) }&lt;/tt&gt; will nearly do the trick - even keeping samples in the right order... except it will only return approximately &lt;tt&gt;n&lt;/tt&gt; elements.&lt;br /&gt;&lt;br /&gt;If we're sampling 1000 out of a billion we might not really care all that much, but it turns out it's not so difficult to do better than that. Sampling &lt;tt&gt;n&lt;/tt&gt; elements out of &lt;tt&gt;[first, *rest]&lt;/tt&gt; collection neatly reduces to: &lt;tt&gt;[first, *rest.sample(n-1)]&lt;/tt&gt; with &lt;tt&gt;n/size&lt;/tt&gt; probability, or &lt;tt&gt;rest.sample(n)&lt;/tt&gt; otherwise. Except Ruby doesn't have decent tail-call optimization, so we'll use counters for it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;module Enumerable&lt;br /&gt;&amp;nbsp; def random_sample_known_size(wanted, remaining=size)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if block_given?&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; each{|it|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if wanted &amp;gt; rand(remaining) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; yield(it)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; wanted -= 1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; end&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; remaining -= 1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rv = []&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; random_sample_known_size(wanted, remaining){|it| rv.push(it) }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rv&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; end&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This way of sampling has an extra feature that it can yield samples  one at a time and never needs to store any in memory - something you  might appreciate if you want to take a couple million elements out of 10  billions or so, and you will not only avoid loading them to memory, you will be able to use the results immediately, instead of only when the entire input finishes.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is only possible if collection size is known - if we don't know if there's 1 element ahead or 100 billion, there's really no way of deciding what to put in the sample.&lt;br /&gt;&lt;br /&gt;If you cannot fit even the sample in memory at once, and don't know collection size in advice - it might be the easiest thing to iterate twice, first to compute the size, and then to yield random records one at a time (assuming collection size doesn't change between iterations at least). CPU and sequential I/O are cheap, memory and random I/O are expensive.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/TD-z4FbCA2I/AAAAAAAAA-k/Gjcd8wVSybo/s1600/russian_blue_by_adam_zdebel_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Russian Blue by Adam Zdebel from flickr (CC-NC-ND)"&gt;&lt;img alt="Russian Blue by Adam Zdebel from flickr (CC-NC-ND)" border="0" height="640" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/TD-z4FbCA2I/AAAAAAAAA-k/Gjcd8wVSybo/s640/russian_blue_by_adam_zdebel_from_flickr_cc-nc-nd.jpg" width="426" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;When size is unknown&lt;/h3&gt;Usually we don't know collection size in advance, so we need to keep a running sample - initialize it with the first &lt;tt&gt;n&lt;/tt&gt; elements, and then for each element that arrives replace a random one from the sample with probability &lt;tt&gt;n / size_so_far&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;The first idea would be something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;module Enumerable&lt;br /&gt;&amp;nbsp; def random_sample(wanted)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; rv = []&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; size_so_far = 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; each{|it|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; size_so_far += 1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; j = rand(size_so_far)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rv.delete_at(j) if wanted == rv.size and wanted &amp;gt; j&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rv.push(it) if wanted &amp;gt; rv.size&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; rv&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It suffers from a rather annoying performance problem - we're keeping the sample in a Ruby Array, and while they're optimized for adding and removing elements at both ends, deleting something from the middle is a O(size) &lt;tt&gt;memmove&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;We could replace &lt;tt&gt;rv.delete_at(j); rv.push(it)&lt;/tt&gt; with &lt;tt&gt;rv[j] = it&lt;/tt&gt; to gain performance at cost of item order in the sample... or we could do that plus Schwarzian transform into &lt;tt&gt;[index, item]&lt;/tt&gt; space to get correctly ordered results fast. This only matters once sample size reaches tens of thousands, before that brute memmove is simply faster than evaluating extra Ruby code.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;module Enumerable&lt;br /&gt;&amp;nbsp; def random_sample(wanted)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; rv = []&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; size_so_far = 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; each{|it|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; size_so_far += 1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; j = wanted &amp;gt; rv.size ? rv.size : rand(size_so_far)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rv[j] = [size_so_far, it] if wanted &amp;gt; j&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; rv.sort.map{|idx, it| it}&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;This isn't what stream processing looks like!&lt;/h3&gt;The algorithms are as good as they'll get, but API is really not what we want. When we actually do have an iterate-once collection, we usually want to do more than just collect a sample. So let's encapsulate such continuously updated sample into &lt;tt&gt;Sample&lt;/tt&gt; class:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;class Sample&lt;br /&gt;&amp;nbsp; def initialize(wanted)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @wanted = wanted&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @size_so_far = 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @sample = []&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;&amp;nbsp; def add(it)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @size_so_far += 1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; j = @wanted &amp;gt; @sample.size ? @sample.size : rand(@size_so_far)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @sample[j] = [@size_so_far, it] if @wanted &amp;gt; j&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;&amp;nbsp; def each&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @sample.sort.each{|idx, it| yield(it)}&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;&amp;nbsp; def total_size&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @size_so_far&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;&amp;nbsp; include Enumerable&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;It's a fully-featured &lt;tt&gt;Enumerable&lt;/tt&gt;, so it should be really easy to use. &lt;tt&gt;#total_size&lt;/tt&gt; will return count of all elements seen so far - calling that &lt;tt&gt;#size&lt;/tt&gt; would conflict with the usual meaning of number of times &lt;tt&gt;#each&lt;/tt&gt; yields. You can even nondestructively access the sample, and then keep updating it - usually you wouldn't want that, but it might be useful for scripts that run forever and periodically save partial results.&lt;br /&gt;&lt;br /&gt;To see how it can be used, here's a very simple script, which reads a possibly extremely long list of URLs, and prints a sample of 3 by host. By the way notice autovivification of &lt;tt&gt;Sample&lt;/tt&gt;s inside the &lt;tt&gt;Hash&lt;/tt&gt; - it's a really useful trick, and Ruby's autovivification can do a lot more than Perl's.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;require "uri"&lt;br /&gt;sites = Hash.new{|ht,k| ht[k] = Sample.new(3)}&lt;br /&gt;STDIN.each{|url|&lt;br /&gt;&amp;nbsp; url.chomp!&lt;br /&gt;&amp;nbsp; host = URI.parse(url).host rescue next&lt;br /&gt;&amp;nbsp; sites[host].add(url)&lt;br /&gt;}&lt;br /&gt;sites.sort.each{|host, url_sample|&lt;br /&gt;&amp;nbsp; puts "#{host} - #{url_sample.total_size}:"&lt;br /&gt;&amp;nbsp; url_sample.each{|u| puts "* #{u}"}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So enjoy your massive data streams.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-7311156327634736459?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/7311156327634736459/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=7311156327634736459' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/7311156327634736459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/7311156327634736459'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/07/random-sampling-or-processing-data.html' title='Random sampling or processing data streams in Ruby'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_IYGc_MWwkfw/TD-zxYV6vbI/AAAAAAAAA-c/I8qGqy6Oxjo/s72-c/7_14_10_by_bernieg10_from_flickr_cc-nc-nd.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-5317250054178740771</id><published>2010-07-15T00:40:00.000+02:00</published><updated>2010-07-15T00:40:48.080+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='unix'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Synchronized compressed logging the Unix way</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/TD48YwTnFDI/AAAAAAAAA-U/j6kkizBxLCY/s1600/tiny_tiny_kitten_4_weeks_old_by_georgeh23_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="tiny tiny kitten 4 weeks old by GeorgeH23 from flickr (CC-NC-ND)"&gt;&lt;img alt="tiny tiny kitten 4 weeks old by GeorgeH23 from flickr (CC-NC-ND)" border="0" height="360" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/TD48YwTnFDI/AAAAAAAAA-U/j6kkizBxLCY/s640/tiny_tiny_kitten_4_weeks_old_by_georgeh23_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;In good Unix tradition if a program generates some data, in general it should write it to STDOUT, and you'll redirect it to the right file yourself.&lt;br /&gt;&lt;br /&gt;There are two problems with that, both easily solvable in separation:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;If it's a lot of data, you want to store it compressed. It would be bad Unix to put compression directly in the program - the right way is to pipe its output through gzip with &lt;tt&gt;program | gzip &amp;gt;logfile.gz&lt;/tt&gt;. gzip is really fast, and usually adequate.&lt;/li&gt;&lt;li&gt;You want to be able to see what were the last lines written out by the program at any time. Especially if it appears frozen. Sounds trivial, but thanks to a horrible misdesign of libc, and everything else based on it, data you write gets buffered before being actually written - a totally reasonable thing - and there are no limits whatsoever how long it can stay in buffers! Fortunately it is possible to turn this misfeature off with a single line of &lt;tt&gt;STDOUT.sync=true&lt;/tt&gt; or equivalent in other languages.&lt;/li&gt;&lt;/ul&gt;Unfortunately while both fixes involve a single line of obvious code - there's no easy way to solve them together. Even if you flushed all data from the program to gzip, gzip can hold onto it indefinitely. Now unlike libc which is simply broken, gzip has a good reason - compression doesn't work on one byte at a time - it takes a big chunk, compresses it, and only then writes it all out.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Still, even if it has good reasons not to flush data as soon as possible, it can and very much should flush it every now and then - with flushing every few seconds reduction in compression ratio will be insignificant, and it will be possible to find out why the program frozen almost right away. The underlying zlib library totally has this feature - unfortunately command line gzip utility doesn't expose it.&lt;br /&gt;&lt;br /&gt;So I wrote this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#!/usr/bin/env ruby&lt;br /&gt;&lt;br /&gt;require 'thread'require 'zlib'&lt;br /&gt;&lt;br /&gt;def gzip_stream(io_in, io_out, flush_freq)&lt;br /&gt;&amp;nbsp; fh = Zlib::GzipWriter.wrap(io_out)&lt;br /&gt;&amp;nbsp; lock = Mutex.new&lt;br /&gt;&amp;nbsp; Thread.new{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; while true&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lock.synchronize{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return if fh.closed?&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; fh.flush if fh.pos &amp;gt; 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sleep flush_freq&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; end&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; io_in.each{|line|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; lock.synchronize{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; fh.print(line)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; fh.close&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;gzip_stream(STDIN, STDOUT, 5)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It reads lines on stdin, writes them to stdout, and flushes every 5 seconds (or whatever you configure) in a separate Ruby thread. Ruby green threads are little more than a wrapper over &lt;tt&gt;select()&lt;/tt&gt; in case you're wondering. The check that &lt;tt&gt;fh.pos&lt;/tt&gt; is non-zero is required as flushing before you write something seems to result in invalid output.&lt;br /&gt;&lt;br /&gt;Now you can &lt;tt&gt;program | gzip_stream &amp;gt;logfile.gz&lt;/tt&gt; without worrying about data getting stuck on the way (if you flush in your program that is).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-5317250054178740771?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/5317250054178740771/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=5317250054178740771' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/5317250054178740771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/5317250054178740771'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/07/synchronized-compressed-logging-unix.html' title='Synchronized compressed logging the Unix way'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_IYGc_MWwkfw/TD48YwTnFDI/AAAAAAAAA-U/j6kkizBxLCY/s72-c/tiny_tiny_kitten_4_weeks_old_by_georgeh23_from_flickr_cc-nc-nd.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-8195778855726457754</id><published>2010-07-02T19:09:00.000+02:00</published><updated>2010-07-02T19:09:57.310+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='israel'/><category scheme='http://www.blogger.com/atom/ns#' term='religion'/><category scheme='http://www.blogger.com/atom/ns#' term='politics'/><title type='text'>Palestinian problem fixed</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/TC4crNj6M3I/AAAAAAAAA-E/4F3SRwacfWU/s1600/good_shabbos_by_anomalous4_from_flickr_cc-by.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="good Shabbos by anomalous4 from flickr (CC-BY)"&gt;&lt;img alt="good Shabbos by anomalous4 from flickr (CC-BY)" border="0" height="608" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/TC4crNj6M3I/AAAAAAAAA-E/4F3SRwacfWU/s640/good_shabbos_by_anomalous4_from_flickr_cc-by.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;This solution is really really simple, has plenty of precedent in history, and yet I haven't heard it proposed seriously by anyone before. So here is goes:&lt;br /&gt;&lt;blockquote style="font-size: 150%;"&gt;Palestinians should convert to Judaism&lt;/blockquote&gt;&lt;br /&gt;&lt;a href="https://secure.wikimedia.org/wikipedia/en/wiki/Law_of_Return"&gt;According to Israeli laws&lt;/a&gt;, anybody who converts to Judaism can trivially get Isreali citizenship. Once sufficient number of Palestinians gets citizenship, not only will they no longer be persecuted as much (Israeli Arabs are still treated as second class citizen, but level of discrimination is much much less) - together with existing non-hawkish Israeli citizens they will constitute majority of voters who will ensure that Israel will become a country that's much more peaceful and friendly toward its neighbours. As a bonus on top of that such mass conversion would immensely piss  off radicals on both sides.&lt;br /&gt;&lt;br /&gt;Now you will very likely complain about freedom of religion and such stuff. But why are these people Muslim in the first place? Because their ancestors &lt;a href="https://secure.wikimedia.org/wikipedia/en/wiki/Muslim_conquests"&gt;converted to religion of previous conquerors of these lands&lt;/a&gt; - some were forced to, others out of opportunism, perhaps some even out of genuine conviction - it doesn't matter. Is following religious choices of ancestors really worth all the death and suffering that exists in Palestine right now? I say no. Especially since the most painful part of such conversion - genital mutilation - they all underwent already.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This wouldn't be without precedent - not only religions like Islam and Christianity, but also languages like Latin, English, and Spanish, national identities, and cultures have all spread largely by members of the losing group adapting habits of members of the winning group. In fact it would be a lot more difficult to point to any major  religion or nationality which didn't spread in such a way.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It's a topic for whole another post, but ignoring this is the primary reason why I hate most analysis of humans in terms of evolutionary biology so much - variance of human behaviour is almost entirely culture-driven, not gene-driven like they all pretend, and culture doesn't only spread from parents to children.&lt;br /&gt;&lt;br /&gt;Anyway, it wouldn't be necessary for everyone to convert - as long as the portion of Palestinians who do is high enough - let's say half - it would completely alter current conflict dynamics enough to solve it. The die-hard few who care too much about Islam can then safety practice their faith in the emerging unified single state (with a huge Jewish majority, even if a lot of that would be rather unenthusiastic converts). As the law doesn't forbid it - children of Palestinian converts could choose whichever religion they wanted - Judaism, Islam, Catholicism, Baha'i, Spaghetti-Monsterism, or whatever. In practice vast majority would simply follow religion of their parents.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/TC4cy7siiLI/AAAAAAAAA-M/4OlP1Y2LUW0/s1600/jewish_cat_by_shira_golding_from_flickr_cc-nc.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="jewish cat by Shira Golding from flickr (CC-NC)"&gt;&lt;img alt="jewish cat by Shira Golding from flickr (CC-NC)" border="0" height="480" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/TC4cy7siiLI/AAAAAAAAA-M/4OlP1Y2LUW0/s640/jewish_cat_by_shira_golding_from_flickr_cc-nc.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h3&gt;Alternatives&lt;/h3&gt;&lt;br /&gt;Everything else having been tried and having failed already - there is really only one alternative to such mass conversion - waiting a few decades for both Israel and Palestine (and if possible all other countries of the region) to undergo demographic transition from short lives and big families to long lives and small families. &lt;a href="http://t-a-w.blogspot.com/2010/04/what-should-south-korea-do-now.html"&gt;Countries after demographic transition are a lot less belligerent&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This is very much happening - but very slowly. According to CIA World Factbook total fertility (number of children per women) between 1990 and 2010 fell from 7.0 to 4.9 for Gaza Strip (still ridiculously high), from 5.0 to 3.12 for West Bank, and from 2.9 to 2.72 for Israel - moving them away from values typical for the worlds' war zones like Afghanistan's 5.50 and Democratic Republic of Congo's 6.11 and more like civilized world's 2.1 and less.&lt;br /&gt;&lt;br /&gt;One day it will very likely happen - all will undergo demographic transition, and while they might still hate each other as much as they do now - they will express it like Japanese and Koreans - by flaming each other on the Internet - not in the good old way of bombs and bullets.&lt;br /&gt;&lt;br /&gt;This will of course take many decades. My solution solves the whole problem overnight. Any takers?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-8195778855726457754?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/8195778855726457754/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=8195778855726457754' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/8195778855726457754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/8195778855726457754'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/07/palestinian-problem-fixed.html' title='Palestinian problem fixed'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_IYGc_MWwkfw/TC4crNj6M3I/AAAAAAAAA-E/4F3SRwacfWU/s72-c/good_shabbos_by_anomalous4_from_flickr_cc-by.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-1167696873813161369</id><published>2010-06-09T10:07:00.002+02:00</published><updated>2010-06-09T21:28:43.223+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='diet'/><category scheme='http://www.blogger.com/atom/ns#' term='fish'/><title type='text'>Best sources of DHA omega-3 essential fatty acid</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/TA9KiaChr7I/AAAAAAAAA9U/sApeKaUrvgQ/s1600/axolotl_by_ethan_hein_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Axolotl by Ethan Hein from flickr (CC-NC-SA)"&gt;&lt;img alt="Axolotl by Ethan Hein from flickr (CC-NC-SA)" border="0" height="480" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/TA9KiaChr7I/AAAAAAAAA9U/sApeKaUrvgQ/s640/axolotl_by_ethan_hein_from_flickr_cc-nc-sa.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;This is surprisingly difficult to find out, so I decided to share the results with everyone. But first, background:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Animals need omega-3 and omega-6 essential fatty acids&lt;/li&gt;&lt;li&gt;The same enzymes are used for omega-3 and omega-6 processing, so too much of one will interfere with the other. People used to have diets with about 1:1 omega-3:omega-6. Today ratio is more like 1:20, and that little omega-3 we eat is mostly ALA.&lt;/li&gt;&lt;li&gt;Three most important omega-3 are ALA (18 carbons), EPA (20 carbons), and DHA (22 carbons).&lt;/li&gt;&lt;li&gt;Brains are made largely out of DHA.&lt;/li&gt;&lt;li&gt;Land plants produce no EPA / DHA. None whatsoever. Zero.&lt;/li&gt;&lt;li&gt;Some land plants produce adequate amounts of ALA, but even this is uncommon. &lt;/li&gt;&lt;li&gt;Algae produce quite a lot of EPA / DHA.&lt;/li&gt;&lt;li&gt;Animals including humans can convert ALA to EPA, and then DHA, but this is a painfully slow and inefficient process; and over-saturation of omega-6 and many conditions interfere with even that much.&lt;/li&gt;&lt;/ul&gt;Based on this some people believe it would be wise to try to increase amount of omega-3 fatty acids in diets. Hard evidence is rather lacking, this is however to be expected as hard evidence of anything about diet is essentially nil. It's almost only short term studies of crappy proxies, and there are millions of reasons why this is just wrong. Anyway, concerning supplementation:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;All mixed omega-3/omega-6/omega-9 supplements are waste of money - you're eating too much omega-6 already, and you can make as much omega-9 as you wish yourself.&lt;/li&gt;&lt;li&gt;You don't want generic "omega-3" supplements - most of these are ALA, which is of very limited use. You want DHA. At worst EPA. ALA is little more than filler, it's not bad for you but it's less relevant, and much easier to get via normal diet anyway.&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Aquatic_ape_hypothesis"&gt;If you're surprised why it's so hard to get DHA, this is possibly highly relevant&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;Hopefully now you see why I'm measuring DHA, not anything else. And to keep science proper what I'm interested in is "% of calories coming from DHA", not "grams of DHA per portion" or anything like it. Portions are whatever manufacturer says they are, "per 100g" measures mostly tell you how much water foods have, and only "% of calories from" measures the right thing.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/TA9LSrddXhI/AAAAAAAAA9k/0keVDhVzaNQ/s1600/escher_symmetry_by_pieter_musterd_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Escher Symmetry by Pieter Musterd from flickr (CC-NC-ND)"&gt;&lt;img alt="Escher Symmetry by Pieter Musterd from flickr (CC-NC-ND)" border="0" height="426" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/TA9LSrddXhI/AAAAAAAAA9k/0keVDhVzaNQ/s640/escher_symmetry_by_pieter_musterd_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Best Sources of DHA&lt;/h3&gt;&lt;br /&gt;I digged through &lt;a href="http://www.nal.usda.gov/fnic/foodcomp/search/"&gt;USDA National Nutrient Database&lt;/a&gt;, and this is what I found.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The data only contains "food" not supplement pills and such. These will of course contain highest concentrations. Rarely eaten foods like dolphin meat are not in the database, so I have no idea how nutritious dolphin sashimi would be.&lt;/li&gt;&lt;li&gt;The best source of DHA is unsurprisingly - &lt;b&gt;fish oil&lt;/b&gt;. Salmon oil is 18.2% DHA and 34.2% omega-3 altogether; other fish oils are pretty good too, but not so much. Other oils like cod liver, sardine, and menhaden are 8.5%-10.9% DHA, 18.8%-26.6% total omega-3. Herring oil is less impressive 4.2%/11.1%. Fish oil also contains most mercury and other poisoning, so enjoy that. Once ultra-refined you won't need to worry about poisoning but it's more supplementation than food.&lt;/li&gt;&lt;li&gt;The second best source is &lt;b&gt;caviar/roe&lt;/b&gt;, with 7.7%-13.6% DHA, and 13.7%-24.2% total omega-3. Might be expensive to turn it into a major part of your diet.&lt;/li&gt;&lt;li&gt;The third best source is &lt;b&gt;seal oil&lt;/b&gt; with 6.5-12% DHA, 14.0-27.7% omega-3. Let's see if you can buy some legally outside Canada. So far we're totally out of luck.&lt;/li&gt;&lt;li&gt;Finally something more useful. The fourth best source is &lt;b&gt;salmon&lt;/b&gt;. There's wide range of nutritious value from 2%/4% to 8.9%/13.7% - depending on where they're caught and what's their diet. Fortunately there doesn't seem to be a big difference between wild and farmed salmon, so either will work. Unfortunately the same mercury poisoning problem applies as to fish oil - poisonous substances are stored in oil so the oilier (and more useful for us) the fish the more toxic, and there is no way to escape that.&lt;/li&gt;&lt;li&gt;Fifth best source is &lt;b&gt;mackerel&lt;/b&gt;. Like salmon, it can have as little as 1.5%/2.8% or as much as 8.7%/14.7%.&lt;/li&gt;&lt;/ul&gt;USDA says the next best source is &lt;b&gt;dried parsley leaves&lt;/b&gt; at 7.3%/9.9% - which is most likely a massive measurement error, as there are no other plants anywhere, and it really makes little sense.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/TA9K_qHI8LI/AAAAAAAAA9c/mJP34sHWhXA/s1600/old_friend_by_jennyhuang_from_flickr_cc-by.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Old friend by JennyHuang from flickr (CC-BY)"&gt;&lt;img alt="Old friend by JennyHuang from flickr (CC-BY)" border="0" height="640" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/TA9K_qHI8LI/AAAAAAAAA9c/mJP34sHWhXA/s640/old_friend_by_jennyhuang_from_flickr_cc-by.jpg" width="436" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Other than that, it's fish, fish, fish, mollusks, jellyfish, crustaceans, and more fish. My hopes for finding something that's not fish are getting slimmer and slimmer, so I'm just going to skip all of them now (you can probably see the pattern), and only focus on things which are not fish/seafood.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Brains&lt;/b&gt;. Beef/lamb/pork brains have 3%-5.4% DHA and 4.4%-7.7% total omega-3. Not surprisingly, as that's what animals primary need DHA for. And we simply throw away this most nutritious part.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Whale oil&lt;/b&gt; - 3.9%/8.3%. Whale meat on the other hand is pretty useless at 0.2%/0.5%. Not that you'll find much of either at the nearest supermarket. It's technically not a fish. Anyway, between brains and ocean creatures we pretty much ran out of good sources, the next source is:&lt;/li&gt;&lt;li&gt;&lt;b&gt;Roasted squirrel&lt;/b&gt; - and that at mere 0.5%/0.6%&lt;/li&gt;&lt;li&gt;&lt;b&gt;Chicken&lt;/b&gt; can be anywhere from 0.1%/0.2% to 0.5%/0.8%&lt;/li&gt;&lt;li&gt;&lt;b&gt;Egg yolk&lt;/b&gt; - 0.3%-0.4% DHA, 0.4%-0.7% total.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Whole egg&lt;/b&gt; - 0.2%-0.3% DHA, 0.2%-0.8% total. Pretty much all of that in yolk.&lt;/li&gt;&lt;li&gt;We're long past useful concentrations anyway, so I won't be listing them. Next on the list are &lt;b&gt;caribou&lt;/b&gt;, &lt;b&gt;green turtles&lt;/b&gt;, &lt;b&gt;turkeys&lt;/b&gt;, &lt;b&gt;lamb kidneys&lt;/b&gt;, &lt;b&gt;frog legs&lt;/b&gt;, &lt;b&gt;guineahen&lt;/b&gt;, &lt;b&gt;lamb hearts&lt;/b&gt;, &lt;b&gt;squab/pigeon&lt;/b&gt;, &lt;b&gt;pork livers&lt;/b&gt;, &lt;b&gt;bear&lt;/b&gt;, &lt;b&gt;raccoon&lt;/b&gt;, &lt;b&gt;pork lung&lt;/b&gt; (and other beef/lamb/pork offal), and &lt;b&gt;emu&lt;/b&gt;. Pork/beef/lamb meat doesn't register other than as rounding error.&lt;/li&gt;&lt;/ul&gt;So to summarize:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Get supplements;&lt;/li&gt;&lt;li&gt;Or eat a lot of fish and other seafood;&lt;/li&gt;&lt;li&gt;Or eat ridiculous amount of poultry, eggs, and game meat;&lt;/li&gt;&lt;li&gt;Or you're fucked.&lt;/li&gt;&lt;/ul&gt;There's no way to get enough DHA in anything resembling standard Western diet. Simply no way. &lt;a href="http://t-a-w.blogspot.com/2009/11/myth-of-5-day-people-never-ate-that.html"&gt;Fruits and vegetables&lt;/a&gt; contain none, even "organic" ones. Actually fast food contains more as it often uses eggs and poultry as ingredients, but that's still not that useful.&lt;br /&gt;&lt;br /&gt;One more long-term option would be to genetically engineer some common oily plants like soy or canola to produce some EPA/DHA - even if humans wouldn't eat them, if they're used as animal feed, we'd benefit indirectly quite a lot. &lt;br /&gt;&lt;br /&gt;Actually &lt;a href="http://pmbcii.psy.cmu.edu/evans/2006_Lia.pdf"&gt;someone already genetically engineered pigs to produce 4x omega-3 fatty acids, including 2x DHA&lt;/a&gt;, which sounds like the most urgent reminder that we need GMO now, and Luddites should not be in charge of policy.&lt;br /&gt;&lt;br /&gt;EDIT: &lt;a href="http://www.nytimes.com/gwire/2010/06/07/07greenwire-as-us-approves-gm-soybean-dupont-and-monsanto-80269.html"&gt;GM soybeans with more omega-3 (this most likely means ALA) and higher stability so they don't need partial hydrogenation has just been approved in US&lt;/a&gt;. If people moved from usual partially hydrogenated soybean oil to that it would be a massive health benefit. Of course our Euro-Luddites + CAP-paid farmer lobby coalition will probably ban it until long after "&lt;a href="http://knowyourmeme.com/memes/the-main-difference-between-europe-and-usa"&gt;America vs Europe&lt;/a&gt;" picture get reversed. It's already much closer than you think.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-1167696873813161369?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/1167696873813161369/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=1167696873813161369' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1167696873813161369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1167696873813161369'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/06/best-sources-of-dha-omega-3-essential.html' title='Best sources of DHA omega-3 essential fatty acid'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_IYGc_MWwkfw/TA9KiaChr7I/AAAAAAAAA9U/sApeKaUrvgQ/s72-c/axolotl_by_ethan_hein_from_flickr_cc-nc-sa.jpg' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-8086686693033862173</id><published>2010-06-02T07:21:00.000+02:00</published><updated>2010-06-02T07:21:42.437+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='internet'/><category scheme='http://www.blogger.com/atom/ns#' term='economy'/><title type='text'>What is Internet good for?</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/TAXpTZ84nuI/AAAAAAAAA9E/X2UW8s6QSCE/s1600/im_in_ur_tube_blockin_ur_internets_by_the_boy_on_the_bike_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="im in ur tube, blockin ur internets by the boy on the bike from flickr (CC-NC-SA)"&gt;&lt;img alt="im in ur tube, blockin ur internets by the boy on the bike from flickr (CC-NC-SA)" border="0" height="502" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/TAXpTZ84nuI/AAAAAAAAA9E/X2UW8s6QSCE/s640/im_in_ur_tube_blockin_ur_internets_by_the_boy_on_the_bike_from_flickr_cc-nc-sa.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Here a quick poll, pick the most fitting answer:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I spend too much time on the Internet, and I'm aware of this&lt;/li&gt;&lt;li&gt;I spend too much time on the Internet, I'm deluding myself about it&lt;/li&gt;&lt;/ul&gt;There's no need to bother with the third option, as people who don't use too much Internet are extremely unlikely to ever read this blog.&lt;br /&gt;&lt;br /&gt;But in the spirit of "&lt;a href="http://www.youtube.com/watch?v=ExWfh6sGyso"&gt;What have the Romans ever done for us?&lt;/a&gt;" - what good is Internet really for? Is it worth all the time we spend on it?&lt;br /&gt;&lt;br /&gt;For the last two weeks in the spirit of &lt;a href="http://lesswrong.com/lw/2aw/seven_shiny_stories/"&gt;Alicorn's luminosity&lt;/a&gt; - by the way definitely read that linked article, her first attempt was at that was a major tl;dr but these "seven shiny stories" are so short and insightful you're probably better off spending some time reading them than whatever else you're typically wasting your time on Internet, and it promoted her to my second favourite lesswrong writer after Eliezer.&lt;br /&gt;&lt;br /&gt;So as I was saying before I interrupted myself, for the last two weeks I've been making a log of my daily activities and how much satisfaction I actually got from a given day.&lt;br /&gt;&lt;br /&gt;Now many people who have learned economics 101 and are treating it too seriously think that whatever we're doing must by definition be the things we most enjoy, our claims to the contrary notwithstanding - so people who say the want to get thinner, but eat fuckloads of pizza actually prefer eating pizza and being fat to not eating pizza and being thin. This point of view is usually something worth considering - people usually say they want things they feel they're "supposed to want". On the other hand, the amount of evidence that we don't do what's best for us is ridiculously overwhelming.&lt;br /&gt;&lt;br /&gt;A very very short list of such examples would include:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Hyperbolic_discounting"&gt;hyperbolic discounting&lt;/a&gt; - there's only one "mathematically consistent" way of treating values over time (exponential discounting), and the evidence is completely unambiguous that we're not doing so.&lt;/li&gt;&lt;li&gt;&lt;a href="http://lutfi-fadil.blogspot.com/2010/04/difference-between-liking-and-wanting.html"&gt;rodent experiments&lt;/a&gt; show also rather unambiguously that brains have separate systems for "wanting something" and "liking something". They are of course connected, so other things being equal if we like something more we will probably want it more - but this influence is far far less than total identity assumed by economics 101. Once you're aware that people might "want" things they don't really "like", and "not want" things they "like" (by the way - I'm using the words "want" and "like" rather vaguely - natural languages are spectacularly bad when analyzing humans - quite surprising actually as they seem to have been originally developed largely for social use) the entire utilitarian / &lt;a href="http://en.wikipedia.org/wiki/Consequentialism"&gt;consequentialist&lt;/a&gt; framework of analysis collapses.&lt;/li&gt;&lt;li&gt;Happiness research in spite of all its ambiguity at least shows that &lt;a href="http://www.ted.com/talks/daniel_kahneman_the_riddle_of_experience_vs_memory.html"&gt;simple models of happiness are plain wrong&lt;/a&gt;. If you have time to waste on the Internet - TED is filled with good talks about happiness, not just the one linked.&lt;/li&gt;&lt;li&gt;Even disregarding these, you'd need to have ridiculously good information on yourself to decide what's the best thing to do. And it would be a massive understatement to say that we don't have it. And it's really really difficult to measure yourself. The idea behind "living luminously" is that increasing your self-awareness of your own mental state even somewhat might lead to highly positive results.&lt;/li&gt;&lt;li&gt;and many many more&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Economics 101&lt;/h3&gt;By the way - and if you don't enjoy how I keep straying away from whatever is my main subject all the time, you probably shouldn't be reading this blog - I'm in no way disparaging "economics 101" thinking. I find it really sad that virtually every single person in the world pretty much belongs to these two classes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;People who don't understand Economics 101. They fail to get even such basic notions like &lt;a href="http://en.wikipedia.org/wiki/Comparative_advantage"&gt;comparative advantage&lt;/a&gt; or &lt;a href="http://t-a-w.blogspot.com/2009/12/libertarianism-is-externality-denialism.html"&gt;externalities&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;People who get Economics 101 - and take it far too seriously. If you even briefly look at assumptions behind all its theorems, none of them is even approximately true in the real world. Very often you get lucky and this toolkit lets you predict things about the real world decently enough, but this is about as often not the case.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;This is not to say Economics 101 should be thrown away. &lt;a href="http://c2.com/cgi/wiki?AllModelsAreWrongSomeModelsAreUseful"&gt;All models are wrong, some are useful&lt;/a&gt;. Or from a closely related perspective - &lt;a href="http://www.joelonsoftware.com/articles/LeakyAbstractions.html"&gt;all abstractions leak&lt;/a&gt;. If you don't perform sanity checks, and blindly trust everything the models tell you, they will lead you far astray (you could always argue that it's not models' fault, it's fault of the way you're applying them - but this is a purely theoretical distinction).&lt;br /&gt;&lt;br /&gt;So for example in theory economics 101 models say that laissez-faire international trade policy should outperform any kind of intervention, but in practice countries which practice &lt;a href="http://en.wikipedia.org/wiki/Export_subsidy"&gt;export subsidies&lt;/a&gt; by currency manipulation like the East Asia are better off than those with less laissez-faire trade policy like Europe, which in turn are better off than those that try to follow the route of &lt;a href="http://en.wikipedia.org/wiki/Import_substitution_industrialization"&gt;import substitution&lt;/a&gt; via high tariffs like Latin America.&lt;br /&gt;&lt;br /&gt;By the way if you find this curious, the standard answer to this puzzle is that benefits of economy of scale overwhelm loses due to comparative advantage - pumping subsidies into narrow range of related industries lets your country specialize in those, and import everything else - while limiting imports of wide range of products to protect diverse local industries means they will all be small and weak. As economics 101 completely ignores the dominant factor of scale advantages, focusing on an undoubtedly real but less important factor instead.&lt;br /&gt;&lt;br /&gt;Similar misapplication of economics 101 says that &lt;a href="http://en.wikipedia.org/wiki/Minimum_wage"&gt;minimum wage laws&lt;/a&gt; invariably increase unemployment. This was universally believed by nearly all economists a few decades ago according to some surveys cited by Wikipedia, and holding such belief became almost the canonical way of signaling that you're "economically savvy". And not surprisingly it turned out to be false, all research showing either no effect whatsoever, or effect that is really tiny compared to the huge increase in well-being of the working poor. The economists have finally figured that out, and they're more or less evenly divided on the question - even those standing against the minimum wage laws typically holding much more nuanced views - and yet &lt;a href="http://www.marginalrevolution.com/marginalrevolution/2010/05/the-new-issue-of-econ-journal-watch.html"&gt;some naive hard-liners still hold this as a measure of "economic enlightenment"&lt;/a&gt;.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/TAXpfJTEs9I/AAAAAAAAA9M/74eXd0rfc0s/s1600/im_in_your_pc_stealing_your_internets_by_the_boy_on_the_bike_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="I'm in your PC, stealing your internets by the boy on the bike from flickr (CC-NC-SA)"&gt;&lt;img alt="I'm in your PC, stealing your internets by the boy on the bike from flickr (CC-NC-SA)" border="0" height="640" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/TAXpfJTEs9I/AAAAAAAAA9M/74eXd0rfc0s/s640/im_in_your_pc_stealing_your_internets_by_the_boy_on_the_bike_from_flickr_cc-nc-sa.jpg" width="564" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;My logs&lt;/h3&gt;&lt;br /&gt;Getting back to the subject, for each day in a bit over the last two weeks I recorded my activities, and some measures of satisfaction. The logs weren't terribly detailed, and "recording one's satisfaction" is exactly the kind of thing which would never get published in any reputable peer-reviewed journal. That's not to say that it's useless - "the official way of doing science" has led to many important discoveries, but it's for many questions it's been rather impotent, and it's important that people &lt;a href="http://en.wikipedia.org/wiki/The_Shangri-La_Diet"&gt;try different ways of finding things out&lt;/a&gt; too, if for nothing else then to fill in the blind spots of the mainstream science.&lt;br /&gt;&lt;br /&gt;So my logs, of however dubious methodology they are, seem to point to the following correlations. I won't even bother pretending to have any "statistical significance" in all that of course, even forgetting about small sample of just two weeks measuring "statistical significance" necessarily assumes that samples are essentially independent, and they're nothing like that. The list is:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Physical exercise&lt;/b&gt; of all kinds - &lt;b&gt;definitely positive&lt;/b&gt; - this isn't really surprising, as this is something that's highly enjoyable once started, but it takes effort to begin, so the hyperbolic discounting excuse applies&lt;/li&gt;&lt;li&gt;With &lt;b&gt;video games&lt;/b&gt; it's &lt;b&gt;mixed&lt;/b&gt;. First person shooter games like online Modern Warfare 2 have positive correlations, but Total War games negatively correlate with my end-of-the-day satisfaction, even though they're not really frustrating or anything most of the time.&lt;/li&gt;&lt;li&gt;&lt;a href="http://t-a-w.blogspot.com/2010/04/weekly-review-checklist.html"&gt;&lt;b&gt;Cleaning up my GTD system&lt;/b&gt;&lt;/a&gt; - &lt;b&gt;definitely positive&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Being productive at work&lt;/b&gt;, and in general &lt;b&gt;getting done things&lt;/b&gt; I want to get done, especially the long postponed ones - &lt;b&gt;definitely positive&lt;/b&gt;&lt;/li&gt;&lt;li&gt;Reduction in caffeine consumption - mildly negative, but that doesn't really imply anything about long term effects of different levels of caffeine, and it wasn't even as bad as I expected&lt;/li&gt;&lt;li&gt;Watching TV series, and reading books - mildly negative; this might be a false result, or the effect might be real but minor, in any case - there's no reason to do much more of those &lt;/li&gt;&lt;li&gt;And the largest and rather surprising correlation - &lt;b&gt;spending more time online&lt;/b&gt; has a &lt;b&gt;huge negative correlation&lt;/b&gt; with my satisfaction levels&lt;/li&gt;&lt;/ul&gt;Now there standard economics 101 disclaimer applies - these measures are necessarily marginal - so finding out that I'm better off exercising more and Internetting less implies only that I would be better off exercising a bit more than now, and Internetting a bit less than now, and it's more likely than at some point increasing amount of exercise and decreasing Internet use will make me worse off. &lt;br /&gt;&lt;br /&gt;It's an interesting find that I seem to actually enjoy my work - I should probably put that one in my CV for future reference. And it's nice to get some insight on what kinds of recreational activities work better for me than others (due to small sample size less repeatable events like those involving interaction with other people not included). But the big find is that Internet is bad for me, and let's focus on that.&lt;br /&gt;&lt;h3&gt;What is Internet good for?&lt;/h3&gt;&lt;br /&gt;Do you remember what life was before the Internet? It was horrible! &lt;a href="http://www.youtube.com/watch?v=Xe1a1wHxTyo"&gt;We had to copy games from friends on stacks of floppies instead of just bittorrenting them&lt;/a&gt;! But really, what good is Internet for?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Email and IM are always far superior means of communication than  phone calls (I really hate those, they should all die in fire); and are  so much faster and easier than driving all the way to meet someone in  person that they usually win, even if the throughput is somewhat less.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;There's shopping - at which Internet really excels, most of the  time. At least when you know exactly what you want, otherwise not so  much. &lt;/li&gt;&lt;li&gt;There is information - but I'm far from happy about it. For some  kinds of thing that you want to find, if they follow "keyword keyword of  keyword" pattern, you can usually google or bing it out in seconds. Otherwise, all  search engines become nearly useless, even if this information is  somewhere. And it requires a lot of knowledge to turn a problem into unique keywords - very often you know little more than "X doesn't work", or "I'm not happy about Y", and search engines won't help you with those at all. This assumes information is even online in the first place - as very often it's not - it's really sad how nearly all research  papers have been successfully pay-walled. It seems that "information  wants to be free" only when the information in question is something on  the top 100 bestsellers list of one kind or another, and not to &lt;a href="http://en.wikipedia.org/wiki/Long_Tail"&gt;the long tail&lt;/a&gt;  which contains most of the real value.&lt;/li&gt;&lt;li&gt;There's Google Maps and similar sites, which are far superior to paper maps.&lt;/li&gt;&lt;li&gt;There are some funny things online - but they're swamped by such amounts of unfunny repetitive material that I really doubt Internet is even good for that. I dare you, go to let's say &lt;a href="http://www.reddit.com/r/funny/"&gt;/r/funny on reddit&lt;/a&gt; - which is supposedly about the most recent funny stuff online (or at least reddittors seem to believe they find stuff first, and everyone else copies stuff from them) - and how many things you'll find there that will make you laugh, and are not nearly ancient? And it's the same on nearly every other place which is supposedly filled with funny stuff. People keep going there because occasionally something good turns out, but it's so rare it's probably not worth it.&lt;/li&gt;&lt;li&gt;There are news - and again the flood problem applies. I'm yet to find any RSS feed with only important news. Everyone seems to believe the right way to do news online is to just throw 10+ trivia items a day - Obama said something, one minor celebrity divorced another minor celebrity, stock prices decreased somewhere, IDF shot a few unarmed civilians somewhere else - as if knowing things like these made you better off in any way. The choice is to either get ridiculous amount of political trivia, or just ignore the news altogether.&lt;/li&gt;&lt;li&gt;There are all kinds of social networking sites - and I'm increasingly doubting their value. I have a Facebook account (and accounts on some other sites) and I might even use it occasionally, but I don't see that my life would be that much worse if Facebook and the rest didn't exist.&lt;/li&gt;&lt;li&gt;There are blogs, wikis, and similar places where you can contribute your knowledge, which can give tremendous amount of satisfaction to the contributor. If you add them all up, they provide a lot of value for readers as long as search engines manage to find a relevant blog post or wiki article, which is always in doubt. On the other hand, I have serious doubts about reading everything on a blog, or unfocused browsing on wikis. I haven't yet seen a blog which had consistently good posts - much less consistently good and relevant to my interests.&lt;/li&gt;&lt;li&gt;There are online video games, for some things playing with people is more fun than playing against computer.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;These seem to cover the main points. And what's obvious is that the most valuable online activities - email, highly focused search, shopping, maps - take rather little time. On the other hand, the ones that take a lot of time - like all the reddits, forums, social sites, wikis, blogs, etc. - don't provide that terribly much value per time spent.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Unless you actually measure how you use internet, it's really easy to overestimate how much value spending time on it gives you - as you're far more likely to remember the high points which didn't really take long - as opposed to relatively pointless activities which took most of your online time. Human memory just works like that.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This distinction would be pointless if it was impossible to make a distinction between the two - if reduction in the bad kind of internet use required essentially proportional reduction in the good kind. Fortunately it seems to me that this is fairly straightforward - good things like email (this of course assuming you have a working spam filter / and all mailing lists etc. go somewhere else than your inbox), shopping, maps, directed search - have different entry points than less useful things like social sites, wikis, news, and funnies etc. Sometime you'll look for something specific and in the process accidentally fall into a wiki trap, but this shouldn't be too common with some self-awareness. Much more often you waste a ridiculous amount of time by wanting to "quickly check if there's anything good on X" and having hyperbolic discounting ("just one more link") turn that into a disaster.&lt;br /&gt;&lt;br /&gt;It doesn't mean reducing your lolcat consumption to zero - only that you should force yourself to make an up-front decision "I'm start looking at funnies now, even though I know well enough it will probably take the next few hours" and having a realistic idea how good this time will be; instead of fooling yourself it will be quick and only filled with the good stuff, as seems typical now.&lt;br /&gt;&lt;br /&gt;tl;dr - using internet only when you have clear goal, and not for vague "maybe there's something good" is good for you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-8086686693033862173?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/8086686693033862173/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=8086686693033862173' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/8086686693033862173'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/8086686693033862173'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/06/what-is-internet-good-for.html' title='What is Internet good for?'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_IYGc_MWwkfw/TAXpTZ84nuI/AAAAAAAAA9E/X2UW8s6QSCE/s72-c/im_in_ur_tube_blockin_ur_internets_by_the_boy_on_the_bike_from_flickr_cc-nc-sa.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-7504867845584149462</id><published>2010-05-22T22:54:00.000+02:00</published><updated>2010-05-22T22:54:56.962+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='empire total war'/><category scheme='http://www.blogger.com/atom/ns#' term='video games'/><title type='text'>Empire Total War mods - no walls, libertarians everywhere</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S_hDDyD5IkI/AAAAAAAAA88/Of7hDQWWe90/s1600/the_look_of_nobody_home_by_tjflex2_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="The look of nobody home by Tjflex2 from flickr (CC-NC-ND)"&gt;&lt;img alt="The look of nobody home by Tjflex2 from flickr (CC-NC-ND)" border="0" height="480" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S_hDDyD5IkI/AAAAAAAAA88/Of7hDQWWe90/s640/the_look_of_nobody_home_by_tjflex2_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Rome Total War was highly moddable. Medieval 2 Total War somewhat less as all data files were in obfuscated packages - but once you unpacked them it was as good as Rome. &lt;a href="http://t-a-w.blogspot.com/2009/11/medieval-2-total-war-concentrated.html"&gt;My M2TW mod&lt;/a&gt; is generated by a bunch of simple regexps, with which I can experiment as much as I like, turning features on and off and changing their magnitude in seconds.&lt;br /&gt;&lt;br /&gt;I knew Empire Total War won't be as easy, but nothing prepared me for the pain I suffered. But I'll complain as I go.&lt;br /&gt;&lt;h3&gt;Libertarians everywhere&lt;/h3&gt;First to see how modding works I wrote a very small mod - turning off taxes adds +10 happiness. Not quite literally, as it seems impossible to have anything triggered by zero taxes, so I gave all non-zero taxes extra -10 happiness, and every government type gets extra +10 happiness - net result being what I wanted, except it looks a bit silly in game.&lt;br /&gt;&lt;br /&gt;Now why did I do so? The answer is my favourite "less micromanagement". I don't particularly having to babysit conquered provinces, chasing rebels around, and counting how many units I can move and how many I need to leave. This is simply not fun. So I decided that every province has a sizable population of armed libertarians who will gladly shoot every protester for me as long as I set taxes to zero. When taxes are not zero &lt;a href="http://t-a-w.blogspot.com/2009/12/what-is-libertarianism-blog-edition.html"&gt;they blog climate change denial or something&lt;/a&gt;, I don't care.&lt;br /&gt;&lt;br /&gt;This is all a stop-gap measure for the first few turns after conquest - if you ever want to get any taxes out of the province, as you usually do, you'll need to deal with taxpayers' happiness eventually. By the way zero taxes essentially means provinces loses money every turn, as it increases administration cost of every other province in your empire.&lt;br /&gt;&lt;br /&gt;Happiness +10 is enough most of the time, but when you conquer someone's capital and have to face -30, on top of all industrialization, religion etc., you might need to deal with rebellions anyway. And as such regions usually bring a lot of money, you probably want to set higher taxes anyway.&lt;br /&gt;&lt;br /&gt;If you want to tweak this bonus, use &lt;a href="http://sourceforge.net/projects/etw-mod-tools/"&gt;DBEditor&lt;/a&gt; for it.&lt;br /&gt;&lt;h3&gt;No walls&lt;/h3&gt;And now the big mod - removing all walls. I'm not ideologically opposed to settlement fortifications - in fact my M2TW mod makes settlements more difficult to take. However:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ETW sieges are broken due to stupid AI and stupid pathfinding&lt;/li&gt;&lt;li&gt;Because they're broken, all ETW sieges follow just two boring scripts:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;either: approach diagonally with infantry from 3 directions, bayonet charge everything;&lt;/li&gt;&lt;li&gt;or: approach diagonally with howitzers with carcass shot and a few line infantry units, once you start bombarding them AI will charge you one by one and you win without loses&lt;/li&gt;&lt;/ul&gt;everything else fails as your units are too stupid to pathfind in more interesting strategies   &lt;/li&gt;&lt;li&gt;After 1710 or so nearly every settlement outside Americas has city walls&lt;/li&gt;&lt;li&gt;And so after the first few years, 90% of battles is unbelievably boring&lt;/li&gt;&lt;/ul&gt;Field battles on the other hand are much more interesting. An unfortunate side effect of this mod is that while in vanilla town watch can use settlement fortifications to defend it from small enemy armies reasonably well, now it's completely useless. I can live with that.&lt;br /&gt;&lt;br /&gt;Unfortunately, this has second order side effect of forcing you to be more aggressive. If before you'd be quite willing to have your armies further away from the front as town watch could serve as good enough first line of defense, now you need to have your armies closer to the borders, preferably on their side of it.&lt;br /&gt;&lt;br /&gt;So how did I write this mod? It was truly painful. First, ETW has building features, and the fact that settlement fortifications building creates walls in the battle is supposedly encoded by such features. I ran into the first problem, as DBEditor is incapable of removing features - only adding or modifying them. To do such thing you need to go to PackFileManager, clone a table, make sure it's named exactly like the original one (so it will be overridden, not merged), and remove rows from that in DBEditor.&lt;br /&gt;&lt;br /&gt;Except for some reason PackFileManager incorrectly mixes up slashes and backslashes, so I needed to fix the mod file from a hex editor.&lt;br /&gt;&lt;br /&gt;Except it turned out in the end ETW ignores this feature, and simply hard-codes walls. So much for my effort.&lt;br /&gt;&lt;br /&gt;It was plan B time. First I needed to remove all walls. And while db files are pain to edit it is nothing compared to the pain of editing startpos.esf which contains campaign information:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Start campaign, look at every single settlement on a map and write down which settlement has walls (as there's no search function in EsfEditor) &lt;/li&gt;&lt;li&gt;Manually find every such settlement in esf tree, and do all necessary changes (change True to False in one node, delete another node).&lt;/li&gt;&lt;/ul&gt;This is of course wholly incompatible with any other esf mod, like those which enable you to play minor factions.&lt;br /&gt;&lt;br /&gt;After that I needed to make it impossible to build walls. I haven't figured out how to do that (I suspect if I remove walls completely the game will simply crash, and no other building in unbuildable) - so I made it require late technology of mass production, and take 999 turns to build. Sort of good enough.&lt;br /&gt;&lt;br /&gt;And all this was possible only after a lot of effort of modding community members who created tools like DBEditor, EsfEditor, PackFileManager, documented what they could etc. This is borderline unmoddable, and I fully expect the next generation of Total War games after Napoleon (which is essentially extra scenario for ETW) to be completely impossible to mod. But hey, maybe they'll sell more DLC this way.&lt;br /&gt;&lt;h3&gt;How to install&lt;/h3&gt;In case you want to install these mods, you need to:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Download &lt;a href="http://taw.chaosforge.org/etw/startpos.esf"&gt;starpos.esf&lt;/a&gt; and replace one in &lt;tt&gt;C:\Program Files (x86)\Steam\steamapps\common\empire total war\data\campaigns\main&lt;/tt&gt; (or similar), first of course making a backup copy - this will remove starting walls. (small warning - it's a big file and the server I'm hosting it on is pretty slow; other files are tiny)&lt;/li&gt;&lt;li&gt;Download &lt;a href="http://taw.chaosforge.org/etw/mod_no_walls.pack"&gt;mod_no_walls.pack&lt;/a&gt; and put it in data directory together with all other packs - this will make walls unbuildable.&lt;/li&gt;&lt;li&gt;Optionally download &lt;a href="http://taw.chaosforge.org/etw/mod_tax_break.pack"&gt;mod_tax_break.pack&lt;/a&gt; and put it into data directory - this will give you +10 happiness bonus for no taxes.&lt;/li&gt;&lt;li&gt;Download &lt;a href="http://sourceforge.net/projects/etw-mod-tools/files/ModManager/ModManager_1-5.zip/download"&gt;ModManager&lt;/a&gt; and unpack it.&lt;/li&gt;&lt;li&gt;Start ModManager, select mods you want to use, and click Launch.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-7504867845584149462?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/7504867845584149462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=7504867845584149462' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/7504867845584149462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/7504867845584149462'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/05/empire-total-war-mods-no-walls.html' title='Empire Total War mods - no walls, libertarians everywhere'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_IYGc_MWwkfw/S_hDDyD5IkI/AAAAAAAAA88/Of7hDQWWe90/s72-c/the_look_of_nobody_home_by_tjflex2_from_flickr_cc-nc-nd.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-4642987875863626300</id><published>2010-05-22T21:23:00.002+02:00</published><updated>2010-05-23T02:36:46.945+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='firefox'/><category scheme='http://www.blogger.com/atom/ns#' term='web 2.0'/><category scheme='http://www.blogger.com/atom/ns#' term='greasemonkey'/><title type='text'>Greasemonkey and jQuery easier than ever</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S_guqr7eDZI/AAAAAAAAA80/QOA_mCLOt5k/s1600/douc_langur_pygathrix_nemaeus__by_ucumari_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Douc Langur (Pygathrix nemaeus) by ucumari from flickr (CC-NC-ND)"&gt;&lt;img alt="Douc Langur (Pygathrix nemaeus) by ucumari from flickr (CC-NC-ND)" border="0" height="494" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S_guqr7eDZI/AAAAAAAAA80/QOA_mCLOt5k/s640/douc_langur_pygathrix_nemaeus__by_ucumari_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Last year I wrote &lt;a href="http://t-a-w.blogspot.com/2009/03/use-greasemonkey-to-vote-for-hotter.html"&gt;a short Greasemonkey tutorial&lt;/a&gt;, in which I explained how to use it with jQuery for some really simple scripts. Since then it became even easier, so here a few more useful scripts.&lt;br /&gt;&lt;br /&gt;Since version 0.8 Greasemonkey has &lt;tt&gt;@require&lt;/tt&gt; feature, in which your scripts can be made to depend on some external Javascript files - like jQuery. Unfortunately there are a few gotchas:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;jQuery 1.4 doesn't work with Greasemonkey, you need to use jQuery 1.3 (or keep pestering them until it's fixed)&lt;/li&gt;&lt;li&gt;&lt;tt&gt;@require&lt;/tt&gt; only works on installation time, you cannot use it with "New User Script..." feature, nor can you change &lt;tt&gt;@require&lt;/tt&gt;s from the editor. If you simply use published scripts and don't write anything - you don't need to worry. If you write your own scripts you need to prepare &lt;tt&gt;something.user.js&lt;/tt&gt; file somewhere, then open it from Firefox (copy&amp;amp;paste it's file path to Firefox URL bar, then click Install).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Show spoilers on tvtropes&lt;/h3&gt;Let's start with something really trivial. I don't care about spoilers. Maybe 1% of "spoilers" significantly diminish viewing pleasure, vast majority of them do not. I knew that Vader is Luke's father, that Snape killed Dumbledore, and that Titanic sunk before watching/reading, and it made it no less enjoyable.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;On the other hand I'm quite annoyed that to read &lt;a href="http://tvtropes.org/"&gt;tvtropes&lt;/a&gt; I needed to constantly select "spoiler" text for everything to see it - but no more. This trivial script solves it entirely:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;// ==UserScript==&lt;br /&gt;// @name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Show all spoilers on tvtropes&lt;br /&gt;// @namespace&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://t-a-w.blogspot.com/&lt;br /&gt;// @include&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://tvtropes.org/*&lt;br /&gt;// @require&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js&lt;br /&gt;// ==/UserScript==&lt;br /&gt;&lt;br /&gt;$(".spoiler").removeClass('spoiler');&lt;/pre&gt;&lt;br /&gt;It's really simple - &lt;tt&gt;@name&lt;/tt&gt; is unique name for the script, which should really be a very short description. We're not going to rely on &lt;tt&gt;@namespace&lt;/tt&gt; at all, so put anything you feel like there.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;@include&lt;/tt&gt; is a pattern of URLs for which the script should be executed. &lt;tt&gt;@require&lt;/tt&gt; is the jQuery library we're including. And thanks to jQuery, removing spoiler tags is really easy.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://userscripts.org/scripts/review/77360"&gt;You can download this script here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Always sort by seeders on The Pirate Bay&lt;/h3&gt;And extremely annoying thing about The Pirate Bay search engine is how it sorts results by its idea of "relevance" - usually giving you some dead ISO of three year old Ubuntu version when you obviously want the most recent one. And nearly always sorting by seeders is the right thing to do.&lt;br /&gt;&lt;br /&gt;There is actually a GreaseMonkey script that claims to do exactly that, but it doesn't always work correctly, and the author decided to obfuscate the source for lulz. I'll have none of that, so I just wrote my own. Again, thanks to jQuery it's truly trivial. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;// ==UserScript==&lt;br /&gt;// @name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Always order by seed count&lt;br /&gt;// @namespace&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://t-a-w.blogspot.com/&lt;br /&gt;// @include&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://thepiratebay.org/*&lt;br /&gt;// @require&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js&lt;br /&gt;// ==/UserScript==&lt;br /&gt;&lt;br /&gt;$("input[name='orderby']").val(7);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://userscripts.org/scripts/show/77361"&gt;You can download this script here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Download Stewart and Colbert from bittorrent&lt;/h3&gt;Now a more complicated and perhaps more useful script. One of the recent developments on the Internet I hate the most are geographic restrictions - Americans can view whatever they like, for everyone else it's "Sorry, Videos are not currently available in your country" or other such nonsense.&lt;br /&gt;&lt;br /&gt;Personally I don't care about licensing restrictions which led to this - I'm not going to accept development like that if I can help it. Fortunately in this case I can - all Stewart and Colbert is available on bittorrent.&lt;br /&gt;&lt;br /&gt;The script does the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Find all dates on the page. They're not kind enough to use consistent class for those, I found at least 3, and perhaps I still missed a few.&lt;/li&gt;&lt;li&gt;Convert every date to from "Month DD, YYYY" to "YYYY MM DD" format, as this is what most torrents use. Half of the script is just doing that because Javascript doesn't have anything like Ruby's &lt;tt&gt;Date.parse&lt;/tt&gt;.&lt;/li&gt;&lt;li&gt;Append link to bittorrent site next to the date. I'm using &lt;a href="http://www.yourbittorrent.com/"&gt;yourbittorrent&lt;/a&gt; here, as ThePirateBay is down due to overload far too often.&lt;/li&gt;&lt;/ul&gt;So every time someone on Reddit posts a "omg Colbert totally pwned Glenn Beck" link, I can actually see the pwnage now thanks to this script.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;// ==UserScript==&lt;br /&gt;// @name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; View Stewart and Colbert on bittorrent&lt;br /&gt;// @namespace&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://t-a-w.blogspot.com/&lt;br /&gt;// @description&amp;nbsp;&amp;nbsp;&amp;nbsp; No more "Sorry, Videos are not currently available in your country"&lt;br /&gt;// @include&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://www.thedailyshow.com/*&lt;br /&gt;// @include&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://www.colbertnation.com/*&lt;br /&gt;// @require&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js&lt;br /&gt;// ==/UserScript==&lt;br /&gt;&lt;br /&gt;var month_names = {&lt;br /&gt;&amp;nbsp; 'January': '01',&lt;br /&gt;&amp;nbsp; 'February': '02',&lt;br /&gt;&amp;nbsp; 'March': '03',&lt;br /&gt;&amp;nbsp; 'April': '04',&lt;br /&gt;&amp;nbsp; 'May': '05',&lt;br /&gt;&amp;nbsp; 'June': '06',&lt;br /&gt;&amp;nbsp; 'July': '07',&lt;br /&gt;&amp;nbsp; 'August': '08',&lt;br /&gt;&amp;nbsp; 'September': '09',&lt;br /&gt;&amp;nbsp; 'October': '10',&lt;br /&gt;&amp;nbsp; 'November': '11',&lt;br /&gt;&amp;nbsp; 'December': '12'&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;$(".date, .airDate, .clipDate").each(function() {&lt;br /&gt;&amp;nbsp; var txt = $(this).text();&lt;br /&gt;&amp;nbsp; var m = txt.match(/(\S+)\s*(\d+),\s*(\d{4})/);&lt;br /&gt;&amp;nbsp; var date = m[3] + "+" + month_names[m[1]] + "+" + m[2];&lt;br /&gt;&amp;nbsp; var url;&lt;br /&gt;&amp;nbsp; if(window.location.hostname == "www.thedailyshow.com") {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; url = 'http://www.yourbittorrent.com/?q=Daily+Show+' + date;&lt;br /&gt;&amp;nbsp; } else {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; url = 'http://www.yourbittorrent.com/?q=Colbert+Report+' + date;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; $(this).append("&amp;lt;div&amp;gt;&amp;lt;a href='"+ url + "'&amp;gt;Download on bittorrent&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;");&lt;br /&gt;});&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://userscripts.org/scripts/show/77362"&gt;You can download the script here.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;See how easy it all was? Now start writing your own scripts and share them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-4642987875863626300?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/4642987875863626300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=4642987875863626300' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/4642987875863626300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/4642987875863626300'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/05/greasemonkey-and-jquery-easier-than.html' title='Greasemonkey and jQuery easier than ever'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_IYGc_MWwkfw/S_guqr7eDZI/AAAAAAAAA80/QOA_mCLOt5k/s72-c/douc_langur_pygathrix_nemaeus__by_ucumari_from_flickr_cc-nc-nd.jpg' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-1610326993975554848</id><published>2010-05-20T07:04:00.001+02:00</published><updated>2010-05-20T07:33:13.211+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='muhammad'/><category scheme='http://www.blogger.com/atom/ns#' term='islam'/><category scheme='http://www.blogger.com/atom/ns#' term='culture'/><title type='text'>Everybody Draws Muhammad Day and lessons in cultural relativism</title><content type='html'>May 20th is &lt;a href="http://en.wikipedia.org/wiki/Everybody_Draw_Mohammed_Day"&gt;Everybody Draw Mohammed Day&lt;/a&gt; - a day when you too can join the defense of Free Speech by drawing a cartoon. Or if you &lt;a href="http://www.deviantart.com/"&gt;really suck at drawing&lt;/a&gt; you can make a shop of Muhammad like me.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/S_TAtPqpUKI/AAAAAAAAA8c/id44VxS9pkg/s1600/pedoprophet.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/S_TAtPqpUKI/AAAAAAAAA8c/id44VxS9pkg/s400/pedoprophet.png" width="261" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Prophet Muhammad, artist's conception&lt;/i&gt;&lt;br /&gt;&lt;i&gt;If you think I'm wrong, draw a better one&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Lesson #1 - Principle of dissimilarity&lt;/h3&gt;&lt;br /&gt;Recently I have been convinced by some &lt;a href="http://www.teach12.com/"&gt;TTC&lt;/a&gt; &lt;a href="http://www.teach12.com/ttcx/coursedesclong2.aspx?cid=643"&gt;audiobooks&lt;/a&gt; that &lt;a href="http://en.wikipedia.org/wiki/Historical_Jesus"&gt;Jesus might have probably existed as a historical person&lt;/a&gt;. You know what's the best argument for it? &lt;a href="http://en.wikipedia.org/wiki/Criterion_of_embarrassment"&gt;The criterion of dissimilarity&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It's not any pomo deconstructionism - just plain old historical analysis. The idea is that authors have an agenda, but life doesn't always agree with it. So every time the text admits to something that is clearly against the authors' agenda, it suggests it probably had some basis in reality - because they wouldn't make this up on purpose. A few examples from Jesus' life:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Crucifixion was embarrassing kind of death reserved for slaves, rebels, and other lowest status scum. If someone was making up the story they would have Jesus die in battle, or die some other "respectable kind of death". So actual Jesus was most likely actually crucified.&lt;/li&gt;&lt;li&gt;All the messy explanations how "everybody thought Jesus was born in middle-of-nowhere Nazareth but actually he was born in Bethlehem like King David" suggest that Jesus was probably born in Nazareth. If they were making this up, they'd skip the Nazareth story altogether.&lt;/li&gt;&lt;li&gt;Jesus was baptized by John the Baptist - being baptized by someone was signaling submission and inferiority to that person. This story is clearly embarrassing to Bible writers, they put words like "I should be baptized by you" in John the Baptist's mouth, and the last Gospel omits it altogether.&lt;/li&gt;&lt;/ul&gt;The sheer volume of such cases suggests that Bible is an "enhanced" story of some actual life, as opposed to being completely made up. There's no question that all the supernatural bits have been inserted, and it's widely believed that the real life stories were quite significantly massaged - but it does such a bad job at covering a lot of embarrassing parts like these that the hypothesis "Bible is vaguely based on a life of a real person, and these embarrassing stories were widely known so couldn't be ignored" is much more compatible with the evidence than "Bible is completely made up" - and as their &lt;a href="http://en.wikipedia.org/wiki/Bayesian_probability"&gt;Bayesian priors&lt;/a&gt; are not terribly different in the first place, historicity of Jesus can be reasonably believed in. The "Bible is real" story on the other hand is both against the priors and against the evidence, so let's not even go there.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S_TCidv2UtI/AAAAAAAAA8s/LbzR5Wn0gE8/s1600/rambo_cat_by_gerard_girbes_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Rambo Cat by Gerard Girbes from flickr (CC-NC-ND)"&gt;&lt;img alt="Rambo Cat by Gerard Girbes from flickr (CC-NC-ND)" border="0" height="480" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S_TCidv2UtI/AAAAAAAAA8s/LbzR5Wn0gE8/s640/rambo_cat_by_gerard_girbes_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h3&gt;Lesson #2 - Why is Muhammad widely considered a pedophile?&lt;/h3&gt;&lt;br /&gt;The criterion of dissimilarity must be truly infuriating to the true believers - it essentially says that every time they like some part it's probably false, and every time they dislike some part it's probably true. By the way this applies to all historical texts, not just religious ones - parts of &lt;a href="http://en.wikipedia.org/wiki/Commentarii_de_Bello_Gallico"&gt;Commentarii de Bello Gallico&lt;/a&gt; that are overly sympathetic to Julius Caesar should be looked at with more suspicion than parts which talk about his failures, and so on.&lt;br /&gt;&lt;br /&gt;So, what does it all have to do with Muhammad being a pedophile? Muslim texts clearly say that he was married to &lt;a href="http://en.wikipedia.org/wiki/Aisha"&gt;Aisha&lt;/a&gt; when she was 6, and fucked her when she was 9 year old.&lt;br /&gt;&lt;br /&gt;Now how likely is it that this particular bit was made up? If you had a prophet who didn't fuck children, would you casually make up a story that he actually did? That'd go against all rules of proper writing. And it's not one isolated verse somewhere - as Wikipedia says "references to Aisha's age by early historians are frequent", and nobody questioned that back then.&lt;br /&gt;&lt;br /&gt;So regardless of our believes, we can be fairly certain that&lt;br /&gt;&lt;blockquote style="font-size: 150%;"&gt;Muhammed fucked a 9 year old girl&lt;/blockquote&gt;&lt;br /&gt;And now some time for &lt;a href="http://en.wikipedia.org/wiki/Cultural_relativism"&gt;cultural relativism&lt;/a&gt; - this was considered fairly unremarkable back then. Our modern culture is obsessed about young people's sexuality and as a civilization we essentially lost the ability to propagate the species, but historically it was entirely normal for much younger people to marry, fuck, and have babies - biologically late teens are the optimal time to have children. In completely typical Ancient Rome - girls typically married in their mid teens, very soon after puberty. The idea was simple:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Regardless of societal constraints, many people will get sexually active once they hit puberty&lt;/li&gt;&lt;li&gt;Of people who get sexually active, many will get pregnant&lt;/li&gt;&lt;li&gt;Nearly everywhere except for modern times, it's really difficult to either provide for your kids without a husband, or get a husband if you already have kids&lt;/li&gt;&lt;li&gt;To avoid risking that, it's better to marry your daughters sooner&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;This was the baseline normal case for girls.&lt;br /&gt;&lt;br /&gt;Western pedophile obsession (where all sexuality of people under 20 or so is a big taboo - this has little to do with what psychology calls "&lt;i&gt;pedophilia&lt;/i&gt;") is a highly atypical case. 7th century Arabic children marriage, and fucking of prepubescent 9 year old girls was also rather atypical.&lt;br /&gt;&lt;br /&gt;Not that it matters what's typical and what's not - abject poverty, illiteracy, and lack of broadband Internet are historical norm, and yet I much rather prefer atypical modern situation.&lt;br /&gt;&lt;br /&gt;Anyway, what we see here is a conflict of values - Muhammed fucking a 9 year old was acceptable within his culture, and is not considered acceptable within ours - not even for most modern Muslim countries. Aisha most likely didn't mind getting fucked, and nobody was weirded out by this, in spite of modern fiction of "age of consent". She was most likely not scarred for life or anything like that - these laws exist primarily to make adult bigots feel good, not to "protect" children, and evidence is clear that plenty of teenagers (and an occasional pre-teen) have sex and enjoy it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S_TBCt7yr-I/AAAAAAAAA8k/5v0JJGRuaHc/s1600/Age_of_Consent.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="288" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S_TBCt7yr-I/AAAAAAAAA8k/5v0JJGRuaHc/s640/Age_of_Consent.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Lesson #3 - Freedom of speech&lt;/h3&gt;&lt;br /&gt;But that's not all. On top of one value dissonance about sex with pre-teens we have a second value dissonance about free speech and religious respect.&lt;br /&gt;&lt;br /&gt;In Western culture since the Enlightenment, we have been very strongly attached to the idea that there is nothing that cannot be criticized. Yes, laws of different countries prohibit different kinds of speech (including United States, Supreme Court's favourite activity is making exceptions to the First Amendment and Elena Kagan doesn't seem any different here) - but every time such law is applied the media get freaked out and people feel highly uneasy about it. Even people who want to limit freedom of speech considerably universally consider it to be the default case - exceptions to be few and made only when "necessary".&lt;br /&gt;&lt;br /&gt;These believes are not shared by many, apparently including modern Muslim societies. It seems that they approach Muhammed cartoons from another direction - that people's religious believes should be respected, and their holy figures shouldn't be mocked - freedom of speech being far lower in their order of priorities than that.&lt;br /&gt;&lt;br /&gt;They don't even see the cartoons as a freedom of speech issue, just like 7th century Arabs didn't see fucking a 9 year old girl as a child abuse issue, and we don't see the cartoons as a blasphemy issue. Different cultures have different perspectives.&lt;br /&gt;&lt;br /&gt;This basic cultural relativism does not mean that all cultures are equally wrong, or equally right. It would be intellectually dishonest to think that your culture is uniquely correct about things, and its beliefs are some sort of human universals - history shows that there are hardly any true human universals, and &lt;a href="http://www.sens.org/"&gt;we might even get rid of death and taxes one day&lt;/a&gt;. But you are still free to follow your own culture's value system.&lt;br /&gt;&lt;br /&gt;If you think that freedom of speech is valuable, and fucking prepubescent girls is creepy, mocking that and not giving a shit about angry Pakistanis is all fine.&lt;br /&gt;&lt;br /&gt;In other words - enjoy the Everybody Draws Muhammad Day.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-1610326993975554848?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/1610326993975554848/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=1610326993975554848' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1610326993975554848'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1610326993975554848'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/05/everybody-draws-muhammad-day-and.html' title='Everybody Draws Muhammad Day and lessons in cultural relativism'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_IYGc_MWwkfw/S_TAtPqpUKI/AAAAAAAAA8c/id44VxS9pkg/s72-c/pedoprophet.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-5391151574220055828</id><published>2010-05-17T07:36:00.002+02:00</published><updated>2010-05-20T07:08:19.034+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='webcomics'/><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Very simple parallelization with Ruby</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S_DVCIqYkxI/AAAAAAAAA8M/niFiVOYidzA/s1600/kitten_geometry_by_tizzie_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="kitten geometry by tizzie from flickr (CC-NC-SA)"&gt;&lt;img alt="kitten geometry by tizzie from flickr (CC-NC-SA)" border="0" height="428" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S_DVCIqYkxI/AAAAAAAAA8M/niFiVOYidzA/s640/kitten_geometry_by_tizzie_from_flickr_cc-nc-sa.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;I hate waiting. And all too often when I tell computer to do stuff, the only reply I get is &lt;a href="http://t-a-w.blogspot.com/2010/05/progress-bar-for-unix-pipes.html"&gt;a progress bar&lt;/a&gt; with ETA far in the future.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Fortunately plenty of such things are highly parallelizable. For this post let's focus on a simple task of downloading every single &lt;a href="http://www.questionablecontent.net/"&gt;Questionable Content&lt;/a&gt; strip ever released because QS has really simple URLs. It's real simple to do it serially but waiting time of about 23 minutes is killing me:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;(1..1665).each{|i|&lt;br /&gt;&amp;nbsp; system "wget", "-q", "http://www.questionablecontent.net/comics/#{i}.png"&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Notice how &lt;a href="http://t-a-w.blogspot.com/2010/03/small-tips-for-making-unix-programming.html"&gt;I didn't even bother with shell, and went straight for a real programming language&lt;/a&gt;. Anyway, Ruby has very easy threading system - just use &lt;tt&gt;Thread.new{ ... }&lt;/tt&gt; to spawn, &lt;tt&gt;Thread#join&lt;/tt&gt; to join, avoid global mutable state, and you're done.&lt;br /&gt;&lt;br /&gt;We can get it running in no time:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;module Enumerable&lt;br /&gt;&amp;nbsp; def in_parallel&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; map{|x| Thread.new{ yield(x) } }.each{|t| t.join}&lt;br /&gt;&amp;nbsp; endend&lt;br /&gt;&amp;nbsp;&lt;br /&gt;(1..10).in_parallel{|i|&lt;br /&gt;&amp;nbsp; system "wget", "-q", "http://www.questionablecontent.net/comics/#{i}.png"&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;The only thing that changed was replacement a one-liner middle-ware method, and replacement of &lt;tt&gt;Enumerable#each&lt;/tt&gt; with &lt;tt&gt;Enumerable#in_parallel&lt;/tt&gt; - so far really good.&lt;br /&gt;&lt;br /&gt;On the other hand, we don't want to spawn 1665 threads all at once - neither our network connection nor QS's servers would appreciate that much. Let's write some code which would create 10 threads and keep them all busy instead.&lt;br /&gt;&lt;h3&gt;Exception handling interlude&lt;/h3&gt;A very common problem with Ruby multi-threaded programming is that we don't want the program (or even thread) to die just because of some error - usually we want to capture, print, and otherwise ignore exceptions. Here Ruby fails hard - &lt;tt&gt;Exception&lt;/tt&gt; has no method to generate user-friendly message of the kind it prints when exceptions fall out of the main loop. There are some gems that handle that, but here I'm rather unconcerned with this - and instead I'll just use a really simple catch-print-ignore method - which does not even bother printing backtrace.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;def Exception.ignoring_exceptions&lt;br /&gt;&amp;nbsp; begin&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; yield&lt;br /&gt;&amp;nbsp; rescue Exception =&amp;gt; e&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; STDERR.puts e.message&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/S_DVhU6wlPI/AAAAAAAAA8U/LyCKDHNQr8U/s1600/black_beauty_by_jakeprzespo_from_flickr_cc-by.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Black Beauty by jakeprzespo from flickr (CC-BY)"&gt;&lt;img alt="Black Beauty by jakeprzespo from flickr (CC-BY)" border="0" height="428" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/S_DVhU6wlPI/AAAAAAAAA8U/LyCKDHNQr8U/s640/black_beauty_by_jakeprzespo_from_flickr_cc-by.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Execute N tasks in parallel&lt;/h3&gt;&lt;br /&gt;How do we communicate with N threads? A simple and wrong way would be to create N queues, and feed them in a round-robin manner. Unfortunately unless tasks always take nearly the same amount of time (this is almost never even close to true) - this results in a lot of threads waiting aimlessly.&lt;br /&gt;&lt;br /&gt;We need exactly one &lt;tt&gt;todo&lt;/tt&gt; queue. Now it would be better if this queue had a size limit - but &lt;tt&gt;SizedQueue&lt;/tt&gt; was giving me troubles, so I did it with the plainest possible &lt;tt&gt;Queue&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;The main thread is really simple:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;require 'thread'&lt;br /&gt;&lt;br /&gt;module Enumerable&lt;br /&gt;&amp;nbsp; def in_parallel_n(n)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; todo = Queue.new # Create queue&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ts = (1..n).map{ # Start threads&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Thread.new{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # Do stuff in threads&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; each{|x| todo &amp;lt;&amp;lt; x} # Push things into queue &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ts.each{|t| t.join} # Wait until threads finish&lt;/pre&gt;&lt;pre&gt;&amp;nbsp; end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;Now the main question is how do we tell threads there are more tasks. Unfortunately queues have only two states:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Queue not empty - dequeue one element, do work, go back for more&lt;/li&gt;&lt;li&gt;Queue empty - sleep and wait for the queue&lt;/li&gt;&lt;/ul&gt;While we need three:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Queue not empty - dequeue one element, do work, go back for more &lt;/li&gt;&lt;li&gt;Queue empty, producer not finished - sleep and wait for the queue&lt;/li&gt;&lt;li&gt;Queue empty, producer finished - finish thread&lt;/li&gt;&lt;/ul&gt;Now I could go for a more complicated signaling solution - but that would either introduce global mutable state (hell no!), or&amp;nbsp;require too much complexity - so I simply went for the simplest possible "flood queue with &lt;tt&gt;nil&lt;/tt&gt;s once you're done" way.&lt;br /&gt;&lt;br /&gt;And because I don't want the program to break when object we're iterating over contains legitimate &lt;tt&gt;nil&lt;/tt&gt;s I'm passing whatever we get in a one-element array (Ruby probably has equivalent of Ocaml's &lt;tt&gt;'a option&lt;/tt&gt; / Haskells's Maybe monad etc. - but for this the simplest solution will work just fine).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;require 'thread'&lt;br /&gt;&lt;br /&gt;module Enumerable&lt;br /&gt;&amp;nbsp; def in_parallel_n(n)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; todo = Queue.new&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ts = (1..n).map{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Thread.new{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; while x = todo.deq&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Exception.ignoring_exceptions{ yield(x[0]) } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; end&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; each{|x| todo &amp;lt;&amp;lt; [x]}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; n.times{ todo &amp;lt;&amp;lt; nil }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ts.each{|t| t.join}&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And now we can happily get the comics. It took 4 minutes 11 seconds instead of 23 minutes - 8x speedup!&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;(1..1665).in_parallel_n(10){|i|&lt;br /&gt;&amp;nbsp; system "wget", "-q", "http://www.questionablecontent.net/comics/#{i}.png"&lt;/pre&gt;&lt;pre&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;What about other comics?&lt;/h3&gt;Now unfortunately far too many comics don't have pretty URLs like that. You can always (well, nearly always) resolve to &lt;tt&gt;wget --mirror&lt;/tt&gt; or find a greasemonkey script which makes the comics' website bearable. Fortunately quite often we can handle even somewhat more complicated URL schemes.&lt;br /&gt;&lt;br /&gt;First, for comicses like &lt;a href="http://www.sinfest.net/"&gt;sinfest&lt;/a&gt;, which use dates in URLs, it's only marginally more difficult:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;require 'date'&lt;/pre&gt;&lt;pre&gt;(Date.parse('2000-01-17')..Date.parse('2010-05-17')).in_parallel_n(10){|d|&lt;br /&gt;&amp;nbsp; system "wget", "-q", d.strftime("http://www.sinfest.net/comikaze/comics/%Y-%m-%d.gif")&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;3536 files, 7 minutes 52 second.&lt;br /&gt;&lt;br /&gt;Because Ruby dates are first class objects and &lt;tt&gt;Range&lt;/tt&gt; class works very sanely with them - it took nearly no effort to code that, other than trying to remember wtf were all those &lt;tt&gt;strftime&lt;/tt&gt; %-codes (or you could use &lt;tt&gt;Date#year&lt;/tt&gt; etc. and plain string interpolation - it would probably be better for your sanity actually).&lt;br /&gt;&lt;br /&gt;And wget will quietly ignore proper 404s, so you don't need to wonder if they're updating on weekends too, or only on weekdays, or what.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;For other comicses like xkcd you might need some hpricoting (and put alt text in metadata, then teach image viewer to read them? Or use imagemagick to put them into the image? choices, oh all the choices...). Or you could use &lt;a href="http://userscripts.org/scripts/show/59842"&gt;This awesome Webcomics Reader Greasemonkey script&lt;/a&gt;. Unfortunately it only knows about a handful of the most popular ones.&lt;br /&gt;&lt;br /&gt;Now this technique is applicable for a lot of uses other than downloading funnies - like handling S3 backups, encoding large number of MP3s and so on. Everything where it makes sense to run multiple threads in parallel, but not too insanely many will be really easy to do now thanks to &lt;tt&gt;Enumerable#in_parallel_n&lt;/tt&gt; or similar code.&lt;br /&gt;&lt;br /&gt;It works with both 1.8, and 1.9 equally well, in spite of their completely different threading systems.&lt;br /&gt;&lt;br /&gt;Enjoy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-5391151574220055828?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/5391151574220055828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=5391151574220055828' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/5391151574220055828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/5391151574220055828'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/05/very-simple-parallelization-with-ruby.html' title='Very simple parallelization with Ruby'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_IYGc_MWwkfw/S_DVCIqYkxI/AAAAAAAAA8M/niFiVOYidzA/s72-c/kitten_geometry_by_tizzie_from_flickr_cc-nc-sa.jpg' height='72' width='72'/><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-1064680592629235838</id><published>2010-05-11T23:40:00.002+02:00</published><updated>2010-05-12T00:25:36.956+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steam'/><category scheme='http://www.blogger.com/atom/ns#' term='games'/><title type='text'>Steam is ripping you off</title><content type='html'>Online distribution of content should be cheap and easy. Compared to the complexities of making and moving around DVDs and such, moving bits is pretty much free. So it's a no-brained that games on Steam should be cheaper than the same games on DVDs, right? Of course that's not how it works.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/S-nLDfPc7PI/AAAAAAAAA8E/-J0m8Zb_ABI/s1600/steam+top+10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="640" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/S-nLDfPc7PI/AAAAAAAAA8E/-J0m8Zb_ABI/s640/steam+top+10.png" width="506" /&gt;&lt;/a&gt;&lt;/div&gt;These are top 10 Steam's best-selling games - this list is rather generous for Steam, as people would prefer to buy games on Steam which were better deal on Steam than on DVD, and would prefer to buy games on DVD which were better deal on DVD - so it's reasonable to expect comparing other games Steam would come out even worse.&lt;br /&gt;&lt;br /&gt;As for DVD alternative, I wasn't looking too hard - just Amazon. I'm sure there are ways to get the games even more cheaply, but let's stick with the default online shop. Here are the prices, all Amazon's are with free shipping:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Call of Duty: Modern Warfare 2 - Amazon £29.65; Steam £39.99 - Steam costs 35% more&lt;/li&gt;&lt;li&gt;Battlefield: Bad Company 2 - Amazon £24.99; Steam £29.99 - Steam costs 20% more&lt;/li&gt;&lt;li&gt;Left 4 Dead 2 - Amazon £19.98; Steam £19.99 - essentially equal&lt;/li&gt;&lt;li&gt;Counter-Strike: Cource - Amazon £14.99; Steam £13.99 - Steam costs 7% less&lt;/li&gt;&lt;li&gt;Grand Theft Auto: Episodes from Liberty City - Amazon £14.99; Steam £19.99 - Steam costs 33% more&lt;/li&gt;&lt;li&gt;Civilization V (pre-order) - Amazon £30.99; Steam £29.99 - Steam costs 3% less&lt;/li&gt;&lt;li&gt;Mount &amp;amp; Blade: Warband - Amazon £16.97; Steam £24.99 - Steam costs 47% more&lt;/li&gt;&lt;li&gt;Borderlands - Amazon £11.78; Steam £19.99 - Steam costs 70% more&lt;/li&gt;&lt;li&gt;Just Cause 2 - Amazon £23.92; Steam £29.99 - Steam costs 25% more&lt;/li&gt;&lt;/ul&gt;In other words - median cost on Steam is about 25% higher than on Amazon. That's even though physical DVD costs quite some money to make, packaging, ship etc., while for Steam it's just pure profit.&lt;br /&gt;&lt;br /&gt;And please don't even mention "Recommended Retail Price" - if you fall for this kind of blatant &lt;a href="http://en.wikipedia.org/wiki/Anchoring"&gt;anchoring effect&lt;/a&gt;, there's no hope for you.&lt;br /&gt;&lt;br /&gt;So to summarize: Steam games cost a lot more, and to make matters worse have no resell value, they're simply ripping you off.&lt;br /&gt;&lt;br /&gt;PS. Amazon prices are for &lt;b&gt;NEW&lt;/b&gt; games. These are not used titles. Anyone claiming otherwise has no idea what they're talking about.&lt;br /&gt;&lt;br /&gt;PS2. Prices I gave are for UK (notice the £s). &lt;a href="http://www.reddit.com/r/gaming/comments/c2sjz/steam_is_ripping_you_off/c0pt9dt"&gt;acct_rdt made a similar list for US prices&lt;/a&gt;, which shows exactly the same thing - US Amazon is cheaper than US Steam too, even though the difference is not as drastic (median 7%)&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Call of Duty: Modern Warfare 2 - $37.80 new on Amazon, $59.99 on  Steam&lt;/li&gt;&lt;li&gt;Bad Company 2 - $43.83 Amazon, $49.99 Steam&lt;/li&gt;&lt;li&gt;Left 4 Dead 2 - $29.99 (both)&lt;/li&gt;&lt;li&gt;Counter-Strike: Source - $19.99 (both)&lt;/li&gt;&lt;li&gt;Episodes from Liberty City - $27.99 Amazon, $29.99 Steam&lt;/li&gt;&lt;li&gt;Civilization V - $49.99 (both)&lt;/li&gt;&lt;li&gt;Mount &amp;amp; Blade: Warband - $24.53 Amazon, $29.99 Steam&lt;/li&gt;&lt;li&gt;Borderlands - $27.99 Amazon, $29.99 Steam&lt;/li&gt;&lt;li&gt;Just Cause 2 - $39.99 Amazon, $49.99 Steam&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-1064680592629235838?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/1064680592629235838/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=1064680592629235838' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1064680592629235838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1064680592629235838'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/05/steam-is-ripping-you-off.html' title='Steam is ripping you off'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_IYGc_MWwkfw/S-nLDfPc7PI/AAAAAAAAA8E/-J0m8Zb_ABI/s72-c/steam+top+10.png' height='72' width='72'/><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-8346360427279644094</id><published>2010-05-11T17:42:00.000+02:00</published><updated>2010-05-11T17:42:29.613+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='greece'/><category scheme='http://www.blogger.com/atom/ns#' term='economy'/><title type='text'>Greeks can pay, Greeks will pay</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/S-l6XKIlVTI/AAAAAAAAA78/Smk8SA6O7CQ/s1600/roborovski_hamster_dwarf_by_cdrussorusso_from_flickr_cc-by.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Roborovski Hamster Dwarf by cdrussorusso from flickr (CC-BY)"&gt;&lt;img alt="Roborovski Hamster Dwarf by cdrussorusso from flickr (CC-BY)" border="0" height="480" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/S-l6XKIlVTI/AAAAAAAAA78/Smk8SA6O7CQ/s640/roborovski_hamster_dwarf_by_cdrussorusso_from_flickr_cc-by.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Most normal blogs' favourite countries to rant about is US, or Israel, or China, or something like that. Not on this blog - my number one target, at least for the last month - is Greece. And I'm really shocked that some of the otherwise sane people I know buy into the whole "can't pay, won't pay" nonsense, so I wrote this short post explaining how it all really works.&lt;br /&gt;&lt;h3&gt;Basics of money lending&lt;/h3&gt;&lt;br /&gt;Let's get back to basics. Why would anybody lend anybody else their money? The most common reason is they want to get even more money back. Now this is in no way the only reason - people routinely lend money to their family members and friends, IMF lends money to countries facing collapse, USA and Soviet Union lent money to support whichever dictator seemed more aligned with their interest, Europe lends money to shit-poor countries out of pity, AIG lent itself taxpayers' money by bribes and threats, and CIA lent money to Osama bin Laden because they're idiots - but while these are all very important cases, most money in the world is lent for profit motive.&lt;br /&gt;&lt;br /&gt;This profit-motivated lending is not only largest in volume - it's also most reliable. Political will can evaporate overnight - ask South Vietnam or Cuba if you don't believe me - but speculators can be reasonably counted on to keep lending as long as it makes business sense. Even in the middle of the latest recession and the Great Depression solvent borrowers had no trouble getting loans - the problem was sudden decrease in solvency, not disappearance of the profit motive.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Political and charitable lending is highly complicated and varied form case to case, but for-profit lending is quite straightforward from game theoretic point of view:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Lender decides to give borrower money or not&lt;/li&gt;&lt;li&gt;Then borrower decides to repay or not&lt;/li&gt;&lt;li&gt;Because borrower would much rather get money, and not repay it - no lender would be willing to lend anything without some pretty hard assurance of seeing their money back&lt;/li&gt;&lt;li&gt;On the other hand, as repayment might be impossible due to objective circumstances, borrowers would be unwilling to provide too much assurance&lt;/li&gt;&lt;li&gt;Level of assurance is based on balance of these two factors.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;And what forms of assurance are available? For private individuals there's debtors' prison - a barbaric institution which is still used in child support and tax cases - not coincidentally both being the kind of "debt" which is incurred unwillingly, where the "borrower" has no leverage whatsoever.&lt;br /&gt;&lt;br /&gt;Another assurance is forceful confiscation of property, and various kinds of physical abuse - these were routinely used as international debt collection in 19th century, see &lt;a href="http://en.wikipedia.org/wiki/History_of_Egypt_under_the_Muhammad_Ali_dynasty"&gt;Egypt&lt;/a&gt;, and &lt;a href="http://en.wikipedia.org/wiki/Haitian_Revolution#Free_republic"&gt;Haiti&lt;/a&gt; for examples - but these rarely happen these days.&lt;br /&gt;&lt;br /&gt;Yes, lenders could try to sue Greece or another unwilling country in foreign or domestic courts, but it would be mostly a PR stunt, and they wouldn't even get enough to cover their legal costs. If a country doesn't want to pay, lenders cannot do shit.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S-l6RtL8YEI/AAAAAAAAA70/6RP4GFerzKU/s1600/russian_dwarf_hamster_winter_white_by_cdrussorusso_from_flickr_cc-by.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Russian Dwarf Hamster Winter White by cdrussorusso from flickr (CC-BY)"&gt;&lt;img alt="Russian Dwarf Hamster Winter White by cdrussorusso from flickr (CC-BY)" border="0" height="480" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S-l6RtL8YEI/AAAAAAAAA70/6RP4GFerzKU/s640/russian_dwarf_hamster_winter_white_by_cdrussorusso_from_flickr_cc-by.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;center&gt;&lt;i&gt;Hamster showing what debtors' prison looks like&lt;/i&gt;&lt;/center&gt;&lt;br /&gt;&lt;h3&gt;The final assurance&lt;/h3&gt;&lt;br /&gt;So what keeps borrowers repaying and lenders borrowing? It's lenders not being stupid. They know very well that if someone didn't honour their debts in the past, they're unlikely to do so in the future - so if you tell the banks to go fuck themselves, you saved yourself a huge pile of money, but you have no chance of getting any money from them in the future.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;When you think about it - it's a pretty weak assurance - it only works when the country is moderately-screwed-up:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;If country's economic situation is truly screwed up - they won't be able to repay - so banks lose&lt;/li&gt;&lt;li&gt;If country's economic situation is bad but not horrible (like most countries now) - they cannot afford losing their credit lines - so they keep repaying - and banks win&lt;/li&gt;&lt;li&gt;If country's economic situation is some awesome they don't care about future loans - they can tell banks to go fuck themselves - and banks lose too!&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Fortunately for banks, the last case is very difficult to achieve - not only you need zero deficit (before interest) now - something already very hard - you need to be certain of being able to keep this zero deficit essentially indefinitely. Recessions, commodity price fluctuations, wars, terrorist attacks, aging population, floods, tsunamis, volcanoes, epidemics, electing Conservatives, and plenty of other natural disasters can screw your budget essentially overnight - all sending you crawling back to the banks begging for money. And bankers will remember what happened to their old loans.&lt;br /&gt;&lt;br /&gt;I cannot think of any country in the world which is financially healthy enough to pull that off. What makes it even less likely is that countries with most balanced budgets tend to have lowest debt levels and borrowing costs as a rule (debts are results of past performance, and past performance is the best predictor of future performance there is) - so for them repaying debts is nearly painless, and provides good insurance in case something screws their economies in the future.&lt;br /&gt;&lt;br /&gt;Essentially the only case in which a country can tell the bankers to fuck off, and has debts high enough to make it worthwhile - is one which used to be horribly mismanaged for many decades, and then turned into one of the healthiest economies in the world essentially overnight.&lt;br /&gt;&lt;br /&gt;Does it sound like Greece? If you believe so, I have some sovereign debt credit default swaps that you might be interested in.&lt;br /&gt;&lt;br /&gt;Greeks simply cannot afford not paying. They can negotiate better terms of repayment, and get some help from EU and IMF, but essentially they will have to get their country in order - cut their bloated civil service and &lt;a href="http://t-a-w.blogspot.com/2010/03/real-reason-behind-greek-economic.html"&gt;bloated military&lt;/a&gt;, cut - and repay their debts, because they simply cannot afford losing their credit lines. And so they will pay.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-8346360427279644094?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/8346360427279644094/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=8346360427279644094' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/8346360427279644094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/8346360427279644094'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/05/greeks-can-pay-greeks-will-pay.html' title='Greeks can pay, Greeks will pay'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_IYGc_MWwkfw/S-l6XKIlVTI/AAAAAAAAA78/Smk8SA6O7CQ/s72-c/roborovski_hamster_dwarf_by_cdrussorusso_from_flickr_cc-by.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-5114772550207323524</id><published>2010-05-07T01:28:00.001+02:00</published><updated>2010-05-07T02:28:50.381+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='audiobooks'/><category scheme='http://www.blogger.com/atom/ns#' term='audible'/><title type='text'>Audible review</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/S-NP_2rcNxI/AAAAAAAAA7k/ATrdLRpRiyM/s1600/dia_mundial_do_rock_by_deadoll_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="dia mundial do rock by deadoll from flickr (CC-NC-SA)"&gt;&lt;img alt="dia mundial do rock by deadoll from flickr (CC-NC-SA)" border="0" height="428" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/S-NP_2rcNxI/AAAAAAAAA7k/ATrdLRpRiyM/s640/dia_mundial_do_rock_by_deadoll_from_flickr_cc-nc-sa.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Before the posting frequency either reaches singularity or crashes like Nick Clegg's hopes, here's a brief review of Audible.&lt;br /&gt;&lt;br /&gt;I have listened to ridiculous amounts of audiobooks (a term I'm going to use for essentially any spoken word - whether an original material or a spoken version of a paper book) for many years now - a very long time before they became anything even vaguely approaching mainstream. And obviously I got most of them from Linux ISO download sites, not counting a very large number which were officially free as podcasts and such.&lt;br /&gt;&lt;br /&gt;Then, my cat threw my iPod into a bathtub full of water, I bought &lt;a href="http://t-a-w.blogspot.com/2009/03/best-mp3-player-in-world.html"&gt;a new and much better MP3 player&lt;/a&gt;, and with it came free subscription to Audible, which I actually extended for a few more paid months more out of curiosity how this world of paid audiobooks operates than anything else.&lt;br /&gt;&lt;h3&gt;DRM&lt;/h3&gt;&lt;br /&gt;First - DRM is as bad as you'd expect. Devices cannot be activate on anything except Windows (the stories about iTunes being able to activate MP3 players are a lie). Then after I formatted the MP3 player, it lost activation and it was impossible to get it back. There was no error message, nothing. Activated successfully, still doesn't work. I had to email Audible for them to fix it... it was really one big pile of ridiculousness, all horror stories about DRM basically came true.&lt;br /&gt;&lt;br /&gt;Does it at least DRM the books? Not at all. First, they left CD burning as an option, so anyone who is desperate enough can get virtual CDs and then rip them. And you can download Audible-ripping software which will happily hack into Audible drivers on any activated PC, and convert all your DRMed files into MP3s, FLACs, or whatever. Essentially they fuck over paid customers, and the pirates will get their warez anyway.&lt;br /&gt;&lt;br /&gt;This is all good enough reason for not using Audible even if they didn't suck in other ways, but suck they do...&lt;br /&gt;&lt;h3&gt;Speech synthesis&lt;/h3&gt;&lt;br /&gt;But before I get to the main dish of Audible suckiness, a brief interlude for state of speech synthesis. 60 years ago, when computing started, people believed that in no time computers will be as smart as humans. You know - 10 years, 20 tops. Which as it turned out in computing world means essentially "never".&lt;br /&gt;&lt;br /&gt;I'm just amazed at how filled with wrong are predictions of people who expect rapid arrival of AI - like most users of the &lt;a href="http://lesswrong.com/"&gt;ironically named LessWrong community blog&lt;/a&gt;. How the fuck are we going to see AI go "foom" if during the last 60 years there has been essentially zero progress at:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Speech recognition&lt;/li&gt;&lt;li&gt;Handwriting (and most importantly hand-written math/diagrams/mindmaps)  recognition&lt;/li&gt;&lt;li&gt;Speech synthesis&lt;/li&gt;&lt;/ul&gt;Yes, they expect a big foom - but better be worried in case this foomy future Kindle 2020 or whatnot will turn out to be unfriendly - and let's say will read the latest Twilight sequel in a very ironic voice... &lt;br /&gt;&lt;br /&gt;The truth is - automated speech synthesis of anywhere near human quality is not coming anytime soon. It just isn't. Amazon knows it as well, while building gimmicky crappy speech synthesis into Kindle, they also purchased Audible for  $300M whose business model totally relies on speech synthesis being crappy for decades to come! How is this $300M for a prediction market? Are you shorting Amazon stocks already? I didn't think so.&lt;br /&gt;&lt;br /&gt;And while I'm at it, remember how &lt;a href="http://t-a-w.blogspot.com/2009/01/which-crackpot-cult-to-join.html"&gt;one of my favourite crackpots - Raymond Kurzweil&lt;/a&gt; boldly predicted that by 2009 "[people] interact with their computers primarily by voice and by pointing  with a device that looks like a pencil. Keyboards still exist but most  textual language is created by speaking". Obviously this crackpottery never came true, I'll keep my &lt;a href="http://www.microsoft.com/hardware/mouseandkeyboard/productdetails.aspx?pid=043"&gt;Microsoft Natural Ergonomic Keyboard 4000&lt;/a&gt; thank you very much. I doubt even Apple would be stupid enough to go into the whole voice thing - but then with iPad they sort of have proven that they can sell absolutely anything, and hipsters will buy it...&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/S-NQSJ4i0uI/AAAAAAAAA7s/4m71fzdc9TA/s1600/icat_by_sontra_from_flickr_cc-by.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="iCat by Sontra from flickr (CC-BY)"&gt;&lt;img alt="iCat by Sontra from flickr (CC-BY)" border="0" height="480" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/S-NQSJ4i0uI/AAAAAAAAA7s/4m71fzdc9TA/s640/icat_by_sontra_from_flickr_cc-by.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Why Audible sucks&lt;/h3&gt;&lt;br /&gt;And now the main part - why Audible sucks. To explain this think for a moment what an Internet shop is. Yes, it needs to have some stuff to sell, and some way to deliver it, and some way to accept payment, but primarily:&lt;br /&gt;&lt;blockquote style="font-size: 150%; font-style: italic;"&gt;An Internet shop is primarily a search engine&lt;/blockquote&gt;&lt;br /&gt;That's right! Everything else is just an insignificant attachment to the main functionality of letting people &lt;b&gt;find&lt;/b&gt; the stuff they want to buy. Go to Amazon - the archetypal Internet shop. What's there - a huge search engine. With user reviews, recommendations based on your previous purchases, and purchases of other users, and a huge wealth of information which helps you find things you might want to buy. Why nobody has copied Amazon yet? Well, there are some economies of scales involved, but dis-economies of scale exist as well. This is not the answer.&lt;br /&gt;&lt;br /&gt;The primary reason is that nobody else has this massive database of data which helps people find what they want. Even if you had all the products Amazon has, at identical prices and terms of delivery, without user reviews and contextual recommendations your shop would be hopeless. And without even as much as Amazon search system? Forget about it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;By the way, I'm probably biased as most of my commercial career was in one way or another related to building custom search engines, just saying for the sake of full disclosure...&lt;br /&gt;&lt;br /&gt;Anyway, Audible fails so hard at search it's not even funny. You go to category - and it's sorted by release date. How is this sane? You can sort by customer review - but most of their books have at most one review and there's no Bayesian filtering applied, so everything on the top will be audiobooks with a single 5-star review. Yes, it's all great that ONE person liked it, but it has extremely low predictive power on how good it actually is. About the only useful way to sort anything is by top selling.&lt;br /&gt;&lt;br /&gt;So what do we see - title, author, price, star rating, a picture (wtf? these are &lt;b&gt;audio&lt;/b&gt;books, these pictures are essentially just some random stock photos of no relationship with the product) - and that's it. And max displayed at once is 30 - but don't worry, it will change back to the default useless value of 10 results as soon as you change anything.&lt;br /&gt;&lt;br /&gt;This is not Google! You don't want to go from search term out of their site in less than a second - you want to figure out what's actually any good! The logic of having smaller number of results so they're faster doesn't apply at all!&lt;br /&gt;&lt;br /&gt;So how do you figure out if the book is any good at all? Well, there are very rarely any customer reviews (just a few star ratings is typical) and the ones there are are typically as useless as "&lt;i&gt;Took me a little while to get into this book, but when I did I  absolutely loved it!  Have just downloaded the second book and can't  wait to begin!&lt;/i&gt;". How does this provide any information whatsoever?&lt;br /&gt;&lt;br /&gt;There is usually a short publisher-provided blurb telling what the book is about - &lt;a href="http://t-a-w.blogspot.com/2010/02/wikipedia-bias-in-video-game-articles.html"&gt;and you can probably guess what I think about such publishers' honesty&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The only thing that's of any use at all - and without which the entire Audible website would be utterly useless - is the audiobook sample. Unfortunately it doesn't work terribly well. One thing you can figure out is that quality of recording tends to be top notch - unlike some other sources which compress audiobooks as if people were still downloading them on dial-up modems, audible handles quality properly. And you can also find out if you like the narrator or not. Which might be very highly relevant for their "erotic" section at least... (seriously, go there for some major lulz and/or facepalming..., but then &lt;a href="http://t-a-w.blogspot.com/2010/05/unified-theory-of-online-dating-and.html"&gt;maybe I'm not the target audience&lt;/a&gt;...).&lt;br /&gt;&lt;br /&gt;What you'll rarely find out is if the book is actually any good, which is what we want to establish. Random pages from the middle of the book rarely tell you that. Even worse, I've seen quite a few books for which the random sample was actually legal blurb + acknowledgments from the first few pages... that definitely is some fascinating book, right !?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately that's all your search options. Audible won't search inside books to figure out what they're about (speech recognition obviously being crap, but on the other hand - they have access to written original most of the time, so that's a weak excuse), and there's no other information on their website.&lt;br /&gt;&lt;br /&gt;If you want to find out a good audiobook, you need to check every audiobook's written equivalent's page on Amazon - for reviews there. Somebody should write a Greasemonkey script for that... (this problem also affects UK Amazon to some extent - often US version has 10x as many reviews, but there's no link and the only way to get to those reviews is Googling... it gets me raging every time...)&lt;br /&gt;&lt;br /&gt;How difficult would it be to link it up with the rest of Amazon? Seriously now.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There's also another issue - the choice on Audible is simply less than on "Linux ISOs download sites" - so when you want an audiobook it's very likely you won't find it there, even if it exists. The opposite - Audible having something which pirates don't also happens, but usually for more obscure titles.&lt;br /&gt;&lt;br /&gt;This is actually an opportunity for them - sure, many people will torrent Dan Brown, but there's long tail to explore - except it is exactly this long tail which is it direst need of good search functionality. And so Audible fails.&lt;br /&gt;&lt;br /&gt;So maybe it's a good idea to short them after all...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-5114772550207323524?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/5114772550207323524/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=5114772550207323524' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/5114772550207323524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/5114772550207323524'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/05/audible-review.html' title='Audible review'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_IYGc_MWwkfw/S-NP_2rcNxI/AAAAAAAAA7k/ATrdLRpRiyM/s72-c/dia_mundial_do_rock_by_deadoll_from_flickr_cc-nc-sa.jpg' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-4617617251461971784</id><published>2010-05-06T23:01:00.001+02:00</published><updated>2010-05-13T18:08:16.319+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unix'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Progress bar for Unix pipes</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/S-Mt1MJ7KDI/AAAAAAAAA7c/Em5ygSdz9TM/s1600/dont_spill_by_ack_ook_from_flickr_cc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Don't Spill! by Ack Ook from flickr (CC-SA)"&gt;&lt;img alt="Don't Spill! by Ack Ook from flickr (CC-SA)" border="0" height="640" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/S-Mt1MJ7KDI/AAAAAAAAA7c/Em5ygSdz9TM/s640/dont_spill_by_ack_ook_from_flickr_cc-sa.jpg" width="480" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;This is getting quite ridiculous, as it's the third post I'm writing in just one day - that's more than I typically wrote monthly over the last two years. This is what you get for finally getting organized - a big pile of 90%-finished stuff which while useless on their own can be very quickly be turned into something of high utility. &lt;a href="http://www.omnigroup.com/products/omnifocus/"&gt;OmniFocus&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Getting_Things_Done"&gt;GTD&lt;/a&gt; are truly awesome. (unfortunately this means there are now two apps for Mac I care about - TextMate and OmniFocus - so switching away from Mac will be even hander)&lt;br /&gt;&lt;br /&gt;The script I want to show you today solves one of the most severe problems with Unix pipes - lack of progress indicators. Normally you'd start a pipe, and until it actually finished what it was doing, you'd have no way of finding out if it's 1% done or 99% done, and how fast it is progressing.&lt;br /&gt;&lt;br /&gt;There are some nasty hacks. Many times I used strace or looked inside &lt;tt&gt;/proc&lt;/tt&gt; to figure out how much progress has been done - but these are painful waste of effort for something that should be builtin. Feedback is the basic principle of good UI design.&lt;br /&gt;&lt;br /&gt;Anyway, here's the final solution to progress bar question:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#!/usr/bin/env ruby&lt;br /&gt;&lt;br /&gt;STDERR.sync = true&lt;br /&gt;&lt;br /&gt;$bytes = true&lt;br /&gt;$max = nil&lt;br /&gt;$count = 0&lt;br /&gt;&lt;br /&gt;until ARGV.empty?&lt;br /&gt;&amp;nbsp; case (arg = ARGV.shift)&lt;br /&gt;&amp;nbsp; when '-l'&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $bytes = false&lt;br /&gt;&amp;nbsp; when '-b'&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $bytes = true&lt;br /&gt;&amp;nbsp; when /\A(\d+)([kmg]?)\Z/&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; units = {'k'=&amp;gt;2**10, 'm'=&amp;gt;2**20, 'g'=&amp;gt;2**10, ''=&amp;gt;1}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $max = $1.to_i * units[$2]&lt;br /&gt;&amp;nbsp; else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; raise "Unrecognized argument: `#{arg}'"&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;$max = STDIN.stat.size if $bytes and STDIN.stat.file? and $max.nil?&lt;br /&gt;&lt;br /&gt;Thread.new{&lt;br /&gt;&amp;nbsp; last_count = nil&lt;br /&gt;&amp;nbsp; while true&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if $count != last_count&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if $max&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; STDERR.print "\r#{$count}/#{$max} [#{$count*100/$max}%]"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; STDERR.print "\r#{$count}"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; end&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; last_count = $count&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; end&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; sleep 1&lt;br /&gt;&amp;nbsp; end &amp;nbsp;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;begin&lt;br /&gt;&amp;nbsp; while data = ($bytes ? STDIN.read(2**12) : STDIN.gets)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; STDOUT.print(data)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $count += $bytes ? data.length : 1&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;&amp;nbsp; STDERR.print "\n"&lt;br /&gt;rescue Errno::EPIPE&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;Explanation time:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You can use this script at any point of the pipeline. &lt;tt&gt;foo | bar | progress | blah&lt;/tt&gt;.&lt;/li&gt;&lt;li&gt;The script will take advantage of the fact that its &lt;tt&gt;STDERR&lt;/tt&gt; is still linked with your terminal, and output progress information there. It will then clear and overwrite the same line every second with new information.&lt;/li&gt;&lt;li&gt;There is no support for multiple progressbars in one pipeline - his is not terribly difficult to do (one would be master, others would send info to it via socket based on tty's inode), but I never found a good use case for it, so I never bothered implementing it.&lt;/li&gt;&lt;li&gt;progress script works in two modes - by default it counts bytes (&lt;tt&gt;-b&lt;/tt&gt;), but it can count lines (&lt;tt&gt;-l&lt;/tt&gt;) as well.&lt;/li&gt;&lt;li&gt;You can specify what counts as 100% if you want percentage information - with &lt;tt&gt;progress -l 1234&lt;/tt&gt;, &lt;tt&gt;progress -b 700m&lt;/tt&gt; etc. If you specify wrong size of course you get garbage.&lt;/li&gt;&lt;li&gt;If you operate in the default byte mode and input is a file - the script will figure out file size automatically. This doesn't happen in line mode, as it would require a potentially expensive &lt;tt&gt;wc -l&lt;/tt&gt; - it's easy to do it manually if you want.&lt;/li&gt;&lt;/ul&gt;Here's a "screenshot": &lt;br /&gt;&lt;pre&gt;$ ./progress &amp;lt; kubuntu-10.04-beta2-desktop-amd64.iso | openssl md5&lt;br /&gt;287244288/708704256 [40%]&lt;/pre&gt;&lt;br /&gt;Enjoy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-4617617251461971784?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/4617617251461971784/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=4617617251461971784' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/4617617251461971784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/4617617251461971784'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/05/progress-bar-for-unix-pipes.html' title='Progress bar for Unix pipes'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_IYGc_MWwkfw/S-Mt1MJ7KDI/AAAAAAAAA7c/Em5ygSdz9TM/s72-c/dont_spill_by_ack_ook_from_flickr_cc-sa.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-5602457296338758133</id><published>2010-05-06T18:30:00.001+02:00</published><updated>2010-05-06T21:48:43.648+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='diet'/><category scheme='http://www.blogger.com/atom/ns#' term='health'/><category scheme='http://www.blogger.com/atom/ns#' term='history'/><title type='text'>Brief history of human diet</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S-Lr20qLFCI/AAAAAAAAA68/lsgAYqsvGGU/s1600/sushi_the_cat_joins_us_for_dinner_3_by_torley_from_flickr_cc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Sushi the cat joins us for dinner 3 by Torley from flickr (CC-SA)"&gt;&lt;img alt="Sushi the cat joins us for dinner 3 by Torley from flickr (CC-SA)" border="0" height="480" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S-Lr20qLFCI/AAAAAAAAA68/lsgAYqsvGGU/s640/sushi_the_cat_joins_us_for_dinner_3_by_torley_from_flickr_cc-sa.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Previously in series: &lt;a href="http://t-a-w.blogspot.com/2009/11/myth-of-5-day-people-never-ate-that.html"&gt;The myth of 5 a day - people never ate that much fruit and veg&lt;/a&gt;, &lt;a href="http://t-a-w.blogspot.com/2009/11/dietary-consequences.html"&gt;Dietary consequences&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I've been listening to an audiobook about history of potato cultivation, which I purchased legitimately, and then proceeded to strip DRM of it in spite of Audible insisting in its FAQ that it's impossible. Are you getting WTF overload already?&lt;br /&gt;&lt;br /&gt;Anyway... for people who are puzzled by the recent obesity/diabetes/metabolic syndrome clusterfuck, here's a quick reminder of history of human diet:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Humans did a lot of hunting and gathering with diet composition being highly varied depending on local circumstances. Normally hunting would bring most high quality protein, while gathering would bring most calories, and diversity of food sources would ensure good dietary balance and protect against bad seasons.&lt;/li&gt;&lt;li&gt;Then humans switched to agriculture. &lt;a href="http://en.wikipedia.org/wiki/Neolithic_Revolution"&gt;This happened at least 7 times&lt;/a&gt;, independently, almost at once, after millions of years during which it could have happened and didn't. Amount of evidence we have is just ridiculously high compared to all other human evolutionary transitions (like language, behavioral modernity, industrial revolution, and scientific revolution - all happening just once) that it's a shame that we don't have any convincing theories explaining why it happened when and where it happened.&lt;/li&gt;&lt;li&gt;Invariably, this switch resulted in severe health problems. Calories were more plentiful, but reliance on a small number of food sources virtually ensured micronutrient deficiencies, and regular famines due to bad weather. Farmers were shorter, died earlier, and generally suffered. This is well documented everywhere transition to agriculture happened.&lt;/li&gt;&lt;li&gt;Gradually, people figured out how to diversify their food sources, and in time farmers got as healthy as hunter-gatherers before them. There were more kinds of food, better agricultural practices, better preservation methods, better cooking methods, varieties of food grown got changed, and &lt;a href="http://en.wikipedia.org/wiki/Lactose_intolerance"&gt;to a small extent even human biochemistry changed to adapt to agriculture&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;There was still one huge problem - people were spending insane amount of time on food preparation. According to some statistics, even as recently as a century ago, average wife spent 45 hours a week on activities related to food preparation. Stay-at-home mums were not a cultural quirk - they were a necessity (unless you could afford servants).&lt;/li&gt;&lt;li&gt;A new revolution in food production happened in the last century. There was quantitative increase in productivity, but most interesting part of it was switch from highly home-labour-intensive food which required rigid gender role separation to semi-prepared food which freed women into general labour force. &lt;/li&gt;&lt;/ul&gt;Yes, it was not feminist nonsense which brought equality, or birth control, or anything like that - it was primarily food processing industry. You might protest that you don't eat that much processed food - but you're fooling yourself. How many of you have milked your own cows, churned your own butter, baked your own bread (milling flour has been industrialized ages ago - but at first it was also done at home), made your own pasta etc.? We have gone so far up the food processing ladder than we forgot how much processing goes into all those seemingly simple foods that form bulk of our diets. Actually, I do bake my own bread sometimes, but with a bread machine, so it hardly counts, and mostly because British bread is atrocious spongy shit.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately food is a complex matter, and this transition went not without causing some serious problems, just like the original switch to agriculture. If you think about it - these problems aren't terribly severe. Yes - untreated obesity is live-threatening, and we haven't found good cure for it, but we have been really good at treating the symptoms. There are drugs for diabetes and hypertension, cars have replaced the need to even as much as walk longer distances, and loss of physical attractiveness can be largely covered by learning the art of myspace shots. People still live longer each year, and don't seem that terribly distressed.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Moreover, it seems that &lt;a href="http://www.latimes.com/news/nationworld/nation/la-sci-obesity14-2010jan14,0,6185851.story"&gt;obesity rates have plateaued in States&lt;/a&gt; in the last decade - at a ridiculously high rate, but it's not unlikely that the worse is already over, and they'll only go down from there.&lt;br /&gt;&lt;br /&gt;If the rates start indeed falling, then perhaps the transition to the new kind of food will have went surprisingly smoothly, compared to all such past transitions.&lt;br /&gt;&lt;h3&gt;Case study - USA&lt;/h3&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S-LsNasl7NI/AAAAAAAAA7E/agV6ruQi4fM/s1600/the_bite_by_ack_ook_from_flickr_cc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="The Bite by Ack Ook from flickr (CC-SA)"&gt;&lt;img alt="The Bite by Ack Ook from flickr (CC-SA)" border="0" height="480" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S-LsNasl7NI/AAAAAAAAA7E/agV6ruQi4fM/s640/the_bite_by_ack_ook_from_flickr_cc-sa.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Let's take a look at how eating patterns changed in one of the worst affected countries - USA. It is so commonly repeated that people eat more sugar, fat and animal products that it gets on my nerves. Here's the definite table of all major food groups (at least 1% share at either date), &lt;a href="http://faostat.fao.org/site/609/DesktopDefault.aspx?PageID=609"&gt;based on FAO data&lt;/a&gt;, as percentage of caloric intake, ordered by relative change. I'd love to have data for 1900, as 1961 was midway the shift from unprocessed to processed food, but we have to do with the data we have, instead of despairing for the data we wished to have.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Product&lt;/th&gt;&lt;th&gt;1961&lt;/th&gt;&lt;th&gt;2005&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Rice&lt;/td&gt;&lt;td&gt;0.93%&lt;/td&gt;&lt;td&gt;2.46%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Poultry Meat&lt;/td&gt;&lt;td&gt;2.23%&lt;/td&gt;&lt;td&gt;5.48%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Cheese&lt;/td&gt;&lt;td&gt;1.67%&lt;/td&gt;&lt;td&gt;3.94%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Vegetable Oils&lt;/td&gt;&lt;td&gt;9.58%&lt;/td&gt;&lt;td&gt;18.58%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Groundnuts&lt;/td&gt;&lt;td&gt;1.1%&lt;/td&gt;&lt;td&gt;1.55%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Maize&lt;/td&gt;&lt;td&gt;2.05%&lt;/td&gt;&lt;td&gt;2.52%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Vegetal Products&lt;/td&gt;&lt;td&gt;64.93%&lt;/td&gt;&lt;td&gt;72.77%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Fruits - Excluding Wine&lt;/td&gt;&lt;td&gt;2.77%&lt;/td&gt;&lt;td&gt;3.03%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Beer&lt;/td&gt;&lt;td&gt;2.36%&lt;/td&gt;&lt;td&gt;2.57%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Meat&lt;/td&gt;&lt;td&gt;11.63%&lt;/td&gt;&lt;td&gt;12.0%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Alcoholic Beverages&lt;/td&gt;&lt;td&gt;3.77%&lt;/td&gt;&lt;td&gt;3.84%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Cereals - Excluding Beer&lt;/td&gt;&lt;td&gt;21.76%&lt;/td&gt;&lt;td&gt;21.44%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Sugar &amp;amp; Sweeteners&lt;/td&gt;&lt;td&gt;17.89%&lt;/td&gt;&lt;td&gt;16.92%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pulses&lt;/td&gt;&lt;td&gt;1.25%&lt;/td&gt;&lt;td&gt;1.14%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Potatoes&lt;/td&gt;&lt;td&gt;2.69%&lt;/td&gt;&lt;td&gt;2.43%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Wheat&lt;/td&gt;&lt;td&gt;17.5%&lt;/td&gt;&lt;td&gt;15.5%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Vegetables&lt;/td&gt;&lt;td&gt;2.22%&lt;/td&gt;&lt;td&gt;1.93%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Starchy Roots&lt;/td&gt;&lt;td&gt;3.14%&lt;/td&gt;&lt;td&gt;2.57%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Animal Products&lt;/td&gt;&lt;td&gt;35.07%&lt;/td&gt;&lt;td&gt;27.23%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Other Alcoholic Beverages&lt;/td&gt;&lt;td&gt;1.19%&lt;/td&gt;&lt;td&gt;0.92%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pigmeat&lt;/td&gt;&lt;td&gt;4.41%&lt;/td&gt;&lt;td&gt;3.36%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Milk - Excluding Butter&lt;/td&gt;&lt;td&gt;13.29%&lt;/td&gt;&lt;td&gt;9.9%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Beans&lt;/td&gt;&lt;td&gt;1.13%&lt;/td&gt;&lt;td&gt;0.79%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Bovine Meat&lt;/td&gt;&lt;td&gt;4.36%&lt;/td&gt;&lt;td&gt;3.02%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Eggs&lt;/td&gt;&lt;td&gt;2.33%&lt;/td&gt;&lt;td&gt;1.45%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Butter, Ghee&lt;/td&gt;&lt;td&gt;2.26%&lt;/td&gt;&lt;td&gt;1.05%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Animal Fats&lt;/td&gt;&lt;td&gt;6.92%&lt;/td&gt;&lt;td&gt;2.91%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;That is:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Americans eat more vegetal, and less animal products - and within this category there's shift towards leaner meats&lt;/li&gt;&lt;li&gt;Americans eat about as much sugar &amp;amp; HFCS&lt;/li&gt;&lt;li&gt;Americans eat absolutely insane amounts of vegetable oil&lt;/li&gt;&lt;/ul&gt;And these are the biggest losers. I will slap around with a large healthy trout everyone who dares to suggest that HFCS is responsible for obesity. HFCS is damn sugar - statistics say it's vegetable oil you eat too much of.&lt;br /&gt;&lt;blockquote style="font-size: 150%; font-style: italic;"&gt;"HFCS causes obesity" is the new "vaccines cause autism"&lt;/blockquote&gt;&lt;br /&gt;&lt;h3&gt;Case study - Germany&lt;/h3&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/S-LsptWBpHI/AAAAAAAAA7M/4y618vQ0YfA/s1600/chef_cat_is_watching_the_sausages_by_ruudb0y_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Chef cat is watching the sausages by ruudb0y from flickr (CC-NC-SA)"&gt;&lt;img alt="Chef cat is watching the sausages by ruudb0y from flickr (CC-NC-SA)" border="0" height="480" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/S-LsptWBpHI/AAAAAAAAA7M/4y618vQ0YfA/s640/chef_cat_is_watching_the_sausages_by_ruudb0y_from_flickr_cc-nc-sa.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;For a second case study, I took a less drastically affected country - Germany. Germany is taking the transition somewhat better than States, and your guess is as good as mine if this is a genuine success, or the worst is simply still ahead of them.&lt;br /&gt;&lt;br /&gt;I wished to simply have EU15 average or something like that, but FAO  lacks good aggregate data, so here's the next best thing. &lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Product&lt;/th&gt;&lt;th&gt;1961&lt;/th&gt;&lt;th&gt;2005&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Maize&lt;/td&gt;&lt;td&gt;0.4%&lt;/td&gt;&lt;td&gt;2.44%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Rice&lt;/td&gt;&lt;td&gt;0.53%&lt;/td&gt;&lt;td&gt;1.34%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Poultry Meat&lt;/td&gt;&lt;td&gt;0.66%&lt;/td&gt;&lt;td&gt;1.53%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Wine&lt;/td&gt;&lt;td&gt;0.61%&lt;/td&gt;&lt;td&gt;1.32%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Nuts&lt;/td&gt;&lt;td&gt;0.55%&lt;/td&gt;&lt;td&gt;1.1%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Cheese&lt;/td&gt;&lt;td&gt;1.93%&lt;/td&gt;&lt;td&gt;3.76%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Other Alcoholic Beverages&lt;/td&gt;&lt;td&gt;0.81%&lt;/td&gt;&lt;td&gt;1.39%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Vegetables&lt;/td&gt;&lt;td&gt;1.08%&lt;/td&gt;&lt;td&gt;1.8%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Fish, Seafood&lt;/td&gt;&lt;td&gt;0.77%&lt;/td&gt;&lt;td&gt;1.17%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Vegetable Oils&lt;/td&gt;&lt;td&gt;8.81%&lt;/td&gt;&lt;td&gt;11.4%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Wheat&lt;/td&gt;&lt;td&gt;14.5%&lt;/td&gt;&lt;td&gt;18.41%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Sugar &amp;amp; Sweeteners&lt;/td&gt;&lt;td&gt;11.71%&lt;/td&gt;&lt;td&gt;14.22%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Alcoholic Beverages&lt;/td&gt;&lt;td&gt;5.71%&lt;/td&gt;&lt;td&gt;6.63%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pigmeat&lt;/td&gt;&lt;td&gt;6.25%&lt;/td&gt;&lt;td&gt;6.96%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Milk - Excluding Butter&lt;/td&gt;&lt;td&gt;8.09%&lt;/td&gt;&lt;td&gt;8.89%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Meat&lt;/td&gt;&lt;td&gt;9.15%&lt;/td&gt;&lt;td&gt;9.79%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Vegetal Products&lt;/td&gt;&lt;td&gt;67.45%&lt;/td&gt;&lt;td&gt;69.96%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Cereals - Excluding Beer&lt;/td&gt;&lt;td&gt;24.94%&lt;/td&gt;&lt;td&gt;25.47%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Animal Products&lt;/td&gt;&lt;td&gt;32.55%&lt;/td&gt;&lt;td&gt;30.04%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Beer&lt;/td&gt;&lt;td&gt;4.3%&lt;/td&gt;&lt;td&gt;3.91%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Fruits - Excluding Wine&lt;/td&gt;&lt;td&gt;3.75%&lt;/td&gt;&lt;td&gt;3.28%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Stimulants&lt;/td&gt;&lt;td&gt;1.07%&lt;/td&gt;&lt;td&gt;0.91%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Eggs&lt;/td&gt;&lt;td&gt;1.7%&lt;/td&gt;&lt;td&gt;1.31%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Animal Fats&lt;/td&gt;&lt;td&gt;12.43%&lt;/td&gt;&lt;td&gt;8.76%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Butter, Ghee&lt;/td&gt;&lt;td&gt;6.56%&lt;/td&gt;&lt;td&gt;3.6%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Bovine Meat&lt;/td&gt;&lt;td&gt;1.99%&lt;/td&gt;&lt;td&gt;1.02%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Potatoes&lt;/td&gt;&lt;td&gt;8.81%&lt;/td&gt;&lt;td&gt;4.06%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Rye&lt;/td&gt;&lt;td&gt;8.2%&lt;/td&gt;&lt;td&gt;2.39%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Interesting points:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Changes are much less drastic than in States. &lt;/li&gt;&lt;li&gt;There's big shift away from local rye and potatoes to more international wheat, maize, and rice.&lt;/li&gt;&lt;li&gt;Just like in States, there's shift from butter to vegetable oil, and from fatter to leaner meat - but it's less significant.&lt;/li&gt;&lt;li&gt;Other than that, German food preferences are remarkably stable over such a long period of time, and such drastic changes in actual agricultural practice.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Case study - Japan&lt;/h3&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S-LtP8zXwJI/AAAAAAAAA7U/hJIZjIZLPRY/s1600/cat_and_birdies_bento_explored_by_gamene_from_flickr_cc-by.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="cat and birdies bento [explored] by gamene from flickr (CC-BY)"&gt;&lt;img alt="cat and birdies bento [explored] by gamene from flickr (CC-BY)" border="0" height="604" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S-LtP8zXwJI/AAAAAAAAA7U/hJIZjIZLPRY/s640/cat_and_birdies_bento_explored_by_gamene_from_flickr_cc-by.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;And finally the country which takes transition remarkably well - they are essentially free of Western metabolic syndrome troubles. You'd think they sticked to their traditional food? No such luck.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Product&lt;/th&gt;&lt;th&gt;1961&lt;/th&gt;&lt;th&gt;2005&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Maize&lt;/td&gt;&lt;td&gt;0.16%&lt;/td&gt;&lt;td&gt;2.74%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Poultry Meat&lt;/td&gt;&lt;td&gt;0.18%&lt;/td&gt;&lt;td&gt;2.03%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pigmeat&lt;/td&gt;&lt;td&gt;0.36%&lt;/td&gt;&lt;td&gt;3.37%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Meat&lt;/td&gt;&lt;td&gt;1.07%&lt;/td&gt;&lt;td&gt;6.38%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Vegetable Oils&lt;/td&gt;&lt;td&gt;3.26%&lt;/td&gt;&lt;td&gt;12.21%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Milk - Excluding Butter&lt;/td&gt;&lt;td&gt;1.42%&lt;/td&gt;&lt;td&gt;3.78%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Animal Products&lt;/td&gt;&lt;td&gt;9.64%&lt;/td&gt;&lt;td&gt;20.58%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Eggs&lt;/td&gt;&lt;td&gt;1.45%&lt;/td&gt;&lt;td&gt;2.75%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Beer&lt;/td&gt;&lt;td&gt;0.74%&lt;/td&gt;&lt;td&gt;1.3%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Other Alcoholic Beverages&lt;/td&gt;&lt;td&gt;1.51%&lt;/td&gt;&lt;td&gt;2.54%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Demersal Fish&lt;/td&gt;&lt;td&gt;1.19%&lt;/td&gt;&lt;td&gt;1.83%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Fruits - Excluding Wine&lt;/td&gt;&lt;td&gt;1.36%&lt;/td&gt;&lt;td&gt;2.0%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Sugar &amp;amp; Sweeteners&lt;/td&gt;&lt;td&gt;7.01%&lt;/td&gt;&lt;td&gt;10.01%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Wheat&lt;/td&gt;&lt;td&gt;9.73%&lt;/td&gt;&lt;td&gt;13.32%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Animal Fats&lt;/td&gt;&lt;td&gt;1.05%&lt;/td&gt;&lt;td&gt;1.38%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Fish, Seafood&lt;/td&gt;&lt;td&gt;4.52%&lt;/td&gt;&lt;td&gt;5.93%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Alcoholic Beverages&lt;/td&gt;&lt;td&gt;3.56%&lt;/td&gt;&lt;td&gt;4.65%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Vegetables&lt;/td&gt;&lt;td&gt;2.4%&lt;/td&gt;&lt;td&gt;2.82%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pelagic Fish&lt;/td&gt;&lt;td&gt;2.5%&lt;/td&gt;&lt;td&gt;2.21%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Vegetal Products&lt;/td&gt;&lt;td&gt;90.36%&lt;/td&gt;&lt;td&gt;79.42%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Soyabeans&lt;/td&gt;&lt;td&gt;4.29%&lt;/td&gt;&lt;td&gt;3.52%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Potatoes&lt;/td&gt;&lt;td&gt;2.09%&lt;/td&gt;&lt;td&gt;1.5%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Cereals - Excluding Beer&lt;/td&gt;&lt;td&gt;60.34%&lt;/td&gt;&lt;td&gt;38.68%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Fermented Beverages&lt;/td&gt;&lt;td&gt;1.3%&lt;/td&gt;&lt;td&gt;0.68%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Rice&lt;/td&gt;&lt;td&gt;46.6%&lt;/td&gt;&lt;td&gt;22.09%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Beans&lt;/td&gt;&lt;td&gt;1.24%&lt;/td&gt;&lt;td&gt;0.54%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Starchy Roots&lt;/td&gt;&lt;td&gt;5.87%&lt;/td&gt;&lt;td&gt;2.45%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pulses&lt;/td&gt;&lt;td&gt;1.44%&lt;/td&gt;&lt;td&gt;0.6%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Sweet Potatoes&lt;/td&gt;&lt;td&gt;3.31%&lt;/td&gt;&lt;td&gt;0.64%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Barley&lt;/td&gt;&lt;td&gt;3.6%&lt;/td&gt;&lt;td&gt;0.17%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Or:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Changes are even more drastic than in other case studies.&lt;/li&gt;&lt;li&gt;There has been huge reduction in consumption of rice, barley, sweet potatoes.&lt;/li&gt;&lt;li&gt;There has been huge increase in consumption of animal products, and vegetable oil, and big increase in consumption of sugar.&lt;/li&gt;&lt;li&gt;Japanese drink far more milk than they used to - and fuck lactose intolerance.&lt;/li&gt;&lt;/ul&gt;So to sum it up... I makes little sense. There's no going back. Stay-at-home mums are as much a thing of the past as bands of hunters chasing mammoths across tundra. You have to switch. The question remains - what to switch to.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The optimistic answer to this is simply follow the crowd, and hope they'll eventually figure out what works. Even if it ends up as badly as the idea of replacing animal fats with partially hydrogenated vegetable oils and simple sugars (yes, these were the original "healthy foods") - someone will come with a pretty good drugs for diabetes by the time you need them. Maybe we'll even stem-cell diabetes away entirely?&lt;br /&gt;&lt;br /&gt;The pessimistic answer is to just copy the Japanese.&lt;br /&gt;&lt;blockquote style="font-size: 150%; font-style: italic;"&gt;Enjoy your whale sushi.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-5602457296338758133?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/5602457296338758133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=5602457296338758133' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/5602457296338758133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/5602457296338758133'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/05/brief-history-of-human-diet.html' title='Brief history of human diet'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_IYGc_MWwkfw/S-Lr20qLFCI/AAAAAAAAA68/lsgAYqsvGGU/s72-c/sushi_the_cat_joins_us_for_dinner_3_by_torley_from_flickr_cc-sa.jpg' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-3276711013103512058</id><published>2010-05-06T12:29:00.000+02:00</published><updated>2010-05-06T12:29:06.046+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dating'/><title type='text'>The unified theory of online dating and porn</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/S-KYe68drhI/AAAAAAAAA6s/h-4XQ7nFmbA/s1600/playing_with_flowers_by_dr_hemmert_from_flickr_cc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Playing with flowers by Dr. Hemmert from flickr (CC-ND)"&gt;&lt;img alt="Playing with flowers by Dr. Hemmert from flickr (CC-ND)" border="0" height="428" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/S-KYe68drhI/AAAAAAAAA6s/h-4XQ7nFmbA/s640/playing_with_flowers_by_dr_hemmert_from_flickr_cc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Most information in this post is based on absolutely no citable sources - it's either private original research or outright ass-pull, and I won't even tell you which is which to protect anonymity of certain sources. &lt;a href="http://xkcd.com/285/"&gt;Wikipedia protesting is futile&lt;/a&gt;. Now the subject of the post is:&lt;br /&gt;&lt;blockquote style="font-size: 150%;"&gt;There is huge gender asymmetry in online dating behaviour&lt;/blockquote&gt;&lt;br /&gt;In case you haven't tried online dating, and/or haven't set up large number of research honey pots it looks like this:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Everyone writes profiles with basic data, a few pictures, and a few fairly generic paragraphs about themselves.&lt;/li&gt;&lt;li&gt;Men message every woman with whom they see even a remote possibility of attraction developing - which is to say every woman with average-or-better picture (this implies that &lt;a href="http://apps.facebook.com/typing-maniac/"&gt;men who type faster get laid more&lt;/a&gt; - as if there weren't enough reasons to learn to type fast already). Unless there's something immediately disqualifying in profile like text-speak, in which case even pretty pictures won't help.&lt;/li&gt;&lt;li&gt;Women get swamped by these messages. They are invariably rather generic like they profiles, and few get a reply. Fortunately the criteria seems to include proper spelling, for another easy win.&lt;/li&gt;&lt;li&gt;Out of this maybe some conversation develops, and maybe some actual dating happens.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;So what causes this asymmetry in messaging behaviour? First, we can reject a few ideas outright:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;While this looks like a self-reinforcing equilibrium (men who don't spam don't get any replies, women don't have any reason to spam if they're getting spammed anyway) - this is not one of two possible self-reinforcing equilibria - the same  result is reported on almost all dating sites.&lt;/li&gt;&lt;li&gt;Alexa insists that ratio of men to women on most dating sites in quite close to 50:50, and so do all dating sites. So it's not one gender being more numerous.&lt;/li&gt;&lt;li&gt;&lt;a href="http://t-a-w.blogspot.com/2010/04/dating-potential-pagerank.html"&gt;Another obvious theory would different age-dependent attractiveness curves for men and women&lt;/a&gt; - nearly every man, regardless of age, is attracted to 18-24 year old girls. This theory is easy to test, as attractiveness curves cross, and old women are far less attractive than old men - so the theory predicts that for 40+ demographics women would spam men with generic messages. My honeypots strongly disagree with this. And neither there is much spam by women with inherently low chances like those with children, no Photoshop skills, or bad spelling.&lt;/li&gt;&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S-KYzmxjE2I/AAAAAAAAA60/BXB3OexTIz4/s1600/yesit_wasnt_me_by_ariffjrs_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="yes...it wasnt me by ariffjrs from flickr (CC-NC-SA)"&gt;&lt;img alt="yes...it wasnt me by ariffjrs from flickr (CC-NC-SA)" border="0" height="480" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S-KYzmxjE2I/AAAAAAAAA60/BXB3OexTIz4/s640/yesit_wasnt_me_by_ariffjrs_from_flickr_cc-nc-sa.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;No, this is something gender-specific, and independent of attractiveness. Now the last wrong theory is that men simply care more and women are not that much into all the relationships and/or sex thing. And this would be completely wrong - just look at evidence of what kind of sex/relationship fiction men and women consume, and how much.&lt;br /&gt;&lt;br /&gt;Men mostly consume visual pornography. Videos and photos of attractive women, some of it is outright "porn" of them having sex, but very large proportion of such material is simply attractive women posing, often mostly or even completely clothed. In other words - a suggestive picture (or even a myspace shot) of a non-nude woman fits very well within male porn consumption patterns.&lt;br /&gt;&lt;br /&gt;And what kind of porn women consume? Yes, some of them watch "porn" porn, there's even a tiny category of porn specifically made for women - but this is a tiny niche. Most women &lt;b&gt;read&lt;/b&gt; their porn. &lt;a href="http://en.wikipedia.org/wiki/Romance_novel"&gt;Romance novels&lt;/a&gt;, Twilight, slash fanfiction - these are all mainstream women's pornography.&lt;br /&gt;&lt;br /&gt;And here we hit a major problem - because while content of women's dating profiles has what men need to feel a tiny initial spark of attraction - suggestive pictures - contents of men's profiles have nothing. It's almost as if it was exclusively men who designed dating sites, and these were the men with least clue on what women wanted (geek jokes go!).&lt;br /&gt;&lt;br /&gt;I don't know how to turn this insight into dating site design advice - it is much easier to teach people how to make myspace shots than to teach them to write decent slash. And even if everyone was a good writer, it takes minutes to read through large blocks of text as opposed to seconds to look at a few pictures and decide, so it might not work within typical dating site flow.&lt;br /&gt;&lt;br /&gt;So perhaps this theory is useless. Or perhaps whoever figures out how to exploit it makes the new Facebook.&lt;br /&gt;&lt;br /&gt;And here's some misandrous, misogynist, and generally spiteful advice:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Men - learn to type. If you cannot fix the spam problem, you can at least outspam others. Have some quality copypasta ready. If you can program, &lt;a href="http://t-a-w.blogspot.com/2009/03/use-greasemonkey-to-vote-for-hotter.html"&gt;Greasemonkey&lt;/a&gt; away better dating flow. Outright spambots might be too easily detected, but feel free to take the risk.&lt;/li&gt;&lt;li&gt;Women - learn to Photoshop, and Photoshop your pictures mercilessly. It really doesn't matter that you won't look anything like your picture. Also keep your profile brief and generic - if pictures are good profile serve mostly negative selection function. Feel free to lie outright.&lt;/li&gt;&lt;li&gt;Everyone - all browsers have built-in spell-checker, use it.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-3276711013103512058?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/3276711013103512058/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=3276711013103512058' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/3276711013103512058'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/3276711013103512058'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/05/unified-theory-of-online-dating-and.html' title='The unified theory of online dating and porn'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_IYGc_MWwkfw/S-KYe68drhI/AAAAAAAAA6s/h-4XQ7nFmbA/s72-c/playing_with_flowers_by_dr_hemmert_from_flickr_cc-nd.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-524473000398036932</id><published>2010-05-04T17:05:00.000+02:00</published><updated>2010-05-04T17:05:31.221+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='greece'/><category scheme='http://www.blogger.com/atom/ns#' term='military'/><category scheme='http://www.blogger.com/atom/ns#' term='politics'/><title type='text'>The real cost of oversized military</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S-A3fbxnCiI/AAAAAAAAA6k/D9pjkzVfJWM/s1600/baby_buddha_by_jurvetson_from_flickr_cc-by.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Baby Buddha by jurvetson from flickr (CC-BY)"&gt;&lt;img alt="Baby Buddha by jurvetson from flickr (CC-BY)" border="0" height="640" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S-A3fbxnCiI/AAAAAAAAA6k/D9pjkzVfJWM/s640/baby_buddha_by_jurvetson_from_flickr_cc-by.jpg" width="622" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;In &lt;a href="http://t-a-w.blogspot.com/2010/03/real-reason-behind-greek-economic.html"&gt;one of my previous posts&lt;/a&gt; I pointed to the elephant in the room - Greek economic problems are largely due to its oversized military - this confused people a lot.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Let's do some calculation, pulling all assumptions out of Google. These numbers are actually very noisy year to year, but let's just take some long term average.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Annual economic per capita growth 2.1% - &lt;a href="http://en.wikipedia.org/wiki/World_economy"&gt;this is world average since 1950&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Annual population growth - 0% - most developed countries we speak about here have little in terms of population growth&lt;/li&gt;&lt;li&gt;Annual economic growth - 2.1% (by two above) - this number might seem low, but that's the facts, and there's not much we can do about it&lt;/li&gt;&lt;li&gt;Starting debt level - 50% GDP - fairly typical for a developed country&lt;/li&gt;&lt;li&gt;Interest on debt is 3% above inflation. This I base on &lt;a href="http://www.treasurydirect.gov/indiv/research/indepth/ibonds/res_ibonds_iratesandterms.htm"&gt;historical rates of series I federal bonds before the recession&lt;/a&gt;, and adjust it a bit because most countries are less safe than States, so would need to pay somewhat more.&lt;/li&gt;&lt;li&gt;Baseline size of military is 1.7% GDP - EU average &lt;/li&gt;&lt;li&gt;Budget has 1% surplus before paying interest.&lt;/li&gt;&lt;li&gt;This results is interest payment of 3% (interest on debt) * 50% (debt to GDP) = 1.5% GDP.&lt;/li&gt;&lt;li&gt;This leads to deficit of 0.5% GDP.&lt;/li&gt;&lt;li&gt;Because economy keeps growing - 0.505 / 1.021 = 0.4946 - so debt level will very slowly fall as percentage of GDP even as total debt keeps rising.&lt;/li&gt;&lt;li&gt;Over 50 years, debt will fall to just 16.3%&lt;/li&gt;&lt;/ul&gt;This is all very reasonable. Now let's assume this country decided to have Greek style ridiculously oversized military - 4.3% of GDP. This is extra 2.6% spending. What happens in 50 years? Their debt grows to&amp;nbsp; 175.5%.&lt;br /&gt;&lt;br /&gt;Assuming anybody was still stupid enough to lend them money at the same rates, oversized military costs them 2.6% GDP (original spending) + 4.78% due to excess interest relative to baseline scenario. Imperialism costs far more than it seems to - and it has been a very long time since anyone made big money on empire building - usually the only benefactors are bankers and arm manufacturers in countries not engaged in hostilities.&lt;br /&gt;&lt;br /&gt;A few inb4s:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;This reasoning applies only to excess military spending.&lt;/li&gt;&lt;li&gt;Normal civilian government spending is typically useful, and if government slashed spending on healthcare, education, pensions, disability insurance etc., people would simply buy more or less as much of such services on private market.&lt;/li&gt;&lt;li&gt;Even worse - if government slashed spending on research, basic infrastructure and so on, where benefits are diffuse, it would be very likely that nobody would pick up the tab, and it would hurt the economy significantly.&lt;/li&gt;&lt;li&gt;Yes, there is some outright waste in civilian government spending, but &lt;a href="http://www.youtube.com/watch?v=3oGFogwcx-E"&gt;similar waste exists in private sector as well&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Baseline scenario already includes EU average military spending - and even if you argue that optimal level of military spending is higher than 0% (something I won't be arguing one way or the other now) - I cannot imagine in what kind of bizarro world EU average is far below the point of rapidly diminishing returns.&lt;/li&gt;&lt;/ul&gt;I'm not done yet. Let's assume interest rates are not constant, but vary depending on country's prospects. So at 0% debt you only need to pay 1%, then it grows linearly to 3% at 50% (like in scenario), and so on. There is some evidence this growth might be ever faster than linear, but let's stick to that.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;In 50 years of baseline scenario debt diminishes to 6.35% and nobody cares any more.&lt;/li&gt;&lt;li&gt;In imperialistic scenario, debt after 10 years is only 73.43% (as opposed to 70.89% with constant interest rates) - it doesn't make a big difference yet.&lt;/li&gt;&lt;li&gt;In 20 years debt reaches 110.62% as opposed to 93.7% - it start to get ugly.&lt;/li&gt;&lt;li&gt;In 30 years debt increases to 189.96%, as opposed to 118.61%, but the glorious Greek empire keeps borowing.&lt;/li&gt;&lt;li&gt;In 40 years debt reaches 531.73%, as opposed to 145.79%, and the interest rates are completely ridiculous over 22% per year.&lt;/li&gt;&lt;li&gt;When the imperial scenario ends in 50 years, debt stands at 738747192.9% GDP, interest rates are almost 5% a day, and everybody is looking for the new suckers into this Ponzi scheme.&lt;/li&gt;&lt;/ul&gt;Of course Greece had to either collapse or change its ways long before that happened.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-524473000398036932?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/524473000398036932/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=524473000398036932' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/524473000398036932'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/524473000398036932'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/05/real-cost-of-oversized-military.html' title='The real cost of oversized military'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_IYGc_MWwkfw/S-A3fbxnCiI/AAAAAAAAA6k/D9pjkzVfJWM/s72-c/baby_buddha_by_jurvetson_from_flickr_cc-by.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-1097101489520538638</id><published>2010-05-03T11:55:00.000+02:00</published><updated>2010-05-03T11:55:47.834+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='politics'/><category scheme='http://www.blogger.com/atom/ns#' term='democracy'/><title type='text'>Want democracy? Get a figurehead king</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S96cPrSPwpI/AAAAAAAAA6U/sUPSYmGbEx4/s1600/fuzzy_queen_of_couchland_by_nibby_nebbulous_from_flickr_cc-by.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Fuzzy Queen of Couchland by Nibby Nebbulous from flickr (CC-BY)"&gt;&lt;img alt="Fuzzy Queen of Couchland by Nibby Nebbulous from flickr (CC-BY)" border="0" height="480" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S96cPrSPwpI/AAAAAAAAA6U/sUPSYmGbEx4/s640/fuzzy_queen_of_couchland_by_nibby_nebbulous_from_flickr_cc-by.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Followup to: &lt;i&gt;&lt;a href="http://t-a-w.blogspot.com/2010/04/how-much-democracy-in-your-democracy.html"&gt;How much democracy in your democracy?&lt;/a&gt;&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;I find the very concept of monarchy obscene - its premise is that some woman has a magical vagina, and whatever first comes out of said vagina is blessed with magic powers that somehow make it most well suited to rule a country. Alternatively, some man has a magical penis - but monarchies are older than  DNA testing so while the theory often emphasized penises, the practice was mostly vaginal.&lt;br /&gt;&lt;br /&gt;In either case, this is just so ridiculous, I cannot imagine how fucked up must someone brain be before they start treating it seriously, and yet they did! Some still do. But as &lt;a href="http://en.wikiquote.org/wiki/Karl_Marx"&gt;Karl Marx said, &lt;i&gt;being determines consciousness&lt;/i&gt;&lt;/a&gt; - and nobody ever came up with an idea so ridiculous, that some privileged people couldn't use it as an excuse for existence of their privileges. Cosmic Jewish Zombie? Magical Vaginas? Social Darwinism? Efficient Market Hypothesis? Anything goes, as long as it implies the privileged stay privileged of course.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Anyway, in spite of my repulsion with the concept of monarchy, I decided to run some data analysis on effects different systems of governments have on levels of freedom and democracy.&lt;br /&gt;&lt;br /&gt;Data comes from Wikipedia - &lt;a href="http://en.wikipedia.org/wiki/List_of_countries_by_system_of_government"&gt;government systems&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Democracy_Index"&gt;Democracy Index&lt;/a&gt; (by The Economist), and &lt;a href="http://en.wikipedia.org/wiki/Freedom_in_the_World_%28report%29"&gt;Freedom in the World Index (Freedom House, essentially CIA)&lt;/a&gt;.&lt;br /&gt;&lt;h3&gt;Monarchies are more free than republics&lt;/h3&gt;It doesn't take a sophisticated statistical analysis to see that monarchies are more free than republics. Here's Democracy Index, &lt;b&gt;higher is better&lt;/b&gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;All countries: 5.6 +- 2.22 [n=163]&lt;/li&gt;&lt;li&gt;Monarchies: 6.37 +- 2.63 [n=28]&lt;/li&gt;&lt;li&gt;Republics: 5.44 +- 2.08 [n=135]&lt;/li&gt;&lt;/ul&gt;That's over 1/3 of standard deviation - about as much as the difference between Canada and USA - decent different, but maybe not worth writing a blog post about yet.&lt;br /&gt;&lt;br /&gt;Just to verify, let's check Freedom in the World Civil Liberties and Political Right indexes (for both &lt;b&gt;lower is better&lt;/b&gt;). Here's Civil Liberties:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;All countries: 3.19 +- 1.81 [n=192]&lt;/li&gt;&lt;li&gt;Monarchies: 2.56 +- 1.7 [n=43]&lt;/li&gt;&lt;li&gt;Republics: 3.38 +- 1.8 [n=149]&lt;/li&gt;&lt;/ul&gt;And Political Rights:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;All countries: 3.35 +- 2.13 [n=192]&lt;/li&gt;&lt;li&gt;Monarchies: 2.88 +- 2.15 [n=43]&lt;/li&gt;&lt;li&gt;Republics: 3.49 +- 2.1 [n=149]&lt;/li&gt;&lt;/ul&gt;So CIA and The Economist agree - that's again about 1/3 of standard deviation. Magical vaginas are not that bad.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S96cWUZZrvI/AAAAAAAAA6c/w5X-EI-z4Hg/s1600/img_5513_by_dave_malkoff_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="IMG_5513 by Dave Malkoff from flickr (CC-NC-SA)"&gt;&lt;img alt="IMG_5513 by Dave Malkoff from flickr (CC-NC-SA)" border="0" height="640" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S96cWUZZrvI/AAAAAAAAA6c/w5X-EI-z4Hg/s640/img_5513_by_dave_malkoff_from_flickr_cc-nc-sa.jpg" width="540" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;It gets better&lt;/h3&gt;The results so far were not terribly interesting, so I tried something else - how important is having ceremonial head of state versus one with actual executive power? It's rather shocking (higher better):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Ceremonial: 7.47 +- 1.42 [n=54]&lt;/li&gt;&lt;li&gt;Executive: 4.67 +- 1.93 [n=109]&lt;/li&gt;&lt;/ul&gt;Civil Liberties (lower better):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Ceremonial: 2.01 +- 1.28 [n=70]&lt;/li&gt;&lt;li&gt;Executive: 3.87 +- 1.72 [n=122]&lt;/li&gt;&lt;/ul&gt;Political Rights (lower better):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Ceremonial: 1.96 +- 1.37 [n=70]&lt;/li&gt;&lt;li&gt;Executive: 4.16 +- 2.07 [n=122]&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;That's 1.25 σ for democracy, and a bit over 1 σ for the other two indices!&lt;br /&gt;&amp;nbsp; &lt;br /&gt;Combining two criteria gets expected results - figurehead kings &amp;gt; figurehead presidents &amp;gt; executive presidents &amp;gt; executive kings. Democracy Index (higher better):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Ceremonial Monarchies: 8.12 +- 1.41 [n=18]&lt;/li&gt;&lt;li&gt;Ceremonial Republics: 7.15 +- 1.32 [n=36]&lt;/li&gt;&lt;li&gt;Executive Republics: 4.82 +- 1.96 [n=99]&lt;/li&gt;&lt;li&gt;Executive Monarchies: 3.23 +- 0.67 [n=10]&lt;/li&gt;&lt;/ul&gt;Civil Liberties (lower better):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Ceremonial Monarchies: 1.76 +- 1.13 [n=29]&lt;/li&gt;&lt;li&gt;Ceremonial Republics: 2.2 +- 1.35 [n=41]&lt;/li&gt;&lt;li&gt;Executive Republics: 3.82 +- 1.75 [n=108]&lt;/li&gt;&lt;li&gt;Executive Monarchies: 4.21 +- 1.47 [n=14]&lt;/li&gt;&lt;/ul&gt;Political Rights (lower better):&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Ceremonial Monarchies: 1.83 +- 1.42 [n=29]&lt;/li&gt;&lt;li&gt;Ceremonial Republics: 2.05 +- 1.32 [n=41]&lt;/li&gt;&lt;li&gt;Executive Republics: 4.04 +- 2.09 [n=108]&lt;/li&gt;&lt;li&gt;Executive Monarchies: 5.07 +- 1.71 [n=14]&lt;/li&gt;&lt;/ul&gt;So turning a king into a figurehead gets you 2.25 σ improvement (or 1.5 on CIA's indices), and even switching from American style executive president to German style figurehead president + prime minister / chancellor with real power scores you a free 1 σ or so.&lt;br /&gt;&lt;h3&gt;Correlation and Causation&lt;/h3&gt;&lt;br /&gt;What does it mean? If correlation equaled causation then replacement of Prime Minister Gordon Brown with President Gordon Brown would turn UK into Russia or Pakistan, on average. Now we all know that correlation doesn't equal causation, but do you really want to risk that? So how about not fixing what's not broken, and fix what is broken - first past the post election system - first?&lt;br /&gt;&lt;br /&gt;Cats would work as such kings and queens just fine - data clearly shows that the head of state should be a figurehead, so why not a cat? Is Cat King much sillier than Magical Vaginas, really? And even if it is, &lt;a href="http://www.overcomingbias.com/2008/04/arbitrary-silli.html"&gt;silliness  is no excuse not to do science&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;If someone thinks this post is a serious argument for monarchy, they might be interested in &lt;a href="http://t-a-w.blogspot.com/2010/04/boobquake-experiment-is-bad-science.html"&gt;this kind of science&lt;/a&gt; too, just saying...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-1097101489520538638?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/1097101489520538638/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=1097101489520538638' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1097101489520538638'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1097101489520538638'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/05/want-democracy-get-figurehead-king.html' title='Want democracy? Get a figurehead king'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_IYGc_MWwkfw/S96cPrSPwpI/AAAAAAAAA6U/sUPSYmGbEx4/s72-c/fuzzy_queen_of_couchland_by_nibby_nebbulous_from_flickr_cc-by.jpg' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-9042030388613922659</id><published>2010-04-28T04:00:00.000+02:00</published><updated>2010-04-28T04:00:08.014+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='religion'/><category scheme='http://www.blogger.com/atom/ns#' term='science'/><title type='text'>Boobquake experiment is bad science</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S9eWB0RaSFI/AAAAAAAAA6Q/XeIEXaT3viE/s1600/mimi_catblue_dynamite_by_evilfenn_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Mimi Catblue Dynamite by evilfenn from flickr (CC-NC-SA)"&gt;&lt;img alt="Mimi Catblue Dynamite by evilfenn from flickr (CC-NC-SA)" border="0" height="320" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S9eWB0RaSFI/AAAAAAAAA6Q/XeIEXaT3viE/s320/mimi_catblue_dynamite_by_evilfenn_from_flickr_cc-nc-sa.jpg" width="240" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;small&gt;&lt;i&gt;In spite of my best attempts I couldn't find any relevant cats, so as a next best thing I included some catgirls possibly participating in the Boobquake experiment&lt;/i&gt;&lt;/small&gt;&lt;/center&gt; &lt;br /&gt;&lt;br /&gt;I'm as appalled by low standards of modern science as cleris Hojatoleslam Kazem Sedighi is about skimpy female outfits. And yesterday, we both had a chance to be outraged at the same thing - boobquake experiment makes travesty of science!&lt;br /&gt;&lt;h3&gt;Background&lt;/h3&gt;The conflict comes from a long accepted paradigm of natural disasters, which explained them as God's punishment for human sins. Research supporting this theory goes as far back as the famous &lt;a href="http://www.biblegateway.com/passage/?search=Gen%2019&amp;amp;version=ESV"&gt;Lot's experiment [Gen 19]&lt;/a&gt;, and countless other papers of similar antiquity. It has been very widely believed until even as recently as mid-18th century, when it was the most commonly believed explanation for the &lt;a href="http://en.wikipedia.org/wiki/1755_Lisbon_earthquake"&gt;1755 Lisbon earthquake&lt;/a&gt; - according to sources of the time supposedly due to slutiness of Portuguese women, and other human sins.&lt;br /&gt;&lt;br /&gt;This paradigm has been largely replaced by current naturalistic paradigm which claims such events are mostly "random" and have no particular reason - replacement motivated more by wish to remove God from the picture than by any hard scientific data, and by crude analogy with cases like creationism vs evolution in which similar removal of God was actually supported by large volume of evidence.&lt;br /&gt;&lt;br /&gt;So it should be no surprise that if even a well researched case of evolution still has many doubters, it should be even more true for less researched case of causes of earthquakes and other natural disasters, where the main argument is compatibility with Western secularism.&lt;br /&gt;&lt;br /&gt;Given all this, we should be grateful that someone finally tried running an experiment to check the sin theory of natural disasters. Unfortunately the experiment was so far from standards of good science as to render it totally unconvincing.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;What went wrong with Boobquake experiment&lt;/h3&gt;The boobquake experiment was an attempt to test the sin theory of natural disasters by having a large number of women wear sluttier outfits than usual, make God angry, and cause increased number of earthquakes.&lt;br /&gt;&lt;br /&gt;Before even looking at its scientific value we should notice that such experiment grossly violates modern ethical standards by risking lives of countless people who didn't volunteer for it. In the future it would be prudent to at least limit such experiments to a singre geographic location, where all sinners would group before commencing the sinning - and which non-sinners would be able to evacuate in advance.&lt;br /&gt;&lt;br /&gt;Now, for the experiment. No attempt was made to establish baseline sin level, or even baseline outfit skimpiness level - and unfortunately we have no way of knowing how large was the change due to boobquake relative to the daily fluctuation of sin. Even the most basic estimates suggest the effect to be minor - supposedly about 200,000 women tried to wear sluttier than normally on that day - such number is far below changes in a single country known for sinning like Sweden due to daily weather variations. Experiment also takes place in the aftermath of Eyjafjallajökull eruption (believed by some to be caused by the deadly sin of greed of Icelanders) - which caused major disruption of tourism, and it is universally accepted that people sin a lot more during holidays.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Moreover, this sample was not random. Experiment participants have been self-selected, and we have reasons to believe that people particularly unconcerned with God's wrath, and therefore with higher than baseline sinfulness level - probably constituted vast majority.&lt;br /&gt;&lt;br /&gt;While data on most participant is missing, comparison between be the supposedly "most scandalous" outfit of the main researcher she wore during the experiment with her profile photo causes serious doubts, as they're about equally revealing.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S9eTqq3DWlI/AAAAAAAAA6A/XZrIc6Jq1pE/s1600/boobquake-300x225.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S9eTqq3DWlI/AAAAAAAAA6A/XZrIc6Jq1pE/s1600/boobquake-300x225.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/S9eTvejNrNI/AAAAAAAAA6E/429pT-YbS24/s1600/JenSurly.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/S9eTvejNrNI/AAAAAAAAA6E/429pT-YbS24/s1600/JenSurly.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;In addition to lack of statistical soundness, and sample randomness, no attempt was made to blind the experiment. This difficulty is inherent, as God's omniscience makes proper double-blinding impossible, but participants knew well in advance that they're assigned to treatment group, so they may have consciously or subconsciously reduced their other kinds of sinning, a blatant violation of basic rules of scientific testing that would pass no peer review. What's worse, no attempt was even made to establish a control group!&lt;br /&gt;&lt;br /&gt;Now it could be argued that blinding participants would be difficult - or that sinning requires conscious action, so both treatment and control groups would be equally in state of sin by even risking wearing revealing clothing - but this difficulty is present in many experiments, and at least serious attempt should be made to reduce placebo effect when it cannot be fully eliminated. Numerous examples of women wearing clothing far more revealing that they thought easily found on the Web suggest this kind of blinding is not fully impossible.&lt;br /&gt;&lt;br /&gt;Not only experiment was of dubious quality, the hypothesis tested is far from the standard theory of sin causing natural disasters. Now the theory has many variations but even the basic Sodom and Gommorah version clearly disagrees with research assumptions:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Assumption was made of no delay between sin and punishment, while the theory says punishment only comes after sinning.&lt;/li&gt;&lt;li&gt;Assumption was made of near-linearity between sin and punishment, while the theory says God was willing to spare Sodom and Gomorrah if even as few as ten righteous people were found.&lt;/li&gt;&lt;/ul&gt;Given all these problems, the Boobquake experiment brings essentially no new knowledge to the discipline of causes of natural disasters, and we can only hope that future experiments are better planned, with better design, better experimental controls, and detailed publicly available photographic documentation of sinning.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/S9eVF2jnfgI/AAAAAAAAA6I/Js3AjgJxMB8/s1600/catgirls_cascadiacon_seattle_wa_by_djwudi_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Catgirls, CascadiaCon, Seattle, WA by djwudi from flickr (CC-NC-SA)"&gt;&lt;img alt="Catgirls, CascadiaCon, Seattle, WA by djwudi from flickr (CC-NC-SA)" border="0" height="320" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/S9eVF2jnfgI/AAAAAAAAA6I/Js3AjgJxMB8/s320/catgirls_cascadiacon_seattle_wa_by_djwudi_from_flickr_cc-nc-sa.jpg" width="240" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;small&gt;&lt;i&gt;With baseline like this, it is dubious Boobquake really changes average sinning level much&lt;/i&gt;&lt;/small&gt;&lt;/center&gt;&lt;br /&gt;&lt;h3&gt;Related research&lt;/h3&gt;&lt;br /&gt;While Boobquake is clearly bad science, a much more relevant research was done by IPCC reports, which claim that we can expect &lt;a href="http://en.wikipedia.org/wiki/Physical_impacts_of_climate_change"&gt;high correlation between global warming and extreme weather effects&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This strongly confirms sin theory of natural disasters, as warmer weather causes many women to wear more revealing outfits, the results being among others "increased droughts, tropical cyclone activity, and tsunamis" (but curiously no mention of earthquakes).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now correlation doesn't equal causation, and IPCC research doesn't directly test the sin theory, but it arguably provides stronger evidence than Boobquake experiment.&lt;br /&gt;&lt;br /&gt;In the future, one would hope solid systematic research is done on variations of female outfit skimpiness - an area that has long been ignored by mainstream science.&lt;br /&gt;&lt;i&gt;&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-9042030388613922659?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/9042030388613922659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=9042030388613922659' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/9042030388613922659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/9042030388613922659'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/04/boobquake-experiment-is-bad-science.html' title='Boobquake experiment is bad science'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_IYGc_MWwkfw/S9eWB0RaSFI/AAAAAAAAA6Q/XeIEXaT3viE/s72-c/mimi_catblue_dynamite_by_evilfenn_from_flickr_cc-nc-sa.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-4075573130230972211</id><published>2010-04-27T11:03:00.000+02:00</published><updated>2010-04-27T11:03:49.262+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gtd'/><title type='text'>Weekly review checklist</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S9aoKYP5EqI/AAAAAAAAA54/ksgh92Kr3zA/s1600/bohu__tohu__3_months_old_by_gattoulucie_from_flickr_cc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Bohu &amp;amp; Tohu  (3 months old) by Gattou/Lucie from flickr (CC-SA)"&gt;&lt;img alt="Bohu &amp;amp; Tohu  (3 months old) by Gattou/Lucie from flickr (CC-SA)" border="0" height="486" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S9aoKYP5EqI/AAAAAAAAA54/ksgh92Kr3zA/s640/bohu__tohu__3_months_old_by_gattoulucie_from_flickr_cc-sa.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Here's a quick list of steps to get my GTD system up to date. It differs somewhat from vanilla GTD, but so does everyone else's.&lt;br /&gt;&lt;br /&gt;Preprocessing:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Go to mailbox, read all unread mails.&lt;/li&gt;&lt;li&gt;Go to mailbox, preprocess all blue-starred items. I use two kinds of stars: blue star means it's inbox item, yellow star is just to find an email quickly, and all activity related to it is tracked.&lt;/li&gt;&lt;li&gt;Preprocess every single item in paper inbox.&lt;/li&gt;&lt;li&gt;Go to both software repository (private and work), and commit or trash  everything. If it cannot be completed right away it deserves an inbox  item.&amp;nbsp; &lt;/li&gt;&lt;li&gt;Preprocess every single item in inbox directory. On Linux I used ~/inbox, on OSX I normall just put stuff on desktop (and omg, I get my desktop to totally clean and empty regularly, I really do)&lt;/li&gt;&lt;li&gt;As result of this preprocessing everything is in the GTD system - currectly OmniFocus, but most is still crap.&lt;/li&gt;&lt;li&gt;A bit more preprocessing - quickly scan everything and mark completed items as done, do less-than-2-minute actions (the only reason such actions are even on the list is because they have been blocked before), mark completed waiting-fors as such - each such completion might trigger addition of extra stuff to inbox. The reason I do this is to save some sanity.&lt;/li&gt;&lt;li&gt;Now the big decision - look at my projects and other lists and decide if they are reasonably clean or a hopeless mess. If they're reasonably clean, leave them for now. If they're a total mess, move absolutely everything to inbox.&lt;/li&gt;&lt;/ul&gt;Processing - every item in inbox is processed. As everything is in one place and obvious trash, loudest items etc. has been mostly dealt with, there shouldn't be that many distractions - but they do happen.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;What the fuck is it about?&lt;/li&gt;&lt;li&gt;Is it already done? If so, mark as completed.&lt;/li&gt;&lt;li&gt;Do I still even care? If not, delete.&lt;/li&gt;&lt;li&gt;Is it waiting for? Tag as @Waiting and move to appropriate project.&lt;/li&gt;&lt;li&gt;Should I push it to someone else? Write email right away and @Waiting &lt;/li&gt;&lt;li&gt;Is it a shopping item? @Shopping and move to appropriate project or generic "Area of Focus : Shopping" list. There are no specific subcontexts for shopping - I buy everything online including groceries - 90% of my shopping is Tesco online + Amazon online - and the main challenge is minimizing number of separate deliveries to reduce cost and annoyance. If I'm out for some reason anyway, I'll take a look at the list to see if there's anything I can buy on my way.&lt;/li&gt;&lt;li&gt;Is it calendar item? Move to calendar. I have very few of those so I'm using OmniFocus for calendar - it won't work well for most people.&lt;/li&gt;&lt;li&gt;Is it a random URL I might want to read someday? Move to "Someday/Maybe : Reading" list.&lt;/li&gt;&lt;li&gt;Is it a random idea I might want to follow through someday but not now? Move to appropriate sublist of Someday/Maybe.&lt;/li&gt;&lt;li&gt;Is it a well-defined action already? Is it simple enough to get it done in a few minutes? If so, do it (that might trigger another inbox item).&lt;/li&gt;&lt;li&gt;Is it a well-defined action that will take longer or I cannot do it right now because of wrong context? Move to appropriate project.&lt;/li&gt;&lt;li&gt;So it's something complex...&lt;/li&gt;&lt;li&gt;What am I trying to see accomplished anyway? If I'm very unclear about it, I might convert it to a new project + some @Mindmap / @Research actions.&lt;/li&gt;&lt;li&gt;If I'm clear about outcomes, do I want to move forward with it? If not, clarify description and move to one of the sublists of Someday/Maybe.&lt;/li&gt;&lt;li&gt;Am I clear about the next action? If so, turn this into a project, and put such action there.&lt;/li&gt;&lt;li&gt;If I'm not clear about next action, turn it into a project + some @Mindmap / @Research actions.&lt;/li&gt;&lt;/ul&gt;At this point inbox should be empty.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Go through project lists, make sure all projects have adequate actions. Some projects might already be completed, in which case mark them as complete.&lt;/li&gt;&lt;li&gt;Quickly go through contexts lists and make sure everything is sensibly contexted. Current list of contexts is: @Blocked @Calendar @Computer @Home @Linux @Mindmap @Outside @Research @Shopping @Waiting @Windows - but I change it if I need to.&lt;/li&gt;&lt;li&gt;Take a quick look at Someday/Maybe if there's anything I want to move forward soon. Usually there isn't, or at least not much. &lt;/li&gt;&lt;/ul&gt;After all this is done, I should be able to stay sane for a few more days.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-4075573130230972211?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/4075573130230972211/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=4075573130230972211' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/4075573130230972211'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/4075573130230972211'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/04/weekly-review-checklist.html' title='Weekly review checklist'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_IYGc_MWwkfw/S9aoKYP5EqI/AAAAAAAAA54/ksgh92Kr3zA/s72-c/bohu__tohu__3_months_old_by_gattoulucie_from_flickr_cc-sa.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-7292370125690744506</id><published>2010-04-26T03:24:00.001+02:00</published><updated>2010-04-26T03:32:20.819+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='korea'/><category scheme='http://www.blogger.com/atom/ns#' term='war'/><category scheme='http://www.blogger.com/atom/ns#' term='politics'/><title type='text'>What should South Korea do now?</title><content type='html'>Nothing. Now the highly relevant Starcraft playing cat and kthxbye.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S9TB0n65gyI/AAAAAAAAA5I/2uyyJRFaNCg/s1600/img_0093_by_unstoppabledrew_from_flickr_cc-nc.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="IMG_0093 by UnstoppableDrew from flickr (CC-NC) "&gt;&lt;img alt="IMG_0093 by UnstoppableDrew from flickr (CC-NC) " border="0" height="480" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S9TB0n65gyI/AAAAAAAAA5I/2uyyJRFaNCg/s640/img_0093_by_unstoppabledrew_from_flickr_cc-nc.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;OK, you might be wondering why I think anyone would want to do nothing when another country sinks your ships and otherwise behaves provocatively for decades.&lt;br /&gt;&lt;br /&gt;The first part of the answer is economy - &lt;a href="http://en.wikipedia.org/wiki/List_of_countries_by_GDP_%28PPP%29"&gt;entire economy of North Korea is worth PPP $40billion&lt;/a&gt;. That's about as much as Alaska or Luxembourg.&lt;br /&gt;&lt;br /&gt;Other countries which might take part in conflict - some on South Korean side, some neutral, none on North Korean - are worth:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;South Korea - 34x as much&lt;/li&gt;&lt;li&gt;Russia - 54x as much&lt;/li&gt;&lt;li&gt;Japan - 110x as much&lt;/li&gt;&lt;li&gt;China - 200x as much&lt;/li&gt;&lt;li&gt;USA - 350x as much &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;If everyone had similar levels of military spending as part of GDP, North Korea would be one big pile of rubble before I even had my second coffee. Now this isn't true, North Korea is the most militarized country in the world. It's hard to get good estimates, but &lt;a href="http://www.globalsecurity.org/military/world/spending.htm"&gt;according to some figures&lt;/a&gt; ratios of military budgets are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;South Korea - 4x&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Japan - 8x&lt;/li&gt;&lt;li&gt;Russia - 10x&lt;/li&gt;&lt;li&gt;China - 13x&lt;/li&gt;&lt;li&gt;USA - 125x&lt;/li&gt;&lt;/ul&gt;It shows how insane North Korea is by even trying to catch up with its neighbours - some of which are low military spenders like China, and Japan; others are high military spenders like Russia and USA (&lt;a href="http://t-a-w.blogspot.com/2010/03/real-reason-behind-greek-economic.html"&gt;and that "high" is still lower than countries like Greece&lt;/a&gt;), South Korea is surprisingly sane 2.7% considering environment it is in.&lt;br /&gt;&lt;br /&gt;So there's absolutely no way North Korea can hope to actually "win" the war, if it actually started.&lt;br /&gt;&lt;h3&gt;War is bad for economy&lt;/h3&gt;These ratios don't tell the whole story. Not only is North Korea ridiculously poor - it is about as poor as it was in 1953 and not improving at all.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S9TJhxFZ4oI/AAAAAAAAA5Q/zxCYWLOSb2M/s1600/koreas+economy.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="526" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S9TJhxFZ4oI/AAAAAAAAA5Q/zxCYWLOSb2M/s640/koreas+economy.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;South Korean economy is growing rapidly. Chinese economy is growing explosively. Japanese and American economies are growing - maybe not as quickly as those, but they reliably grow. Russian grows and shrinks as commodity prices change, that's a story for another post. And what about North Korea? It was doing fine until 1973 - at which point is was still better than the South - when it hit a wall, and stopped growing for tho decades, and then collapsed hard when the entire Communist world crashed in 1991, getting worse every single year ever since.&lt;br /&gt;&lt;br /&gt;North Koreans are desperate. With each year, their chance of not winning but even putting up a good fight is diminishing.&lt;br /&gt;&lt;br /&gt;This, paradoxically, means that everyone else would really really want to avoid a war. If you're getting richer and richer, while your enemy is getting more and more fucked up - why speed things up? Sure, &lt;a href="http://en.wikipedia.org/wiki/Dick_Cheney"&gt;militaristic dick waving looks good on TV&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/United_States_presidential_election,_2004"&gt;can get you some extra votes&lt;/a&gt; - but if you're anything resembling rational you'd prefer to postpone the conflict - assuming you want one in the first place.&lt;br /&gt;&lt;h3&gt;How empires are built&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;This grow-economy-and-wait approach is how empires get created. Did Brits try to engage in European Continental Wars? They mostly let the Continentals bleed each others, while they kept themselves safe with the Royal Navy, picked only easy fights, and let the stability led to explosive economic growth which eventually led to their global domination.&lt;br /&gt;&lt;br /&gt;That's how American Empire started as well - other than the infamous 1812-1815 war with Canada Americans mostly stayed isolationist, picking up Indians and growing their population and economy - after all other empires bled themselves to death twice USA became the world superpower by default.&lt;br /&gt;&lt;br /&gt;A quick aside - it is commonly incorrectly believed that America has seen significant fighting in two world wars, or like ever. &lt;a href="http://en.wikipedia.org/wiki/World_War_I_casualties"&gt;In the First World war it was rather laughable&lt;/a&gt; - Americans joined when the war was nearing the end, and by the time Americans reached Europe, it was over. Even countries like Bulgaria and Romania had seen far more fighting.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S9TOZFC8H0I/AAAAAAAAA5g/8uwl_wUCuK0/s1600/500px-WorldWarI-MilitaryDeaths-EntentePowers-Piechart.svg.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="350" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S9TOZFC8H0I/AAAAAAAAA5g/8uwl_wUCuK0/s400/500px-WorldWarI-MilitaryDeaths-EntentePowers-Piechart.svg.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/S9TOVnejYQI/AAAAAAAAA5Y/yHX9Jl3LERk/s1600/500px-WorldWarI-MilitaryDeaths-CentralPowers-Piechart.svg.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/S9TOVnejYQI/AAAAAAAAA5Y/yHX9Jl3LERk/s320/500px-WorldWarI-MilitaryDeaths-CentralPowers-Piechart.svg.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;That of course without civilian deaths, Spanish flu deaths, countless wars following WW1, and such. WW1 was essentially Germany+Austria vs France+Russia+Britain.&lt;br /&gt;&lt;br /&gt;WW2 was even simpler - being basically Germany vs Soviet Union, with a second unrelated front of Japan vs China - Americans and for that matter British had very little active role in either.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S9TPst_qBOI/AAAAAAAAA5o/39CmEHR_kvE/s1600/1000px-World_War_II_Casualties.svg.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="640" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S9TPst_qBOI/AAAAAAAAA5o/39CmEHR_kvE/s640/1000px-World_War_II_Casualties.svg.png" width="582" /&gt;&lt;/a&gt;&lt;/div&gt;And the entire Western Front? For German soldiers fighting Soviets getting sent to the Western Front was like getting sent for holidays. The only reason Western Allies even managed to land in Europe was because Nazis were forced to move everyone they could to fight the Ruskis, and there was barely anyone left to defend anything.&lt;br /&gt;&lt;br /&gt;America didn't get its empire by winning wars - it got it by not getting involved in wars too much. &lt;a href="http://en.wikipedia.org/wiki/Lend-Lease"&gt;Lend-Lease&lt;/a&gt; , the &lt;a href="http://en.wikipedia.org/wiki/Marshall_Plan"&gt;Marshall Plan&lt;/a&gt;, and a few successful CIA operations here and there did far more for the empire than the actual military, which is only good at bombing whoever cannot defend themselves.&lt;br /&gt;&lt;br /&gt;And this is precisely what all East Asian powers do. Why even bother spending buckets of money on armies? Japan and China have ridiculously small armies by international standards. Taiwan and South Korea are closer to world average - but considering what kind of danger they're facing close-to-world-average shows incredible levels of restraint. No, they just sit there quietly, making shoes, building iPhones, drawing tentacle porn, steadily growing their industries to catch up with the West - time is on their side.&lt;br /&gt;&lt;br /&gt;And starting a war now? Not only your odds are worse than in foreseeable future, you risk messing up with your economic growth. There's nothing particularly Black-Swanish about it - wars take much more time and much more money than anyone predicts more often than not. Ask Americans about Afghanistan. Or Soviets about Afghanistan. Or Brits about Afghanistan. I'd like to see a list of wars which were actually won on budget - it would be a really short one I believe.&lt;br /&gt;&lt;h3&gt;A small distraction - nukes&lt;/h3&gt;Every discussion of North Korea invariably gets sidetracked into an entirely irrelevant issue of nukes. Here's the only funny Subnormality strip ever:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.viruscomix.com/subnormality.html" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img alt="Strip from Subnormality. Fair use." border="0" width="800" height="979" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S9TVwKl7mgI/AAAAAAAAA5w/tfCHNvtgjHw/" /&gt;&lt;/a&gt;&lt;/div&gt;This is highly accurate. Nuclear weapons never had any use. Manhattan Projects was a highly misguided idea of getting nukes to get long term strategic advantage over the Soviet Union - Japan never being a serious threat - and it lasted only 4 years before Soviets managed to catch up.&lt;br /&gt;&lt;br /&gt;And as far as everyone knows, North Korea does not have nuclear weapons. Yes, they've probably managed to setup a nuclear explosion, but amount of damage a few tiny nukes without proper ICBMs can do is fairly low compared to the power of conventional artillery aimed at Seoul right now. &lt;a href="http://en.wikipedia.org/wiki/V-2#Assessment"&gt;This is the same mistake Nazis did with V2&lt;/a&gt; - sure, they were cool, but they cost so ridiculously much compared to spending the same amount on conventional hardware Alies were very probably very happy about them.&lt;br /&gt;&lt;br /&gt;Projects like North Korean nukes and V-2 are not military projects. They are half propaganda, and half massive cases of &lt;a href="http://en.wikipedia.org/wiki/Optimism_bias"&gt;optimism bias in planning&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;And even if North Koreans had large number of good nukes on good missiles, it's not at all certain they'd use them. Everyone during the Second World War - and you don't get more total war than that - &lt;a href="http://en.wikipedia.org/wiki/Chemical_warfare#World_War_II"&gt;had massive stocks of chemical weapons&lt;/a&gt;. And yet, they weren't used at all. At least against people who could retaliate in kind - Japanese had no qualms about mustard-gasing Chinese, just like Brits had no qualms about mustard-gasing Iraqis, and so on. &lt;br /&gt;&lt;h3&gt;Demographic transition&lt;/h3&gt;&lt;br /&gt;And now we're getting to my main point - why South Korea is extremely unwilling to take part in any war. Unlike Americans, who can sit at home, eating supersized burgers, and drinking gallons of HFCS-laced soda while their missiles drop on Pyongyang, or even Japanese, Chinese, and Russians, who might get a few missiles here and there but will be mostly fine - the largest population center of South Korea is just 40km &lt;a href="http://en.wikipedia.org/wiki/Korean_Demilitarized_Zone"&gt;from the border&lt;/a&gt;. It doesn't require fancy guided ICBM to kill someone - a totally straightforward dumb howitzer can reach it just fine, and good luck evacuating a 25M people big metropolitan area in a hurry.&lt;br /&gt;&lt;br /&gt;If war starts, there will be blood. Now you might be wondering - what happened to the world that it's so unwilling to have people die? Countries used to be totally blasé about a few thousand of their citizens here and a few thousand there dying. In some places like Afghanistan and most of Africa this is still the case. Yet - most of the world is highly unwilling to risk that. Even when wars take place - ridiculous amount of money is spent on protecting their soldiers' lives.&lt;br /&gt;&lt;br /&gt;And the simple answer is demographic transition. In countries with high birth rates life is cheap. So what if someone dies? If your son dies, you make another - it's not terribly hard. Yes, you'd rather he didn't, but on the scale of most important things in life a small chance of child's death is not that high.&lt;br /&gt;&lt;br /&gt;On the other hand once demographic transition happens, people have fewer children and have children later - it's all different. People spend ridiculous amount of money and effort on their children, are highly overprotective (limiting children's liberties in process, but that's another stories), and under no circumstances would they be willing to risk death or injury due to politics. And if your child dies? Not only you lose all investment you put into them, you are probably too old to have any more children, and your grandchildren aren't coming. There is probably some deep Darwinian reason why it works like that, I won't be getting into this - but the correlation between demographic transition and unwillingness to risk your lives in war is huge.&lt;br /&gt;&lt;br /&gt;Notice this doesn't apply about lives of others - Americans don't give a shit if a few hundred thousand Iraqis here and there die; Israelis don't give a shit about bombing a Palestinian school here or a hospital there - seriously, who cares about "them" as long as "we" are fine? &lt;br /&gt;&lt;br /&gt;Here's the best test case - WW1 and WW2. In 1913 total fertility was 6.3 in Russian, 3.52 in Germany 2.93 in UK, and 2.47 in France - they were at different stages of demographic transition, but still long before the point at which lives become scarce. So who cares if a million young men die meaninglessly in trenches?&lt;br /&gt;&lt;br /&gt;In 1938 it was very different. Russia (I wonder how gapminder draws boundaries from these times, anyway...) was at 4.74 - still in the "so who cares if a ten million of our citizens die?". Germany was in "we should put serious effort into blitzkrieg - a few deaths due to quick war are acceptable, but painful" territory with 2.25. But France and UK were already well into "surrender if you can see tanks from Paris/London" territory with 2.13 and 1.84 - the only reason UK didn't surrender was its ability to wage war remotely, protected by the Royal Navy. And just look how ridiculous was their overreaction to small amount of bombing. So 43 thousand civilians died? These numbers are a rounding error compared to what was happening on the Eastern Front or in Asia.&lt;br /&gt;&lt;br /&gt;Likewise Japan was very Kamikaze-happy with its 3.88 fertility rate - something Americans with their 2.22 would never try.&lt;br /&gt;&lt;br /&gt;Once fertility drops, anyone's willingness to fight does too. And that's why we have so few wars in post-demographic-transition world. You still think I'm making this up? &lt;a href="http://en.wikipedia.org/wiki/List_of_countries_and_territories_by_fertility_rate"&gt;Look at fertility rates top 10&lt;/a&gt;:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="19" src="http://upload.wikimedia.org/wikipedia/commons/thumb/f/f4/Flag_of_Niger.svg/22px-Flag_of_Niger.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Niger" title="Niger"&gt;Niger&lt;/a&gt; - somehow managed to get away with just a few coups, and &lt;a href="http://en.wikipedia.org/wiki/Tuareg_Rebellion_%281990%E2%80%931995%29"&gt;some minor Tuareg rebellions&lt;/a&gt;. &lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="11" src="http://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_Guinea-Bissau.svg/22px-Flag_of_Guinea-Bissau.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Guinea-Bissau" title="Guinea-Bissau"&gt;Guinea-Bissau&lt;/a&gt; - had &lt;a href="http://en.wikipedia.org/wiki/Guinea-Bissau_Civil_War"&gt;civil war 1998-1999&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="15" src="http://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Flag_of_Afghanistan.svg/22px-Flag_of_Afghanistan.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Afghanistan" title="Afghanistan"&gt;Afghanistan&lt;/a&gt; - had a war or another every year since 19th century.&lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="13" src="http://upload.wikimedia.org/wikipedia/commons/thumb/5/50/Flag_of_Burundi.svg/22px-Flag_of_Burundi.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Burundi" title="Burundi"&gt;Burundi&lt;/a&gt; - had &lt;a href="http://en.wikipedia.org/wiki/Burundi_Civil_War"&gt;civil war  1993 to 2005&lt;/a&gt;.&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="12" src="http://upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Flag_of_Liberia.svg/22px-Flag_of_Liberia.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Liberia" title="Liberia"&gt;Liberia&lt;/a&gt; - &lt;a href="http://www.blogger.com/post-create.g?blogID=27488238"&gt;one civil war 1989–1996&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Second_Liberian_Civil_War"&gt;another 1999–2003&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="17" src="http://upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Flag_of_the_Democratic_Republic_of_the_Congo.svg/22px-Flag_of_the_Democratic_Republic_of_the_Congo.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Democratic_Republic_of_the_Congo" title="Democratic Republic of the Congo"&gt;Democratic Republic of the  Congo&lt;/a&gt; - &lt;a href="http://en.wikipedia.org/wiki/Second_Congo_War"&gt;managed to pull one of the top 10 bloodiest wars of all times&lt;/a&gt;, just a few years ago; not counting minor ones.&lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="11" src="http://upload.wikimedia.org/wikipedia/commons/thumb/2/26/Flag_of_East_Timor.svg/22px-Flag_of_East_Timor.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/East_Timor" title="East Timor"&gt;East   Timor&lt;/a&gt; - &lt;a href="http://en.wikipedia.org/wiki/Indonesian_occupation_of_East_Timor"&gt;decades  of fighting against Indonesia&lt;/a&gt;. &lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="15" src="http://upload.wikimedia.org/wikipedia/commons/thumb/9/92/Flag_of_Mali.svg/22px-Flag_of_Mali.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Mali" title="Mali"&gt;Mali&lt;/a&gt; - doing surprisingly well for the list, just some spillover conflicts from neighbouring countries and minor fights between government and Tuaregs. &lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="15" src="http://upload.wikimedia.org/wikipedia/commons/thumb/1/17/Flag_of_Sierra_Leone.svg/22px-Flag_of_Sierra_Leone.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Sierra_Leone" title="Sierra Leone"&gt;Sierra   Leone&lt;/a&gt; - &lt;a href="http://en.wikipedia.org/wiki/Sierra_Leone_Civil_War"&gt;civil war 1991-2002&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="15" src="http://upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Flag_of_Uganda.svg/22px-Flag_of_Uganda.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Uganda" title="Uganda"&gt;Uganda&lt;/a&gt; - &lt;a href="http://en.wikipedia.org/wiki/Ugandan_Bush_War"&gt;one war&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Lord%27s_Resistance_Army"&gt;another civil war&lt;/a&gt;, plus participation in the Congo bloodbath on top of that.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;And this is what the entire world looked like most almost all of human history. So who's on the other end? This is actually pretty good.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="15" src="http://upload.wikimedia.org/wikipedia/commons/thumb/6/63/Flag_of_Macau.svg/22px-Flag_of_Macau.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Macau" title="Macau"&gt;Macau&lt;/a&gt; (&lt;a href="http://en.wikipedia.org/wiki/People%27s_Republic_of_China" title="People's Republic of China"&gt;PRC&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="15" src="http://upload.wikimedia.org/wikipedia/commons/thumb/5/5b/Flag_of_Hong_Kong.svg/22px-Flag_of_Hong_Kong.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Hong_Kong" title="Hong Kong"&gt;Hong  Kong&lt;/a&gt; (&lt;a href="http://en.wikipedia.org/wiki/People%27s_Republic_of_China" title="People's Republic of China"&gt;PRC&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="15" src="http://upload.wikimedia.org/wikipedia/commons/thumb/4/48/Flag_of_Singapore.svg/22px-Flag_of_Singapore.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Singapore" title="Singapore"&gt;Singapore&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="15" src="http://upload.wikimedia.org/wikipedia/commons/thumb/7/72/Flag_of_the_Republic_of_China.svg/22px-Flag_of_the_Republic_of_China.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Republic_of_China" title="Republic of China"&gt;Republic of China&lt;/a&gt; (Taiwan)&lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="15" src="http://upload.wikimedia.org/wikipedia/commons/thumb/0/09/Flag_of_South_Korea.svg/22px-Flag_of_South_Korea.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/South_Korea" title="South Korea"&gt;South  Korea&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="15" src="http://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Flag_of_Japan.svg/22px-Flag_of_Japan.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Japan" title="Japan"&gt;Japan&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="11" src="http://upload.wikimedia.org/wikipedia/commons/thumb/d/d0/Flag_of_Montserrat.svg/22px-Flag_of_Montserrat.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Montserrat" title="Montserrat"&gt;Montserrat&lt;/a&gt;&lt;/i&gt;  (&lt;a class="mw-redirect" href="http://en.wikipedia.org/wiki/British_overseas_territory" title="British overseas territory"&gt;UK&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="13" src="http://upload.wikimedia.org/wikipedia/commons/thumb/1/11/Flag_of_Lithuania.svg/22px-Flag_of_Lithuania.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Lithuania" title="Lithuania"&gt;Lithuania&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="15" src="http://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Flag_of_the_Czech_Republic.svg/22px-Flag_of_the_Czech_Republic.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Czech_Republic" title="Czech  epublic"&gt;Czech Republic&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="flagicon"&gt;&lt;img alt="" class="thumbborder" height="11" src="http://upload.wikimedia.org/wikipedia/commons/thumb/8/85/Flag_of_Belarus.svg/22px-Flag_of_Belarus.svg.png" width="22" /&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Belarus" title="Belarus"&gt;Belarus&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;So other than some tiny territories - the lowest fertility and therefore least belligerent counties are exactly the most interested ones - South Korea and Japan.&lt;br /&gt;&lt;br /&gt;By the way Czechs and Lithuanians are somewhat overstated here - they have fairly large migration to Western Europe, and many of their babies are born abroad. Their fertility is low, but not as drastically low as implied by the rank.&lt;br /&gt;&lt;br /&gt;And no, North Korea isn't likely to be terribly trigger-happy either. Their fertility rate is 1.85 - soldiers will be difficult to replace. Not to mention they'll lose the war in a week.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conclusions&lt;/h3&gt;South Korea should go to UN and get some sternly worded letter from Security Council and let it pass. Far more people could be saved by replacing a busy crossing with a &lt;a href="http://en.wikipedia.org/wiki/Magic_Roundabout_%28Swindon%29"&gt;roundabout&lt;/a&gt; than by stopping North Koreans from sinking your ships (or for that matter, stopping bin Laden from flying planes into your buildings).&lt;br /&gt;&lt;br /&gt;Every argument shows that South Koreans win nothing by going into the war, and they will find loses unacceptable.&lt;br /&gt;&lt;br /&gt;Now that I made Greeks and Koreans hate me, it's only 190 or so nationalities to go.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-7292370125690744506?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/7292370125690744506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=7292370125690744506' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/7292370125690744506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/7292370125690744506'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/04/what-should-south-korea-do-now.html' title='What should South Korea do now?'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_IYGc_MWwkfw/S9TB0n65gyI/AAAAAAAAA5I/2uyyJRFaNCg/s72-c/img_0093_by_unstoppabledrew_from_flickr_cc-nc.jpg' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-4037083502633294662</id><published>2010-04-24T20:35:00.000+02:00</published><updated>2010-04-24T20:35:22.601+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='personal'/><title type='text'>Notes on personal experience points system</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/S9M5Jg8YiMI/AAAAAAAAA5A/vm0TartYs3Y/s1600/gimme_gimme_by_fofurasfelinas_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Gimme gimme by fofurasfelinas from flickr (CC-NC-ND)"&gt;&lt;img alt="Gimme gimme by fofurasfelinas from flickr (CC-NC-ND)" border="0" height="426" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/S9M5Jg8YiMI/AAAAAAAAA5A/vm0TartYs3Y/s640/gimme_gimme_by_fofurasfelinas_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Here's a very quick post. I tried to run a personal experience points system, with &lt;a href="http://t-a-w.blogspot.com/2010/03/personal-experience-points-and-osx.html"&gt;software described in this article&lt;/a&gt;. I tried something like this before, &lt;a href="http://lesswrong.com/lw/178/notes_on_utility_function_experiment"&gt;it was described here on lesswrong&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So, the notes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;As I'm writing this, I have level 6 IRL avatar (251 XP)&lt;/li&gt;&lt;li&gt;In general, it didn't work terribly well. This isn't in itself a bad thing. As Edison said after failing and failing repeatedly "&lt;i&gt;&lt;span class="body"&gt;I have not failed. I've just found 10,000 ways that  won't work&lt;/span&gt;&lt;/i&gt;", and then proceeded to steal Tesla's work.&lt;/li&gt;&lt;/ul&gt;Urgent vs important: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;So one thing I learned doesn't work are big rewards for things I know I'm going to do at some point anyway. If I can get 25 points today - or play some video games today and I will get these 25 points in a few days anyway - this provides zero marginal benefit. &lt;a href="http://en.wikipedia.org/wiki/Dynamically_inconsistent"&gt;It's just like people who always want to quit smoking next week&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;With small recurring items like exercise - motivations due to these points sometimes managed to be just enough to push me in the right direction when I was undecided between doing that and doing something else.&lt;/li&gt;&lt;li&gt;I thought the system just doesn't work that well - but there was one exception. The "keep leechblock on whole day" item was a resounding success - at least at making me search new sites to waste time on but never mind that - somehow this urgency really works.&lt;/li&gt;&lt;li&gt;It seems faux urgency drives me more than actual importance. Unfortunately most important things in life are long term and not terribly urgent.&lt;/li&gt;&lt;li&gt;This is all because I am a one-marshmallower. I have no doubt that in &lt;a href="http://en.wikipedia.org/wiki/Deferred_gratification"&gt;the marshmallow experiment&lt;/a&gt; I would just eat that damn marshmallow right away - while children who waited would get another one, be more successful in life, and then get type 2 diabetes due to eating so many fucking marshmallows.&lt;/li&gt;&lt;li&gt;By the way, standard economics with its &lt;a href="http://en.wikipedia.org/wiki/Exponential_discounting"&gt;silly exponential discounting&lt;/a&gt; of time cannot explain this urgency - but it all makes a lot more sense if you use &lt;a href="http://en.wikipedia.org/wiki/Hyperbolic_discounting"&gt;hyperbolic discounting&lt;/a&gt;. And life is definitely hyperbolicly discounted - if you doubt it ask the Egyptian pharaohs who prudently granted land to their temples so that it would maintain priests who would pray to the gods for them until end of time how is compound interest working for them. Exponential function is merely a mathematical artifact, nothing more.&lt;/li&gt;&lt;/ul&gt;User interface:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Scripts to record XP-able actions are not terribly annoying. &lt;a href="http://www.microsoft.com/hardware/mouseandkeyboard/productdetails.aspx?pid=043"&gt;This makes the most awesome keyboard in the world even more awesome&lt;/a&gt;. I'm wondering if it would be better to get it integrated with OmniFocus inbox, but annoyance is low enough for it to not be worth the effort.&lt;/li&gt;&lt;li&gt;XP bar is nowhere near flashy enough, and slowly filling up bar doesn't provide much motivation at all.&lt;/li&gt;&lt;/ul&gt;Economics and video games:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Video games solve this by giving level-dependent bonuses - unfortunately life is not like that, and I cannot think of any meaningful ways of granting myself a level bonus (also see the point about one-marshmallowing).&lt;/li&gt;&lt;li&gt;One way to think about would be compound xp interest - increase my XP level by some % every day to restore exponential discounting behaviour.&lt;/li&gt;&lt;li&gt;Another idea would be extra XP points for streaks of positive actions - like "3rd day with leechblock on" / "exercised 3 times in the week already" etc. &lt;/li&gt;&lt;li&gt;I would really like to find something less blunt than leechblock - the problem is that I actually need to access those websites every now and then for legitimate reasons - and &lt;a href="http://tvtropes.org/pmwiki/pmwiki.php/Main/TVTropesWillRuinYourLife"&gt;I just want to make sure I don't fall into tvtropes trap&lt;/a&gt; (I accidentally clicked on this link and tvtroped myself dammit).&lt;/li&gt;&lt;/ul&gt;So I think I'll try another iteration based with far more urgency in it. Let's see how it works out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-4037083502633294662?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/4037083502633294662/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=4037083502633294662' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/4037083502633294662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/4037083502633294662'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/04/notes-on-personal-experience-points.html' title='Notes on personal experience points system'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_IYGc_MWwkfw/S9M5Jg8YiMI/AAAAAAAAA5A/vm0TartYs3Y/s72-c/gimme_gimme_by_fofurasfelinas_from_flickr_cc-nc-nd.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-8930629655566090243</id><published>2010-04-23T07:27:00.000+02:00</published><updated>2010-04-23T07:27:53.863+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='osx'/><title type='text'>How to configure OSX for software development</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/S9EuxMHUTQI/AAAAAAAAA4g/zE9IojIQENk/s1600/grimlock_vs_munkzilla_by_fanboy30_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Grimlock vs Munkzilla by Fanboy30 from flickr (CC-NC-SA)"&gt;&lt;img alt="Grimlock vs Munkzilla by Fanboy30 from flickr (CC-NC-SA)" border="0" height="426" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/S9EuxMHUTQI/AAAAAAAAA4g/zE9IojIQENk/s640/grimlock_vs_munkzilla_by_fanboy30_from_flickr_cc-nc-sa.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;In &lt;a href="http://t-a-w.blogspot.com/2010/04/osx-vs-linux.html"&gt;my previous post about OSX and Linux&lt;/a&gt; I mentioned that I maintain a very long document explaining how to turn a fresh OSX into something usable for software development and general use. Well, here it is - but be warned I only mildly cleaned it up.&lt;br /&gt;&lt;br /&gt;This is all based on OSX 10.5 Leopard. For some reason OSX 10.6 Snow Leopard crashes like Windows 98 - at least once a day - and I cannot work like that, so I downgraded back after the upgrade. This seems to affect quite a few people, and 10.6 enhancements are nowhere near good enough to deal with such crashes.&lt;br /&gt;&lt;h3&gt;Install all necessary applications&lt;/h3&gt;First of course - upgrade the system, as installation DVD is always rather outdated. Then install applications - this is more difficult than apt-get line, so here's list of links, sorted by category. All is open source or at least free download unless noted.&lt;br /&gt;&lt;br /&gt;Browsers: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.mozilla.com/"&gt;Firefox&lt;/a&gt; - Safari is IE for Mac. &lt;a href="http://t-a-w.blogspot.com/2010/01/best-addons-for-firefox-36.html"&gt;Here's my post on best Firefox 3.6 extensions&lt;/a&gt; - it's the same on any system. Normally that's the only browser you need, but for web development testing I also install:&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.opera.com/download/"&gt;Opera&lt;/a&gt; &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.google.com/chrome"&gt;Google Chrome&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Drivers: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/macfuse/"&gt;MacFUSE&lt;/a&gt; - drivers required by NTFS drivers&lt;/li&gt;&lt;li&gt;&lt;a href="http://macntfs-3g.blogspot.com/"&gt;NTFS-3G drivers&lt;/a&gt; - NTFS is essentially the only reasonably portable filesystem for external drives as FAT doesn't support files larger than 4GB.&lt;/li&gt;&lt;li&gt;&lt;a href="http://arduino.cc/en/Main/Software"&gt;Arduino drivers&lt;/a&gt; - ok, you most likely won't need these.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.microsoft.com/hardware/download/DownloadResult.aspx?category=MK&amp;amp;type=Keyboard&amp;amp;name=B2M-00012&amp;amp;os=mac104x57&amp;amp;lang=en"&gt;Microsoft  Keyboard drivers&lt;/a&gt; (I like binding those extra keys to  something useful - Mac doesn't even see them by default). You won't need it unless you have Microsoft Keyboard or care about such extras.&lt;/li&gt;&lt;li&gt;&lt;a href="http://perian.org/"&gt;Perian&lt;/a&gt; - a pack of media codecs. &lt;/li&gt;&lt;/ul&gt;Software development:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://developer.apple.com/technologies/xcode.html"&gt;Xcode&lt;/a&gt; - this is a bundle of gcc and other development essentials - but instead of giving it a straight download Apple hides it under registrationwall on some horribly failful page.&lt;/li&gt;&lt;li&gt;&lt;a href="http://macromates.com/"&gt;TextMate&lt;/a&gt; - the only reason I even use Mac. &lt;b&gt;Only trial version is free.&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://developer.mozilla.org/en/XULRunner"&gt;Xulrunner&lt;/a&gt;  - Firefox-based environment in which you  can make your own XUL-based applications&lt;/li&gt;&lt;/ul&gt;Basic system functionality:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; &lt;a href="http://witch.en.softonic.com/mac/download"&gt;Witch&lt;/a&gt; - it fixes alt-tab to work. Alt-tab is broken by default in OSX, has always been, and they don't plan to fix it ever - so this is absolutely essential. It's supposedly a trial version&lt;/li&gt;&lt;li&gt;&lt;a href="http://wakaba.c3.cx/s/apps/unarchiver"&gt;Unarchiver&lt;/a&gt; - Mac supports most common archive formats, but you will need this sooner or later.&lt;/li&gt;&lt;li&gt;&lt;a href="http://dev.mysql.com/downloads/mysql/"&gt;mysql&lt;/a&gt; - I don't remember exactly what was wrong with MacPorts' version (it was long time ago), but due to some brokenness I use this DMG version.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.macports.org/install.php"&gt;MacPorts&lt;/a&gt; - however much it sucks, it's absolutely necessary. &lt;a href="http://www.finkproject.org/"&gt;Fink&lt;/a&gt; might seem like a nicer (apt-get based) alternative, but it just lacks most packages, and mixing them is a recipe for fail.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Internet communication:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://adium.im/"&gt;Adium&lt;/a&gt; - multi-protocol IM  program&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.skype.com/intl/en/download/skype/macosx/"&gt;Skype&lt;/a&gt;  - another IM program (Adium doesn't support Skype) - these two should cover all your IM needs&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.transmissionbt.com/download.php"&gt;Transmission&lt;/a&gt; - all bittorrent clients for OSX suck, but this seems to suck relatively less.&lt;/li&gt;&lt;/ul&gt;Desktop applications:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://porting.openoffice.org/mac/download/aqua-Intel.html"&gt;OpenOffice.org&lt;/a&gt; - there's native version these days, or at least decently native-ish&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.stepmania.com/wiki/Downloads"&gt;Stepmania&lt;/a&gt; - if you're into DDR&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.videolan.org/vlc/download-macosx.html"&gt;VLC&lt;/a&gt; - music player (OSX version of mplayer isn't as good as Linux's, so it's nice to have a backup)&lt;/li&gt;&lt;li&gt;&lt;a href="http://wakaba.c3.cx/s/apps/xee"&gt;Xee&lt;/a&gt; -  image  browser (OSX has none)&lt;/li&gt;&lt;/ul&gt;Others:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://growl.info/"&gt;Growl&lt;/a&gt; - notifier system&lt;/li&gt;&lt;li&gt;&lt;a href="http://willmore.eu/software/isolator/"&gt;Isolator&lt;/a&gt; - a really nice gadget which lets you blur all but active window, if you need to concentrate.&lt;/li&gt;&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S9EvADhLsqI/AAAAAAAAA4o/gNOWOlSOxFk/s1600/pamuk__pebbles_by_sil__hasenbande_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Pamuk &amp;amp; Pebbles by Sil &amp;amp; Hasenbande from flickr (CC-NC-SA)"&gt;&lt;img alt="Pamuk &amp;amp; Pebbles by Sil &amp;amp; Hasenbande from flickr (CC-NC-SA)" border="0" height="446" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S9EvADhLsqI/AAAAAAAAA4o/gNOWOlSOxFk/s640/pamuk__pebbles_by_sil__hasenbande_from_flickr_cc-nc-sa.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;System settings&lt;/h3&gt;After basic applications are installed it's useful to create some symlinks that make OSX more Linux-compatible (&lt;tt&gt;sudo ln -s /Volumes /mnt; sudo ln -s /Volumes /media; sudo mv /home /home-old; sudo ln -s /Users /home&lt;/tt&gt;) in case your scripts or you want to switch seamlessly between the two.&lt;br /&gt;&lt;br /&gt;Then clean up the dock - it's filled with every stupid Apple program ever made (Garage Band ...), except for the most useful one (Terminal). So remove everything you won't be using, add all you will be (start application; right click; "Keep in Dock"), and mark applications you want to start when you login as such - typically Adium/Skype/Terminal/Firefox (start application; right click; "Open at login")&lt;br /&gt;&lt;br /&gt;Now here's a long list of configuration tweaks:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Settings &amp;gt; Mouse &amp;gt; faster - I wish installer asked me if I have Parkinson's disease or not, or default to assumption that I don't. Protip for OS designers: Most people have reasonable control over they hand movement.&lt;/li&gt;&lt;li&gt;Settings &amp;gt; Keyboard &amp;gt; faster - likewise&lt;/li&gt;&lt;li&gt;Settings &amp;gt; Keyboard &amp;gt; Use all F1, F2, etc. keys as standard function keys - you use them about 50x more often than laptop controls, and the only common control - volume up/down/zero - has dedicated keys on my external keyboard anyway&lt;/li&gt;&lt;li&gt;Settings &amp;gt; Keyboard &amp;amp; Mouse &amp;gt; Ignore trackpad when mouse is present - it was extremely useful, except the most recent update of OSX 10.5 broke it - it's no longer there, even messing with registry file won't give it back&lt;/li&gt;&lt;li&gt;Settings &amp;gt; Universal Access &amp;gt; enable - needed by witch driver&lt;/li&gt;&lt;li&gt;Settings &amp;gt; Energy Saver &amp;gt; Power Adapter &amp;gt; Performance + no brightness reduction - it's just annoying&lt;/li&gt;&lt;li&gt;Settings &amp;gt; Displays &amp;gt; Automatically adjust brightness as ambient light changes &amp;gt; off - equally annoying&lt;/li&gt;&lt;li&gt;Settings &amp;gt; Displays &amp;gt; Make external display the main one&lt;/li&gt;&lt;li&gt;Settings &amp;gt; Displays &amp;gt; Show displays in menu bar (so you can quickly fix resolution if Mac autodetects it wrong as it does every 10 or so times)&lt;/li&gt;&lt;li&gt;Settings &amp;gt; Time Machine &amp;gt; Show Time Machine status in menu bar &amp;gt; off - unless you use Time Machine&lt;/li&gt;&lt;li&gt;Settings &amp;gt; System &amp;gt; Play user interface sound effects &amp;gt; off - now to stay sane you absolute need to turn off system bell - this setting needs to be repeated in multiple places&lt;/li&gt;&lt;li&gt;Settings &amp;gt; Sound &amp;gt; Alert volume 0%&lt;/li&gt;&lt;li&gt;Terminal &amp;gt; Advanced &amp;gt; Audible Bell off&lt;/li&gt;&lt;li&gt;Terminal &amp;gt; Shell &amp;gt; Close if exited cleanly - no idea why it's not a default, get rid of useless dead windows&lt;/li&gt;&lt;li&gt;Terminal &amp;gt; Window &amp;gt; Dimensions - disable - less clutter&lt;/li&gt;&lt;li&gt;Terminal &amp;gt; Text &amp;gt; Antialias text - without antialiasing Terminal.app looks like shit. Not antialiasing in terminal is just like making "look like shit" option and turning it on by default. WTF Apple?&lt;/li&gt;&lt;li&gt;Terminal &amp;gt; Monaco 14pt font, line and character spacing 0.90/0.90 - somewhat nicer than defaults.&lt;/li&gt;&lt;/ul&gt;Because I want access to development console in Safari, I need to mess in registry: &lt;tt&gt;defaults write com.apple.Safari IncludeDebugMenu 1&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;It's also a good idea to get rid of crash reporter - especially if you develop XUL applications wink wink - &lt;tt&gt;defaults write com.apple.CrashReporter DialogType none&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S9EvjDaylcI/AAAAAAAAA4w/0PqPVwmBDrs/s1600/russian_dwarf_hamster_by_cdrussorusso_from_flickr_cc-by.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Russian Dwarf Hamster by cdrussorusso from flickr (CC-BY)"&gt;&lt;img alt="Russian Dwarf Hamster by cdrussorusso from flickr (CC-BY)" border="0" height="372" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S9EvjDaylcI/AAAAAAAAA4w/0PqPVwmBDrs/s640/russian_dwarf_hamster_by_cdrussorusso_from_flickr_cc-by.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Configuring applications and shell&lt;/h3&gt;&lt;a href="http://t-a-w.blogspot.com/2010/03/small-tips-for-making-unix-programming.html"&gt;Now let's go to shell and copy my .bash_profile and such&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It's a good time to find that TextMate license and install it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Then get the most recent bundles:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;mkdir -p /Library/Application\ Support/TextMate &lt;br /&gt;cd /Library/Application\ Support/TextMate/svn co http://svn.textmate.org/trunk .&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I have some TextMate hacks which I install at this point - I'll write about them in another post.&lt;br /&gt;&lt;br /&gt;Now start Adium / Skype and enter your logins and passwords.&lt;br /&gt;&lt;br /&gt;Start Transmission, make sure incomplete downloads are in &lt;tt&gt;~/Downloads/Incomplete/&lt;/tt&gt; and are not mixed up with completes. You may also change your share ratio settings at this point if you're an asshole ;-) &lt;br /&gt;&lt;br /&gt;StepMania needs a link to songs located on external drive:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;rm -rfv /Applications/StepMania/Songs/&lt;br /&gt;ln -s ~/e/Dancing/Songs /Applications/StepMania/&lt;/pre&gt;&lt;br /&gt;And now install some packages from MacPorts/rubygems/CPAN. This set is related to what I'm working on right now and will probably differ for you - but everyone needs git, wget, unrar, pstree etc.:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;sudo port -v selfupdate&lt;br /&gt;sudo port install mplayer unrar ruby19 mc git-core pstree rb-rubygems wget mp3infosudo port install octave ImageMagick id3v2 p5-libwww-perl p5-dbi p5-heap p5-yaml&lt;br /&gt;sudo gem install rak hpricot objectiveflickr url_escape mongrel s3sync mechanize RMagick&lt;br /&gt;sudo cpan Sys::Mmap DBD::mysql Socket::GetAddrInfo&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Have fun&lt;/h3&gt;At this point it's almost usable. There are some extra steps related to building stuff in my repository, configuring mysql for my applications etc. - all totally me-specific and of little use to anyone else.&lt;br /&gt;&lt;br /&gt;Not that the rest of the advice is in any way universal - but it should be a good starting point for you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-8930629655566090243?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/8930629655566090243/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=8930629655566090243' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/8930629655566090243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/8930629655566090243'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/04/how-to-configure-osx-for-software.html' title='How to configure OSX for software development'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_IYGc_MWwkfw/S9EuxMHUTQI/AAAAAAAAA4g/zE9IojIQENk/s72-c/grimlock_vs_munkzilla_by_fanboy30_from_flickr_cc-nc-sa.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-1131513774664540339</id><published>2010-04-21T19:19:00.000+02:00</published><updated>2010-04-21T19:19:09.385+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='osx'/><title type='text'>OSX vs Linux</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/S88y8bryp5I/AAAAAAAAA4Q/EcGSxXHWJAE/s1600/the_ipad2_is_finally_revealed__by_rolfsteinar_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="The Ipad2 is finally revealed :-) by RolfSteinar from flickr (CC-NC-ND)"&gt;&lt;img alt="The Ipad2 is finally revealed :-) by RolfSteinar from flickr (CC-NC-ND)" border="0" height="428" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/S88y8bryp5I/AAAAAAAAA4Q/EcGSxXHWJAE/s640/the_ipad2_is_finally_revealed__by_rolfsteinar_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;I hate OSX and yet I use OSX because alternatives (by which I mean Linux, obviously) seem even worse. Here's a very short list of pros and cons as I see them.&lt;br /&gt;&lt;br /&gt;Most important things:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;OSX pro: TextMate&lt;/b&gt;. I really cannot use any other editor  without feeling physically ill, they just do everything wrong. There are some attempts at getting semi-decent editors for Linux like &lt;a href="http://redcareditor.com/screenshots/"&gt;redcar&lt;/a&gt;, but I have no idea how good they are.&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;OSX con: MacPorts&lt;/b&gt; - source based distribution systems are just failful, and MacPorts is far more failful than most. It is completely routine that upgrade will leave you with broken packages - neither upgradable nor downgradable.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Linux pro: apt-get&lt;/b&gt;. I wouldn't even seriously consider any  Linux without apt-get for anything.&lt;/li&gt;&lt;/ul&gt;Extra points:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Linux pro: same software on desktop and  servers&lt;/b&gt;. It saves me a lot of complications, 32bit vs 64bit is annoying enough without OSX vs Linux.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Linux pro: better development tools&lt;/b&gt;. strace, ltrace, and LD_PRELOAD for example. It is system made for developers by developers and it shows. &lt;/li&gt;&lt;li&gt;&lt;b&gt;Linux pro: virtual desktops&lt;/b&gt;. Spaces on OSX doesn't work and it will never work as long as OSX stays Application-centric instead of document-centric like Windows and Linux GUIs.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Linux pro: better internationalization&lt;/b&gt;. Especially if I want to type  in multiple languages. There's proper Polish Dvorak keyboard for example. (I remember I  once haxored such for Windows 95 by editing binary drivers... these  were good times).&lt;/li&gt;&lt;li&gt;&lt;b&gt;Linux pro: Amarok&lt;/b&gt;. It's vastly more awesome than any OSX music playing program, especially shit like iTunes. Even old Winamp is far better than iTunes.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Linux pro: shell&lt;/b&gt;. Ubuntu bash has smart tab-completion, command not found suggests what to install, and everything else in shell got as much attention to detail as GUI got for OSX. &lt;/li&gt;&lt;li&gt;&lt;b&gt;Linux con: Support for laptop hardware&lt;/b&gt;. Last time I tried it, even something as simple as getting external monitor in and out was a massive pain.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Linux con: GUI usability&lt;/b&gt;: Now that Windows 7 finally catched up, KDE is in general the second least polished GUI, the absolute worst being GNOME of course. It's not just looks, it's all the minor things that make it work seamlessly.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Linux con: GUI programming&lt;/b&gt;. C++ based Qt, and fake-OO-C based Gtk are both massive pain in the ass compared to even less than amazing Cocoa. There are Ruby etc. bindings for all, but it's just like putting lipstick on a pig. Everyone develops GUI for web these days - that even dealing with MSIE6 and all ridiculous web limitations is still far less pain than desktop GUI programming shows how bad it is.&lt;/li&gt;&lt;li&gt;&lt;b&gt;OSX pro: It's prettier&lt;/b&gt;. Font rendering is a particularly good example&lt;b&gt;&lt;br /&gt;&lt;/b&gt; &lt;/li&gt;&lt;li&gt;&lt;b&gt;OSX pr&lt;/b&gt;&lt;b&gt;o: Omnifocus&lt;/b&gt;. Every other GTD software I tried was so bad I simply stayed with paper, but Omnifocus suckiness is fairly moderate.&lt;/li&gt;&lt;li&gt;&lt;b&gt;OSX pro: Development for mobiles&lt;/b&gt;. Right now the only categories of mobiles are iPhones and turdbricks - one needs OSX, the other nobody wants to develop for. It might change in 2-5 years, but right now I need OSX if I wanted to develop for OSX.&lt;/li&gt;&lt;li&gt;&lt;b&gt;OSX con: Support for laptop hardware&lt;/b&gt;. It's ridiculously bad, even though it's Apple's own hardware. The only way to turn off laptop monitor is by sacrificing a  chicken (put computer to sleep; wake it up without fully opening the  laptop screen; then maybe it will work, maybe not) - and routine  software upgrade broke the "turn off trackpad when mouse is in" option.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/S88zVvfgthI/AAAAAAAAA4Y/Mu7If0d5658/s1600/ipad_stand_by_veronica_belmont_from_flickr_cc-by.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="iPad stand by Veronica Belmont from flickr (CC-BY)"&gt;&lt;img alt="iPad stand by Veronica Belmont from flickr (CC-BY)" border="0" height="480" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/S88zVvfgthI/AAAAAAAAA4Y/Mu7If0d5658/s640/ipad_stand_by_veronica_belmont_from_flickr_cc-by.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;I see no chance of OSX ever catching up with Linux before I get old.&lt;br /&gt;&lt;br /&gt;Linux would need at least a decent editor - and if redcar won't work, I'm out of hope - Emacs and vim are stuck in 80s and haven't improved the slightest since I started using Linux. All KDE/GNOME-based editors are made without any clue.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Laptop hardware support gets better each year, while Mac seems be to getting worse somehow, so that problem doesn't bother me that much. And I can live with ugly fonts and less GUI polish.&lt;br /&gt;&lt;br /&gt;I might miss Omnifocus a bit, but that's definitely something I can live without, especially since Omnifocus is OK but not that awesome, and fairly moderate amount of GUI programming should make it possible to make something more or less as good, if only GUI programming wasn't such pain.&lt;br /&gt;&lt;br /&gt;So I'm quite tempted to switch to Linux. Am I missing some big pro or con of either system?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-1131513774664540339?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/1131513774664540339/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=1131513774664540339' title='27 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1131513774664540339'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1131513774664540339'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/04/osx-vs-linux.html' title='OSX vs Linux'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_IYGc_MWwkfw/S88y8bryp5I/AAAAAAAAA4Q/EcGSxXHWJAE/s72-c/the_ipad2_is_finally_revealed__by_rolfsteinar_from_flickr_cc-nc-nd.jpg' height='72' width='72'/><thr:total>27</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-6843906293660277461</id><published>2010-04-19T22:31:00.000+02:00</published><updated>2010-04-19T22:31:25.580+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='politics'/><title type='text'>How much democracy in your democracy?</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/S8y76YEVR_I/AAAAAAAAA4A/ovyR1pnHnn0/s1600/dewey_by_angela_n_from_flickr_cc-by.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Dewey by angela n. from flickr (CC-BY)"&gt;&lt;img alt="Dewey by angela n. from flickr (CC-BY)" border="0" height="480" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/S8y76YEVR_I/AAAAAAAAA4A/ovyR1pnHnn0/s640/dewey_by_angela_n_from_flickr_cc-by.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;As elections in both UK and Poland get closer, I want to write a bit about some severe flaws in modern Western-style representative democracy. Unfortunately it's very difficult to hold a meaningful discussion about such subjects, as far too many things get collectively labelled "democracy".&lt;br /&gt;&lt;br /&gt;This is not at all unreasonable, as they tend to cluster together. So rule of law, constitutional limits on government powers, freedom of speech and press, ability to run business independent of government connections, high standards of living, low corruption, regular elections, existence of multiple political parties, and even bicameral Parliaments tend to be present all at once in the same set of countries, or to be absent all at once in others.&lt;br /&gt;&lt;br /&gt;Yet, there's nothing causal about this, and this is largely a historical accident. Many people are under impression that the kind of governments we have are a result of long careful thinking, or many experimentations with different government design - and nothing could be further from truth - it's all one big historical accident.&lt;br /&gt;&lt;h3&gt;History lesson&lt;/h3&gt;&lt;br /&gt;Between death of Julius Caesar and establishment of United States, there was only one large country which could be even vaguely described as "democratic" - &lt;a href="http://en.wikipedia.org/wiki/Polish-Lithuanian_Commonwealth"&gt;the Polish–Lithuanian Commonwealth&lt;/a&gt;. And like most things in history, it all happened by accident - after the main line of &lt;a href="http://en.wikipedia.org/wiki/Piast_dynasty"&gt;Piast kings&lt;/a&gt; went extinct in Poland in 1370, Polish lords figured out that instead of electing a new dynasty, they will be approving every new king one by one.&lt;br /&gt;&lt;br /&gt;Normally it would bother the king a lot, as most kings had been obsessed with making sure their children inherit their realm, but &lt;a href="http://en.wikipedia.org/wiki/Jagiellon_dynasty"&gt;Jagiellons&lt;/a&gt; weren't that terribly bothered as they had still been guaranteed succession in Lithuania, and Polish lords could be relied on to elect someone from the Jagiellon family if they wanted to keep the Polish-Lithuanian union going. The only thing they had to agree to were fairly modest limitations on their powers - limitations that would get larger and larger with each next generation, and power was shifted further downwards from big lords to wider nobility.&lt;br /&gt;&lt;br /&gt;By the time of death of the last Jagiellon in 1572, the system was something like this:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;There was a bicameral Parliament - upper house Senate (&lt;i&gt;Senat&lt;/i&gt;) consisting of major lords and bishops&lt;/li&gt;&lt;li&gt;Lower house House of Representatives (&lt;i&gt;Izba Poselska&lt;/i&gt;) consisting of representatives of various districts elected freely by all noblemen living in a given district.&lt;/li&gt;&lt;li&gt;King was elected for life by all noblemen.&lt;/li&gt;&lt;li&gt;All legislation had to be approved by both houses of parliament and the king.&lt;/li&gt;&lt;li&gt;No war could be waged without approval of the Parliament.&lt;/li&gt;&lt;li&gt;All taxes and tariffs required approval of the Parliament.&lt;/li&gt;&lt;li&gt;Before the coronation, the king had to take an oath to uphold &lt;a href="http://en.wikipedia.org/wiki/Henrician_Articles"&gt;basic constitutional right&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Szlachta"&gt;Polish "nobility"&lt;/a&gt; (&lt;i&gt;szlachta&lt;/i&gt;) was a very wide social class - comprising of about 10% of population, and in some parts of the Commonwealth as much as 30% (of that only males could vote, not surprisingly) - this is far more than even in most of 19th century republics, the main different being that in Poland this status was hereditary while in most 19th century republics it was based on wealth.&lt;/li&gt;&lt;li&gt;There was no slavery as such, but there was very harsh serfdom system in some regions.&lt;/li&gt;&lt;li&gt;While Catholic Church still had semi-official status, &lt;a href="http://en.wikipedia.org/wiki/Warsaw_Confederation"&gt;unprecedented levels of freedom of religion was guaranteed&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;This is essentially identical to American system of government as founding fathers made it, and very very close to American system of government as it exists today. Modern American system of government, and also those of other democratic countries - is based on such accidents from a half millennium ago, similar accidents from British history, more accidents from 19th century conflicts between demising landed aristocracy and growing bourgeoisie, and on top of that those due to 20th century's rise of social democratic welfare state.&lt;br /&gt;&lt;br /&gt;Is this the only way to organize a democratic state? Not at all! Even a very quick look at &lt;a href="http://en.wikipedia.org/wiki/Athenian_democracy"&gt;Athenian democracy&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Roman_Republic"&gt;Roman Republic&lt;/a&gt;, and Medieval &lt;a href="http://en.wikipedia.org/wiki/Republic_of_Venice"&gt;Republic of Venice&lt;/a&gt; - three particularly notable historical example - show how ridiculously vast is the range of possible democratic models. According to some ranks &lt;a href="http://en.wikipedia.org/wiki/Democracy_Index"&gt;there are 80 or so countries which are reasonably "democratic"&lt;/a&gt;, but nearly every single one of them a tiny variant of essentially a single political system, with neither theory nor experimentation to show that it's any better than the alternatives, and even outliers like Switzerland are not that terribly far off.&lt;br /&gt;&lt;h3&gt;How democratic are Western democracies?&lt;/h3&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/S8y9K3kngmI/AAAAAAAAA4I/b3Y_3CxrVcc/s1600/sarah_palin_political_effigy__kissy_by_laiane_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Sarah Palin Political Effigy &amp;amp; Kissy by Laiane from flickr (CC-NC-SA)"&gt;&lt;img alt="Sarah Palin Political Effigy &amp;amp; Kissy by Laiane from flickr (CC-NC-SA)" border="0" height="640" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/S8y9K3kngmI/AAAAAAAAA4I/b3Y_3CxrVcc/s640/sarah_palin_political_effigy__kissy_by_laiane_from_flickr_cc-nc-sa.jpg" width="548" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;It's not terribly difficult to make up some ad hoc stories explaining why this particular historical accidents just "happen" to be the best system possible - every political system, every feature of social organization, essentially everything anyone has ever done had plenty of apologists of this kind.&lt;br /&gt;&lt;br /&gt;But can we actually measure it? Yes we can. Let's start with one very simple metric - what percentage of votes did the ruling coalition get. Surely we should expect &lt;b&gt;at least 50%&lt;/b&gt;, right? And we would prefer if policies set had support of reasonably solid majority, let's say 55%-60%, instead of the country being governed by what is essentially a rounding error?&lt;br /&gt;&lt;br /&gt;Not so! Even without considering &lt;a href="http://en.wikipedia.org/wiki/Tactical_voting"&gt;tactical voting&lt;/a&gt;, electoral systems tend to be ridiculously flawed, and in many countries it is actually completely common for well placed minority to be able to hold control over the government.&lt;br /&gt;&lt;br /&gt;Going down the list according to Democracy Index score, ruling coalitions in the top democracies had such shares of popular vote:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Sweden_general_election,_2006"&gt;Sweden - 48.24%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Norwegian_parliamentary_election,_2009"&gt;Norway - 47.8%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Icelandic_parliamentary_election,_2009"&gt;Iceland - 51.5%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Dutch_general_election,_2006"&gt;Netherlands - 51.7%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Danish_parliamentary_election,_2007"&gt;Denmark - 36.7%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Finnish_parliamentary_election,_2007"&gt;Finland - 58.5%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/New_Zealand_general_election,_2008"&gt;New Zealand - 44.93%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Swiss_federal_election,_2007"&gt;Swiss system doesn't really compare to others on the list.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Luxembourgian_legislative_election,_2009"&gt;Luxembourg - 59.6%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Australian_federal_election,_2007"&gt;Australia - 43.38%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Canadian_federal_election,_2008"&gt;Canada - 37.65%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Irish_general_election,_2007"&gt;Ireland - 49.0%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/German_federal_election,_2009"&gt;Germany - 48.8%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Austrian_legislative_election,_2008"&gt;Austra - 55.24%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Spanish_general_election,_2008"&gt;Spain - 43.87%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Maltese_general_election,_2008"&gt;Malta - 49.34%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Japanese_general_election,_2009"&gt;Japan - 48.4%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/United_States_House_of_Representatives_elections,_2008"&gt;United States - 53.18%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Czech_legislative_election,_2006"&gt;Czech Republic - 48.9%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Belgian_general_election,_2007"&gt;Belgium - 59.78%&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/United_Kingdom_general_election,_2005"&gt;United Kingdom - 35.3%&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;So skipping the Swiss, of 20 supposedly "most democratic" countries in the world - governments of only 7 got majority of votes - and this doesn't even account for tactical voting - as I'm sure plenty of Americans would rather vote Green or Teabag, but the system essentially forced them to choose between the two leading parties or staying at home, so all these numbers seriously overestimate actual support for governments.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And even in spite of this overestimation, three governments are so far from majority of votes - UK, Denmark, and Canada - that their inclusion among "democracies" is highly dubious. OK, current situation in Denmark seems to be unusual, but &lt;b&gt;&lt;a href="http://en.wikipedia.org/wiki/United_Kingdom_general_election,_1931"&gt;no government in United Kingdom received majority of votes since 1931&lt;/a&gt;&lt;/b&gt;. And it isn't terribly likely to change - unless a miracle happens in the next elections and in the hung Parliament Liberal Democrats push a Parliamentary reform through.&lt;br /&gt;&lt;br /&gt;Three more governments - Spain, New Zealand, and Australia - are still in highly dubious low 40s, and like with UK and Canada this seems to be the norm. So in one third of top 20 "democracies" governments rule thanks to quirks of electoral systems, not thanks to actual popular support - before tactical voting is even accounted for!&lt;br /&gt;&lt;br /&gt;I haven't studied all 20 systems in detail, so this might be a serious oversimplification, but it seems to me that we could divide them into 3 groups:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Most of continental Europe has proportional representation with mild distortions due to electoral system and low levels of tactical voting - typically government support in high 40s / low 50s&lt;/li&gt;&lt;li&gt;UK and its former dominions tend to have first-past-the-post or otherwise highly distorting systems, but moderate level of tactical voting - typical government support in high 30s / low 40s - but once you account for tactical voting often even less&lt;/li&gt;&lt;li&gt;USA - first-past-the-post with very high distortions (including routine active manipulation of voting system via gerrymandering etc.) and very high level of tactical voting - typical government support in high 40s / low 50s - but this is mostly illusion thanks to very successful exclusion of third parties, and real support is much lower (not that parliamentary majority in USA matters that much, but presidential elections are about equally distorted)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In other words top democracies are either borderline democratic "rule of the rounding error" of continental Europe, or simply not democratic at all in the British and American world. And in case you think I'm exaggerating about United States - &lt;a href="http://www.gallup.com/poll/127343/Congress-Job-Approval-Rating-Improves-Low.aspx"&gt;polls show only 23% or so of voters approve of what Congress is doing&lt;/a&gt;. I wouldn't be surprised if even Chinese Communist Party and Hugo Chávez had far more support than that.&lt;br /&gt;&lt;br /&gt;So if voters have so little influence, what good is Western-style representative democracy? Yes, &lt;a href="http://en.wikipedia.org/wiki/Correlation_does_not_imply_causation"&gt;it correlates with many good things&lt;/a&gt; like civil liberties, and general welfare, but which way does the causation go if there is any at all? And shouldn't countries with less voter control like UK and US be far worse off than those with more voter control like Iceland or the Netherlands? Or maybe they actually are... I'll leave that for another post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-6843906293660277461?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/6843906293660277461/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=6843906293660277461' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/6843906293660277461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/6843906293660277461'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/04/how-much-democracy-in-your-democracy.html' title='How much democracy in your democracy?'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_IYGc_MWwkfw/S8y76YEVR_I/AAAAAAAAA4A/ovyR1pnHnn0/s72-c/dewey_by_angela_n_from_flickr_cc-by.jpg' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-4406672272395274980</id><published>2010-04-15T20:31:00.000+02:00</published><updated>2010-04-15T20:31:02.903+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dating'/><title type='text'>Dating Potential PageRank</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S8daZZPHfXI/AAAAAAAAA3o/Ke2B4HQMas4/s1600/2010040218_by_robynanderson_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="2010-04-02-18 by RobynAnderson from flickr (CC-NC-ND)"&gt;&lt;img alt="2010-04-02-18 by RobynAnderson from flickr (CC-NC-ND)" border="0" height="640" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S8daZZPHfXI/AAAAAAAAA3o/Ke2B4HQMas4/s640/2010040218_by_robynanderson_from_flickr_cc-nc-nd.jpg" width="612" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Some people, when confronted with a problem, think “&lt;a href="http://t-a-w.blogspot.com/2007/06/regular-expressions-and-strings-with.html"&gt;I know, I’ll use regular expressions&lt;/a&gt;”.&lt;br /&gt;Some people, when confronted with a graph problem, think "&lt;a href="http://t-a-w.blogspot.com/2008/01/pagerank-new-addition-to-your-data.html"&gt;I know, I'll use PageRank&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;Being a member of both groups, I was wondering about &lt;a href="http://blog.okcupid.com/"&gt;all the data analyses okcupid was running&lt;/a&gt; - and how can we actually measure dating potential correctly? Using chance of getting a reply to your messages like okcupid's analyses is strongly biased towards Internet trolls who are really good at getting replies - but that's not concern of this post. Let's say we actually have a good measure of how attracted one person is to another (and for simplicity assume it's between 0 and 1, values in between being interpreted as either levels or probabilities).&lt;br /&gt;&lt;br /&gt;The problem is that even such simple kind of attractiveness requires a graph analysis - counting how many people are attracted to someone is not terribly useful as it ignores some distinctions that proper graph analysis would catch:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;how attractive are people being attracted to you? (by recursive graph analysis)&lt;/li&gt;&lt;li&gt;to how many other people are they attracted in addition to you (or do they simply have low standards?)&lt;/li&gt;&lt;li&gt;is it mutual or are you attracted to wrong kind of people?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;What I'm going to do is to turn every person into a website, attractiveness into linking, and compute PageRank on the entire dating market. Scenarios presented here are hypothetical, as right now I'm more interested in figuring out proper analysis tools than in running any real analysis before I know if I'm measuring a sensible thing or not.&lt;br /&gt;&lt;br /&gt;By the way, these graph measures works surprisingly well in presence of an arbitrary mix of hetero-, homo-, and bisexuals in the network, and it's fine if some people are homophobes or ... let's call them "biphiles" - guys who are really into lesbians (think threesomes) and girls who are really into gays - and in either case typically preferring a bisexual opposite gender partner to a heterosexual one - we can just note that in their attractiveness links.&lt;br /&gt;&lt;h3&gt;AttractiveRank&lt;/h3&gt;&lt;br /&gt;The most naive thing to measure would be PageRank of "link to someone if you're attracted to them".&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Scenario 1&lt;/b&gt;. Let's populate the world with 10 ensembles of girls and 10 ensembles of guys separated by which decile of physical attractiveness they fall into. People are only attracted to those at least as attractive as they are.&lt;br /&gt;&lt;br /&gt;The results are quite drastic. Because the 10s are desired by everyone, yet extremely picky, they get really high scores - AttractiveRank by decile is 0.110 0.122 0.138 0.158 0.186 0.227 0.292 0.418 0.759 7.591 - and that's only because the model includes a 10% leak - traditionally meant to represent "user getting bored and typing a new URL" - here maybe "someone getting really really drunk at some party".&lt;br /&gt;&lt;br /&gt;Let's modify it a bit and create &lt;b&gt;Scenario 2&lt;/b&gt; - with people attracted to those of just one decile less too. So 7s are attracted to everyone from 6 to 10 and so on.&lt;br /&gt;&lt;br /&gt;This is great news for 9s, and pretty good news for everyone except 10s - now the ranks are 0.124 0.140 0.162 0.194 0.253 0.394 0.780 1.715 3.119 3.119. All that thanks to just slight lowering of everyone's standards.&lt;br /&gt;&lt;h3&gt;ReciprocityRank&lt;/h3&gt;&lt;br /&gt;There's a serious problem with this anyway. In scenario 1, 10s could have any 3s or 8s if they wanted - but they very much don't. So everybody is actually is a very similar situation - 3s have as many other 3s to date, as 10s have 10s. &lt;br /&gt;&lt;br /&gt;Let's introduce ReciprocityRank - which is just like regular AttractiveRank except non-mutual links are dropped. So it's you're a 7 and you wouldn't actually mind that 9 over there if you thought you had any chances, but as a good graph analyst you know you don't - you forget about that 9 in no time.&lt;br /&gt;&lt;br /&gt;For scenario 1 ReciprocityRank correctly identifies that everyone has the same rank 1. Scenario 2 is more interesting - with ranks of 0.781 1.098 1.058 1.036 1.027 1.027 1.036 1.058 1.098 0.781. First, it is strangely symmetrical - it sucks as much to be a 10s as it does to be a 1s - in one case because your standards are too high, in other because everyone else's standards aren't low enough - but the effect is the same. What might be more surprising is how 2s and 9s are in the best position - not only can they date other 2s and 3s / 8s and 9s respectively - they have access to large number of fairly desperate 1s or 10s. Yes, 10s' desperation comes from unreasonable standards, but it doesn't matter (mathematically that is).&lt;br /&gt;&lt;h3&gt;DateRank&lt;/h3&gt;&lt;br /&gt;That's probably not what we're looking for. You'd think that these 10s are in better situation - they might not have much choice but it's all quality choice. And if you're a really desperate 10 you can always change your mind about one of those 8s that stalks you. A 1 doesn't have such luxury. So let's count unreturned links, but only for 1/5 as much as returned ones, sort of like ref="nofollow" about which search engines changed their mind so many times.&lt;br /&gt;&lt;br /&gt;Scenario 1 results in DateRank by decile of 0.147 0.167 0.194 0.229 0.281 0.359 0.493 0.759 1.474 5.897 - quite reasonable. Scenario 2 results in 0.210 0.282 0.336 0.424 0.569 0.808 1.194 1.755 2.408 2.013 - 9s are strangely still better than 10s - but notice that everyone is equally attracted to both, it's only 9s' lower standards which increase their dating potential.&lt;br /&gt;&lt;br /&gt;Now that our links have weight, let's try &lt;b&gt;scenario 3&lt;/b&gt; - people are attracted to those less attractive than them only 50% as much as to those equally or more attractive than they are. Surprisingly it only helped 9s and now DateRank is 0.188 0.235 0.278 0.349 0.469 0.686 1.080 1.730 2.558 2.426.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S8dafuhWw8I/AAAAAAAAA3w/zFof4exHRRU/s1600/everyone_should_have_their_own_nena_by_tom_poes_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Everyone should have their own Nena by Tom Poes from flickr (CC-NC-ND)"&gt;&lt;img alt="Everyone should have their own Nena by Tom Poes from flickr (CC-NC-ND)" border="0" height="252" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S8dafuhWw8I/AAAAAAAAA3w/zFof4exHRRU/s640/everyone_should_have_their_own_nena_by_tom_poes_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Height and education&lt;/h3&gt;&lt;br /&gt;Now that we have a sensibly defined PageRank - let's try something closer to reality. Let's say guys and girls come in three tertiles by height - short, medium, and tall; and in three independent tertiles by intelligence and education - let's say dumb, average, and smart. Of course they're not directly comparable across gender lines - what counts as tall for a woman might count as medium for a man.&lt;br /&gt;&lt;br /&gt;So the rules of &lt;b&gt;scenario 4&lt;/b&gt; are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Women don't like men shorter than them&lt;/li&gt;&lt;li&gt;Women don't like men dumber than them&lt;/li&gt;&lt;li&gt;Men don't like women taller than them&lt;/li&gt;&lt;li&gt;Men don't like women either smarter on dumber than them&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a href="http://www.overcomingbias.com/2010/04/women-want-heavy-men.html"&gt;It's all loosely based on this paper&lt;/a&gt;, I'm not making this up. Could you guess who has it easier and who has it harder in such situation?&lt;br /&gt;&lt;br /&gt;Here's table for guys (rows by height, columns by intelligence):&lt;br /&gt;&amp;nbsp;&amp;nbsp; 0.240&amp;nbsp;&amp;nbsp; 0.401 &amp;nbsp; 0.985&lt;br /&gt;&amp;nbsp;&amp;nbsp; 0.380&amp;nbsp;&amp;nbsp; 0.703 &amp;nbsp; 1.873&lt;br /&gt;&amp;nbsp;&amp;nbsp; 0.550 &amp;nbsp; 1.047 &amp;nbsp; 2.821&lt;br /&gt;&lt;br /&gt;And here's one for girls:&lt;br /&gt;&amp;nbsp;&amp;nbsp; 0.652&amp;nbsp;&amp;nbsp; 1.091&amp;nbsp;&amp;nbsp; 2.676&lt;br /&gt;&amp;nbsp;&amp;nbsp; 0.436 &amp;nbsp; 0.730&amp;nbsp;&amp;nbsp; 1.789&lt;br /&gt;&amp;nbsp;&amp;nbsp; 0.265&amp;nbsp;&amp;nbsp; 0.414&amp;nbsp;&amp;nbsp; 0.946&lt;br /&gt;&lt;br /&gt;So how good was the analysis? Let's look at girls' table first. It's best for the girl to be short and smart. We could have predicted the shortness - guys not liking taller girls was explicitly in the rules - but why would girls want to be smart if equally many guys will be attracted to her regardless? This is a good example of why graph analysis matters. If a girl is dumb, plenty of men will be attracted to her, but these will all be dumb men shunned by most. If a girl is smart, she gets exactly as many men to choose from, but these are some quality men.&lt;br /&gt;&lt;br /&gt;And unsurprisingly it pays for a man to be either taller or smarter - but intelligence is a far greater factor than height. How did that happen? And why does the same hold for girls? (except with reverse order of height) In this model men are more selective on intelligence than on height - and only same-intelligence combinations are possible (3 combinations out of 9 are ok), while plenty of mismatched height combinations are possible (6 combinations out of 9 are ok). You decide how meaningful this is.&lt;br /&gt;&lt;h3&gt;Age&lt;/h3&gt;&lt;br /&gt;A couple months ago &lt;a href="http://blog.okcupid.com/index.php/2010/02/16/the-case-for-an-older-woman/"&gt;OkTrends wrote an interesting post about men not being terribly attracted to older women&lt;/a&gt;. Now I'm not going to use their data because I'm too lazy to convert pictures into numbers, and it's rather noisy, so the rules of &lt;b&gt;scenario 5&lt;/b&gt; are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;There are 31 ensembles of men and women, for each age between 18 and 48.&lt;/li&gt;&lt;li&gt;Women are attracted to men no older than their age + 6, and no younger than their age - 4; and half as attracted to men between their age - 8 and their age + 10.&lt;/li&gt;&lt;li&gt;Men are attracted to women at most 4 years older than them, and this is a hard limit, no exceptions.&lt;/li&gt;&lt;li&gt;Men are most attracted to women older than their minimum target - which grows linearly from 18 at 23 to 32 at age 48; however they're still open to younger girls (0.5x).&lt;/li&gt;&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/S8dVLy4sexI/AAAAAAAAA3Y/LVLhSgyvYUc/s1600/daterank+scenario+5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="390" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/S8dVLy4sexI/AAAAAAAAA3Y/LVLhSgyvYUc/s640/daterank+scenario+5.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And these are the result - unsurprisingly men peak later than women (around 28, not 22), and while they're not as hot at their peak as women, they don't crash as hard as women either.&lt;br /&gt;&lt;br /&gt;There are some limitations of this analysis - first, because okcupid's data used hard cutoff of 18-year, it discounts the possibility that a given 18 year old might wish to date someone who's 16 or 17 - their actual potential is higher than indicated - and likewise for older people. By the way it is blatantly obvious in okcupid's graphs that there are plenty of early-30s women who lie and pretend they're exactly 29. And if you've ever been there you'll know that there are quite a few under-18s who pretend to be 18. So take their data with a pinch of salt.&lt;br /&gt;&lt;br /&gt;Another problem is assumption that all ensembles are equally sized - in reality while there are about as many 48 old women alive as there are 22 year old, there are far fewer of them on the dating market. Let's run &lt;b&gt;scenario 6&lt;/b&gt; - with ensembles of under-30s are 5x as numerous as ensembles of over-40s, with sizes decreasing linearly during the 30s.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/S8dVP2JwZ2I/AAAAAAAAA3g/9Z1czHMLPjQ/s1600/daterank+scenario+6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="390" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/S8dVP2JwZ2I/AAAAAAAAA3g/9Z1czHMLPjQ/s640/daterank+scenario+6.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The peaks stayed where they were - but the fall with age is far more drastic, especially for women.&lt;br /&gt;&lt;h3&gt;Offensive misogynist advice&lt;/h3&gt;Guardian-reading liberals are asked to skip this section.&lt;br /&gt;&lt;br /&gt;To the extent that these models are valid - the advice they give to men seeking long term relationships would be to go after teenage girls before their peak; while men looking for a quick hookup would do better going after women in their late 20s or early 30s - when they are still hot but already getting desperate. And in either case go after taller girls to avoid competition.&lt;br /&gt;&lt;br /&gt;Model's advice to women is - get pregnant while you can. Unless you're still a teen, your dating value is only going down, and quality of men you will be able to attract for a serious relationship is getting worse each year. And remember - your biological clock is ticking, and setting up a family takes years (accidents excepted). You might think that you're still hot now, but what if after 2 years with someone you decide he's not the right guy, then you spend 2 more years with someone else, then you decide to perhaps maybe try getting a baby - nowhere near as quick and easy as it seems in your 30s - all while your younger friends look more and more tempting to your man; while your eggs are less and less cooperative. The legal system is what it is - in most countries getting married and having a few babies sets up woman for life, so even if it doesn't seem terribly appealing now, you need to decide thinking what will be appealing in a decade.&lt;br /&gt;&lt;br /&gt;That, or freeze your eggs and start saving for regular botox. Works either way.&lt;br /&gt;&lt;br /&gt;Don't blame me - &lt;a href="http://en.wikipedia.org/wiki/Truthiness"&gt;it's the reality which is misogynist&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S8da2c4YJXI/AAAAAAAAA34/eGYULdVsk0M/s1600/kitty_by_rubyblossom_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="kitty by rubyblossom. from flickr (CC-NC-SA)"&gt;&lt;img alt="kitty by rubyblossom. from flickr (CC-NC-SA)" border="0" height="640" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S8da2c4YJXI/AAAAAAAAA34/eGYULdVsk0M/s640/kitty_by_rubyblossom_from_flickr_cc-nc-sa.jpg" width="420" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Code and mathematics&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://taw.chaosforge.org/dating_pagerank.rb"&gt;Code can be downloaded here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;One problem with this approach is existence of two completely arbitrary numbers - booze factor (0.1) and stalker factor (0.2) - they are not derived from anything meaningful and changing them can completely change the results. In fact the booze factor gives a hard floor to how low can anyone's attractiveness fall, and three values of stalker factor (0.0, 1.0, 0.2) result in three completely different ranks discussed here.&lt;br /&gt;&lt;br /&gt;Another problem is assumption of constant ratio of mutual to unreturned attraction. We might as well assign constant percentage of links to mutual attraction and the rest to all links bundled together. It matters as people with low standards would focus on attraction returned instead of wasting their link power / time on stalking. It would be a fairly straightforward modification, and I don't know which version would work better.&lt;br /&gt;&lt;br /&gt;And remember - all models are wrong, some are useful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-4406672272395274980?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/4406672272395274980/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=4406672272395274980' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/4406672272395274980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/4406672272395274980'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/04/dating-potential-pagerank.html' title='Dating Potential PageRank'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_IYGc_MWwkfw/S8daZZPHfXI/AAAAAAAAA3o/Ke2B4HQMas4/s72-c/2010040218_by_robynanderson_from_flickr_cc-nc-nd.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-1507244131062192693</id><published>2010-04-10T02:31:00.000+02:00</published><updated>2010-04-10T02:31:35.859+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='kubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>First look at kUbuntu 10.4 Lucid Lynx or why I hate KDE4</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S7_EUc_Mc6I/AAAAAAAAA2s/IUjoz2X9vNU/s1600/close_lynx_by_tambako_the_jaguar_from_flickr_cc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Close lynx by Tambako the Jaguar from flickr (CC-ND)"&gt;&lt;img alt="Close lynx by Tambako the Jaguar from flickr (CC-ND)" border="0" height="426" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S7_EUc_Mc6I/AAAAAAAAA2s/IUjoz2X9vNU/s640/close_lynx_by_tambako_the_jaguar_from_flickr_cc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;One thing that still amazes me is how in 2010 operating systems still require ridiculous amount of work from inserting installation DVD to having a semi-decent system - even though no technical reasons prevent that from being a 5 minute zero-click operation.&lt;br /&gt;&lt;br /&gt;First, installer decided to crash a few times. It is only beta 2 I've been testing, not final release - but seriously, that just shouldn't happen. Random installer crashes a couple of weeks before Long Term Support release?&lt;br /&gt;&lt;br /&gt;Next there's a few classic system configuration questions - region, timezone, keyboard - and shouldn't they just set the defaults based on DHCP + geoip? Anyway, it's a small issue compared to those to come.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a (cc-nc-nd)="" *best="" ...="" by="" flickr="" from="" href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S7_EjXGL_bI/AAAAAAAAA20/JJ6eS4c8lnM/s1600/eastern_chipmunk_sweet__best_viewed_large_by_vickis_nature_from_flickr_cc-nc-nd.jpg" imageanchor="1" large*="" nature="" s="" style="margin-left: 1em; margin-right: 1em;" sweet="" title="Eastern chipmunk " vicki="" viewed=""&gt;&lt;img (cc-nc-nd)="" *best="" ...="" alt="Eastern chipmunk " border="0" by="" flickr="" from="" height="628" large*="" nature="" s="" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S7_EjXGL_bI/AAAAAAAAA20/JJ6eS4c8lnM/s640/eastern_chipmunk_sweet__best_viewed_large_by_vickis_nature_from_flickr_cc-nc-nd.jpg" sweet="" vicki="" viewed="" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;And here we come to my first big complaint - partitioning. First, why the fuck do they still use swap partitions instead of swap files like every other operating system? Don't make it more difficult for users for some marginal gain in performance. If they cared about performance that much they wouldn't be using KDE, you know. And second - how about some sane defaults? There was an ext3 partition from some old Linux and ntfs partition on that computer, but I had to manually tell the installer what I want to do with them - as if it was so difficult to suggest &lt;tt&gt;/&lt;/tt&gt; and &lt;tt&gt;/media/c&lt;/tt&gt; or somesuch so as defaults.&lt;br /&gt;&lt;br /&gt;Did I mention installer was ridiculously slow? Did they use framebuffer graphics driver or what? Anyway, a few clicks, and the system is installed - this is of course only the beginning.&lt;br /&gt;&lt;br /&gt;Go to the OSX-ripoff system settings panel (Applications &amp;gt; Settings &amp;gt; System Settings), and let's start fixing things.&lt;br /&gt;&lt;br /&gt;It's been an ancient tradition in all operating systems I know that mouse and keyboard defaults are designed for old people with Parkinson's - so we need to go to keyboard, reduce repeat delay and increase repeat rate to saner values. Of course unlike every system since probably Windows 3.11 KDE didn't even bother including test box in its keyboard speed configuration dialog. Seriously guys? If you cannot get even something as obvious as that right, what chance do you have for even chasing the 2x overpriced Apple, let alone Microsoft?&lt;br /&gt;&lt;br /&gt;It's even worse when it comes to configuring mouse. Instead of one mouse speed slider there are 6 confusing numeric entry boxes. Tip: increase the first from 2x to 5x to restore sanity.&lt;br /&gt;&lt;br /&gt;While in keyboard and mouse settings I was wondering if I can make one of special keys launch a browser - but application launching didn't seem to be available anywhere. And I stumbled upon something really ridiculous - monitor brightness controls are under "KDE dæmon". With a ligature. You're trying to outhipster Macs or what? Seriously, fix that spelling - or even better label these "monitor settings" or something like that.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S7_F2KRo9UI/AAAAAAAAA3M/FXyA_bzY-xQ/s1600/hello_by_elekesmagdi_from_flickr_cc-nc.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="hello by elekesmagdi from flickr (CC-NC)"&gt;&lt;img alt="hello by elekesmagdi from flickr (CC-NC)" border="0" height="480" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S7_F2KRo9UI/AAAAAAAAA3M/FXyA_bzY-xQ/s640/hello_by_elekesmagdi_from_flickr_cc-nc.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Now it was time to install some software to make the system useful. Konsole was hidden deep is "Applications &amp;gt; System" and I needed to scroll down to get to it. I know it's &lt;a href="http://lesswrong.com/lw/f1/beware_trivial_inconveniences/"&gt;a trivial inconvenience&lt;/a&gt;, but even Windows fucking 95 had that right. Do not use tiny constant height widgets for Start menu - and to add insult to injury make them use huge icons. It can only display 8 programs without scrolling, and they're not even arranged in any sensible order (it's supposedly alphabetic, except "Konsole" is under T for "Terminal"). Are you trying to repeat the spectacular success of "let's throw away everything and reinvent GUI" OLPC?&lt;br /&gt;&lt;br /&gt;So I was looking for apt-something, and because it was not obvious I just typed "apt" in the program search box - it came with literally 15 results, and KPackageKit was not even in the first half.&lt;br /&gt;&lt;br /&gt;While I looked around the menu I accidentally clicked Akregator - there's zero pixels of inactive margin between clickable areas to run programs - Fitts' Law called me and told to says hello - and instantly proceeded to quit it. Instead of quitting it showed me the "You're not gonna catch me, I'm going to stay in the system tray" message - I tried looking for it but the system tray in fresh KDE is as filled with unnecessary garbage as a Windows 98 installation which has been running since literal year 1998. Why do I need half of that? Anyway, I located some icon which looked like Akregator, asked it to quit and it proceeded to enrage me with "Are you sure you want to quit Akregator" dialog? What kind of question is that? I've told you to quit twice in the last 30 seconds you dumb program! And there are no unsaved documents or anything there - you're a fucking RSS reader! If there were unsaved documents you should tell me about them - and there is never ever under any circumstances any reason why a program should ask if it should quit or not, other than unsaved documents. How is it that every minute of using KDE I stumble upon such a basic usability failure?&lt;br /&gt;&lt;br /&gt;So, KPackageKit started - let's install Firefox because you won't catch me using Konqueror even for web testing and I'm the kind of person who still tests in IE6. Actually I wanted to check if Firefox is maybe already installed - the useless Konqueror is prominently displayed in Start menu, but maybe Firefox is somewhere there. So I typed "firefox" in start menu search box and clicked on something called "Mozilla Firefox Web Browser Installer" - the only result this time. It steals the whole screen for some reason (all right, some video came installers use fullscreen mode, but I've never seen any regular installer do that before...) and when I click "Install"... it tells me that "Requested packages are already installed".&lt;br /&gt;&lt;br /&gt;So is Firefox installed or not? KPackageKit search for firefox only lists "kubuntu-firefox-installer" package - exactly the same one which fails so hard. I even tried to search for "iceweasel" - in case kUbuntu shares Debian's obsession with legalistic minutiae of its trademark amendment to DFSG but no. I typed "firefox" in Konsole to get "Program 'firefox' is not installed. You can install it by typing &lt;tt&gt;sudo apt-get install firefox&lt;/tt&gt;" - apt is the most awesome thing that ever came out of Linux - but when I tried that I've been told firefox package is not available.&lt;br /&gt;&lt;br /&gt;Wait, did they even get apt repository listings? I assumed they must have done it automatically, as KPackageKit showed no button or anything suggesting that manual action was required - but "&lt;tt&gt;sudo apt-get update; sudo apt-get install firefox&lt;/tt&gt;" actually did the trick. &lt;a href="http://t-a-w.blogspot.com/2010/01/best-addons-for-firefox-36.html"&gt;I wrote a whole post about configuring Firefox 3.6 a couple of months ago&lt;/a&gt;, so I won't be repeating myself now.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/S7_E0sKAfYI/AAAAAAAAA28/732EJhBkomk/s1600/faces_of_god_by_unitopia_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Faces of God by Unitopia from flickr (CC-NC-ND)"&gt;&lt;img alt="Faces of God by Unitopia from flickr (CC-NC-ND)" border="0" height="428" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/S7_E0sKAfYI/AAAAAAAAA28/732EJhBkomk/s640/faces_of_god_by_unitopia_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;So, time for some serious package installation. Now I've noticed something I'm rather ambiguous about. Dragging a window to the left or right edge of the screen semi-maximizes it to full height / half width - which is an idea so brilliant that if I ever meet the person who came up with it they're getting some free booze. Unfortunately X is also the only graphics system with usable virtual desktops (if any of you ever mentions Mac Spaces, God is going to drown some puppies) - and usable virtual desktops work even better if screen edges move between desktops - especially since by default there are no keyboard shortcuts to move windows either - Mouse and Keyboard &amp;gt; Global Keyboard Shortcuts &amp;gt; Window to Desktop 1 &amp;gt; Custom &amp;gt; Ctrl+Shift+F1 etc. fixes that fortunately. I like having both ways of moving stuff from one virtual desktop to another, but at a very least one way should be provided, no? (right clicking on title bar doesn't count)&lt;br /&gt;&lt;br /&gt;So package installation. First, 159 packages got updated since beta 2 release - maybe not that surprising so shortly before the big release. And upgrading programs with apt is such a joy after suffering of MacPorts.&lt;br /&gt;&lt;br /&gt;Back to Firefox for a moment. Why is there no &lt;a href="http://www.collegehumor.com/video:1915736"&gt;Bing&lt;/a&gt; in default search engines list, when they have ever obscure ones nobody uses like ask.com and creative commons? Is it all Firefox or just kUbuntu's? It's not a big deal by any means, but if you want Microsoft to offer users choice of browser with its operating system, why not offer users choice of search engine with your browser? And speaking of browser choice - why nobody asks me which browser I want as default? Because the answer is very much not Konqueror. Konqueror is the MSIE of ... well, of not-Microsoft. I have about as much interest in using Konqueror as I have in using Safari or IE. Basically, default browsers for all platforms somehow suck massively, and all sane people use Firefox... or maybe Opera. So I went to youtube to see if Flash works. I've been greeted with the usual "Missing plugins" message, so I clicked some buttons - and the relevant plugins have not been found obviously - why would it work if it can rather not? Fortunately &lt;tt&gt;apt-get install flashplugin-installer&lt;/tt&gt; worked - by this time I abandoned pretty much all hope of installing anything from GUIs and went straight to good old console, as if it was 1999 and I was still using Debian 2.1 slink... By the way did you know youtube had ads? Wow, sometimes I don't realize how different the &lt;a href="http://adblockplus.org/"&gt;Internet for smart people&lt;/a&gt; is from the Internet for everybody else.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S7_FfiKLXdI/AAAAAAAAA3E/Dy_LPEqvbMQ/s1600/crazy_kitten__nikkor_50mm_14_by_merlijn_hoek_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Crazy Kitten? // Nikkor 50mm 1.4 by Merlijn Hoek from flickr (CC-NC-ND)"&gt;&lt;img alt="Crazy Kitten? // Nikkor 50mm 1.4 by Merlijn Hoek from flickr (CC-NC-ND)" border="0" height="428" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S7_FfiKLXdI/AAAAAAAAA3E/Dy_LPEqvbMQ/s640/crazy_kitten__nikkor_50mm_14_by_merlijn_hoek_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;This installation guide/diary gets ridiculously long, and we're still quite far from a usable system. From memory I just typed &lt;tt&gt;apt-get install build-essential irb1.8 irb1.9 octave3.2 unrar ttf-mscorefonts-installer mplayer mc git subversion mongodb&lt;/tt&gt; - I'm sure I forgot half the programs needed, but I'll figure them out someday. By the way, how hard would it be to just have &lt;tt&gt;apt-get install everything&lt;/tt&gt;? Yes, there will be a couple of conflicts, complicated packages, and such, but 90% of packages should be installable everywhere without any hassle. I couldn't find Sun Java, and I know past Open Source javas like Kaffe and gcj were essentially useless - but I'll give that OpenJDK a try. Once. Like I did with Tesco Value.&lt;br /&gt;&lt;br /&gt;At this point the system is reasonably close to usable except for a few things which I'll keep open:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Why don't PageUp / PageDown / Home / End work in Konsole (or xterm)? They work in Firefox just fine and &lt;a href="http://www.microsoft.com/hardware/mouseandkeyboard/productdetails.aspx?pid=043"&gt;my keyboard is not unusual - just awesome&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;How do I make Konsole and Firefox start when I log in? It's right there in dock menu on Mac, so it shouldn't be too hard in KDE either.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-1507244131062192693?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/1507244131062192693/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=1507244131062192693' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1507244131062192693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/1507244131062192693'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/04/first-look-at-kubuntu-104-lucid-lynx-or.html' title='First look at kUbuntu 10.4 Lucid Lynx or why I hate KDE4'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_IYGc_MWwkfw/S7_EUc_Mc6I/AAAAAAAAA2s/IUjoz2X9vNU/s72-c/close_lynx_by_tambako_the_jaguar_from_flickr_cc-nd.jpg' height='72' width='72'/><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-487873045674869765</id><published>2010-04-05T15:15:00.000+02:00</published><updated>2010-04-05T15:15:38.153+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='unix'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>How to kill all your children</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S7ng5Gw6O_I/AAAAAAAAA2U/Ied6GVNNESE/s1600/flinitudei_by_etolane_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Félinitude-I by Etolane from flickr (CC-NC-ND)"&gt;&lt;img alt="Félinitude-I by Etolane from flickr (CC-NC-ND)" border="0" height="468" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S7ng5Gw6O_I/AAAAAAAAA2U/Ied6GVNNESE/s640/flinitudei_by_etolane_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;I'm sure you all had this problem a few times - you tell your children to do something, and they just won't obey. At first you wait, but your patience grows thin until you come to face the inevitable - &lt;b&gt;you have no choice but to kill all you children&lt;/b&gt;. But first you need to find them.&lt;br /&gt;&lt;br /&gt;Unfortunately there's no portable API for traversing process tree to find all your descendant processes. ps, pstree and similar programs use operating system-specific hacks, like reading procfs (Linux) or &lt;a href="http://en.wikipedia.org/wiki/Tasseography"&gt;reading tea leave patterns&lt;/a&gt; (OSX). Even command line options for ps seem to follow three different mutually incompatible systems. And careful tracking of return values of &lt;tt&gt;fork&lt;/tt&gt; won't do you any good, as forked processes might have kept spawning.&lt;br /&gt;&lt;br /&gt;So we'll need more than one line of Ruby. Maybe even as many as five!&lt;br /&gt;&lt;br /&gt;First, let's get raw data out of the operating system. If it was Linux-only exercise, procps would work fine, but some experimentation shows that both Linux and OSX versions of ps support &lt;tt&gt;-eo pid,ppid&lt;/tt&gt; options for getting process parentage graph.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ ps -eo pid,ppid&lt;br /&gt;&amp;nbsp; PID&amp;nbsp; PPID&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0&lt;br /&gt;&amp;nbsp;&amp;nbsp; 10&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&lt;br /&gt;&amp;nbsp;&amp;nbsp; 11&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&lt;br /&gt;&amp;nbsp;&amp;nbsp; 12&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&lt;br /&gt;&amp;nbsp;&amp;nbsp; 14&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&lt;br /&gt;    ... &lt;br /&gt;&amp;nbsp;3367&amp;nbsp; 3366&lt;br /&gt;&amp;nbsp;3382&amp;nbsp; 3367&lt;br /&gt;&amp;nbsp;3441&amp;nbsp; 1240&lt;br /&gt;&amp;nbsp;3442&amp;nbsp; 3441&lt;br /&gt;&amp;nbsp;3460&amp;nbsp; 3442&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Before doing anything else, let's just turn it into a hash.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Hash[*`ps -eo pid,ppid`.scan(/\d+/).map{|x|x.to_i}]&lt;/pre&gt;&lt;br /&gt;Now we know what's parent of every process and the only problem is reverting this graph - something that's strangely missing from the usual Hash/Array toolkit that Ruby and Perl are based upon.&lt;br /&gt;&lt;br /&gt;A brief pause time. You might be wondering what happens when process's parent dies. Normally it is the reparented to its grandparent, or init process, whichever is more sensible based on process groups and other things we don't need to concern ourselves with. So process graph is always proper, unless something weird happened during execution of ps (atomicity in my Unix? it's less likely than you think).&lt;br /&gt;&lt;br /&gt;Now it's time to do a lazy half-unification. Create a list for every process containing just its id, and then go through all processes and add reference to its list to its parents' list. When we're done every process's list will contain at some depth ids of all its descendants. Now it's just &lt;tt&gt;flatten&lt;/tt&gt; and remove yourself from the list to avoid a suicide. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;def Process.descendant_processes(base=Process.pid)&lt;br /&gt;&amp;nbsp; descendants = Hash.new{|ht,k| ht[k]=[k]}&lt;br /&gt;&amp;nbsp; Hash[*`ps -eo pid,ppid`.scan(/\d+/).map{|x|x.to_i}].each{|pid,ppid|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; descendants[ppid] &amp;lt;&amp;lt; descendants[pid]&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; descendants[base].flatten - [base]&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;Once you've found all your children and further descendants, it's just a matter of a quick &lt;tt&gt;kill -9&lt;/tt&gt; to finish them all off.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S7nhZcmhhrI/AAAAAAAAA2k/vDlPQnjR18Q/s1600/death_sentence__help_roni__california_by_fofurasfelinas_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Death Sentence - Help Roni - California by fofurasfelinas from flickr (CC-NC-ND)"&gt;&lt;img alt="Death Sentence - Help Roni - California by fofurasfelinas from flickr (CC-NC-ND)" border="0" height="426" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S7nhZcmhhrI/AAAAAAAAA2k/vDlPQnjR18Q/s640/death_sentence__help_roni__california_by_fofurasfelinas_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;As a bonus, here's the version of the same function in Perl.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;sub flatten {&lt;br /&gt;&amp;nbsp; map{ (ref($_) eq "ARRAY") ? map{flatten($_)}@$_ : $_ } @_;&lt;br /&gt;}&lt;br /&gt;sub descendant_processes {&lt;br /&gt;&amp;nbsp; my ($base) = (@_, $$);&lt;br /&gt;&amp;nbsp; my %parentage = (`ps -eo pid,ppid` =~ /\d+/g);&lt;br /&gt;&amp;nbsp; my %reverse = map { ($_, [$_]) } %parentage;&lt;br /&gt;&amp;nbsp; while (($pid,$ppid) = each %parentage){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; push @{$reverse{$ppid}}, $reverse{$pid};&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; shift @{$reverse{$base}};&lt;br /&gt;&amp;nbsp; flatten($reverse{$base});&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Notice the advantage Ruby has over Perl - and how workaround while annoying are not that difficult:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;There are no default arguments, but we can easily hack them with an equivalent of &lt;tt&gt;[*arguments, default]&lt;/tt&gt; for one-argument functions.&lt;/li&gt;&lt;li&gt;I wanted to say in Perl we don't need &lt;tt&gt;to_i&lt;/tt&gt; - but then it doesn't really change anything in Ruby either, operating on pids like &lt;tt&gt;1234&lt;/tt&gt; instead of &lt;tt&gt;"1234"&lt;/tt&gt; just feels saner.&lt;/li&gt;&lt;li&gt;We can use Ruby autovivification which takes blocks, but Perl autovivification is useless as we want hash values to default to &lt;tt&gt;[key]&lt;/tt&gt; not &lt;tt&gt;[]&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;There's no &lt;tt&gt;flatten&lt;/tt&gt; so we need to implement it (and it's such an extremely common function - the reason it's not in Perl is because Perl started without any support for nested arrays whatsoever)&lt;/li&gt;&lt;li&gt;There's no way to subtract lists from each other like Ruby's &lt;tt&gt;[1,2,3] - [2]&lt;/tt&gt;. Fortunately we know own pid is always first, so we can just shift the list.&lt;/li&gt;&lt;/ul&gt;As always, C++ version left as an exercise for the readers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-487873045674869765?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/487873045674869765/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=487873045674869765' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/487873045674869765'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/487873045674869765'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/04/how-to-kill-all-your-children.html' title='How to kill all your children'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_IYGc_MWwkfw/S7ng5Gw6O_I/AAAAAAAAA2U/Ied6GVNNESE/s72-c/flinitudei_by_etolane_from_flickr_cc-nc-nd.jpg' height='72' width='72'/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-8568683324682194490</id><published>2010-03-29T03:42:00.000+02:00</published><updated>2010-03-29T03:42:02.425+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='osx'/><title type='text'>Personal experience points and OSX menulets</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S7AEO2O98WI/AAAAAAAAA18/E866dYQA5oo/s1600/world_of_warcraft_obsession_by_stacina_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="World of Warcraft Obsession by Stacina from flickr (CC-NC-SA)"&gt;&lt;img alt="World of Warcraft Obsession by Stacina from flickr (CC-NC-SA)" border="0" height="528" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S7AEO2O98WI/AAAAAAAAA18/E866dYQA5oo/s640/world_of_warcraft_obsession_by_stacina_from_flickr_cc-nc-sa.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Doesn't it seem odd how people are willing to spend so much time and effort on doing everything that's best for their in-game characters, and yet they never do anything for their real lives?&lt;br /&gt;&lt;br /&gt;And it's not just highly complex MMORPGs like &lt;a href="http://www.youtube.com/watch?v=msmRwlg23Qc"&gt;World of Warcraft&lt;/a&gt; and &lt;a href="http://www.escapistmagazine.com/videos/view/zero-punctuation/208-Eve-Online"&gt;Eve Online&lt;/a&gt; - look how many people spend how much effort on &lt;a href="http://www.ninjapirate.com/article/farmville"&gt;FarmVille&lt;/a&gt; - which is about logging it at scheduled times and clicking harvest/plow/plant seeds on a large number of virtual squares! Many of them are &lt;a href="http://en.wikipedia.org/wiki/Make_Love,_Not_Warcraft"&gt;the same people&lt;/a&gt; who avoid putting any effort into their real life characters as much as possible.&lt;br /&gt;&lt;br /&gt;There's been some interesting discussion about this real world - gaming world divide, started by this TED talk by Jane McGonigal - like vast majority of TED talks &lt;a href="http://t-a-w.blogspot.com/2009/01/which-crackpot-cult-to-join.html"&gt;it's totally wrong&lt;/a&gt;, and totally worth watching for entertainment value and some intellectual stimulation:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;object height="385" width="640"&gt;&lt;param name="movie" value="http://www.youtube.com/v/dE1DuBesGYM&amp;hl=en_US&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/dE1DuBesGYM&amp;hl=en_US&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;By the way - to people who are new to this blog - links here are like on Wikipedia - they usually lead somewhere interesting.&lt;br /&gt;&lt;br /&gt;Anyway. Assuming you want to achieve some real life outcomes &lt;a href="http://lesswrong.com/tag/akrasia/?sort=new"&gt;but your laziness and disorganization stops you&lt;/a&gt; - like most people - &lt;a href="http://www.reddit.com/r/gaming/comments/bi7rk/being_a_gamer_helped_my_procras"&gt;why couldn't you simply approach life just as if it was a game&lt;/a&gt;? Well for one thing &lt;a href="http://globalguerrillas.typepad.com/globalguerrillas/2010/03/online-games-superempowerment-and-reality.html"&gt;games give you a lot of immediate feedback that you're doing well, but real life doesn't&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So why not fix the problem and create such immediate feedback? This "feedback" is usually little more than just some numbers, progress bars, and make some badges or other icons. Let's do it!&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Experience points log&lt;/h3&gt;Well, first thing you need is log actions which give your real life character &lt;a href="http://lesswrong.com/lw/178/notes_on_utility_function_experiment/"&gt;experience points&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;A log can be a simple semi-structured text file like this.&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;= RULES =&lt;br /&gt;# Every time&lt;br /&gt;+10 write a blog post&lt;br /&gt;+2 read a book&lt;br /&gt;+1 go to gym&lt;br /&gt;+1 play with cat&lt;br /&gt;&lt;br /&gt;# Just once&lt;br /&gt;+100 setup a backup system&lt;br /&gt;+500 organize free elections in Belarus&lt;br /&gt;&lt;br /&gt;= 2010-03-27 Sat =&lt;br /&gt;+10 blog post&lt;br /&gt;+1 played with the cat&lt;br /&gt;&lt;br /&gt;= 2010-03-28 Sun =&lt;br /&gt;+1 played with the cat&lt;br /&gt;+2 read a book&lt;br /&gt;&lt;/pre&gt;Example is completely made-up but you can think of some points for yourself. And of course you can go back and change these rules and numbers any time you want.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/S7AE3p67DMI/AAAAAAAAA2E/oDvIXlp2k5s/s1600/kitten_by_biwanoki_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="kitten by biwanoki from flickr (CC-NC-SA)"&gt;&lt;img alt="kitten by biwanoki from flickr (CC-NC-SA)" border="0" height="428" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/S7AE3p67DMI/AAAAAAAAA2E/oDvIXlp2k5s/s640/kitten_by_biwanoki_from_flickr_cc-nc-sa.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Recording actions&lt;/h3&gt;Unfortunately there are no iPhone apps for that yet, so we'll have to record our actions manually - but let's make it as easy as possible. The log is located at &lt;tt&gt;/home/taw/all/xp/xp.txt&lt;/tt&gt; and I have the bound one of the keys on &lt;a href="http://www.microsoft.com/hardware/mouseandkeyboard/productdetails.aspx?pid=043"&gt;the most awesome keyboard in the world&lt;/a&gt; to open this log in case I want to edit it.&lt;br /&gt;&lt;br /&gt;And because I almost always have terminal open, I wrote a script which appends current date header if it changed, and if you passed it any arguments it appends them to the log, otherwise it opens it. Actually now that I think about it, it wouldn't be a bad idea to get the keyboard shortcut to do this date change too... &lt;a href="http://t-a-w.blogspot.com/2010/03/small-tips-for-making-unix-programming.html"&gt;The script also edits itself if I pass it &lt;tt&gt;--edit&lt;/tt&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;#!/usr/bin/env ruby1.9&lt;br /&gt;exec "mate", __FILE__ if ARGV[0] == '--edit'&lt;br /&gt;&lt;br /&gt;require "time"&lt;br /&gt;require "date"&lt;br /&gt;&lt;br /&gt;fn = "/home/taw/all/xp/xp.txt"&lt;br /&gt;last_day = Date.parse(File.read(fn).scan(/^= (\d{4}-\d{2}-\d{2} \S{3}) =$/)[-1][0]) rescue nil&lt;br /&gt;&lt;br /&gt;out = []&lt;br /&gt;unless last_day == Date.today&lt;br /&gt;  out &amp;lt;&amp;lt; Date.today.strftime("\n= %Y-%m-%d %a =\n")&lt;br /&gt;end&lt;br /&gt;out &amp;lt;&amp;lt; ARGV.join(" ") unless ARGV.empty?&lt;br /&gt;unless out.empty?&lt;br /&gt;  open(fn, "a"){|fh| fh.puts out.join}&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;system "mate", fn if ARGV.empty?&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It's all highly portable so far as long as you adjust paths etc. - nothing OSX-specific about it.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Drawing progress bar&lt;/h3&gt;&lt;br /&gt;It's fairly simple to think of a regexp to parse experience points out of the log - the only nontrivial bit is skipping rules section. But we'd much rather have pretty icon than numbers.&lt;br /&gt;&lt;br /&gt;Well, first let's parse XP and convert it to levels, in a typical quadratic system (code assumes &lt;tt&gt;Symbol#to_proc&lt;/tt&gt;; upgrade your Ruby to 1.8.7 or paste it from core_ext if it dies).&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;module XP&lt;br /&gt;  class &amp;lt;&amp;lt; self&lt;br /&gt;    def read_xp&lt;br /&gt;      log = File.read("/home/taw/all/xp/xp.txt").sub(/\A.*?= \d{4}-\d{2}-\d{2} \S{3} =\n/m, "")&lt;br /&gt;      log.scan(/^\+\d+/).map(&amp;amp;:to_i).inject(&amp;amp;:+)&lt;br /&gt;    end&lt;br /&gt;    def threshold(level)&lt;br /&gt;      10 * (level ** 2)&lt;br /&gt;    end&lt;br /&gt;    def stats(xp=(ARGV[0] || read_xp).to_i)&lt;br /&gt;      level = 0&lt;br /&gt;      level += 1 while xp &amp;gt;= threshold(level)&lt;br /&gt;      [xp, level, xp-threshold(level-1), threshold(level)-threshold(level-1)]&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;tt&gt;XP.stats&lt;/tt&gt; returns an array of [experience ponits, level, XP since acquiring current level, XP needed from current level to next] so code drawing pictures doesn't have to think about it.&lt;br /&gt;&lt;br /&gt;Now the drawing part. We want 32x16 icon - height is constrained by OSX menu bar height, this ratio just looks good. On the bottom we have progress bar, on the top 1-4 colored circles showing your level - levels 1-4 are green, 5-8 are cyan etc. Here are some examples:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S7ADWzHUoKI/AAAAAAAAA10/9cl_K_Fl1TI/s1600/xp-examples.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S7ADWzHUoKI/AAAAAAAAA10/9cl_K_Fl1TI/s320/xp-examples.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;And the code:&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;require "rubygems"&lt;br /&gt;require 'RMagick'&lt;br /&gt;&lt;br /&gt;canvas = Magick::Image.new(32, 16){&lt;br /&gt;  self.background_color = 'transparent'&lt;br /&gt;}&lt;br /&gt;Magick::Draw.new.instance_eval {&lt;br /&gt;  stroke('black')&lt;br /&gt;  fill('none')&lt;br /&gt;  rectangle(2, 9,  30, 14)&lt;br /&gt;&lt;br /&gt;  xp, level, xp_got, xp_needed = XP.stats&lt;br /&gt;&lt;br /&gt;  stroke('none')&lt;br /&gt;  fill('#0F0')&lt;br /&gt;  rectangle(3, 10, 3 + (29-3)*xp_got/xp_needed, 13)&lt;br /&gt;&lt;br /&gt;  level_colors = %w[#0FF #FF0 #F0F #00F]&lt;br /&gt;  while level &amp;gt; 4 and !level_colors.empty?&lt;br /&gt;    fill(level_colors.shift)&lt;br /&gt;    level -= 4&lt;br /&gt;  end&lt;br /&gt;  level.times{|i|&lt;br /&gt;    x = 4+8*i&lt;br /&gt;    circle(x, 4, x, 1)&lt;br /&gt;  }&lt;br /&gt;  draw(canvas)&lt;br /&gt;}&lt;br /&gt;canvas.write(ARGV[0] ? "xp-#{ARGV[0]}.png" : "/home/taw/all/xp/xp.png")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In both parts of the code weird &lt;tt&gt;ARGV[0]&lt;/tt&gt; code is just there for making sample images instead of reading the actual log. Not exactly a masterpiece of modularity, but that's real world Unix scripting for you ;-)&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S7AFPaHuhZI/AAAAAAAAA2M/z32zMpfd0QU/s1600/wich_wun_will_teh_kitty_beet_yous_wif_by_throcket_luther_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Wich wun will teh kitty beet yous wif??? by Throcket Luther from flickr (CC-NC-ND)"&gt;&lt;img alt="Wich wun will teh kitty beet yous wif??? by Throcket Luther from flickr (CC-NC-ND)" border="0" height="428" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S7AFPaHuhZI/AAAAAAAAA2M/z32zMpfd0QU/s640/wich_wun_will_teh_kitty_beet_yous_wif_by_throcket_luther_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Putting it in OSX menu bar&lt;/h3&gt;All this work is fairly useless we put the icons generated somewhere no display - like on OSX menu bar. So far everything has been reasonable system-independent - this part is highly OS-specific - unfortunately all cross-platform GUI toolkits take lowest common denominator approach, and look like shit on all systems equally. But it's really simple code. It's really easy to make the menu icon interactive but then I don't have any particular need for it to be interactive yet. &lt;br /&gt;&lt;br /&gt;It must use OSX-shipped ruby interpretter (&lt;tt&gt;/usr/bin/ruby&lt;/tt&gt;), not one from MacPorts unless you want to deal with some serious library hell.&lt;br /&gt;&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;#!/usr/bin/ruby&lt;br /&gt;&lt;br /&gt;require "osx/cocoa"&lt;br /&gt;include OSX&lt;br /&gt;&lt;br /&gt;class Timer&lt;br /&gt;  def init&lt;br /&gt;    tick&lt;br /&gt;  end&lt;br /&gt;  def tick&lt;br /&gt;    system "./draw_xp.rb"&lt;br /&gt;    $statusitem.setImage(NSImage.alloc().initWithContentsOfFile("/home/taw/all/xp/xp.png"))&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;app = NSApplication.sharedApplication &lt;br /&gt;$statusitem = NSStatusBar.systemStatusBar().statusItemWithLength(NSVariableStatusItemLength)&lt;br /&gt;NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats(1.0, Timer.new, 'tick:', nil, true)&lt;br /&gt;app.run &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Alternatives&lt;/h3&gt;One thing I found while writing this blog is &lt;a href="http://www.chorewars.com/"&gt;Chore Wars&lt;/a&gt;, which seems to be like a website for getting XP for performing real life actions - there might even be a Firefox port for constant visibility, but making it public is kinda creepy. You don't want Belarusian secret police finding out about your "+50 sent information about Lukashenko's secret Swiss bank account to &lt;a href="https://secure.wikileaks.org/"&gt;WikiLeaks&lt;/a&gt;".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-8568683324682194490?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/8568683324682194490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=8568683324682194490' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/8568683324682194490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/8568683324682194490'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/03/personal-experience-points-and-osx.html' title='Personal experience points and OSX menulets'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_IYGc_MWwkfw/S7AEO2O98WI/AAAAAAAAA18/E866dYQA5oo/s72-c/world_of_warcraft_obsession_by_stacina_from_flickr_cc-nc-sa.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-5214557516695015042</id><published>2010-03-27T01:39:00.000+01:00</published><updated>2010-03-27T01:39:51.577+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unix'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Small tips for making Unix programming nicer</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/S61SVlEz98I/AAAAAAAAA1U/9Q2_gUZwglA/s1600/koma_is_a_mac_addict_by_pixteca_mx_from_flickr_cc-by.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="Koma is a Mac Addict by Pixteca MX【ツ】 from flickr (CC-BY)"&gt;&lt;img border="0" height="480" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/S61SVlEz98I/AAAAAAAAA1U/9Q2_gUZwglA/s640/koma_is_a_mac_addict_by_pixteca_mx_from_flickr_cc-by.jpg" width="640" alt="Koma is a Mac Addict by Pixteca MX【ツ】 from flickr (CC-BY)"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Every Unix programmer - and I tell it authoritatively based on my statistically significant sample of 1 - creates millions of tiny scripts that he never bothers publishing. Because they're small, so overhead of cleaning up, documenting, and publishing such script would be immense. And not obviously googleable/bingable/baiduable or whatever people call it these days - it might surprise you but most things in the world are not described by a few well-defined key phrases.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I decided to get a few of such scripts, and throw a bunch of tips on top of them - hopefully you'll find a useful trick or two here.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;How to avoid Unix destroying your files&lt;/h3&gt;First, we need to fix some of the famous Unix brain damage - cp, mv, and bash overwriting your files.&lt;br /&gt;Now a case could be made for rm removing files without asking for confirmation - that's what rm stands for.&lt;br /&gt;But how in the world is this:&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;mv most_awesome_song_ever.mp3 ~/Music/&lt;br /&gt;&lt;/pre&gt;supposed to quietly overwrite existing &lt;tt&gt;~/Music/most_awesome_song_ever.mp3&lt;/tt&gt;?&lt;br /&gt;In 99% of cases this is behaviour you do not want - and if you actually do,&lt;br /&gt;you know to type this instead:&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;mv -f most_awesome_song_ever.mp3 ~/Music/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So open your &lt;tt&gt;~/.bashrc&lt;/tt&gt; and put these commands there (at least ones for mv and cp):&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;alias rm='rm -i'&lt;br /&gt;alias mv='mv -i'&lt;br /&gt;alias cp='cp -i'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;There's one more way Unix can destroy your files - &lt;tt&gt;command &amp;gt;file&lt;/tt&gt; redirection will overwrite file without asking, so it's pretty easy for accidents this way. You really don't want&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;cat &amp;gt;~/notes/girlfriend&lt;br /&gt;&lt;/pre&gt;to lose information about all your exes, do you? (example purely speculative) Get yourself into habit of always saying &lt;tt&gt;command &amp;gt;&amp;gt;file&lt;/tt&gt; - appending to &lt;tt&gt;file&lt;/tt&gt;. 99% of time the file in question won't exist  - so the result will be the same - and in cases where file exists, you remove it first. If you make a mistake, you just ^C and you're back when you started. I haven't used overwriting redirection is years - it's completely purged from my Unix dictionary. Do the same thing.&lt;br /&gt;&lt;br /&gt;By the way some Unix distributions do these by default. And some shells have options for asking for confirmation if &amp;gt; would override files. Do these anyway, just to be sure.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Make shell history useful&lt;/h3&gt;By default shell history stores entire 500 entries - a sensible decision back when you had 4MB of RAM, most of which taken by Emacs. It's just ridiculous these days so as first line of &lt;tt&gt;.bashrc&lt;/tt&gt; put &lt;tt&gt;export HISTSIZE=1000000&lt;/tt&gt;. It must be first, because if bash ever decides to exit without &lt;tt&gt;HISTSIZE&lt;/tt&gt; set to a sane value, it might decide to trim your history file and lose all your history. Of course if you want to tempt the fate...&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Get rid of .pyc file everywhere&lt;/h3&gt;Python's habit of creating &lt;tt&gt;.pyc&lt;/tt&gt; files all over the place gets on my nerves - and it's dubious that they really improve performance that much. If they want to fix performance, how about dealing with GIL first instead of resorting to such hacks? Anyway &lt;tt&gt;export PYTHONDONTWRITEBYTECODE=1&lt;/tt&gt; totally fixes the problem without any side effects.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Saner output from Unix commands&lt;/h3&gt;Compared to fatal loss of data, these are just minor annoyances, but they're really easy to fix, so let's do it.&lt;br /&gt;For stupid reasons &lt;tt&gt;du&lt;/tt&gt; and &lt;tt&gt;df&lt;/tt&gt; commands give sizes in units of 512 bytes or something like that.&lt;br /&gt;Probably some ancient BSD file system allocated files in multiplies of that. That they care more about file system&lt;br /&gt;implementation details than about human usability tells you something about the Unix mindset (if these were at least kBs&lt;br /&gt;that would make sense but no...) - and in any case these assumptions are no longer true on modern operating systems,&lt;br /&gt;which don't rely so mindlessly on blocks. So add these two lines to get human-readable output:&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;alias df='df -h'&lt;br /&gt;alias du='du -h'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;By the way &lt;tt&gt;alias&lt;/tt&gt; command only applies to what you type in the terminal, not what scripts do. So if you run mv or df from scripts, it will not have this default -i/-h. Be cautious.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/S61Spt9209I/AAAAAAAAA1c/SiaHiUNZRGY/s1600/felek__my_home_tiger_by_jarosaw_pocztarski_from_flickr_cc-by.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="FELEK - My Home "Tiger" by Jarosław Pocztarski from flickr (CC-BY)"&gt;&lt;img border="0" height="490" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/S61Spt9209I/AAAAAAAAA1c/SiaHiUNZRGY/s640/felek__my_home_tiger_by_jarosaw_pocztarski_from_flickr_cc-by.jpg" width="640" alt="FELEK - My Home "Tiger" by Jarosław Pocztarski from flickr (CC-BY)"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Final touches for .bashrc&lt;/h3&gt;If some commands require root access, and you're tired of typing &lt;tt&gt;sudo this&lt;/tt&gt; and &lt;tt&gt;sudo that&lt;/tt&gt;, just add a few of:&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;alias port='sudo port'&lt;br /&gt;alias gem='sudo gem'&lt;br /&gt;alias apt-get='sudo apt-get'&lt;br /&gt;alias reboot='sudo reboot'&lt;br /&gt;&lt;/pre&gt;to your &lt;tt&gt;.bashrc&lt;/tt&gt;. They only save you a little typing, and don't chance anything about security (you still need your admin password etc.), but why type more if you can type less.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Colorful shell&lt;/h3&gt;Depending on your distribution you might already have colors in your shell or not.&lt;br /&gt;&lt;tt&gt;export CLICOLOR=1&lt;/tt&gt; in &lt;tt&gt;.bashrc&lt;/tt&gt; will convince many commands that you want nicely colored output.&lt;br /&gt;To tell that to git, you need to add to your &lt;tt&gt;.gitconfig&lt;/tt&gt;:&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;[color]&lt;br /&gt; diff = auto&lt;br /&gt; status = auto&lt;br /&gt; branch = auto&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And now your Unix comes with more rainbows.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;GNU grep must die&lt;/h3&gt;Never use GNU grep. Use pcregrep for everything - or rak/ack if you want coloring, automatic .git directory skipping etc. Unfortunately pcregrep is ridiculously slow to type so do yourself a favour and add&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;alias gr='pcregrep'&lt;br /&gt;&lt;/pre&gt;to make your life even easier.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;wget HTTPS nonsense&lt;/h3&gt;I don't know if it's just MacPorts' version of wget, or is it universal, but it seems to miss all HTTPS root CAs (take that VeriSign!). Another alias solves the problem. By "solves" I mean it opens a massive security vulnerability, but we already know that CAs will create fake certs for NSA, Mossad, RIAA, and Hackney Borough Council if asked, so the vulnerability is much less than it seems at first.&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;alias wget='wget --no-check-certificate'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Use ruby or perl for nontrivial actions&lt;/h3&gt;In early 1980s, before Perl got invented to solve exactly this problem I talk about,&lt;br /&gt;people would write insanely complicated shell scripts to automate their Unix actions.&lt;br /&gt;&lt;br /&gt;Unfortunately you cannot really serve two aims at once - being highly accepting for casual real time input,&lt;br /&gt;and being highly robust for programmable interfaces - so shell sucks at both. Fortunately the problem&lt;br /&gt;is solved since December 18, 1987 when Perl got invented just for this reason.&lt;br /&gt;&lt;br /&gt;And yet - many people act as if 12/18 never happened. Wake up sheeple!&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYGc_MWwkfw/S61TR2COn-I/AAAAAAAAA1k/QIphjKOo41E/s1600/curious_sheeple_by_ztephen_from_flickr_cc-nc-sa.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="curious sheeple by ztephen from flickr (CC-NC-SA)"&gt;&lt;img border="0" height="480" src="http://1.bp.blogspot.com/_IYGc_MWwkfw/S61TR2COn-I/AAAAAAAAA1k/QIphjKOo41E/s640/curious_sheeple_by_ztephen_from_flickr_cc-nc-sa.jpg" width="640" alt="curious sheeple by ztephen from flickr (CC-NC-SA)"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Shell is ridiculously stupid. It has arcane and fragile escaping rules.&lt;br /&gt;It cannot even reliably expand a file list:&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;$ ls ~/porn/*.jpg&lt;br /&gt;-bash: /bin/ls: Argument list too long&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;How useless is that? And don't even get me started with &lt;tt&gt;xargs&lt;/tt&gt;, &lt;tt&gt;find&lt;/tt&gt;, &lt;tt&gt;awk&lt;/tt&gt; and the rest horrible mess.&lt;br /&gt;&lt;br /&gt;How do you find top largest MP3 files - in any subdirectory?&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;ruby -e 'Dir["**/*.mp3"].sort_by{|fn| -File.size(fn)}[0,10].each{|fn| system "ls", "-l", fn}'&lt;br /&gt;&lt;/pre&gt;And yes, I'm calling ls 10 times here, as otherwise it would see fit to rearrange them alphabetically just for lulz.&lt;br /&gt;This Ruby code is really easy and really obvious.&lt;br /&gt;&lt;br /&gt;What would be shell solution? Something like this:&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;find . -name '*.mp3' -print0 | xargs -0  ls -l | sort -k25 -rn | head -n 10&lt;br /&gt;&lt;/pre&gt;You need find and xargs to avoid "argument list too long" error, then you need &lt;tt&gt;-print0&lt;/tt&gt; and &lt;tt&gt;-0&lt;/tt&gt; because file names can contain single quotes or - longcat forbid - spaces! Then you need to manually count at which position of &lt;tt&gt;ls -l&lt;/tt&gt;'s output is file name (conveniently ls -l uses something close enough to fixed column width to make sort work - otherwise you'd have to do some heavy &lt;tt&gt;awk&lt;/tt&gt;ing around it), then you finally &lt;tt&gt;head&lt;/tt&gt;. Personally I prefer waterboarding to having my brain suffer any of this.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Learn GUI integration basics&lt;/h3&gt;The chasm between nice programmable world of Unix terminals and hostile world of closed GUI programs can be to some extend lessened.&lt;br /&gt;&lt;br /&gt;If you use KDE, &lt;tt&gt;&lt;a href="http://en.wikipedia.org/wiki/DCOP"&gt;dcop&lt;/a&gt;&lt;/tt&gt; command gives you decent level of control over GUI programs and you can explore the interface from command line.&lt;br /&gt;&lt;br /&gt;On OSX there's a convenient &lt;tt&gt;open&lt;/tt&gt; command for opening URLs and files with the most sensible program. And &lt;tt&gt;osascript&lt;/tt&gt; command, which is about as powerful as KDE's dcop except far more painful to use by trying to be "friendly" too hard, resulting in unsurprising failure. Google will help.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Editing your scripts made easy&lt;/h3&gt;You probably have five billion scripts in your path (you have &lt;tt&gt;~/bin&lt;/tt&gt; or &lt;tt&gt;~/local/bin&lt;/tt&gt; or &lt;tt&gt;~/gitrepo/bin&lt;/tt&gt; or such in your &lt;tt&gt;$PATH&lt;/tt&gt; right?) - and you're tweaking them all the time.&lt;br /&gt;Typing &lt;tt&gt;mate `which some_script.rb`&lt;/tt&gt; takes forever and is not easily tabbable (Ubuntu has really good&lt;br /&gt;bash autocompletion package which might alleviate this problem a lot - but most distros don't).&lt;br /&gt;&lt;br /&gt;Wouldn't it be easier to just say &lt;tt&gt;some_script.rb --edit&lt;/tt&gt;? It would also be far easier to type - &lt;tt&gt;somTAB --edit&lt;/tt&gt;. It's really easy. Just put this below the shebang line of all your scripts:&lt;br /&gt;&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;# Ruby&lt;br /&gt;exec 'mate', __FILE__ if ARGV[0] == '--edit'&lt;br /&gt;&lt;br /&gt;# Perl&lt;br /&gt;exec "mate", __FILE__ if $ARGV[0] eq '--edit';&lt;br /&gt;&lt;br /&gt;# Python&lt;br /&gt;import os, sys&lt;br /&gt;if sys.argv[1:2] == ['--edit']: os.execlp("mate", "mate", __file__)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If someone passed --edit as first argument it will start the editor instead of running the script - otherwise it will not affect it in any way.&lt;br /&gt;&lt;br /&gt;Python code is fairly painful because Python decided to keep low level C interface to exec* instead of providing sane Perl-style interface. And you know something is wrong if Perl is described as "sane" compared with you.&lt;br /&gt;&lt;br /&gt;Feel free to figure out how to get this effect with C++.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S61TgQKxaGI/AAAAAAAAA1s/Cq8A-hQ3iYI/s1600/prrrrrrr_by_milkyway_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="PRRRRRRR!!! by milky.way from flickr (CC-NC-ND)"&gt;&lt;img border="0" height="440" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S61TgQKxaGI/AAAAAAAAA1s/Cq8A-hQ3iYI/s640/prrrrrrr_by_milkyway_from_flickr_cc-nc-nd.jpg" width="640" alt="PRRRRRRR!!! by milky.way from flickr (CC-NC-ND)" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Find kittens for your blog&lt;/h3&gt;I only want CC kittens, so nobody sues my blog. Except for defamation, that I don't mind. Here's the script&lt;br /&gt;&lt;br /&gt;&lt;pre style="margin-left: 5em;"&gt;#!/usr/bin/env ruby&lt;br /&gt;uri = "http://www.flickr.com/search/?q=#{ARGV.join '+'}&amp;amp;l=cc&amp;amp;ss=2&amp;amp;ct=0&amp;amp;mt=all&amp;amp;adv=1&amp;amp;s=int"&lt;br /&gt;# On OSX&lt;br /&gt;system "open", uri&lt;br /&gt;# On Linux&lt;br /&gt;#system "firefox", "-new-tab", uri&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;By the way could someone get Linux distros to copy &lt;tt&gt;open&lt;/tt&gt; command? It's really simple and really useful.&lt;br /&gt;&lt;br /&gt;That's it for today. Enjoy your Unix.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27488238-5214557516695015042?l=t-a-w.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://t-a-w.blogspot.com/feeds/5214557516695015042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=27488238&amp;postID=5214557516695015042' title='26 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/5214557516695015042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/27488238/posts/default/5214557516695015042'/><link rel='alternate' type='text/html' href='http://t-a-w.blogspot.com/2010/03/small-tips-for-making-unix-programming.html' title='Small tips for making Unix programming nicer'/><author><name>taw</name><uri>http://www.blogger.com/profile/16972845140253292628</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_IYGc_MWwkfw/S61SVlEz98I/AAAAAAAAA1U/9Q2_gUZwglA/s72-c/koma_is_a_mac_addict_by_pixteca_mx_from_flickr_cc-by.jpg' height='72' width='72'/><thr:total>26</thr:total></entry><entry><id>tag:blogger.com,1999:blog-27488238.post-2728281503836992594</id><published>2010-03-20T13:29:00.000+01:00</published><updated>2010-03-20T13:29:21.670+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='evolution'/><category scheme='http://www.blogger.com/atom/ns#' term='status'/><title type='text'>How to be a high-status blogger (like Robin Hanson)</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_IYGc_MWwkfw/S6S-3fx-rkI/AAAAAAAAA1M/970BJ0fthwM/s1600-h/p1010334titfanee_030208bizous__vous_by_julicathcath_pas_vraiment_prsente_from_flickr_cc-nc-nd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" title="P1010334-Tit'Fanee 03.02.08...Bizous à vous...!!! by julicath/Cath (pas vraiment présente) from flickr (CC-NC-ND)"&gt;&lt;img alt="P1010334-Tit'Fanee 03.02.08...Bizous à vous...!!! by julicath/Cath (pas vraiment présente) from flickr (CC-NC-ND)" border="0" height="624" src="http://2.bp.blogspot.com/_IYGc_MWwkfw/S6S-3fx-rkI/AAAAAAAAA1M/970BJ0fthwM/s640/p1010334titfanee_030208bizous__vous_by_julicathcath_pas_vraiment_prsente_from_flickr_cc-nc-nd.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Welcome my to highly inflammatory and highly meta post, which I wrote to show-off my high status as a blogger, obviously. I could have made this post more structured and logical, but it would suggest I actually care about my readers, and caring is low status, right? Or is it? (making this sound deeper will definitely make the subject more high status).&lt;br /&gt;&lt;br /&gt;So what's &lt;a href="http://www.overcomingbias.com/"&gt;Robin Hanson&lt;/a&gt;'s theory of status? The basics are simple - people have different hierarchical "status" in society, which is based on organization of paleolithic tribes of hunter-gatherers, and before that of primate bands. These monkeys/cavemen/or such would always try to figure out what's whose status in the tribe so they could engage in tribal politics effectively, but people are not cats so they don't come with captions (making silly jokes is high status, I think), so they had to rely on subtle cues - minor differences in behavior between high-status and low-status monkeys. If you acted like a high-status monkey, everyone would assume you're a high-status monkey and treat you accordingly.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYGc_MWwkfw/S6S9NDHlNGI/AAAAAAAAA08/DIJSeXoMz-Y/s1600-h/129016802167326655.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="572" src="http://4.bp.blogspot.com/_IYGc_MWwkfw/S6S9NDHlNGI/AAAAAAAAA08/DIJSeXoMz-Y/s640/129016802167326655.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Funnily enough, there are even some experiment showing such effects in monkeys. (I could find you a Wikipedia link, but I already told you what caring would signal) The difference is that with monkeys it's pretty easy to figure out what high-status or low-status behavior would be - and quite easy for researchers to fake it - so it's nice testable theory.&lt;br /&gt;&lt;br /&gt;But that's not what Hansonian status is about. Meta time! People incorrectly assume that bloggers write because they believe what they're writing to be true! By showing a few examples of popular and yet false blogs &amp;lt;GLaDOS&amp;gt;insert link to a study showing this here&amp;lt;/GLaDOS&amp;gt;, we can convincingly demonstrate that bloggers don't write things that are true, but to signal their high status. It doesn't really follow? Well, it doesn't matter - it works well enough for showing off you're smart and high-status, and that's the only thing which counts in life!&lt;br /&gt;&lt;br /&gt;That's basically the methodology. And it's not just Robin Hanson, I've seen far too many people on &lt;a href="http://lesswrong.com/"&gt;Less Wrong&lt;/a&gt; doing the same - without any doubt they're just trying to associate with high status originator this way.&lt;br /&gt;&lt;br /&gt;And what are these high and low status signals? Now it gets even more interesting:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Anything for which you can make a &lt;a href="http://en.wikipedia.org/wiki/Just-so_story"&gt;just-so story&lt;/a&gt; that it might have been a high/low status signal in some imaginary primate/Neolithic community, can be treated as high/low status signal without any further evidence&lt;/li&gt;&lt;li&gt;Anything which some of people you think are high/low status today seem to be doing, can be treated as high/low status signal, or not, depending on how you feel about it, and regardless of there existing even a correlation.&lt;/li&gt;&lt;li&gt;Anything that seems high status might be treated as low status, because obviously only low status person would try so hard&lt;/li&gt;&lt;li&gt;Anything that seems low status might be treated as high status, because obviously only high status person could signal that they don't care what others think like that&lt;/li&gt;&lt;/ul&gt;That is - virtually any behavior can be described as high or low status, depending on how you're feeling on a particular day. Mocking others' theories like that is obviously high status, as some high status people like... let's say Jon Stewart do so. And I don't have to care if other high status people like let's say The Pope don't - or if it might be as common or more among the low status people - such concerns are no part of the Hansonian methodology. &lt;br /&gt;&lt;br /&gt;This all has zero predictive power, and no falsifiability whatsoever.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYGc_MWwkfw/S6S-uMmgVcI/AAAAAAAAA1E/MkTcfl8kgRU/s1600-h/alpha+cat.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="574" src="http://3.bp.blogspot.com/_IYGc_MWwkfw/S6S-uMmgVcI/AAAAAAAAA1E/MkTcfl8kgR
