Posts RSS Comments RSS 0 Posts and 49 Comments till now

Thoughts on Redesigning a Framework

(I haven’t been in the writing lane for a while. In lieu of stuff about life, here I repost an entry from the ObjectiveFlickr blog.)

I haven’t really been taking care of ObjectiveFlickr.framework for a while. For the past few months many things have demanded my attention. In between I’ve attended sfMacIndie Soirée 2008 and been to this year’s WWDC too. How time flies! I want to apologize for my late response on everything regarding the framework.

Lately we’ve seen fresh influx of discussions on the mailing list. Reading them, I always have this feeling that “it’s time we’ve got to update the framework.” There are a few things that ObjectiveFlickr needs to do better. Some of them are the result of operating system and development environment changes. Here they are:

  1. Better and clear run loop support
  2. Proxy support in OFHTTPRequest
  3. Fixing the delegate implementation–delegate should never be retained
  4. Support for both 10.4 and 10.5 targets
  5. Properties
  6. Linkage against CommonCrypto instead of OpenSSL (libcrypto)
  7. In with NSXMLParser, out with NSXMLDocument
  8. Support for the-device-and-the-OS-that-shalt-not-be-named-until-July-11th

Many of the items actually have to do with OFHTTPRequest and OFPOSTRequest, two nifty (I think) wrappers of Cocoa’s NSURLConnection (for receiving data) and CFNetwork’s CFHTTP stack (for posting data with progress callbacks). I use them all the time in many of my Cocoa projects, but even they feel a bit rusty now.

The removal of OpenSSL and NSXMLDocument dependency has also clear reasons (or, reasons-that-shall-not-be-mentioned).

I’m thinking of a new HTTP request class that solely depends on CFHTTP stack and does not use NSURLConnection. Which means that part needs to be redesigned. The existing OFFlickr* class interfaces look fine, but they’re also a bit wordy compared to their Ruby counterparts, ObjectiveFlickr-Ruby.

Should I create a set of new interfaces that break with the past, or should I maintain the interfaces and swap the internals? This is the question that is troubling me now. I appreciate any feedback on those design decisions.

Matsumoto Shinosuke, the Blogger Killer

It rained, serendipitously, when he was deciding which part of his past to throw away, whom to avenge, and how to forget.

Matsumoto Shinosuke, also known as Dr. T in his pro circle, was an ASP .NET programmer who wrote bespoke, or customized, blog systems in Akihabara, Tokyo. But his real job was a professional assassin. Ironically, the blog systems he made had such a good reputation of having very little spam. Probably it’s because Mr. Matsumoto applied his pro assassin knowledge to spam killing, at the expense of his victims.

There was once when Mr. Matsumoto’s cover and real jobs overlapped. A certain telecom conglomerate was suffering huge bandwidth loss because of botnet attacks. The conglomerate, run by one of Japan’s oldest families, had finally had enough and sought the help from the underworld. While picking up the hit man was not hard, finding out the mastermind behind the botnet was trickier. An anti-spam strike team finally identified the man, a script language black-belt who scoffed anyone whose expertise ends in the word dot en ee tee. What the man, let’s call him the V, didn’t realize was that, he made some of such scoffs on a free, anonymous blog system, which, to his haughty ignorance, was a bespoke work implemented by no one but our Dr. T, in, to the V’s horror, ASP .NET. And Mr. Matsumoto hated it most when people scoffed at his being master of ASP .NET, even if he was equally fluent in any script language the source code of which requires to start with a shebang.

So a detective service paid Mr. Matsumoto’s cover job employer (actually, one of his cover job employers) to locate the V, and the conglomerate paid Mr. Matsumoto, indirectly through layers of underworld connections, for the ultimate strike. It couldn’t be a happier assignment: a fat double-pay. But of course it would not be a happy ending for the V.

On a rainy, quiet night Mr. Matsumoto arrived at the door of the V’s posh apartment in the equally posh community of Daikanyama. The doorbell rang, and exactly 180 seconds later, a spammer was totally unwound just like a most insignificant exception in a try-catch clause, and to Dr. T’s delight, one less ASP .NET scoffer. A bloodstained laptop was left in the scene, the signature of Mr. Matsumoto’s yet another tour de force.

dataWithContentsOfURL: inconsistencies

Was tracing a mysterious bug. Some software component that uses NSData’s dataWithContentsOfURL: suddenly fails to work with a specific URL endpoint only when it is run on Tiger. Switching the URL endpoint to the dev server, and the problem is gone.

