Cloud Four Blog

Technical notes, War stories and anecdotes

Apple Rejects Health Care Reform App for being “Politically Charged”

iSinglePayer ScreenshotLast week I wrote about Apple’s policy of censoring political speech and why this was more important than Google Voice. Today, we find out that Apple has rejected a Health Care Reform App for being “politically charged.”

The application in question, iSinglePayer, appears to be mostly informative from the screenshots the developer posted. It contains bar graphs and charts with information on the cost of health care. It uses GPS to find local representatives and encourages you to call them.

Frankly, there is nothing in this application that wasn’t in the Obama ’08 official iPhone application that we helped develop.

Obama ’08 had the following features:

  • An issues section containing position papers and data similar to the bar graphs and pie charts in iSinglePayer.
  • GPS location used to determine where you can contribute to the campaign similar to iSinglePayer’s use of GPS to figure out your representatives.
  • A system to encourage you to call your friends to encourage them to vote for Obama similar to iSinglePayer’s feature encouraging you to call your representative.

And in case anyone thinks that Health Care Reform is substantially more controversial than last year’s Presidential election, Gallop showed Obama at 48% when the Obama ’08 application was released. That is only seven percentage points ahead of where Rasmussen polls put public opinion on health care reform as of today.

I find rejections of applications like iSinglePayer to be more offensive than I do the rejection of Google Voice. And while I don’t expect mobile gatekeepers to change their policies, I strongly believe it is in our best interest to make sure we have viable alternatives to the app stores as soon as possible.

Freedom Time: Google Voice Letter to the FCC, iPhone App Store & Mobile Gatekeepers

Friday is the day to release news you want people to forget. No surprise then that Friday was when Google released the unredacted version of its letter to the FCC about Apple’s rejection of the Google Voice application.

In case you missed it, the FCC sent letters to Apple, Google, and AT&T asking them about Apple’s rejection of the Google Voice for iPhone application and what role each company played.

Apple and AT&T released the full content of their responses to the FCC. Google asked for portions of its response to be redacted. However, a Freedom of Information Act request prompted Google to divulge the full content of their response.

And yet despite this latest revelation, the he said, she said nature of the follow ups, and word that Google may even have a screenshot proving that Apple is lying, Google Voice is nowhere near the most important App Store rejection.

That distinction belongs to Freedom Time.

Why Freedom Time Matters More than Google Voice

Freedom Application ScreenshotLike many iPhone applications, Freedom Time was a frivolous application. The application displayed a cartoon character of George Bush with arms like a Mickey Mouse watch. But instead of telling time, the application counted down the days until Inauguration Day.

Freedom Time wasn’t one of the more high-profile iPhone App Store rejections. Unlike Google Voice, people barely noticed when the application was rejected.

What is important is the reason why Freedom Time was rejected. Apple’s response to the developer was:

Upon review of your application, Freedom Time cannot be posted to the App Store because it contains content that does not comply with Community Standards. Usage of such materials, as outlined in the iPhone SDK Agreement section 3.3.12, is prohibited:

“Applications must not contain any obscene, pornographic, offensive or defamatory content or materials of any kind (text, graphics, images, photographs, etc.), or other content or materials that in Apple’s reasonable judgement may be found objectionable by iPhone or iPod touch users.”

Defaming, demeaning, or attacking political figures is not considered appropriate content for the App Store.

Can you imagine political discourse of any significance that doesn’t include demeaning or attacking political figures? Like it or not, that’s part of the exchange of ideas that form a democracy.

This policy essentially bans any editorial cartoons—cartoons that have been part of America’s history since its inception.

The idea that political discourse might be rejected from the App Store as a matter of policy surely must be a mistake, right?

Think Different? What’s the Point?

Unfortunately, it isn’t a mistake. The developer of Freedom Time emailed Steve Jobs, and he actually got a reply. Steve wrote:

Even though my personal political leanings are democratic, I think this app will be offensive to roughly half our customers. What’s the point?

Steve

I’ve often wondered what the Steve Jobs who attended Reed College during the early days of the Watergate scandal would think of that quote.

Steve Jobs, George Bush, Richard Nixon, and Scott Ritter

