Nov 17

Update Dec. 4, 2009: added Google public DNS servers.

There is a lot of confusion about whether Facebook is in the process of being blocked right now. Here are my thoughts to try to clear up some of the misconceptions.

In short, these are my claims: Yes, Facebook is being blocked by the internet service providers in Vietnam because of the authorities. Yes, there are workarounds in order to access Facebook. No, that’s not enough. Yes, this totally blows.

What access problems is Facebook experiencing in Ho Chi Minh City recently?

As stated on wikipedia:

Starting around November 4, 2009, the major Internet Service Providers (ISPs) SCTV/VDC and Viettel blocked access to Facebook by removing www.facebook.com and apps.facebook.com from their DNS service for a time ranging from a few hours to a few days. Another major ISP FPT followed suit for a few hours on November 10, 2009. Rumors have designated these as tests in anticipation of an official censorship decree. Starting on November 16, 2009,FPT, Viettel, SCTV/VDC, and EVN all started blocking DNS requests for Facebook, in what many people believe to be a permanent ban.

How is this evidence of an official block and not just an accident or glitch?

The ongoing Facebook block is not an accident. It is not due to technical unreliability. It is a surgical strike on the each of the major Internet Service Providers’ (ISPs’) DNS service (which is a service to translate www.facebook.com and apps.facebook.com into addresses that computers can understand, e.g. 69.63.184.31).

The recent access problems are akin to having the Yellow Pages all of a sudden missing the entries for Highlands Coffee. It’s not as if someone spilled food all over your Yellow Pages and you have trouble reading it. The rest of your Yellow Pages is completely fine but suspiciously missing 2 major entries. Moreover, there isn’t just one set of Yellow Pages. FPT, SCTV, Viettel all have their own Yellow Pages books and each of them are missing the same 2 entries.

The odds of the DNS omission being due to accident are thus close to nil. All this adds up to evidence of deliberate action.

What other evidence is there of an impending official block?

The actions from the ISPs speak for themselves, but there is no known concrete proof of an official decree to block Facebook yet.

A supposedly-official decree demanding that the ISPs block Facebook was earlier leaked on the internet in September 2009, but its authenticity has not been confirmed. There is a version of this document with a stamp and signature from a hospital, but this version can be ignored as it has clearly been doctored (look at the bottom line where letters are chopped off, right where the original version of the decree is cut off).

A commercial customer of FPT talked to representatives who have unofficially stated that there is a pending decree banning Facebook which has not yet been publicly released.

Why do you think it’s being blocked if some of my friends can still access Facebook?

We are hearing reports that some people can still access Facebook, e.g. at universities like RMIT.

A block does not have to be complete to be real. And in any case, as I explain below, a partial block is all that’s needed to kill off the widespread use of Facebook.

Why not just wait until there is an official decree instead of going nuts over this?

An official decree may never become public.

And for some of us, waiting is not an option. We need to anticipate whether we can rely on Facebook to communicate with groups or promote events in the future. Any downtime affects the effectiveness of online marketing initiatives, organizational efforts, let alone being able to keep up with friends and family.

What are motives for a Facebook block?

As everyone can guess, political censorship and control. But also, there are rumors that local competitors may be using their government connections to shut out the mighty giant Facebook.

Are there workarounds to access Facebook?

Yes, right now, you can use either of these workarounds:

  • Use the limited functionality of http://lite.facebook.com/, which has not been blocked.
  • Configure your computer or router to use Google Public DNS or OpenDNS instead of your ISP’s default DNS service.
  • Hard-code some IP addresses for Facebook servers.
  • Use some of the freely available web proxies
  • If you have access to a server overseas, you can use VPN or set up your own SOCKS proxy using ssh tunneling.
    • Since this is for advanced computer users, I’m sure you can figure it out yourself

Of course, these workarounds may stop working in the future if the authorities or the ISPs want to tighten their block. But there is a reasonable chance that they won’t go that far, for reasons I discuss below.

Why aren’t they blocking the workarounds?

Blocking some of the above workarounds is easier than others. Certainly, throwing lite.facebook.com in with the rest would be simple. But what about blocking OpenDNS or blocking Facebook by IP address?

It’s easier, quicker, and cheaper to block Facebook by DNS than to block Facebook or OpenDNS by IP address. First, DNS requests are much less frequent than web content requests by nature of the data. Second, DNS requests are cached at many different levels making them even less frequent. Third, there are much fewer DNS entries for Facebook than there are IP addresses for Facebook to block. Not only are there many Facebook domain names, but each domain name such as www.facebook.com can actually map to hundreds of ever-changing servers around the world, which is a technique that big web sites use to distribute traffic and keep things going fast.