Turns out that the specific URL endpoint is served by an Apache server with gzipped data option turned on. Many a modern day web servers do that to lighten the traffic load (especially if you serving tons of JavaScripts, for example). Unfortunately, the naïve dataWithContentsOfURL: does not unzip the data for you automatically, so your NSData object contains actually a zipped data.

Interestingly, on Leopard dataWithContentsOfURL: works just as transparently as it should always be. Digging through the mailing list some Apple people confirmed that it behaved inconsistently since the days of 10.3.3. It’s just unfortunate.

The solution? Ask the server side people to turn off that option.

Helveticul

Bought a pin at a museum shop, it says “Helveticul”. The salesperson, who just like many others are bilingual, confirmed my guess: it combines the word Helvetica with the French insulting word (think of “en-” plus the word in question then verbalize it). In a genius stroke it becomes a subtler message than Helvetica the Film’s official “I Love Helvetica” and “I Hate Helvetica” pin-pair. In Helvetica.

So I put it on my backpack and enjoy the love-hate relationship with the typeface, à la française.

Hamlet in Ruby (Version 2)

question = self.be?

o_f = fortune(:outrageous)
suffer = s.mind.suffer(slings(o_f) && arrows(o_f))

sea_of_trouble = [:trouble, :trouble, :trouble]
fight = sea_of_trouble.map { |t| kill self.arm.take.against(t) }

nobler = suffer > fight ? suffer: fight

if fork == 0
  while 1
    sleep
  end
else
  die
end

nil  # no more

Hamlet in Ruby

question = self.be?

self.call nobler? ?
    lambda{|s| s.mind.suffer([:slings, :arrows].each {|x| fortune(:outrageous, x) }) }
  : lambda{|s| s.fight_and_kill([:trouble, :trouble, :trouble]) }

if fork == 0
  while 1
    sleep
  end
else
  die
end

# no more

Some History on the .cin Format, and on Apple’s .cin Support

Eric Rasmussen of Yale Chinese Mac has started a discussion on the .cin support in Apple’s Mac OS X Leopard, an addition to their exisitng input method framework as an alternative to help users create their own input methods. I was invited to share what I know about the format, so I wrote a long reply to Eric’s post. The length of the follow-up seems to warrant a standalone blog entry, so here it is. I’ll put more links in the text later.

History of the .cin Format

.cin was first introduced by Xcin, an input method framework for X11 developed in the mid 1990s, as a data format for table-based input methods. By table-based I mean input methods that can be implemented, or seen, as a table look-up mechanism. Around 90% of input methods (Chinese and beyond) can be implemented that way. Apple’s .inputplugin also belongs to that category. Almost every mainstream input method framework supports at least one form of user-customizable IME creation. .cin seems to have become one of the standard data formats because it’s simple and many user-generated tables are already in wide
circulation.

I have very limited knowledge of Xcin and other frameworks, but in the early days, .cin was intended as a source format, not to be consumed directly by input method framework (or more precisely, the table-based input method “generator”). Also back then a .cin could use any encoding recognized by the framework. So phone.cin (renamed to bpmf.cin in OV) was encoded in Big5, pinyin.cin in GB, and so on. When we were developing the “generic” module (first named OVIMXcin, later renamed to OVIMGeneric) to support .cin in OpenVanilla, we made two decisions: first, we no longer require user to run a compiler/ converter to make .cin into a binary format, as it was so, which means the .cin is consumed by the input method module directly. Second, all .cin files must use UTF-8 encoding. This opened the door to bigger character set and the famous “♨” input method.

What’s in a .cin?

So what constitutes a valid .cin file? For OpenVanilla, a .cin file consists of three sections:

  1. A header consisting of directives beginning with “%”, like %ename, %selkey, %endkey. Some of them are like meta-data, some of them are controlling directives;
  2. a keyname block between the directives “%keyname begin” and “%keyname end”. This tells the generic input method to map the key typed to a character displayed in the composing stage (mostly to represent radicals in radcial-based input methods), and
  3. a chardef block between the directives “%chardef begin” and “%chardef end”. This is the body of the data table. “chardef” is somewhat an anachronistic misnomer. It used to define the relationship between key sequences to characters (hence the name), but modern implementations like OV and gcin allow phrases in this block