These four people—two that I admire and two that broke our trust—have become linked in my mind because of the Freedom Time rejection.

Freedom of speech is easy to defend when the speech is popular, but the real test comes when you have to defend unpopular speech or things that you don’t agree with.

In Fall 2008, George Bush had the worst approval ratings since Nixon. At a time in which we had one of the most unpopular Presidents in American history, Apple didn’t have the courage to approve a simple, stupid application like Freedom Time.

What is the likelihood that Apple would approve a truly controversial and unpopular application during a time when popular opinion makes it difficult to stand up for what’s right?

I find myself wondering what would have happened if former marine and U.N. Weapons Inspector Scott Ritter had tried to release an application in 2002 talking about how there were no weapons of mass destruction in Iraq.

When Ritter did speak up in 2002 and told the world that he had been in Iraq and that there were no weapons of mass destruction, popular opinion was so high in favor of Bush policies that despite being known as a patriot, conservative, and a hawk, Ritter was called a traitor by some.

What if the only means Scott Ritter had to share what he knew with the rest of the world had been through an App Store?

Flickr Censorship Pales in Comparison

Censored Obama imageRecently Flickr received a lot of scrutiny and pressure because of perceived censorship of a political image. The image showed a modified version of Obama on the cover of Time Magazine where Obama was made to look like the Joker from the most recent Batman movie.

Yahoo, the parent company for Flickr, later explained that they removed the image from Flickr because they had received a copyright infringement claim.

I don’t care to debate the Flickr censorship case. Instead, I want to ask simply why Flickr got a lot of grief for censoring a single image that they say they removed because of a copyright claim, but Apple has thus far escaped scrutiny for a standing policy that rejects any applications that attack political figures.

The image that Flickr removed would have never made it through the iPhone app review process in the first place.

The Mobile Proposition: Trade Liberty for Security

Apple has good reasons for why it has an App Store review process. It told the FCC that:

We created an approval process that reviews every application submitted to Apple for the App Store in order to protect consumer privacy, safeguard children from inappropriate content, and avoid applications that degrade the core experience of the iPhone.

This is a very similar argument that carriers and handset manufacturers have been making for years now. The argument is that mobile phones contain so much personal, sensitive information that applications need to be vetted to ensure that consumers are protected.

This is the same argument that Ben Franklin famously warned us about when he said:

Those who would give up Essential Liberty to purchase a little Temporary Safety, deserve neither Liberty nor Safety.

And despite the fact that we would not accept similar arguments from our government, we seem willing to give up our freedoms to mobile companies for the sake of our own security.

It’s Not About Apple. It’s About Gatekeepers

While I’ve spent most of my time focusing on Apple, please don’t mistake this as a tirade against Apple. Apple just happens to be leading the way in this area of mobile as well.

The reality is that if mobile is going to live up to its promise, we need a future without gatekeepers.

It isn’t hard to conceive of a future where more people have smartphones than have PCs. In some countries, people get more news from their mobile phones than they do from their desktop computers.

Before we get to the point where mobile phones have become the primary way that people get their news and information, we need to ensure that we have the freedom to publish what we want without restrictions.

For these reasons, I’m encouraged by the work of organizations like the Open Mobile Consortium. They are tackling the difficult work of providing truly open mobile solutions that allow people in repressive regimes to communicate freely.

The Moral Imperative of the Mobile Web

In addition to the Open Mobile Consortium, we need to make sure that there are alternatives to app stores and their gatekeepers. The best alternative is web technology.

This is why I’ve gone from thinking about mobile web technology as a smart business decision for some applications to thinking of it as a moral imperative.

Even if you are an Objective-C programmer who has had a lot of success on the iPhone App Store, it is in your best interest that the mobile web develop into a viable alternative to app stores. It is in society’s best interest.

To get to that point, we need to solve the short-coming of the mobile web. We need the technology to stabilize. We need real browsers on all phones. And we need a reliable and easy way to accept payment for our mobile web applications and services.

I cannot state this strongly enough: we need an open and free mobile web to be a viable alternative to the mobile gatekeepers to ensure that we have the freedom to say what must be said and the ability to have our voices heard by others.

Reflections on Foo Camp 09