IP filtering could slow down internet traffic in Vietnam, which is not the case for DNS filtering. It’s reasonable that ISPs would try to discourage IP blocks.

As for web proxies, there are just so many out there it would take quite a while. And if you have your own proxy that you can VPN or ssh to, then that’s effectively impossible to block.

It’s still conceivable that the workarounds will stop working, but it will take some time.

If there are workarounds, why worry?

The workarounds I listed above, e.g. OpenDNS and proxies, help but only a little. Blocking a social network is not like blocking YouTube or some anti-government complaint website. We generally don’t get on Facebook just to access titillating information. We are on Facebook to connect with one another. As Metcalfe’s Law states, “the value of a telecommunications network is proportional to the square of the number of connected users of the system.”

In order for a social network to have all its promised value, you need a majority of your friends and community on it, not only you. In order to effectively promote an event on Facebook, you need most of your audience on it. If you can’t ensure that everyone in your community, whether it’s locals or expats, can get on easily, then your community will eventually die off. Proxies and OpenDNS are not well known and not easy to use. If 80% of your community don’t know how to use them and cannot access Facebook even if you can, you could still have lost 99% of the value of the social network.

And because of these network effects, Facebook will get fewer and fewer users logging on, even if they know how to use workarounds. Eventually, you may be all alone, and how fun is that? In China, the number of Facebook users dropped from a million to 14,000 in 3 months because of their ban.

So while DNS blocking is not effective in completely censoring information or censoring sites like YouTube, DNS blocking is highly effective in simply destroying the value of a social network like Facebook.

On the bright side, after Facebook gets so much less usage from Vietnam, there may not even be interest from the authorities to tighten their ban, which means workarounds would continue to work. This may be a sufficient situation for those of us who are still interested in staying in touch with overseas communities.

So what can we do?

Well, as we all know, there is no comparable web site out there with the same functionality and power as Facebook. Most likely, local Vietnamese will go to a number of local Vietnamese-language competitors.

And expats may choose to go back to the inferior Hi5, Orkut, or god-forbid MySpace. But I’m hoping that all expats in VN learn to use the access workarounds in order to maintain the value of the Facebook network.

Where can we find more information?

Here’s an AP story “Vietnam Internet users fear Facebook blackout“.

Lonely Planet has some interesting backstory regarding software licenses.

Tagged with:
Sep 27

If your application is acting strange when your users are switching between 12-hour and 24-hour mode in their iPhone settings, you may be experiencing the same thing we are: an NSDateFormatter bug in the iPhone SDK 3.1 (or earlier).

MultiNC develops iPhone applications for a number of global markets, and sometimes we run into bugs unique to globalized applications.  One application that we’re developing has France as primary market.  U.S. users very rarely change their settings from the usual 12-hour mode (AM/PM mode) to 24-hour mode.  However, in France it’s not rare for users to switch from the more common 24-hour mode to 12-hour mode.  And that’s when things start acting strange, even causing your application to crash.

Because of users’ regional habits, developers of globalized applications are more likely to encounter this time bug than for US applications.

Region format & 24-hour mode setting

First, a little background on the iPhone user interface.  When iPhone users change their region format between, say, “United States” and “France”, the users’ “24-Hour Time” setting is automatically switched to the mode that is most prevalent in that region.  In France, that would set 24-Hour Time to “ON”, and in the U.S., that would set it to “OFF”.  The users can then manually override that setting and that’s where trouble starts.

NSDateFormatter bug

The pattern of this SDK bug was relatively tricky to determine because of the specific combination and sequence of user settings that would trigger it, but now it’s actually quite simple to explain.

The problem comes from NSDateFormatter somehow “getting stuck” in the 12 or 24-hour time mode that the user has manually selected.  So if a French user manually selects 12-hour mode,  and the application requested NSDateFormatter to output time with the 24-hour format “HHmm”, it would actually receive time in a 12-hour format, e.g. “01:00 PM”, as if the application had instead requested “hhmm aa”.  The reverse would happen if a US user manually selected 24-hour mode: outputting time with the 12-hour  format “hhmm aa” would actually get you time in the 24-hour format instead, e.g. “17:00″.

This bug turns especially nasty when your application is trying to parse time from a string, rather than outputing.  Similar to the above, the NSDateFormatter seems to be stuck in the time mode that the user has manually chosen and insists on reading time that way, regardless of the string format.  What you can end up with is an incomplete or invalid NSDate, which when later used can cause other parts of the application to crash, as the UIDatePicker did for us.

