Sunday, December 14, 2008

iPhone App Pyramid Scheme Plan

Where is the next fertile soil for a pyramid scheme? Why, the iPhone Application store, of course! Following these few easy directions, you can scam millions of yuppies for fun and profit.

How: First, create an iPhone Application with some kind of cheesy social-networking appeal (e.g. 'How many friends do you REALLY have?'). It doesn't really matter what the functionality of the app is as long as each install of the app is assigned a unique identifier. The buyer will enter the id of the person who referred them to the app. In this way, an n-ary tree can be constructed (with you at the root) of subsequent referrals and installs of the app. Motivate the spread of the app by promising some amount of money to a user every time someone else buys the app and enters the his or her 'promo code.' Price the app such that you net the difference of the cost of the app and the amount you are paying out on each install.

Why it will work: People who purchase iPhones have a proven record of buying a lot of iPhone applications with their disposable income. It is perfectly reasonable to believe that many of them would not mind spending a few bucks more to purchase another novelty application (indeed, some have proven that they will spend a great deal for a novelty application / status symbol). Second, sites like Facebook have proven users' insatialbe thirst for social applications that connect them to their friends/coworkers/strangers/etc. Many of these applications exploit some kind of emotional dynamic (for instance, who are your 'Top Friends'?) to appeal to users. The sucess of these applications leaves no doubt that other appeals of the same kind would find an audience. Third, the iPhone App store provides a quick and easy means of distribution and, presumably, payment. Finally, every pyramid scheme exploits people's motivation for profit, a powerful motive indeed.

Variables: The setting of a reasonable price and payout is critical. Ask too much and nobody will buy the app; ask too little and you won't make much money. Promise too much as a payout and you won't make much money, promise too little and the app will not virally spread. Another important decision is the appeal of the application -- how are you going to convince uses to buy the application in the first place? What is the most compelling social/emotional/psychological/whatever message that you can send to them that makes them want to buy? Going hand in hand with that, what does the application actually do? Does it simply redirect to a web page showing some statistics of who has recruited the most people to the scheme, or does it have something more sophisticated?

Unknowns: Apps need to be approved by Apple and can be yanked by Apple at any time, with or without explanation. The app needs to be written in such a way that it does not appear to be something that Apple would find questionable. The legality of these practices is another issue. Depending on what the function of the application is, you might be able to make a case that you are actually delivering a product to the user. Another unknown is the most effective way to move many small payments of money between people, and what kind of cost is incurred for those services.

Saturday, November 29, 2008

Funny UNIX tricks from Slashdot