Last month I had a unique opportunity to attend Foo Camp at the O’Reilly campus in Sebastopol, CA. This weekend’s WordCamp Portland reminded me that I had yet to write about my Foo Camp experience.

Foo Camp is a free, invitation only event organized by O’Reilly. Foo stands for Friend of O’Reilly as well as being a play on words on a popular term used in programming documentation.

While resembling a conference in many ways (there is a schedule with multiple sessions at any given time), Foo Camp is most often called an unconference because the sessions are suggested by the attendees on the first night of the conference. It is also truly a camp as many people, myself included, pitched tents on the O’Reilly campus.

Many tents on the O'Reilly Campus during Foo Camp '09

Photo courtesy laughingsquid (thanks Scott!)

While the format is unique and fun, that’s not why people go to Foo Camp. The reason people attend and rave about their experiences is because Foo Camp brings together many of the smartest and most creative people working with technology.

Bring 300 brilliant people together for the weekend, then step back and watch the ideas and connections take off.

Part of the reason I’ve had so much trouble writing this summary of my experience is because there were so many amazing experiences and people that I met that I find it difficult to convey to other people. The simplest way I’ve explained it is that I didn’t want the weekend to end.

There are some other observations that I made during the weekend:

  • People were not just smart, but genuinely nice and helpful. Going into Foo Camp can be a bit intimidating “How did I get an invitation? I’m not worthy.” The warmth of the people I met is probably the thing I will remember the most.
  • That first point bears repeating. The people were amazing and wonderful.
  • I found myself gravitating to sessions on the economy, politics and health care despite the fact that there were many technology sessions. Some of the really good ones were:
    • Bill Janeway of Warburg Pincus led a great session on the current recession and the parallels/differences to the great depression. BTW, Mark Sigal has a great extended summary of this session on his Foo Camp recap.
    • Susan Crawford and Andrew McLaughlin from the White House talked about ways to help the government and what types of data the government could open up that would help the public the most.
    • Mitch Kapor and Jay Parkinson shared how they are each attempting to change Health Care and in particular Health Care IT.

    I realized that I’ve been spending so much time on the day-to-day things that we need to do to build our business and deliver for our customers that I’ve track of what is going on in the world. One of the things that motivated me to start working on mobile was the fact that it can be a transformative technology—something that can make people’s lives better in substantial ways. I need to find ways to make more of that happen.

  • I find the idea that Tim O’Reilly has been promoting of government as a platform to be intriguing and there were a lot of sessions at Foo Camp talking about what is currently being done with the data the government provides. I didn’t realize how much was already happening in this space. Really nice to see.
  • I had a great time leading a session with Andre Charland from Nitobi on building applications using mobile web technology. The folks at Nitobi are the lead developers of the PhoneGap framework. Good discussion and ideas during the session.
  • It was really, really hot. Many people chose to stay inside where it was air conditioned which meant we didn’t get that many people for our session. I didn’t feel too bad because every other outdoor session had low turnout during the same mid-afternoon time slot. But what did happen was many people who wanted to attend the session, but didn’t, later asked me for a summary. I had more than one person ask me if this information was written down anywhere. It has been a big incentive to start blogging more. Posts like The Five Most Common Arguments for Native iPhone Development are direct responses to comments from people like Mok Oh who rightly said, “What’s the url for that blog post? I’d like to read it.” :-)
  • B.J. Fogg is working on peace in 30 years. He says peace has a bad brand. He is looking to change that and make peace happen. Yes, please.
  • Werewolf rocks. We played into the wee hours of the morning. What a blast!

There were many, many other conversations that made it a wonderful experience. I cannot thank everyone at O’Reilly enough for the invitation and for hosting me. I wish there was some way I could repay their generosity. Tim, Sara and the rest of the team, you have an open invitation to dinner at our house any time you are in Portland. For that matter, if you need a place to crash (or pitch a tent), mi casa es su casa.

I left the weekend inspired and reminded again of the great things that individuals can accomplish. I turned 35 the week after Foo Camp. Being around people working on world-changing things has me thinking again about my legacy and about how the work that I do and the life that I lead can help make the world that my daughter is going to grow up into a better place.

I’m not yet sure what I’m going to do with this renewed perspective, but I’m thankful to Foo Camp for the reminder to think and dream big.

