Welcome to my personal blog. If you're looking for my academic profile page, click the UCD in the upper right corner. Or maybe you're looking for my open source development blog?

Firefox 54 and Looking Ahead

20 Jun 2017

Apparently, the Firefox 54 release a week ago was a bigger deal than I had originally thought.

As I was toiling away on my WebExtensions addon, I took note that Firefox 54 was going to enable the sidebar API, so you can pull up a sidebar drawer from your extension. I mentioned last month in my rough plans of porting Perakun to WebExtensions that it’d be nice to have a drawer that holds the list of word lookups just like in the legacy Firefox addon, and theoretically, it is now possible to do that in WebExtensions. (By the way, I forked another Rikai-kun-based addon that looked further developed, called rikaigu, and the addon works in Firefox and Chrome: check out rikaigu.we.) But I also learned in that time that, while there was discussion of adding it to Chrome as well, in early 2016, they decided not to proceed with sidebar API. So looks like if the addon’s going to be cross-browser compatible, I’m going to have to ditch the idea of a sidebar.

But there’s a bigger reason to be excited about Firefox 54 and that’s the multiprocess architecture revamp! I’m looking forward to web development without the browser choking out because I toggled the DOM inspector while a monster of a page is loading…

Except multiprocess functionality is disabled if you make use of any addons that are “multiprocess incompatible”, i.e. utilizing deprecated APIs.

Perapera Japanese being deprecated is not so bad because our Rikaigu port is essentially a drop-in replacement. Woo!

TiddlyFox is a hard one to lose. I’m pretty dependent on Tiddlywiki for jotting notes, and without this, the Tiddlywiki can’t overwrite itself when you press save but prompts you to save the file to disk. You can just point it to the same file and it will function the same way as a workaround, though.

Also looming at the end of this year is Firefox 57 when some more addons are going to stop working because they’re not WebExtensions. I’m really worried about Tree Style Tab possibly going away in November.

So I’m excited about the changes that have been brought on at the expense of breaking API support for all these addons. I feel like there’s some vocal opposition from addon developers who are getting shafted for something they don’t necessarily agree with from an engineering perspective, and I really do feel for them. While I can see that there’s nothing that can be done if the WebExtensions API is incomplete and you just can’t rewrite what you have if it’s not supported, I believe it’s going to be continually improving, and I really hope that some addons end up living into next year.

I’m also looking to join in the fray with Rikaigu, but that progress report will have to wait until another blog post.

Figuring out Rails API calls via WebExtensions XHR

16 May 2017

One of the questions I had in my last post was about how to manage sessions and login to a Rails app from a WebExtensions client. For example, let’s say your Rails app provides a Profiles resource that you handle in Rails with a route GET /profiles/:id. Let’s say you provide an API endpoint as well, at GET /api/v1/profiles/:id. From your WebExtensions script, you would issue the XHR like so:

var url = "http://localhost:4000/api/v1/profiles/2";
var req = new XMLHttpRequest();
req.open('GET', url, false);

Most likely, the endpoint will be protected by some sort of authentication check. The nifty thing is if you happen to have cookies from, say, having logged in through the web interface of the app, those are automatically sent when you send the XHR, and you can potentially be authenticated that way. But more typically for an API, you might be using Rails token authentication. Rails provides authenticate_or_request_with_http_token, which will look at the Authorization request header for a token that will be used instead of cookies. So you’ll need to do two things:

  1. get the token, and
  2. set it in the request header.

Conventionally, you might see the token made available by the app through some sort of user settings page where the user can copy and paste it into the extension to use for authorization. There might be a more automated way to do this, though.

The second part can be achieved by adding the following to the above snippet:

  var url = "http://localhost:4000/api/v1/profiles/2";
  var req = new XMLHttpRequest();
  req.open('GET', url, false);
+ req.setRequestHeader('AUTHORIZATION', 'Token token=your_token_here');