We are developing with the iPhone SDK version 3.1 beta, but we wouldn’t be surprised if it applied to all previous SDKs.

Workaround

Now that you know the source of the bug, a workaround is straightforward.  But to save you time until Apple fixes it, with our client faberNovel‘s gracious permission, here’s our workaround when dealing in 24-hour time (dealing in 12-hour time would be very similar):

// Returns time string in 24-hour mode from the given NSDate
+(NSString *)time24FromDate:(NSDate *)date withTimeZone:(NSTimeZone *)timeZone
{
	NSDateFormatter *dateFormatter= [[NSDateFormatter alloc] init];
	[dateFormatter setDateFormat:@"HH:mm"];
	[dateFormatter setTimeZone:timeZone];
	NSString* time = [dateFormatter stringFromDate:date];
	[dateFormatter release];
 
	if (time.length > 5) {
		NSRange range;
		range.location = 3;
		range.length = 2;
		int hour = [[time substringToIndex:2] intValue];
		NSString *minute = [time substringWithRange:range];
		range = [time rangeOfString:@"AM"];
		if (range.length==0)
			hour += 12;
		time = [NSString stringWithFormat:@"%02d:%@", hour, minute];
	}
 
	return time;
}
 
// Returns a proper NSDate given a time string in 24-hour mode
+(NSDate *)dateFromTime24:(NSString *)time24String withTimeZone:(NSTimeZone *)timeZone
{
	int hour = [[time24String substringToIndex:2] intValue];
	int minute = [[time24String substringFromIndex:3] intValue];
	NSDateFormatter *dateFormatter= [[NSDateFormatter alloc] init];
	[dateFormatter setTimeZone:timeZone];	
 
	NSDate *result;
	if ([Util userSetTwelveHourMode]) {
		[dateFormatter setDateFormat:@"hh:mm aa"];
		if (hour > 12) {
			result = [dateFormatter dateFromString:[NSString stringWithFormat:@"%02d:%02d PM", hour - 12, minute]];
		} else {
			result = [dateFormatter dateFromString:[NSString stringWithFormat:@"%02d:%02d AM", hour, minute]];
		}
	} else {
		[dateFormatter setDateFormat:@"HH:mm"];
		result = [dateFormatter dateFromString:[NSString stringWithFormat:@"%02d:%02d", hour, minute]];
	}
	[dateFormatter release];
 
	return result;
}
 
// Tests whether the user has set the 12-hour or 24-hour mode in their settings.
+(BOOL)userSetTwelveHourMode
{
	NSDateFormatter *testFormatter = [[NSDateFormatter alloc] init];
	[testFormatter setTimeStyle:NSDateFormatterShortStyle];
	NSString *testTime = [testFormatter stringFromDate:[NSDate date]];
	[testFormatter release];
	return [testTime hasSuffix:@"M"] || [testTime hasSuffix:@"m"];
}
 
// Converts a 24-hour time string to 12-hour time string
+(NSString *)time12FromTime24:(NSString *)time24String
{
	NSDateFormatter *testFormatter = [[NSDateFormatter alloc] init];
	int hour = [[time24String substringToIndex:2] intValue];
	int minute = [[time24String substringFromIndex:3] intValue];
 
	NSString *result = [NSString stringWithFormat:@"%02d:%02d %@", hour % 12, minute, hour > 12 ? [testFormatter PMSymbol] : [testFormatter AMSymbol]];
	[testFormatter release];
	return result;
}

References:

Tagged with:
Sep 27

If your application is acting strange when your users are switching between 12-hour and 24-hour mode in their iPhone settings, you may be experiencing the same thing we are: an NSDateFormatter bug in the iPhone SDK 3.1 (or earlier).

MultiNC develops iPhone applications for a number of global markets, and sometimes we run into bugs unique to globalized applications.  One application that we’re developing has France as primary market.  U.S. users very rarely change their settings from the usual 12-hour mode (AM/PM mode) to 24-hour mode.  However, in France it’s not rare for users to switch from the more common 24-hour mode to 12-hour mode.  And that’s when things start acting strange, even causing your application to crash.

Because of users’ regional habits, developers of globalized applications are more likely to encounter this time bug than for US applications.

Region format & 24-hour mode setting

First, a little background on the iPhone user interface.  When iPhone users change their region format between, say, “United States” and “France”, the users’ “24-Hour Time” setting is automatically switched to the mode that is most prevalent in that region.  In France, that would set 24-Hour Time to “ON”, and in the U.S., that would set it to “OFF”.  The users can then manually override that setting and that’s where trouble starts.