JavaScript GZIP Compression in WordPress: What’s Possible and what Hurts

WordPress 2.8 introduced some constants and bits and bots that nominally make certain kinds of compression of JavaScript and CSS possible. This post looks at JavaScript compression and explains what is possible, and what is very, very hard.

In a nutshell, with a bit of tweaking, you can GZIP and concatenate the scripts that come packaged with WordPress. GZipping and concatenating anything else–plugin scripts or scripts in your own theme–is not currently supported in any obviously sane way (using WP’s WP_Scripts management class anyway).

I’m going to give away the ending to save you some time:

add_action('wp_enqueue_scripts', 'lyza_force_compress');
function lyza_force_compress()
{
    global $compress_scripts, $concatenate_scripts;
    $compress_scripts = 1;
    $concatenate_scripts = 1;
    define('ENFORCE_GZIP', true);
 
    /* enqueue your scripts here */
}

Putting the above in your functions.php file may result in insanely good compression on your subsequently-enqueued JavaScript files. I say may because GZIP is one of those fidgety server-side things that varies from hosting provider to hosting provider. I tested this approach on two vastly different environments and had good success, but as always with these things, YMMV.

While this may look rather silly and simple, figuring out exactly which constants and globals to set and when to set them took me just about forever.

The most important thing to note is that this only works on scripts that come pre-packaged with WordPress and are listed in the wp_default_scripts() function in wp-includes/script-loader.php. This is slightly irritating.

When it Does Work

The above will concatenate and GZIP all of the applicable enqueued JavaScript into a single request, served out through the wp-admin/load-scripts.php script.

  • By “applicable”, I mean scripts listed in wp-includes/script-loader.php in the wp_default_scripts() function.
  • If you have applicable JavaScript in both the head and the foot, you will end up with two script src tags. If everything is in the foot (or the head), you’ll get one tag. You not only get GZipping, you get fewer HTTP requests! Yay!
  • JavaScript in plugins and your own theme won’t get concatenated and GZipped in this approach, but it certainly doesn’t break it.

In testing, the following:

    wp_enqueue_script('jquery');
    wp_enqueue_script('thickbox');
    wp_enqueue_script('scriptaculous');
    wp_enqueue_script('editor');

Went from:

10 requests, 310kB

to

2 requests, 90kB

with the activation of the above function. Nice! I got two requests because the above enqueueing puts stuff in both the head and the footer.

That’s a 340% improvement on filesize alone.

Why Won’t It Work for All JavaScript?

Because there are no, nada, zilch, none hooks for making it do so without doing some deep surgery and writing a plugin. It boils down to a couple of places in code:

From wp-includes/class.wp-scripts.php in the do_item() function:

100
101
102
103
104
105
106
107
108
	if ( $this->in_default_dir($srce) ) {
		$this->print_code .= $this->print_scripts_l10n( $handle, false );
		$this->concat .= "$handle,";
		$this->concat_version .= "$handle$ver";
		return true;
	} else {
		$this->ext_handles .= "$handle,";
		$this->ext_version .= "$handle$ver";
	}

To get the built-in concatenation and GZIPped delivery, it is necessary that the if statement here evaluate true. I won’t explain the nitty gritty unless you really want me to.

So, my first approach was to add paths to the $wp_scripts->default_dirs Array to add entries for my theme’s scripts and my plugin dir’s scripts. Big fat fail.

The reason is that the actual file — wp-admin/load-scripts.php — that serves up the concatenated, zipped JavaScript is a standalone script. I imagine that this is both for security and for performance. It does not have the complement of WordPress constants and hooks that we are accustomed to. In fact, it is completely and absolutely unpluggable (unless I missed something). It only includes the files that define the WP_Scripts and WP_Dependencies classes, and utility functions for those. It does not include any theme- or plugin-level items.

And it does something that completely shuts down the game. It instantiates a new, clean WP_Scripts object and then calls wp_default_scripts().