With this, Rails should be able to pick out the token from the request header and use that to authenticate the request and get your JSON response.

What’s next?

So while you now theoretically have full access to the API, there’s another thing to consider called Cross Origin Resource Sharing (CORS). Basically, it’s a way for a server to specify access control to resources from cross-site scripts, which is what our browser extension is. For example, we don’t want a malicious script to be able to send DELETE requests or otherwise mess with your data. CORS is a way to permit or deny requests, based on where the originating script is coming from.

This may not be an issue because a malicious script would somehow have to get access to the authentication token. But this may mean extra server-side setup depending on how this protocol is enforced across browsers. I’ll investigate the details in the next few days.

Rough plan for Perakun port

13 May 2017

What is Perakun

Perakun is a Firefox extension that helps Japanese learners by providing dictionary lookups for mouseover text. A great feature is its ability to save lookups to a word list. This gif gives a good summary:

State of Perakun

As I mentioned previously, Chrome has taken the lion’s share of the browser market, and Firefox has plans to move to an addon subsystem based on WebExtensions, which will be compatible with Chrome.

Perakun exists as a legacy addon in Firefox for Japanese and Chinese, but only the Chinese WebExtensions addon exists in Chrome, with only a subset of the functionality.

In theory, an addon written in WebExtensions should plug and play in any supporting browser, but there is enough inconsistency in API support where the code will need some updating.

Rough plan of action

  1. Update the Chinese Perakun WebExtensions addon to be fully cross-browser compatible.
  2. Update the addon to support Japanese dictionary.
  3. Restore word list functionality missing from legacy addon.
  4. Add functionality to post to HiNative server for richer learning experience.


Currently, I’ve gotten started fixing up the WebExtensions addon, which you can find on github. I’ve made some simple replacements to some deprecated calls, but it still isn’t functional in Firefox.

Things I need to figure out still, are:

  1. document.caretRangeFromPoint has no equivalent function in Firefox but is being used in Chrome to get the mouseover text. It may be the case that the old way of doing it is still compatible and I will have to port it back in.
  2. Possibility of local SQLite database access? The old addon used Components to get read/write access to a SQLite dictionary packaged with the addon, but I’m not sure it’s possible with WebExtensions.
  3. Login/Session management? I’m pretty sure it’s possible to get user/password and login to HiNative with XHR and proper addon permissions.

WebExtensions and Perakun

09 May 2017

I’ve had this idea of hacking additional functionality onto Perakun for a while now, to make it more useful for taking snippets while reading Japanese. Now that I’m actually diving into it, I’ve learned that there’s a lot of doom and gloom in the Firefox extensions community surrounding the new WebExtensions addon system.

Apparently, the old addon system is going to be phased out by Firefox 57 (slated for November 2017) in favor of WebExtensions. Cited reasons for the move include a need to optimize performance by moving away from the old system (i.e. Gecko) and cross-browser compatibility – WebExtensions addons ostensibly plug into Chrome or any compliant browser with minimal effort. Seeing as how Chrome has 60% market share as of this post, it would be nice to write an extension that can reach that many more users. But developers protest, saying that WebExtensions is still a couple of years out from being even feature-equivalent with what the current addon system offers. The future of some big-name addons beyond the end of this year is unclear. Personally, I am worried about what will happen to my Tree Style Tabs and TiddlyFox support.

But technology trends aside, I really want to take this chance to try my hand at modifying a WebExtensions addon. Chinese Perakun is available in Chrome, but conspicuously, the Japanese version is missing, so I have a straightforward goal:

  1. Clone the Chinese Perakun WebExtensions project and make it fully cross-platform. My test will be that it installs on Chrome and Firefox with no modification.
  2. Create a fork that supports Japanese.
  3. Once the Japanese addon is ready, extend it to be able to post to a Rails app.

I’ve already made headway with my first goal by setting up the cperakun repository. I’ll post a writeup when I’m able to get it up and running in Firefox.