Different frameworks have implemented the details somewhat differently. OV’s implementation disallows the use of Windows-style CR LF (so only the UNIX-style \n is used, and that’s also what OS X uses), and comment lines (beginning with #) is not allowed in the chardef block.

Although .cin contains enough information for key-character/phrase mapping, but many input methods (like 倉頡 Cangjei/”Changjei” or 簡易 Simplex/Jianyi) require finer control. For OpenVanilla, the control is provided in the form of input method preferences (with some mind- bogging names like “force composition when reaching maximum length of radical” or “use space to select the 1st candidate). Different input methods require different controls (and those are a must — failure to provide those controls yields barely usable input methods). gcin
differs from OV’s implementation in that it allows those control directives to be expressed as a .cin header, with its own directive extensions.

OpenVanilla’s Own Take of .cin

OpenVanilla’s repository of .cin is available at: http://openvanilla.googlecode.com/svn/trunk/Modules/SharedData/

Zonble has written an excellent tutorial (in Chinese) on how to create
your own input method by writing up a .cin, which is kind of standard
text now: http://docs.google.com/View?docid=ah6d8th954vw_201fd5dkx

Technically .cin is really just a set of key-value pairs with its own convention. OV makes heavy use of .cin as a format. Things like reverse radical/pinyin lookup or associated phrases are also done with .cin-based data tables. I see it a good sign that Apple adopts a popular (and mostly consistent and cross-framework compatible) data format for Leopard.

Leopard’s Support of .cin

So what about Leopard? As far as I know, dropping in a UTF-8-encoded .cin into ~/Library/Input Methods or /Library/Input Methods then re-login just works. A new input method, using the name defined in the .cin, shows up in the Input Menu tab of the International preferences panel. I’m not aware of any per-method level control so far (I might be very ignorant on this).

In terms of limitation, I’m not aware of that either. OV’s own implementation (and many others) is only limited by memory and your patience (loading a .cin with 200,000 entries on a G3 is no small thing; a database-backed design will solve the problem). Leopard’s own take should not differ much. So it should be very flexible and easily customizable.

Cover-Flowize Your Application

People on the cocoa-dev mailing list talked about the cover flow API, which does exist, albeit not in public. If you know how to use IKImageBrwoserView, you already know how to cover-flowize your application.

In your Interface Builder project, drop in a custom view and make its class IKImageFlowView. In the data source class (which has the same form as IKImageBrowserDataSource), implement these two required methods:

  • - (NSUInteger)numberOfItemsInImageFlow:(id)aFlowLayer
  • - (id)imageFlow:(id)aFlowLayer itemAtIndex:(int)index

And there you have it:

Cover Flow Study

I showed that in yesterday’s CocoaHeads Taipei meet-up. The sample code is available here.

As this is an undocumented class, so caveat programmor. It may change in the next version’s OS X or simply be snapped away under your nose.

OpenVanilla 0.8.0: Now for Leopard

Today we announce the release of OpenVanilla 0.8. It is the third major version of OpenVanilla (0.6, 0.7, 0.8) since 2004. Version 0.8 is available for Mac OS X and Windows. For the unpatient, the new release is available at openvanilla.org.

One thing that I’d like to mention is that the OS X version comes in two flavors–one for OS X 10.4 and above, and one solely for OS X 10.5–the big cat that is finally unleashed today, and that’s why we choose today to announce its release.

LeopardVanilla

OpenVanilla 0.8 for Mac OS X Leopard has a redesigned engine under the hood. From the appearance it feels just the same as the non-Leopard version, but because Leopard offers us a more clear, easy architecture of developing input methods, we’ll start migrating the entire OpenVanilla framework accordingly. Other than maintain releases of 0.8.x, the next major version of OpenVanilla on OS X will be for Leopard (and above) only.

The major changes of version 0.8, in short words, includes:

  • better visual design elements, including a redesigned candidate window and a set of new icons;
  • redesigned web-site and user manual;
  • the latest version of libchewing for Chewing input method, with an expanded phrase database coverage;
  • wildcard support in Array and Generic input methods, and
  • Support for 3rd party on-screen keyboardlets.

Once again, for download and other information, just visit openvanilla.org.

OpenVanilla: Three Years On

It’s sweet watching a software project grow. And as a birthday present…

OpenVanilla on That Thing

The most important of all is that OpenVanilla helps people–then it fades in the background. It’s getting more interesting and more fun. Bon anniversaire, OpenVanilla!

Next Page »