If you’ll recall, the WP_Scripts object in a normal WordPress request is a global singleton that manages all of the enqueued scripts. By creating a new instantiation, the load-scripts.php script has obliterated any notion of any enqueued scripts. Further, the wp_default_scripts() function is a hard-coded list of the JavaScript files that WordPress comes packaged with. While this function nominally triggers the ‘wp_default_scripts’ action, this is not usable here because no files are getting included in which I could take advantage of that hook. Further, it redefines do_action() and other API functions as blank functions that do nothing.

The load-scripts.php file then iterates through the requested JavaScript handles (comma-delimited GET) and sees if it recognizes them from the wp_default_scripts() list. As anything that’s in your own theme or in a plugin won’t be in this list, FAIL.

Though I see some possible options for me in the writing-a-plugin realm, I also sadly see that it would replicate functionality and am highly curious as to what the WordPress developers had in mind here.

Getting all JavaScript into the Footer in WordPress? Not so fast, Buster!

[toc title="JavaScript in Footer"]
Warning: Technical WordPress post ahead!

Overview: Really Getting JavaScript Into the Footer

Quoth the WordPress Version 2.8 feature list:

– Improvements to the script loader: allows plugins to queue scripts for the front end head and footer, adds hooks for server side caching of compressed scripts, adds support for ENFORCE_GZIP constant (deflate is used by default since it’s faster)

At the time, I thought Wow, cool. When I have time, I’ll investigate that and then immediately forgot about it for a few months. During RSS-coffee-breaks I read Lester Chan’s post about how to put JavaScript in the footer (sounds easy enough!) and Andrew Ozz’s post, which left me coated with an intense and foolish optimism about compression.

What I aim to do in this post — part one of a series of three if I find time to investigate the second and third pieces — is explain why it’s not as easy as you’d expect to get some scripts (specifically scripts that come with WordPress by default) into the footer, and how you can make it happen.

If you’re in a hurry, you can skip to the Summary section at the end of the post.

WP JavaScript Inclusion: Header vs. Footer

What I read had me believe that it is falling-off-log easy to put all WordPress JavaScript in the footer. If you are trying to include a piece of JavaScript, say, in a plugin, that WP has not previously known about, it is that easy. But woe if you try this on certain scripts that come packaged with WordPress.

Let’s take a look at the functions that are involved in letting WordPress know that you want to use a given piece of JavaScript.

These are taken from wp-includes/functions.wp-scripts.php.

wp_register_script() and wp_enqueue_script()

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
 * Register new JavaScript file.
 *
 * @since r16
 * @see WP_Dependencies::add() For parameter information.
 */
function wp_register_script( $handle, $src, $deps = array(), $ver = false, $in_footer = false ) {
	global $wp_scripts;
	if ( !is_a($wp_scripts, 'WP_Scripts') )
		$wp_scripts = new WP_Scripts();
 
	$wp_scripts->add( $handle, $src, $deps, $ver );
	if ( $in_footer )
		$wp_scripts->add_data( $handle, 'group', 1 );
}
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/**
 * Enqueues script.
 *
 * Registers the script if src provided (does NOT overwrite) and enqueues.
 *
 * @since r16
 * @see WP_Script::add(), WP_Script::enqueue()
*/
function wp_enqueue_script( $handle, $src = false, $deps = array(), $ver = false, $in_footer = false ) {
	global $wp_scripts;
	if ( !is_a($wp_scripts, 'WP_Scripts') )
		$wp_scripts = new WP_Scripts();
 
	if ( $src ) {
		$_handle = explode('?', $handle);
		$wp_scripts->add( $_handle[0], $src, $deps, $ver );
		if ( $in_footer )
			$wp_scripts->add_data( $_handle[0], 'group', 1 );
	}
	$wp_scripts->enqueue( $handle );
}

As a theme developer, you may only ever have encounters with wp_enqueue_script(). But let’s look at what each of these functions does so I can then explain the issue.

wp_register_script() tells WordPress about a script, but does not actually cause it to be included in a given page request. By default, WordPress registers a gripload of scripts that are then available to you, the theme hacker, when or if you should need them. A list of these can be found in wp-includes/script-loader.php in the wp_defalut_scripts() function. Highlights include jQuery, prototype, scriptaculous, etc., as well as extensions to those frameworks (e.g. jQuery UI). WordPress (via the WP_Scripts class, itself extended from WP_Dependencies) handles dependencies and makes sure that jQuery UI doesn’t get included without its necessary jQuery, if you should forget to enqueue jQuery itself or it gets enqueued after jQuery UI.