First Android App

23 May 2015 / Filed under Writeup

I’ve finally gotten around to scratching this itch I’ve had and writing this Android app to lookup how to type Chinese characters in Cangjie.

Cangjie is a graphological input method, meaning you type out the character the way it looks rather than how it sounds, like with some Chinese input methods like Pinyin or with Japanese. Knowing Cangjie is handy for studying written language where you don’t know how a character is pronounced. You just decompose the character according to some rules and type it in. The problem is there are a lot of exceptions and tricky cases where you might get stuck. Well, a lot of times, characters reuse components, and you might know how a similar character is pronounced and so you can input it with another method, but at the same time you want to remind yourself of how to key it in with Cangjie. This is the problem I wanted to solve.

Here’s an example character I can easily key in in Japanese. I want to remind myself how to type it with Cangjie…


You take the code and you key it in with the Cangjie keyboard. Practice makes perfect.

I thought this was a simple enough app to get into Android with, so I started off with the Android starter tutorials. The first tutorial gave me pretty much everything I needed as far as UI – then I added a SearchView to the action bar.

The hard part was setting up the database. I decided to piggyback off masaruyokoi’s ChineseCharConverter project. He used Ruby to build a tokyocabinet database to hash Chinese characters to their pronunciations and their Cangjie codes. tokyocabinet is nice and simple database written in C that also has Java bindings, so my plan was to build it for Android and ship the library and the database file with my Android application and access it from there.

That did not really go according to plan.

I really had a tough time figuring out how to properly cross-compile the library. First of all, I didn’t get the Android NDK toolset right at the start but rather downloaded a generic gcc package for aarch64 (this is appropriate for the arm64-v8a architecture of the Samsung S6 that I’m working with). But after I realized that I needed it and got it, I just focused on manually building the library rather than bother with an NDK setup. I just focused on my phone, but NDK contains all the toolchains to support all the Android architectures. I will want to go back and set up the C sources with a proper NDK build as part of the Android project itself. It looks like white-gecko did this conversion a while ago, so I’ll have to refer to his setup.

There was a dependency on bzip2, and I had to build the library itself along with the Java bindings. bzip2 was a simple Makefile project, while tokyocabinet used autoconf. It was quite tricky to configure and I had to tweak the resulting Makefiles. For instance, I had to make sure the soname did not have the version number at the end, otherwise the dynamic libraries can’t resolve and I get a java.lang.UnsatisfiedLinkError from the application. Here are assorted links that helped me figure out how to get it built:

So I was able to get the prebuilt library and database shipped on the phone, but I was still having trouble because I couldn’t open the database. It took me a while trying different methods and locations of storing assets/resources, all the while wondering if I had a permission issue. Android takes care to abstract you from dealing with Files directly, but tokyocabinet actually wants you to give it a File to load its database from. In the end, after asserting I had permission to write, and I’d written a test database on the phone and sent it back to my desktop, I finally realized that the database itself was binary-incompatible across machines. I had to export what I needed from the database in a portable format and build the database up on the phone.

So I had a fun time with Ruby figuring out how to extract JSON from the HDB. This is when I remembered I had OBS set up and started recording a screencast. You can watch me export and import JSON and setup the database query in the Youtube video. Check the description for some timestamps at events leading up to the screenshots you see in this writeup up above. There’s no commentary in this video, so feel free to mute the music if it’s not your thing. I’ve always thought watching people code is cool, and I want to do this kind of thing more, possibly with commentary or just idle chatter with the mic on.

Anyways, I think I had a pretty fun coding session. Android Studio feels quite nice to work with, and I feel like I have gotten a good warmup with Android. As far as this app goes, I want to add a few more things before I put it up on Github, like search history.

← Older

Newer →

Alex Tsui

Alex Tsui

Computer science grad student at UC Davis, writes C++, enjoys learning languages, and occasionally video games.