There was a recent story on slashdot about useless (or useful) things one can do in UNIX. Being a command line junkie, I read through virtually every comment (all 2300+ of them) to learn some new tricks. Here are some of the better ones:

  • Bash History
    • history -c # clear history (good for preserving privacy/passwords, or check out the more precise -d option)
    • In vi command mode, type /query and hit Enter to search history, n to keep searching backwards, N to search forwards
  • vimdiff
    • vimdiff original_file patched_file
    • unified format: open original file, then :vertical diffpatch path/to/diff
  • Encryption
    • openssl aes-256-cbc -a -e -salt -in INPUT_FILENAME -out OUTPUT_FILENAME # encrypt
    • openssl aes-256-cbc -a -d -salt -in INPUT_FILENAME -out OUTPUT_FILENAME # decrypt
    • echo Oe lbh pna vzcyrzrag UK tbireazrag fgnaqneq rapelcgvba jvgu ge | tr a-z n-za-m # Rot 13 encrypt/decrypt
    Others:
    • sleep 8h; cat /dev/urandom > /dev/dsp # alarm clock
    • eject -T # close cd tray if open, open if closed (useful to find out which physical machine you are logged into)
    • sl # punish users who accidentally type 'sl' instead of 'ls'
    • eposd && say 'hello' # make the computer talk
    • :(){ :|:& };: # forkbomb (space required between { and :) (protect against this with ulimit -u)
    • for I in $(seq 1 100) ; do echo $I; sleep .25; done | dialog --gauge "PIZZA" 6 50 100 # Pizza timer via dialog

    Wednesday, October 29, 2008

    New MTV Video Site's Censorship -- Bleeping out Names of File-Sharing Software

    MTV has just launched a new online video site. While I won't go through the trouble of mocking the site (or the TV network) for its irrelevance (please visit this slashdot thread for plenty of that), it is worth noting that it does have one feature that other video sites do not: in-video censorship! As this observant slashdot commenter says:

    I was perusing this yesterday, and came across the Weird Al video "Don't Download This Song". One line in the original song goes:
    o/~ Like Morpheus or Grokster or Limewire or KaZaA o/~

    But the version on the new MTV site goes:
    o/~ Like *beep* or *beep* or *beep* or *beep* o/~

    Does anyone know if it was aired on MTV/VH1 this way, or is this unique to the web version?

    MTV: http://www.mtvmusic.com/video/?id=108884 [mtvmusic.com]
    Youtube: http://www.youtube.com/watch?v=Yz-grdpKVqg [youtube.com]

    Update
    More coverage: Slashdot Techdirt

    Thursday, October 23, 2008

    Interesting New Perspective on DRM

    While browsing a Slashdot thread about a purported "open-source DRM" product I came across an interesting comment by a guy named Sancho. While I had always viewed DRM as a uniquely new development, he ties it to practices that have been occurring in the recording industry for some time:

    I tend to think of it as ensuring repeated sales of their art throughout their lifetimes.

    For a while there, ensuring this was as easy as making sure that your music was released on the format du jour. Records, 8-tracks, cassettes, CDs.... With the advent of digital music sans a physical medium, this trend of rebuying all of your albums is at risk. Suddenly, you're faced with customers never having to rebuy the White album, and you see your sustained profits going down the tubes.

    DRM solves that. Now, rather than coming out with a new format every few years, you just have to come up with a new DRM scheme and turn off the old servers. Because the devices playing the music are somewhat general purpose, it's easy to move quickly--you don't have to worry about market penetration for the players, because it's just a free software update away.

    One small point: in the old days, format upgrades, say from tape to CD, often brought with them added benefits (better sound quality, more convenient access to songs, larger storage space, etc.) so there were actually justifiable reasons to upgrade. Now, switching from one DRM-encumbered format to the next offers no such incentives for the consumer.
    Link

    Friday, October 10, 2008

    wmctrl and friends

    wmctrl seems like an awesome utility. I first read about it in Kyle Rankin's Linux Journal column here. The wmctrl project page also has links to a bunch of other desktop-automation and related utilities. This is all going in the "to learn when I have some spare time" file along with screen.

    Monday, September 08, 2008

    Critique of Zittrain's "The Future of the Internet and How to Stop It"

    One book that the technorati have been talking about recently (ok, not so recently... it took me a while to write this article) is Jonathan Zittrain's The Future of the Internet and How to Stop It. For a book written by a co-founder of the Berkman Center and someone who is a remarkably good speaker, I found the work to be disappointing. The book's argument is not convincing and the writing seems to lack discipline, often wandering from one loosely related subject to another.

    Zittrain's main point is that the security failings of generative technologies will push consumers to buy more restrictive, and supposedly safer, devices. This claim has a number of problems with it. The first is that tethered devices are not safer or more secure than generative ones -- in fact, normally the opposite is true. Compare the number of vulnerabilities in the Windows operating systems vs the number in Linux or BSD operating systems. Or bugs in Internet Explorer vs bugs in Firefox. This claim is even more dubious the more control the manufacturer has over the device: Richard Stallman points out in his response to Zittran that the iPhone's remote kill-switch makes the iPhone "designed for remote attack by Apple."

    The second problem with Zittrain's principal claim is that a consumer has no incentive to prefer a non-generative device. Since non-generative devices are less secure than generative ones, any purported advantage that the non-generative device manufacturer could claim is lost. There is empirical evidence to support the belief that consumers prefer generative devices --Stallman cites the number of jailbroken iPhones as an example. Roger Grimes adds in his response: "It’s hard to say that closed systems are taking a more prominent role when open examples abound. Even the 'closed' systems he mentions are becoming more open thanks to competition and customer demand."

    Even if, for the sake of argument, locked-down devices were somehow more secure than generative devices, consumers wouldn't necessarily migrate to non-generative appliances because users rarely make purchasing decisions based on security. Most computers are purchased because the user is comfortable with the platform or because he thinks that the computer is pretty or because that particular computer is necessary to run some type of software. Rarely will a run-of-the-mill consumer take into account a record of operating system vulnerabilities or the pros and cons of different systems architectures when deciding between OSX and Windows.

    There are other shortcomings of the book besides the weakness of the main argument. For one, Zittrain mistakes generativity as being a zero-sum game: something is either generative or it isn't. There is a continuum of generativity: for instance, Linux is more generative than Windows XP, but Windows XP is more generative than Windows Vista. It is a fallacy to simply assume that all products fall into one non-generative bucket or the other generative one.

    For a book whose title suggests solutions to the problems with the Internet, Zittran's ideas underdeliver. Virtual machines, extra-legal incentives, data portability and network neutrality are all things that are familiar, and have been, to policymakers and programmers for a while. In a book such as this which only worries about theoretical overtures and not about the detailed technical implementation, more out-of-the-box, grander thinking and proposals would have been welcome.

    The book has a couple of chapters that feel decidedly out of place. The final chapter regarding privacy and the chapter exploring Wikipedia both don't seem to fit in to the framework of the book. That being said, both are certainly worthy of scholarship on their own merits. I particularly found the chapter on privacy engaging, if not particularly relevant to the rest of the book.

    Zittrain's book is still worth a read: it addresses areas of concern in today's Internet and references much interesting material. The end result, however, is unconvincing and disappointing -- keep a few grains of salt handy when reading.

    =========================================
    REFERENCES / FURTHER READING

    Jonathan Zittrain
    http://bostonreview.net/BR33.2/zittrain.php
    "Protecting the Internet Without Wrecking It"

    Richard Stallman
    http://bostonreview.net/BR33.2/stallman.php
    "The root of this problem is software controlled by its developer"

    Bruce M Owen
    http://bostonreview.net/BR33.2/owen.php
    "As long as flexibility has value to users, suppliers will have incentives to offer it"

    Roger A Grimes
    http://bostonreview.net/BR33.2/grimes.php
    "Fixing Web insecurity requires more than a caring community"

    Hal Varian
    http://bostonreview.net/BR33.2/varian.php
    "Ultimately, the best protection is an informed buyer who demands openness"

    Susan Crawford
    http://bostonreview.net/BR33.2/crawford.php
    "In the eyes of many exiting institutions, security isn't a problem -- it's an opportunity"

    David D. Clark
    http://bostonreview.net/BR33.2/clark.php
    "We need to develop a socially embedded online experience"

    Jonathan Zittrain
    http://bostonreview.net/BR33.2/zittrainresponse.php
    "The best solutions don't assume a zero-sum tradeoff between security and generativity"

    Coverage on BoingBoing

    Ars Technica review and interview

    Friday, August 29, 2008

    Watch High Quality YouTube Videos by Default

    Explained here. Man, I missed the boat on this one... it's been out for half a year!

    Cool Gmail Feature -- Periods do not Matter

    It's true: john.doe@gmail.com is the same email address as johndoe@gmail.com as far as Gmail is concerned. And to think that everyone makes such a big fuss about making sure you have that period in the right place when they give out their emails...

    This feature is documented in Gmail help here. Gmail even idiot-proofs this feature by having a link to the docs when you receive an email at a different address from the one you registered (see photo).

    Some have used this feature to their advantage to reduce spam or create multiple accounts on a web service that all send mail to the same Gmail address.

    Friday, August 22, 2008

    Thoughts on Facebook and Privacy (or Lack Thereof)

    After watching a DEFCON 16 presentation about the vulnerabilities in social networks, I reflected further upon Facebook and the privacy it offers you and me, which is close to nil. Your guarantees to privacy on Facebook depend on a multitude of assumptions, all of which are quite poor. [B]

    First, you are trusting that the Facebook developers have implemented the privacy controls correctly such that there is no inadvertent information leakage on the site as a result of bugs. I write code for a living, and let me tell you, bug-free code does not exist. Facebook, like other applications, has had its share of bugs to scramble to fix in the past (including at least one truly amateur mistake) and the future will be (and the present is) no different.

    Second, you are assuming that you can configure the myriad privacy options correctly such that every piece of information on your site is accessible to only those that you want it to be. Are you really sure that marking one person as only being allowed to see your limited profile and specifying that picture as globally viewable, for example, will turn out the restrictions you desire for the correct people? How can you tell which preferences override which? It would certainly be tedious to register other accounts (or use friends') and test various combinations of privacy features against their profiles and I am not aware of anyone that does this.

    Third, anyone that can see your information is capable of leaking it to the public. [A] With the addition of every friend you are increasing the chance that your pictures, contact info, videos, etc. will be posted and shared outside of the Facebook walled garden. It is simply not possible that each of your 500 friends is not susceptible to give away information that you thought was just between you and them, especially when they have some kind of (monetary or otherwise) incentive to do so. The scenarios of a rival political party digging up dirt on a candidate and gossip magazines researching what someone did last night both come to mind.

    Fourth, all of your information can be accessed by any Facebook engineer or executive who choses to do so. The engineers likely need access to real-world pages to debug their code, and the managers can order information from a compliant underling (if Facebook doesn't have internal tools set up already for them to access this information). And let's not forget everyone else that works there (sales, PR, HR, etc.) who can request your personal information as a favor from an engineer friend.

    Fifth, just as with any other website, information on Facebook can be subpoenaed in a trial. Facebook, needing to comply with the law, will gladly turn over your personal information to any judge who so wishes.

    Sixth, let's not forget the countless ways Facebook could involuntarily compromise your information. A malicious hacker could slurp down personal data off the site. A Facebook employee could negligently leave an unencrypted disk drive with your information on it in a public place. Etc.

    The only conclusion is this sound advice: don't put anything on Facebook that you don't want to be exposed to the world. Because chances are, sooner or later, it will be.

    Footnotes:

    [A] This is, of course, assuming that your group of Facebook friends can not be considered 'the public.' With the amount of friends some have, and especially one's willingness to accept any request that comes their way and fire out friend requests at random, this distinction begins to blur.

    [B] I was going to add this post to my Facebook Sucks article but it became too long and I thought it deserved a post of its own.

    Updates:

    Here is a post for those that want a HOWTO for micromanaging their privacy settings on Facebook. (Even Schneier likes it).

    Here is a Slashdot story about a court demanding Facebook information pursuant to a case

    Tuesday, August 19, 2008

    DEFCON 16

    DEFCON 16 was awesome, as expected. Some highlights:
    • The first presentation I went to was called "Hacking in the Name of Science." Here a bunch of University of Washington grad students and a professor discussed the sweet research they are doing, almost all of which has been in the news (Implicating 'downloading' printers to the RIAA monitors, RFID ghost proxies, TCP information leakage, voting machine vulnerabilities, TrueCrypt vulnerabilities, implantable medical device hacking, ISP injected ads, etc.). They discussed the difference between just hacking and what you need to do in an academic setting to study what anyone else would call hacking. They encouraged attending academic security conferences, such as ACM CCS, NDSS, IEEE Security + Privacy, HotSec and Woot
    • A talk entitled "Satan is on my Friends List" detailed the security vulnerabilities in OpenSocial-enabled websites. These guys demonstrated some hilarious things, including using a CSRF DOS attack: using an img tag placed in an html-enabled form that displays on a page, you can automatically logout anyone that sees that img by pointing the img's src attribute to the logout page. The speakers talked about how the socnet widget applications space is essentially a security free-for-all: apps hacking personal information, apps hacking other apps, etc. An opt-in security model for javascript safety in apps exacerbates the problem. An amusing conclusion to the talk was the speakers' impersonation of another security researcher on social networks which fooled his colleagues and family alike.
    • Locksport enthusiast Eric Schmedl gave a talk that had some amusing anecdotes about cloak-and-dagger spying. Mary Lou McFate (NRA infiltrator of anti-gun groups), reconstructing passwords from audio of keystrokes, and multiple phone bugging technologies were discussed.
    • Fyodor gave a talk on nmap, the tool he created and how he used it to scan a large subset of the Internet. He also presented some new features of the tool, including traceroute, ping, and netcat-like functionality... what can't it do?
    • I briefly stopped in on a talk called "Taking Back Your Cellphone" which plugged the site HowardForums as an excellent resource for phone modification.
    • The activity that I took part in for a fair share of my time there was the Lockpicking Village. I bought a set of lockpicks, and tried my skills on a variety of locks lying about the room. I also listened to talks on how to crack certain types of locks, including masterlocks (use coke can shiv, patterns for figuring out combo).
    • Probably the most interesting thing that happened at DEFCON nobody got to see: a judge ordered a group of MIT students not to talk about hacking the Boston Subway system. This was rather pointless because 1) the presentation was distributed on CD before the gag was ordered 2) the ban was lifted after the conference 3) MIT's student newspaper put the presentation up on its site
    • Other cool things: the badge, the mystery box
    • Didn't see these presentations, but I looked at them on the CD:
      • "The Death of Cash" features a preview of a world without cash. People are turning to credit because it is more convenient, banks love it because of better profit margins, government loves it because it makes you easier to track. (Note: Illegal to transfer $10,000 in/out of the country without declaring it). This is getting worse with stupid legislation (Patriot Act). Also, national security risk: electronic outages now mean that people can't get access to cash (even more troublesome as electric grid becomes less reliable). Strong crypto might be the basis of a future E-payment system. Advice: keep some cash on hand for emergencies, use non-cash as little as possible. thowlett@netsecuritysvcs.com says the presentation can be downloaded at www.netsecuritysvcs.com/presentations/defcon16/ but I don't see it there...
      • An introduction to ham radio called "Ham for Hackers"
      • A presentation on Javascript obfuscation that goes over the following methods: ASCII/Unicode escapes, XOR (ASCII/encoding), string splitting, simple encryption, non-obvious variable and function names, member enumeration, whitespace encoding/decoding
      • Another presentation on SCADA systems that made me have nightmares
      • A HOWTO on SSL cookie hijacking by Tor developer Mike Perry: insert an img tag with src mail.yahoo.com into an unencrypted connection and read their cookie, then save that cookie to cookies.txt and read their email (over SSL, if you want!)
      • OCR tools: tesseract, jocr, ocrad
      • A presentation similar to "Satan is on my Friends List" for Google Gadgets
    Update:
    Good photos of the event can be found here

    Monday, August 18, 2008

    Proposal: Free Parking through Self-Booting

    San Francisco is a tough city to park in, so I've been scheming up some ways in which to get free parking... here's one thing I've come up with, but haven't had the guts to try yet.
    1. Buy four boots (or more formally, wheel immobilizers).
    2. Park in a tow-away parking zone.
    3. Affix one boot to each wheel of your car.
    4. Laugh at the people figuring out how to tow your car away seeing that they can not drag your car along on its back wheels nor wheel the car up onto a platform.
    5. Return to your car at your leisure, detach boots, drive away.
    Some things to consider:
    • Boots are somewhat expensive, so the whole cost-efficiency of this scheme needs to be taken into consideration (price of tickets, if you plan to pay them, price of parking, risk of having car destroyed by angry tow truckers).
    • I'm not sure what kinds of contracts tow truckers have with the city, private establishments, etc. If they are not liable for any harm that comes to your car, this probably isn't such a good idea, as the towers have no incentive to not damage your car trying to toe it away.
    • Not paying tickets can bite you in the ass if the ticket-giver somehow manages to figure out your Vehicle Identification Number, usually found etched in various places in the car. Unpaid tickets can come up when you try and re-register your vehicle.
    • Boots can be pried off... I'm sure this isn't the only way
    UPDATE: Nothing to do with booting, but here's another way to get free parking in San Francisco, courtesy of Black Hat

    Monday, August 11, 2008

    HOWTO vertical display (X, Nvidia)

    Here is how to get your monitor looking something like this (not my monitor, btw):




























    Put this line as an option in the "Device" section of /etc/X11/xorg.conf: Option "Rotate" "CCW" Then, restart X with Ctrl+Alt+Backspace. Afterwards, start up sudo nvidia-settings and shuffle the screens around in X Server Display Configuration so that they are properly aligned. Be sure to press the Save to X Configuration File button.

    Found via this forum thread and a tip from Arash.

    Update:
    Following is an xorg.conf file to get 2 Dell 2407 monitors in a T formation (with one on the left vertical and one on the right horizontal aka Rajiv-style). This setup has a few problems, though...
    1) The screens are flush at the top, which makes a window across both monitors look disjointed... not a huge problem, and could probably be solved by tweaking the config
    2) Can't seem to get compiz-fusion to work
    3) Using Xinerama instead of Twinview is waaaaay slower, especially when an object is on both screens
    4) Just feels too unnatural... I'm going back to both screens horizontal
    It's also a bit hard finding helpful forum posts on these things anyways because everyone seems to misuse the terminlogy (Xinerama, Twinview, etc.) and problems are very individual (Depending on video drivers, screens, etc.). Anyways, here's the xorg.conf:

    Section "ServerLayout"
    Identifier "Default Layout"
    Screen 0 "Screen0" RightOf "Screen1"
    Screen 1 "Screen1" 0 0
    EndSection

    Section "Module"
    Load "glx"
    EndSection

    Section "ServerFlags"
    Option "Xinerama" "1"
    EndSection

    Section "InputDevice"
    Identifier "Generic Keyboard"
    Driver "kbd"
    Option "XkbRules" "xorg"
    Option "XkbModel" "pc105"
    Option "XkbLayout" "us"
    EndSection

    Section "InputDevice"
    Identifier "Configured Mouse"
    Driver "mouse"
    Option "CorePointer"
    EndSection

    Section "Monitor"
    Identifier "Configured Monitor"
    EndSection

    Section "Monitor"
    Identifier "Monitor0"
    VendorName "Unknown"
    ModelName "DELL 2407WFP"
    HorizSync 30.0 - 83.0
    VertRefresh 56.0 - 76.0
    EndSection

    Section "Monitor"
    Identifier "Monitor1"
    VendorName "Unknown"
    ModelName "DELL 2407WFP"
    HorizSync 30.0 - 83.0
    VertRefresh 56.0 - 76.0
    EndSection

    Section "Device"
    Identifier "Videocard0"
    Driver "nvidia"
    VendorName "NVIDIA Corporation"
    BoardName "GeForce 7900 GS"
    Option "Rotate" "CCW"
    Option "NoLogo" "True"
    BusID "PCI:1:0:0"
    Screen 0
    EndSection

    Section "Device"
    Identifier "Videocard1"
    Driver "nvidia"
    VendorName "NVIDIA Corporation"
    BoardName "GeForce 7900 GS"
    BusID "PCI:1:0:0"
    Screen 1
    EndSection

    Section "Screen"
    Identifier "Screen0"
    Device "Videocard1"
    Monitor "Monitor0"
    DefaultDepth 24
    Option "TwinView" "0"
    Option "metamodes" "DFP-0: nvidia-auto-select +0+0"
    EndSection

    Section "Screen"
    Identifier "Screen1"
    Device "Videocard0"
    Monitor "Monitor1"
    DefaultDepth 24
    Option "TwinView" "0"
    Option "metamodes" "DFP-1: nvidia-auto-select +0+0"
    EndSection

    Monday, July 21, 2008

    Keep SSH connections from timing out, client-side

    Put these lines in ~/.ssh/config

    ServerAliveInterval 300
    TCPKeepAlive yes

    Sunday, July 06, 2008

    txt2regex

    txt2regex is an awesome tool that allows you to specify a regular expression in an interactive curses-based interface that is then printed out in a variety of formats, including English, vim, perl, etc. Perfect for when you know exactly what you want to match, but are not particularly knowledgeable about the idiosyncrasies of the current regex engine you're using.

    Friday, July 04, 2008

    Stop Spamming me with Corporate Birthday Cards

    It is the time of year when my birthday is fast approaching and that means that I am receiving a few birthday cards, sometimes from parties from which I would not expect one. Some of these parties are not people, but corporations who happen to have my birth date on file for one reason or another.

    In any other context, snail mail sent from a corporation to one's home mailbox for marketing purposes would be called junk mail or spam. Sunglasses Hut, et al. try and disguise the purpose of the letter (making you want to buy more of their products) by making the implication that they're corresponding out of consideration for you by politely remembering the celebration of your birth. Now, some may think that this is a genuine gesture of kindness, but I disagree. The entire point of a card is to remind someone that you are thinking about him or her and his/her particular situation. I find nothing personal or redeeming about being the recipient of a letter sent by a cron job at HQ once a year which was ordered by a marketing director that neither knows me nor has any reason to care about my circumstance save trying to extract more of my hard-earned cash out of my pocket.

    In fairness I must note that, unlike most every other sender of birthday spam, Sunglasses Hut at least sent me a twenty-dollar gift certificate to their store. Considering that I don't need another pair of sunglasses and would hesitate to buy from SH again given this annoying practice, I find it small recompense for wasting my time and mailbox space with their spam.

    I guess this can just be chalked up to another consequence of an age when more private parties are holding our personal data and are ever eager to exploit it for their own ends. It seems as there is no disincentive for corporations to send all the spam they want, I'll be receiving quite a few more cards from well-wishing chief marketing officers in the future.


    bigshotcmo@sunglasseshut27:~$ crontab -l
    # m h dom mon dow command
    0 0 1 * * ./send_birthday_cards_for_month

    ...

    db.execute("SELECT * FROM customer WHERE MONTH(birthday) = MONTH(NOW())).each do |customer|
    Notifier.send_individual_card(customer)
    end

    ...

    Dear $customer.first_name,

    Happy birthday! You are super special to us! Spend more money at our store!
    Thanks for providing us with your birthday! Thanks to our expert DBAs and
    comprehensive database backup policy, we're able to retrieve your personal
    information on demand and sure to never expunge your data from our records.
    Have a nice day!

    Love,

    Moneybags
    CMO

    Tuesday, June 17, 2008

    HOWTO Swap caps lock and escape keys in Linux

    Caps lock takes up way too much space on a keyboard for how little (never) one presses it. Esc is a very useful key that gets pressed a lot (especially for vi users) but is rather far away and takes more effort to press in the corner of the keyboard. Here is how to switch the functionality of the two keys (solution adapted from the xmodmap manpage) in Linux.

    Create a file called .Xmodmap in your home directory. Put the following text in the file:

    !
    ! Swap Caps_Lock and Escape
    !
    remove Lock = Caps_Lock
    remove Control = Escape
    keysym Escape = Caps_Lock
    keysym Caps_Lock = Escape
    add Lock = Caps_Lock
    add Control = Escape

    Next time you log in, these settings should stick. If you want to switch the keys manually instead of on startup, run xmodmap .Xmodmap to do so. Loading the file again after you have loaded it once will switch the keys back to their original functionalities.

    Btw, an informative discussion of all of this X customization stuff is found in chapter 6 of Unix Power Tools.

    Tuesday, April 29, 2008

    Google Experimental Search

    Today I stumbled across Google's experimental page which has some add-ons to search that can be enabled. "Keyboard shortcuts" kicks ass: it's basically a vi-like interface to search. j to go down, k to go up, / to search, etc. It's really quite slick.

    Although Google says that you can only add one of these experimental features at a time, "Keyword suggestions" is an option that can be enabled via the Customize Google Firefox extension. "Keyword suggestions" is a great feature as well.

    The "Alternate views" options , on the other hand, are a heaping waste of time. Even the search results for the example queries listed on the page are unintuitive and uninformative.

    Google also offers keyboard shortcuts for a lot of other products (Gmail, Calendar, Docs, Reader, Maps, Video), detailed here.

    UPDATE: I actually disabled the experimental features. The vi emulation was not helpful enough... I could scan the page visually faster than my fingers could keep up. Furthermore, I missed the utility of Firefox's "/" to search the text on the page fast on a Google search result page.

    Friday, April 04, 2008

    Searching SVN trees with Ack (for Ruby on Ubuntu)

    Searching through a subversion tree with grep is a pain in the ass. It wastes time searching through files I don't want to look into and its syntax is inconvenient for the task. Fortunately, there is a tool called ack which is suited specifically for matching text in VCS trees (including svn trees). Here's how to set it up on Ubuntu Gutsy (apparently you won't need to do all this in the next Ubuntu release; there's a package for Hardy).

    First, you're going to need some relevant libraries. sudo apt-get install perl-doc to start. Next, download the File-Next archive from CPAN. Extract the archive and cd into the directory, then use the series of commands perl Makefile.PL && make && make test && sudo make install to install it.

    Now for ack itself. svn checkout http://ack.googlecode.com/svn/trunk/ ack-read-only to checkout the source tree from Google Code and cd into the directory. Now if you want to edit some of the types that are built into the program, here's where to do it. For example, I want to also search for haml files with the --ruby flag. I grep -R rhtml * to see that four files (actually, less, but let's go ahead and edit all of them anyways...) require modification. The ruby line in Ack.pm, for instance, now reads ruby => [qw( rb rhtml rjs rxml erb haml )]. (Types can also be set on the command line using the --type-add and --type-set flags). Once you're finished tweaking types, use the same perl Makefile.PL && make && make test && sudo make install command to install ack.

    For extra credit, you can also add flags to a ~/.ackrc file that get executed upon each invocation of ack. Personally, I add the --ruby flag because it seems to be that .rb, .haml and .rhtml files are all that I'm searching for these days.

    And voila! Now a simple ack -f gives me a listing of all the ruby files in my svn tree (and no vi swp files, svn files, log files, etc.). ack "regex" returns a grep-like search of the relevant parts of the subversion tree with the parts of the line that matched the regex highlighted. SWEET! Get more information on the command line with ack --help for more help, ack --help type for a listing of matching types.

    Do you know how hard this would have been with find/grep/xargs? Well, tough. grep -RE "regex" * | grep -v svn | grep -v log | ...etc... searches all files in the tree and might exclude matching lines if the contain one of the strings being filtered out by the later grep instances. That syntax can be improved to a alternating regular expression with grep -RE "regex" * | grep -v -E \(log\|svn\) but it still has the same problems. grep also has an --exclude flag which can exclude certain filenames that match a glob from being searched (although the manpage would seem to imply otherwise), but it doesn't have regex capabilities. So maybe we can use find and xargs? Nope, a svn tree output will kill xargs, which will compain that the "argument line is too long" if too much gets sent to it: grep -E "regex" `find . -regex '.*\.\(rhtml\|rb\|haml\)' | xargs -0` Perhaps find's --exec flag could be of use? Well, only if you want to kill your computer with the overhead of creating a new grep process and forking and context switching a couple times (etc.) upon each file match... find . -regex "regex" -exec grep -E "regex" '{}' \; will really do your cpu in. Then there's the cumbersome grep -E "regex" $(find . -regex "regex" | grep -vE \(log\|svn\)) ... well, let's just say I'm glad I found ack at this point.

    UPDATE:
    Put --type-add=ruby=.haml in your .ackrc to add haml as a type dynamically.

    Sunday, March 30, 2008

    Amazon's Music Store on Ubuntu Gutsy

    Unfortunately, there are some CDs that are so obscure nobody is seeding them on BitTorrent. One of these happens to be Hicksville by Celtic Cross. I decided to give the Amazon Music Store, where this CD is available for purchase, a shot.

    On Ubuntu Gutsy, there are a few things you need to do to make this work. The first, of course, is to download the .deb package from this page. Install that with sudo dpkg -i amazonmp3.deb or sudo dpkg --force-architecture -i amazonmp3.deb if on a 64 bit system. You're also going to need a few Boost libraries: sudo apt-get install libboost-date-time1.34.1 libboost-thread1.34.1 libboost-iostreams1.34.1 libboost-signals1.34.1 If you're on a 32 bit system, launching the /usr/bin/amazonmp3 binary should now work (it also inserts an entry in the GNOME panel under Applications->Internet).

    But for all you 64-bit'ers out there, there's a bit more work to do. Launching the binary fails with the message "amazonmp3: error while loading shared libraries: libgtkmm-2.4.so.1: cannot open shared object file: No such file or directory". This is because amazonmp3 needs 32 bit libraries, not 64 bit ones (see this thread). Download getlibs, a bash script which installs 32 bit versions of libraries on 64 bit systems. Install the package with sudo dpkg -i getlibs-all.deb and then run getlibs /usr/bin/amazonmp3 to install the 32 bit libraries. The program should now run without error.

    The application, by the way, is quite minimalistic. I don't know why they put users through this trouble and don't just send you a tarball of the music files. I guess there might be some reason on other platforms where it integrates with other applications... not on Linux, though!

    Wednesday, March 12, 2008

    Why NIN's "Ghosts" Release Matters

    Nine Inch Nails ushered in another landmark event in the slow march towards freedom of digital media recently when it released its newest work for free (gratis and libre) on its web site. NIN band member Trent Reznor has frequently been at the forefront of innovation in music and the surrounding areas and it is not at all surprising and very pleasing that it is him to be the first high-profile artist (to my knowledge) to release a major work under a Creative Commons license. However, not everyone seems to grasp the significance of what has happened here. In fact, not even the article that the Slashdot article links to reports the fact that the album has been released under a CC license and many other news outlets have neglected this important point as well. In this article, I'll give a summary of the events surrounding NIN's release of Ghosts I-IV and an analysis of its significance.

    First, some history of the band: Nine Inch Nails has never been a conformist where promoting its music has been concerned. The history of their original ideas is impressive: breaking off from their label and releasing their work independently; encouraging fans at concerts to "steal" music; hiding USB drives for fans to find with new, unreleased songs on them; performing surprise concerts as part of an elaborate fantasy world constructed for fans and releasing Garageband samples for others to remix.

    There is precedent for releasing music free (both gratis and libre) online. Most artists now have a myspace page or other limited Internet presence where one can listen to, but usually not download (or only download a small piece of) an album. Many low-profile artists have been releasing their music online for years under various licenses. Radiohead, arguably, has been the most famous band to release an album free of charge online (with In Rainbows last year). Radiohead allowed each customer to specify their own price for a full download of the album off of its site, even $0. It is estimated that Radiohead made many millions of dollars with this tactic.

    Next, the facts about the Ghosts release. From the Nine Inch Nails website there are a variety of options for downloading the album, etc:
    • Free: The first 9 tracks from the Ghosts I-IV collection available as high-quality, DRM-free MP3s, including the complete PDF.
    • $5: All 36 tracks in a variety of digital formats including a 40 page PDF.
    • $10: Ghosts I-IV on two audio CDs in a six panel digipak package with a 16 page booklet. Pre-order, to be shipped April 8, 2008. INCLUDES immediate full download in a variety of digital formats.
    • $75: Ghosts I-IV in a hardcover fabric slipcase containing: 2 audio CDs, 1 data DVD with all 36 tracks in multi-track format, and a Blu-ray disc with Ghosts I-IV in high-definition 96/24 stereo and accompanying slideshow.
    • $300:



    Nine Inch Nails also uploaded a torrent to the Pirate Bay of the first 9 tracks of the album (out of 36 total) with the following message:
    Hello from Nine Inch Nails.

    We\\\'re very proud to present a new collection of instrumental music, Ghosts I-IV. Almost two hours of music recorded over an intense ten week period last fall, Ghosts I-IV sprawls Nine Inch Nails across a variety of new terrain.

    Now that we\\\'re no longer constrained by a record label, we\\\'ve decided to personally upload Ghosts I, the first of the four volumes, to various torrent sites, because we believe BitTorrent is a revolutionary digital distribution method, and we believe in finding ways to utilize new technologies instead of fighting them.

    We encourage you to share the music of Ghosts I with your friends, post it on your website, play it on your podcast, use it for video projects, etc. It\\\'s licensed for all non-commercial use under Creative Commons.

    We\\\'ve also made a 40 page PDF book to accompany the album. If you\\\'d like to download it for free, visit http://ghosts.nin.com/main/pdf

    Ghosts I is the first part of the 36 track collection Ghosts I-IV. Undoubtedly you\\\'ll be able to find the complete collection on the same torrent network you found this file, but if you\\\'re interested in the release, we encourage you to check it out at ghosts.nin.com, where the complete Ghosts I-IV is available directly from us in a variety of DRM-free digital formats, including FLAC lossless, for only $5. You can also order it on CD, or as a deluxe package with multitrack audio files, high definition audio on Blu-ray disc, and a large hard-bound book.

    We genuinely appreciate your support, and hope you enjoy the new music. Thanks for listening.

    http://ghosts.nin.com
    A little while after the release of the album and the spreading of the news, the NIN website got overloaded with requests, prompting Trent Reznor to post the following message there:
    Update: The response to this album has been overwhelming, causing our website to slow to a crawl. We THOUGHT we were ready, but...
    We've been adding more servers to accommodate the unexpected demand and we expect to be running smoothly in the next few hours. In the meantime, if you've had any problems with downloads from the Ghosts site, don't worry - you'll be able to use your download link again when the site is more stable. Thanks everyone for making this such an immediate success.

    posted by Trent Reznor at 5:47 PM pst, from hong kong.
    So why is the release of Ghosts significant? Because it's the most visible release of art under a Creative Commons license to date (by-nc-sa 3.0, to be exact). This means that Trent Reznor can not take you to court for distributing the music on, say, the Pirate Bay; it explicitly permits this kind of activity. All the license mandates is that if you use the work, you must credit the original author and you must release your new work that incorporates NIN's art under the same license. The license also prohibits any use of the work for financial gain by a third party (no selling the album on the street for five bucks a pop). This is in marked contrast to Radiohead, who did not specify the license that In Rainbows was under, so because of this ambiguity we must only assume that it is under a traditional copyright license. This means that Radiohead CAN take you to court for distributing the music if one day it decides that suing its fans is fashionable. Releasing art, especially music, in this fashion is going to become increasingly prevalent as more artists realize the benefits of instantly sharing art with the world via the Internet in preference to traditional distribution channels such as record labels. With computer technology, how fans use music is increasingly out of an artists' control. It is a much more amicable arrangement for the artist to indulge fans by releasing music in a way they find convenient (and, also, not sue them).

    The release of Ghosts also establishes BitTorrent as a recognized distribution channel in which established artists can release their music. Frequently, the BitTorrent protocol and its users are denigrated in the media as "pirates" or "thieves." The fact that a respected artist is using BitTorrent in preference to direct download or a record label-sponsored distribution will legitimize this method of sharing in the eyes of many and heighten the profile of BitTorrent generally. Using BitTorrent was also a good move simply because it is a superior protocol for large files, as the slowness of the NIN website showed. Also, it is more convenient to use than having to click through the kind of omg-it's-free messages (or, more generally, an unfamiliar interface) that Radiohead made users weather to buy In Rainbows. Being so in touch with how music fans want to acquire their music definitely doesn't hurt NIN's publicity, either.

    Reznor also proves that it is wholly possible to make a lot of money off of a free product on the Internet, something that many ill-informed pundits think impossible. Slashdot reports that the most expensive option sold out in about a day, netting Reznor $750,000. This is to say nothing of any of the other purchasing options, which also likely brought in a significant amount of revenue, possibly much more than the $300 dollar option. So why are people paying for something that they could more or less otherwise get for free? A few answers can be found in Kevin Kelly's essay Better Than Free. Kelly claims that the Internet has made copyable material infinitely abundant, and therefore impossible to charge money for. What can be charged for are what Kelly calls "generatives" -- things that can't be copied. He suggests 8 generatives from which money can be made in a world with Internet technology: immediacy, personalization, interpretation, authenticity, accessibility, embodiment, patronage and findability (convinience). By autographing records, NIN provides authenticity and personalization. By offering downloads off its site in a variety of digital formats, NIN makes money off of findability, accessibility and immediacy. And, of course, being an artist offering up works for free under a CC license NIN reaps the benefit of patronage: listeners loving what they are seeing and hearing and willing to pay for more of the same.

    Another important point about this event is that all the data on NIN's site will eventually find its way out from behind the wall of authentication and payment and onto public networks. That is, users that paid for enhanced versions of the product will upload them to a BitTorrent tracker: here already are the ($5) FLAC versions of all 36 songs and some extras. It is often repeated that information wants to be free, as we can see here. What is not often repeated, but equally true, is that information wants to be convenient. Fans of In Rainbows proved this yet again when they uploaded the album to BitTorrent (humorously leading some ignorant columnists to castigate users for "stealing" it -- how can you steal something if it's free and able to be infinitely copied?).

    In conclusion, the experimental release of Ghosts on the Internet under a Creative Commons license and for free is a milestone event for a variety of reasons. It is the first high-profile musical release that is free, both as in freedom and as in beer. It made NIN a whole lot of money, proving that artists can survive in the Internet era (even without performing). And it enhances the profile of the BitTorrent protocol as a distribution mechanism and reinforces some well-understood properties of Internet-based information distribution. Hopefully other artists will follow NIN's example and release their work in a similar manner.

    ===============================
    Further reading:
    • Reznor decries fact that people see Radiohead as first to release free online, says industry won't follow his lead anytime soon because it's inept. (Link)

    Thursday, February 21, 2008

    Ruby (vs Python): a preliminary assessment

    I've been using Ruby for a little over a month now. While this hasn't been enough time to explore the depths of the language, it has given me ample time to evaluate how I feel about some of the more superficial aspects of Ruby. There are some things I like about it, a few things I don't care about, and a lot of things I don't like. In some aspects it is quite similar to Python, my favorite programming language. In the following sections I lay out what I do, kinda, and don't like about Ruby, sometimes in comparison to or in contrast with Python to put things in context.

    Things I like about Ruby


    Naming conventions are enforced The less surprises there are in code, the easier it is to read. I would be very surprised, for example, if a C VARIABLE_IN_ALL_CAPS were not a constant. It only takes one joker working on code to completely screw with convention and degrade readability of code for everyone else working on it. Ruby heads off this problem at the pass. Instance variables look like @this, class variables look like @@this, constants look like THIS, global variables look like $this, etc. This is a Good Idea. I can easily live without the flexibility to name my class h0We\/ER_I_want. This also makes the code easier to parse and syntax highlight.

    Block Comments I'm not sure how Python missed the boat on this one. The "large chunks of code shouldn't be commented anyway, so take them out" and "get a decent text editor that can :50,70s/^/#/" and "that's what doc comments are for" school of thought just doesn't resonate with me. Too often there is some large chunk of code lying around that just isn't applicable anymore and quickly commenting it out is a temporary solution.

    Constants There is just something about the assurance that certain variables are read-only that makes me sleep well at night. Otherwise, I need to worry about things getting overwritten, and that's no fun. I guess there's always CONVENTION to prevent this in Python, but that doesn't stop someone from breaking CONVENTION += 1

    Examples are the norm in documentation Examples are the quickest way to learn about new code. However, the docs could benefit from some non-example elaboration most of the time. How is one supposed to figure out corner cases? I guess "examples first" goes along with the whole Ruby-has-no-formal-spec thing.

    'case' syntax The syntax of Ruby's case statement (analogous to switch in other languages) is pretty rad. It's a great feature for when multiple properties of one variable need to be tested. The case statement accepts comparisons, ranges, regular expressions, etc. Very cool.

    Things I could go either way on

    Regular expressions built into the language Regular expressions are cool, and I use them a lot, but I just don't know if they have a place amongst the pantheon of hashes, lists and the like. They are convenient, but overuse might turn your code into *gasp* Perl. No one likes unreadable ASCII-splatter, although it's tough for Ruby to get that bad. Plus, half the time I am using regexes some other function might do just as well, like rindex. Maybe that's just my laziness that Ruby caters to.

    Interned strings It's like a pointer, I get it. It saves memory over using a string object, cool. Was it really worth including in the language? Not sure. It seems like their most common uses, such as keys in hashes, could be implemented under the hood anyway (well, at least in a real language like Python where hash keys are immutable).

    ! and ? as legal characters in method names I can understand that does_this_work? is a natural way to read that a function returns a boolean. I get that destroy! suggests an internal change of state of the object. But then there's the problems. First, not every method that returns a boolean or changes an object's state is forced to use these constructs. If they were enforced like all-caps constants and @ before instance members, maybe I'd be more bullish on them. Second, what qualifies as a change of state can get kind of messy: maybe a method only conditionally changes its object's state; is an exclamation mark appropriate then? The exclamation mark can also be misread, especially if parentheses are omitted (looks an awful lot like a logical not operator, doesn't it?). And now for my nitpicky objections: ? and ! are harder to type than letters and vim doesn't auto-complete the full method name by default (it completes everything but the last character) if one of those characters is included.

    Marriage to Rails On the one hand, it's nice to have a large support community for tools that one is likely to use. On the other hand, it's annoying to wade through a bunch of comments by people on forums and mailing lists that are completely irrelevant to what you're trying to do with the language. These people are normally exclusively concerned with getting their website up and running, aren't terribly gifted programmers and don't really care about the language per se. Some bloggers assume that any talk about Ruby is in the context of Rails because... well, isn't that what you're using it for? What else could you possibly do with Ruby?

    Indentation Python has a unique indentation system. In most cases (Makefiles) whitespace indentation is a horrible idea, but Python manages to make it work. It reduces noise on the screen and is pretty intuitive. I'm not convinced that Python wouldn't be more effective, however, with a traditional bracket-defined indentation scheme which Ruby is close to. It's a toss-up for me.

    Things I don't like about Ruby


    TMTOWTDI There's more than one way to do it in Ruby, alright -- you're smothered with options. This is the dark path that leads to Perl. Take looping as an example. In Python, you have for and while. That's it. In Ruby, you have for, while, times, upto, downto, begin/end and each (there's probably more that I missed). What's wrong with for? It's really difficult to be intimately familiar with this many options. And this symptom doesn't just plague looping, it also plagues the standard library. Do we really need every one of <<, push and + to append to the end of an array? Why have both brackets and "end" to enclose a block? Has anyone ever used all three versions of defining a class method in any mood but malice and spite? I guess we can all take solace in the many ways in Ruby via active_support to compute the amount of bytes in a gigabyte: 1.gigabyte, 1024.megabytes, 1048576.kilobytes, etc.

    Go with the Flow There is a prevailing attitude with Ruby users, especially in Rails, to favor convention over configuration. This means that tools that espouse this philosophy reward going with the flow and punish breaking out of the mold and customizing your applications. My attitude towards this philosophy is this: unless you are creating the most pedestrian and generic of applications, you are going to need to customize the application at some point. When that happens, it is much better to have a tool that allows flexibility than one that disdains it. Otherwise you are going to need to go down to the core of the tool to make minor changes to your application, and that will cost you in time and sanity.

    Hashes are broken In Python, it's impossible to change the keys in a dictionary because those keys must be immutable when they go in. Python also nicely throws a KeyError when something you're looking for in a dictionary is not there. Ruby does neither of these things; the programmer is expected to maintain the immutability of hash keys. High-level languages are supposed to take care of important details like these for us humans who are busy thinking about other things. In fact, the Python FAQ lists this as an "unacceptable solution" for an alternative implementation of hashes: "Allow lists as keys but tell the user not to modify them. This would allow a class of hard-to-track bugs in programs when you forgot or modified a list by accident." Default return values aren't that much of a design travesty, but I still prefer the error. Besides, if you really want a default return value in python, you can just use setdefault when accessing the element that may or may not be there instead of setting a default value for the whole hash at creation.

    Ranges are broken This absolutely baffles me. Why did Ruby not choose to incorporate Python's elegant slicing syntax and instead chose a less powerful and more confusing one? Why did Ruby choose to create an unnecessary class called Range when they just could have had a function called, oh I don't know, range that is much more powerful, simple and general and that returns lists/arrays? Why do you need to call range.to_a to convert your useless Range object to an array in Ruby when they could have just used a function like range and gotten to the point? Furthermore, why are there two ways to create ranges, .. (two periods) and ... (three periods) that look EXACTLY THE SAME! Argh.

    Optional omission of syntax elements Sure, it's less typing in Ruby, but remember what I said earlier about less surprises equaling more readable code? It holds here as well. Is this_thing a variable or a function call? This also excludes the convenient syntax for introspection that calling function() without parentheses in Python affords. And the fact that sometimes you need the "do" keyword and sometimes you don't is also a design decision that just begs for unnecessary tripping over the syntax.

    Inline control flow constructs When I first saw these, I thought "Wow! I can now do in one line what previously took me three in Ruby!" And then I started reading a lot of lines and wondering why they weren't executing. And then I read those lines a bit further and saw that they had conditional statements tacked on to the end of them. And then I vowed to never use them again. One example of how this can go bad is tacking on "and return" to the end of a long statement. If you're looking at the code, and not scrolling right far enough (and your lines are that long that you need to scroll, which may or may not be a good idea), it looks like the code falls through after every statement instead of returning. Confusing.

    Different names for the same method find_all? What the hell does that do? Oh, it's the same as select. Collect? What's that? Oh, it's the same as map. Too bad I only found these things out after going to the documentation. Why can't one function just have one name, so we can all have a common point of reference? Oh, right, because Ruby "allows you to program in your natural language." Which means confusing everybody else, including myself.

    Different precedence for seemingly identical operators ! binds more tightly than not. && and || bind more tightly than "and" and "or". This is incredibly confusing; why not just make them the same precedence? Changing one form to the other form when it is right near another operator whose precedence is between the two could alter the control flow of your code.

    Inability to override = (and non-obvious performance gotcha) There is some fine print to go along with the "every operator is just a function" propaganda. One annoying exception to the rule is the = operator. Now, why would anyone want to override the equals sign? First let me point out that it's not just =, but also -=, +=, *=, etc. that also are incapable of being overridden, so it affects a substantial set of important operators that are literally expanded to x = x + y, etc. Now here's the kicker: these methods are orders of magnitude slower than their true method counterparts for arrays and strings. So I want to override += for arrays to have it call concat or << which are both efficient as a way of aliasing all +='s in the existing codebase. In C++ and other languages, this would be quite possible (never mind that you wouldn't be facing this problem in C++ to being with) but in C Ruby, a design decision has been made that no one can override the sacred = and therefore coders will inevitably trip over this performance gotcha. Why? I'm not sure... maybe this or that post may offer some insight. In any event, don't use += and its cousins for anything but numbers or risk serious performance hits (changing one to the other is further complicated by their difference in precedence... both behave differently within a conditional operator, for example. Grrr.)

    Confusing operator overloading << is a way to print things out (a la C++), define a class method, and append to the end of an array. Only the last one makes sense to me; the other two seem out of place. Remember what I said about less surprises = better code readability? It's beginning to become quite a theme...

    No list comprehensions [heavy_sigh for each_time_I_can_not_do_this in Ruby if I_am_particularly_exasperated] I guess there's always select and collect. Too bad I need to decide if I want all the items in the list or only a subset before I can select the correct method to use (instead of at the end in Python, where I can insert if statements if necessary). I also haven't discovered a way in Ruby (yet?) to do the related task of a one-line instantiation of a hash. In Python, this would be d = dict((x, None) for x in [1,2,3])

    Perl-like operators << <=> and =~? Sorry, I just can't get into it. Keep it simple, please. Function calls with letters are good.

    Lists and hashes are printed strangely puts {1=>2,2=>3,3=>4} gives me 122334 in Ruby. WTF? I thought I was dealing with a hash, not a number. print {1: 2, 2: 3, 3: 4} gives me {1: 2, 2: 3, 3: 4} in Python. puts [1,2,3] gives me numbers on separate lines in Ruby. print [1,2,3] gives me [1, 2, 3] in Python. The seemingly small detail that data structures are printed out exactly how they are written in code makes a world of a difference.

    Strings are unintuitive Strings are iterated over by word, not by character in Ruby: "one two".each {|x| puts x} in Ruby outputs "one" and "two" on separate lines. Compare this to for i in "one two": print i in Python, which prints out a character on each line. To iterate over each character in a string in Ruby, you'll have to use each_byte (in which case you'll find that Ruby will print out numbers unless you convert the numbers with .chr... this problem also occurs when selecting a character from a string, as in str[5] even though the docs say otherwise) or each_char.

    Bad decisions on naming Why is there a built in variable called $DEBUG? Doesn't everyone have a global variable called that in their program at some point or another? Well, overwriting this variable unknowingly will cause your code do very strange things, like disregard begin/rescue/ensure blocks. I found this out the hard way. Python's is __debug__. Who is going to create a variable called __debug__ in their program? Nobody, that's who. The closest thing Ruby has to a constructor is called initialize. Why so long? __init__ works fine, and programmers who failed literature can actually spell it.

    Shortcuts for everything "p" for print. The attr family of keywords for attribute access. Why not just create usable constructs and stick with them, instead of inventing unwieldy constructs and then working around them with shortcuts?

    Hype Ruby is definitely the flavor of the week in programming languages. This results in a bunch of n00bs flocking to the language when they want to learn to program. Now, I have nothing against people who want to learn how to program. In fact, I'm thrilled that anyone wants to take a little time to learn the art. But the experience of a community has benefits: better tools and better discussions. As a result the conversations in Ruby forums and mailing lists are generally of a lower quality than that on Python mailing lists which tend to be frequented by more knowledgeable, veteran coders.

    Japanese Origins As an English speaker, I appreciate that most of the cutting-edge blog posts and PEPs and what not are in English. Ruby originated from Japan, so this is not the case there. It's frustrating for me to see a link like "the solution to your problem is here" only to be led to a page which to me might as well be in... well, Japanese. I am sure I would feel differently if I were Japanese, of course.

    OSX/TextMate-centric community A large number of Ruby users use Macs. Not sure why, that's just the way it is. They also seem to like TextMate. Me? I hate Apple and love vim. The more people that use the tools that you use, the higher probability that someone has already solved the configuration problem that is bugging you. Although I will note that the default settings for Ruby in vim are very nice... there's at least one knowledgeable vim user writing Ruby out there.

    Younger Language Python has been around since the late 80s. Ruby has been around since 1993 (both for certain definitions of "around"). Python has a head start on Ruby in terms of developer time. A more mature language is likely to have fewer bugs, more features, less experimentation and and more users. The same goes for libraries written for that language: a greater number of better-implemented libraries will be available to users of a language that has been around longer. All other things being equal, the older language has to win the stability and reliability battle.

    Unfamiliar keywords Instead of try/catch (or except)/finally, Ruby has begin/rescue/ensure. Instead of continue, Ruby has next. Instead of else if or elif, Ruby has elsif. Instead of switch/case, Ruby has case/when. I guess every language commits this foul to some extent, but it's just one more thing to trip over.

    Implicit returns Another Perlism that I despise. To me, a function looks like it doesn't return anything if it doesn't have the "return" keyword in there at some point. It's much easier to read (and maintain) code if the points at which a function could return something are explicitly outlined.

    Things I don't have an opinion on... yet

    Introspection/Reflection Haven't really dug that deeply into what Ruby can do here yet...

    Package management The gems system vs letting apt-get do everything. Neither has failed me in any way thus far, but then again, I haven't really tried to do anything remotely complicated with either and I'm not a sysadmin presiding over a myriad of different configurations...

    Threading Ruby doesn't support native threads. What are Python's options? This looks like a good article and what about Stackless Python?

    Object Oriented stuff Namespaces, modules, Inheritance, etc. I'm sure there's some Python vs Ruby flamewar going on out there, I just have to find the thread...

    Monday, January 07, 2008

    Funny UNIX utilities

    Some humorous UNIX utilities that brighten my day:
    • cowsay -- get a cow, etc. to do the talking
    • fortune -- witticisms, some more offensive than others (fortunes-off package contains more offensive fortunes, fortune -o invokes offensive fortunes)
    • banner -- big friggin letters

    Printing with enscript

    enscript is an awesome utility for printing text files; it kicks lpr's lame ass. Here are some examples of usage (more to come as the need arises):
    • Letter enscript --no-header --word-wrap example_file.txt
    Also, navigate to localhost:631 on any system with CUPS installed in order to configure the default printer and such.