NSDateFormatter bug

The pattern of this SDK bug was relatively tricky to determine because of the specific combination and sequence of user settings that would trigger it, but now it’s actually quite simple to explain.

The problem comes from NSDateFormatter somehow “getting stuck” in the 12 or 24-hour time mode that the user has manually selected.  So if a French user manually selects 12-hour mode,  and the application requested NSDateFormatter to output time with the 24-hour format “HHmm”, it would actually receive time in a 12-hour format, e.g. “01:00 PM”, as if the application had instead requested “hhmm aa”.  The reverse would happen if a US user manually selected 24-hour mode: outputting time with the 12-hour  format “hhmm aa” would actually get you time in the 24-hour format instead, e.g. “17:00″.

This bug turns especially nasty when your application is trying to parse time from a string, rather than outputing.  Similar to the above, the NSDateFormatter seems to be stuck in the time mode that the user has manually chosen and insists on reading time that way, regardless of the string format.  What you can end up with is an incomplete or invalid NSDate, which when later used can cause other parts of the application to crash, as the UIDatePicker did for us.

We are developing with the iPhone SDK version 3.1 beta, but we wouldn’t be surprised if it applied to all previous SDKs.

Workaround

Now that you know the source of the bug, a workaround is straightforward.  But to save you time until Apple fixes it, with our client faberNovel‘s gracious permission, here’s our workaround when dealing in 24-hour time (dealing in 12-hour time would be very similar):

// Returns time string in 24-hour mode from the given NSDate
+(NSString *)time24FromDate:(NSDate *)date withTimeZone:(NSTimeZone *)timeZone
{
	NSDateFormatter *dateFormatter= [[NSDateFormatter alloc] init];
	[dateFormatter setDateFormat:@"HH:mm"];
	[dateFormatter setTimeZone:timeZone];
	NSString* time = [dateFormatter stringFromDate:date];
	[dateFormatter release];
 
	if (time.length > 5) {
		NSRange range;
		range.location = 3;
		range.length = 2;
		int hour = [[time substringToIndex:2] intValue];
		NSString *minute = [time substringWithRange:range];
		range = [time rangeOfString:@"AM"];
		if (range.length==0)
			hour += 12;
		time = [NSString stringWithFormat:@"%02d:%@", hour, minute];
	}
 
	return time;
}
 
// Returns a proper NSDate given a time string in 24-hour mode
+(NSDate *)dateFromTime24:(NSString *)time24String withTimeZone:(NSTimeZone *)timeZone
{
	int hour = [[time24String substringToIndex:2] intValue];
	int minute = [[time24String substringFromIndex:3] intValue];
	NSDateFormatter *dateFormatter= [[NSDateFormatter alloc] init];
	[dateFormatter setTimeZone:timeZone];	
 
	NSDate *result;
	if ([Util userSetTwelveHourMode]) {
		[dateFormatter setDateFormat:@"hh:mm aa"];
		if (hour > 12) {
			result = [dateFormatter dateFromString:[NSString stringWithFormat:@"%02d:%02d PM", hour - 12, minute]];
		} else {
			result = [dateFormatter dateFromString:[NSString stringWithFormat:@"%02d:%02d AM", hour, minute]];
		}
	} else {
		[dateFormatter setDateFormat:@"HH:mm"];
		result = [dateFormatter dateFromString:[NSString stringWithFormat:@"%02d:%02d", hour, minute]];
	}
	[dateFormatter release];
 
	return result;
}
 
// Tests whether the user has set the 12-hour or 24-hour mode in their settings.
+(BOOL)userSetTwelveHourMode
{
	NSDateFormatter *testFormatter = [[NSDateFormatter alloc] init];
	[testFormatter setTimeStyle:NSDateFormatterShortStyle];
	NSString *testTime = [testFormatter stringFromDate:[NSDate date]];
	[testFormatter release];
	return [testTime hasSuffix:@"M"] || [testTime hasSuffix:@"m"];
}
 
// Converts a 24-hour time string to 12-hour time string
+(NSString *)time12FromTime24:(NSString *)time24String
{
	NSDateFormatter *testFormatter = [[NSDateFormatter alloc] init];
	int hour = [[time24String substringToIndex:2] intValue];
	int minute = [[time24String substringFromIndex:3] intValue];
 
	NSString *result = [NSString stringWithFormat:@"%02d:%02d %@", hour % 12, minute, hour > 12 ? [testFormatter PMSymbol] : [testFormatter AMSymbol]];
	[testFormatter release];
	return result;
}

References:

Tagged with:
preload preload preload