wp_enqueue_script() tells WordPress, hey, I actually need this script, in this request. You may have seen or done something like this:

wp_enqueue_script('jquery');

This spools up jQuery and spits out a script tag to include the requested script.

In a lot of cases, it seems easy and straightforward to do this simple enqueue request. jQuery comes packaged with WP and is automatically registered for you, so you just have to hand the wp_enqueue_script() function one argument: $handle.

As a clever theme hacker, you may have noticed that the signature for wp_enqueue_script() and wp_register_script() changed in version 2.8 and this seems exciting. An $in_footer parameter was added:

wp_enqueue_script( $handle, $src = false, $deps = array(), $ver = false, $in_footer = false );

Totally psyched, you update your theme and use:

wp_enqueue_script('jquery','','','',true);

And wait for the magic. RELOAD! Wait, maybe something’s cached. RELOAD! Wait, what? RELOADRELOADRELOAD.

jQuery is still in the head.

So you get irritable and you quit trying, or like me you spend a few hours deactivating all of your plugins and trying to figure out where the problem is. You notice that the same thing happens with other scripts that WP already knows about (that is, the scripts in wp_default_scripts()). Stubbornly, they won’t get out of your page’s head element.

Here’s why.

Why WordPress Default JavaScripts Won’t Move to the Footer

The crux is: if the script you are enqueueing has anything defined as a dependency in WordPress’ wp_default_scripts() function, it will ignore your request to put it in the footer (I’ll provide a workaround shortly).

The reason for this is twofold.

Dependency Handling and “Groups”

Part of WordPress’ dependency handling for scripts involves “groups”, the ins and outs of which I’ll leave as an exercise for an intrigued reader. In an oversimplification, it put scripts with dependencies (e.g. jQuery, Scriptaculous) in groups[0]. It explicitly puts scripts that depend on other scripts in groups[1]. The default behavior of both wp_register_script() is to put a script in groups[0] if the $in_footer argument != true.

How Groups Handling does Something Possibly Confusing

OK, now check out this snippet from class.wp-scripts.php (do_item() method):

85
86
87
88
if ( 0 === $group && $this->groups[$handle] > 0 ) {
	$this->in_footer[] = $handle;
	return false;
}

This piece of logic puts groups > 0 into the footer. So that’s how WP decides to move things into the footer–it’s based on where the script is in the $wp_scripts->groups Array.

But here’s a potential pitfall in the wp_enqueue_script() function:

	if ( $src ) {
		$_handle = explode('?', $handle);
		$wp_scripts->add( $_handle[0], $src, $deps, $ver );
		if ( $in_footer )
			$wp_scripts->add_data( $_handle[0], 'group', 1 );
	}
	$wp_scripts->enqueue( $handle );

If you don’t give wp_enqueue_script() a $src (which you don’t have to provide do if the script has already been registered) for your $handle, it is going to enqueue it in whatever group it’s already registered in. So, when you do your little simple enqueue:

wp_enqueue_script('jquery','','','',true);

The entire part of the function where it would put it in the footer doesn’t execute because the if($src) test fails. And jQuery has already been registered—in groups[0].

Possible Workaround

I don’t like this but it works:

wp_enqueue_script('jquery','/wp-includes/js/jquery/jquery.js','','',true);

jQuery is now in the footer.

This does still appear to handle dependencies correctly, but I haven’t deeply tested. Also, there are some valid reasons to have some scripts, and possibly jQuery, in the head. This was just a demo.

Getting JS into the Footer: Quick Summary

// This will NOT put jquery in the footer
wp_enqueue_script('jquery','','','',true);
 
// But this will, if inelegant and circumventing abstraction
wp_enqueue_script('jquery','/wp-includes/js/jquery/jquery.js','','',true);

For My Next Trick…Compression

Really, this post was a red herring. I tripped into this oddity while investigating the second part of the WordPress 2.8 feature claim: adds hooks for server side caching of compressed scripts, adds support for ENFORCE_GZIP constant (deflate is used by default since it’s faster). We’ll talk about that next time.