My Nostalgia for Physical QWERTY Keyboard Phones

Recently I got a niche physical QWERTY keyboard phone named Unihertz Titan Slim. This phone ignited my enthusiasm for QWERTY keyboard phones again, so I am starting to draft this post to note this enthusiasm.

From what I can recall, it was in 2008 when I was still studying for my master’s degree. I was totally a Microsoft fan, and using my first touchscreen cellphone, which was running Windows Mobile OS. It was pretty interesting because I could flash the phone with different kinds of third-party ROMs sometimes and also could implement cellphone-dedicated software by myself in C# when I could not find suitable software to meet my own requirements. We even did not call software an App. But I must say, the touchscreen didn’t provide a good experience. Also, the interaction of mobile OS was not fully evolved, and most of the operations should be performed with a stylus.

Samsung i718

One of my classmates, Solrex, introduced his BlackBerry cellphone to me. Although the BlackBerry cellphone also has a non-touchscreen like other mainstream phones, its OS, together with the side pressable scroll wheel, made a pretty fluent interaction that totally attracted me. After that, I also got a second-hand BlackBerry 8700 for myself. As I know, only second-hand BlackBerry phones were available in China in 2008.

BlackBerry 8700

This became my first physical QWERTY keyboard cellphone.

Blackberry 8700

At a time when stroke and nine-grid input methods were dominating, the QWERTY keyboard was kinda a breath of fresh air in the cellphone market. The experience brought by the full keyboard really kept me from using the numerical nine-grid keyboard for quite a long while. Furthermore, the fluent experience of the pressable scroll wheel significantly overpassed the most popular combination of arrow and confirmation buttons. At that time, BlackBerry mainly focused on the business sector, and it was deniable that BlackBerry made a lot of effort to hardware interaction to improve the efficiency of the operation to a new level.

Actually, for quite a long while, BlackBerry was just a niche brand focusing on the business sector until former U.S. President Obama made a stubborn decision that brought BlackBerry into public sight. Theoretically, Obama should replace his own cellphone with a presidential cellphone when moving into the White House, but Obama insisted on retaining his BlackBerry cellphone. This interesting decision successfully pushed BlackBerry into the headlines.

With the rising market domination of Android and iPhone, most of the Apps stopped to improve the compatibility with BlackBerry OS, so I had to stop to use a physical QWERTY keyboard cellphone. Still, I never stopped to wait for BlackBerry to release a new fantastic product. Finally, it came.

BlackBerry Passport

BlackBerry is called Passport because its shape and size are the same as a passport.

Size of Blackberry Passport

Its unique design language, such as the square screen, deeply attracted me. Furthermore, BlackBerry innovatively added a touch feature to the QWERTY keyboard that can allow you to scroll through menu items and browse web pages by sliding your fingers on the keyboard, which really amazed me.

Navigating the cursor by sliding your fingers on the keyboard

Moreover, the BlackBerry OS 10 running on BlackBerry Passport supports Android Apps, although only up to Apps of Android 2.3, this definitely could meet daily requirements at that moment. This was one of the significant reasons I used the BlackBerry QWERTY keyboard cellphone again.

To buy this phone, I tried overseas shopping for the first time. I ordered from the US BlackBerry official site, and shipped it to Hong Kong, then asked my friend to help bring it from Hong Kong to mainland China.

Generally speaking, except for the UI compatibility issue caused by the square screen, all is well 😄.

The End of BlackBerry Cellphone

Since 2016, BlackBerry has stopped to develop any cellphone hardware. Instead, it started to license third-party companies to release cellphones. Although BlackBerry no longer developed hardware, it still participated in the design part, so several cellphones released by TCL, one of the third-party licensed companies, such as BlackBerry KEYone, was still good product. However, TCL also claimed it would not design and release any BlackBerry cellphones in 2020. BlackBerry ended all the BlackBerry cellphone services in 2022, leading to the end of BlackBerry cellphones.

One Gift to Physical QWERTY Keyboard Cellphone Enthusiasts

Although BlackBerry phones have exited the stage of history, there are still some niche companies carrying on this nostalgia, such as Unihertz. The cellphones released by this company are all very niche and distinctive. For example, the Atom XL, which is also a walkie-talkie; the Jelly series, featuring the smallest 4G phone in the world; the Tank with a terribly long battery life (22000 mAH); and the Titan series that replicates BlackBerry cellphones with a physical QWERTY keyboard.

Titan Brought me Back to BlackBerry.

Unihertz Titan

Because of my love for BlackBerry Passport, Titan caught me at first glance. Although there was really a big gap between Titan and BlackBerry Passport, some of Titan’s design elements made me feel that Unihertz truly understands some of the characteristics and pain points of BlackBerry.

The Dilemma of the Square Screen

The most frequent problem during the usage of BlackBerry is that some of the applications cannot be compatible with the square screen. However, Titan allows us to toggle the mini mode, which can change the aspect ratio of the screen’s display area by wiping the screen downward with three fingers. This is really convenient.

Toggle Mini Mode

Excellent Inheritance and Optimization

Also, besides inheriting some advantages from BlackBerry Passport, such as using the keyboard as a touchpad, and physical QWERTY keyboard, it provides the Kika input method that is highly optimized for a physical QWERTY keyboard.

Too Heavy!

No matter whether Titan is a replica of the BlackBerry Passport or a rugged cellphone, it is both qualified. But it is so heavy that it causes wrist soreness after using it for a while. Maybe the good thing is this can significantly reduce my screen hours. Besides this, with the rising complication and functionalities integration of applications, the square screen definitely becomes a terrible bottleneck.

The high frequent toggle of mini mode and heavyweight made me eagerly hope that Unihertz will release a slim and relatively light physical QWERTY keyboard cellphone. Finally, Titan Slim came.

Titan Slim

Unihertz Titan Slim

In the image above, Titan is on the left; in the middle, it is Titam Slim, and on the right is Titan Pocket. Titan Pocket was released after Titan before Titan Slim. Although it is lighter, its square screen made me give up.

Unihertz Titan Slim

Regarding hardware and software, Titan Slim has certain improvements compared to Titan, but it does not have significant changes overall. Besides inheriting several UI features from Titan, such as using the keyboard as a touchpad, physical QWERTY keyboard, etc., finally, it uses a rectangle screen to replace the square screen to have better compatibility with current mainstream Apps. Maybe due to the physical QWERTY keyboard, Titam Slim is still relatively thick, but at least it is much lighter compared to Titan. Long use of this cellphone doesn’t easily cause wrist soreness. So at present, Titan Slim is my primary cellphone.

Will BlackBerry Like Cellphone Continue?

In fact, continuing with BlackBerry is not an easy thing. Nowadays, niche manufacturers such as Unihertz are still remastering BlackBerry cellphones, and I can’t say the remasters are perfect or satisfying. To continue with BlackBerry, I have to make some compromises. For example, Samsung is my favorite none physical keyboard cellphone brand, but I had to temporarily say goodbye to physical QWERTY keyboard cellphones to use Samsung cellphone. And now I need to leave my Samsung cellphone for a while to use Titan Slim as my primary cellphone. Maybe the only thing that comforts me a little is mostly I need two cellphones, one for primary use and one for work. But actually, the screen hours of my work cellphone are very few. Mostly, I use my work laptop.

So I always hope that a more perfect physical QWERTY keyboard cell phone will come so that I don’t need to make compromised choices.

reMarkable 2: One Highly Customisable New Toy

Got the budget on my birthday, and the Black Friday deal was not bad, so I finally got a new toy: the reMarkable 2. 😂

reMarkable 2
reMarkable 2

Before I got this tablet, several guys recommended this to me, and what finally convinced me to buy it was no more than its extreme paper-like writing, thinness, lightness, design, etc. But after I experienced this reMarkable 2, I found its usefulness and customizability were totally beyond my expectation. The most surprising thing is that reMarkable OS is based on Linux and the manufacturer generously exposes the SSH port and root password.

During the year-end holiday, I went through this tablet a lot and would take notes with this post.

Functionality Completeness

Language Issues

The reMarkable 2 does not support non-Latin characters, so CJK (Chinese, Japanese, and Korean) characters are displayed as squares, as below.


One compromised solution is to use PDF only if possible, but we still need to ensure that all the necessary fonts are embedded in the PDF documents. If any CJK characters apply fonts not embedded in the documents, they will still be displayed as squares.

Luckily, the OS of reMarkable is based on Linux, and the SSH and the root password are available, so we can easily install the CJK fonts. Take this page as a reference for installing the RMPKG.

cd /tmp;
chmod +x *.rmpkg
./NotoSansCSFont.rmpkg --install
./NotoSansCTFont.rmpkg --install
./NotoSansJPFont.rmpkg --install
./NotoSansKRFont.rmpkg --install
rm -f *.rmpkgCode language: Bash (bash)

And the Noto Sans font can support CJK characters now.

Type Diversity

The reMarkable 2 only natively supports PDF and EPUB, but more is needed. Toltec, this community-maintained repository of free software for the reMarkable tablet, helps. With Toltec, we can install KOReader into reMarkable 2. Thanks to the powerful format compatibility, we can read documents in almost all major formats with the reMarkable 2.

## Use opkg to install remux and koreader after installing the Toltec
opkg update
opkg upgrade
# remux
# Launcher that supports multi-tasking applications 
opkg install remux
# KOReader
# Ebook reader supporting PDF, DjVu, EPUB, FB2, and many more formats
opkg install koreaderCode language: Bash (bash)

There is one thing that needs to be highlighted. The shelves of the reMarkable and KOReader do not share; we can surely use cloud storage to solve this. I will share this later. Before installing the Toltec, please ensure that the current Toltec release can support the OS version of your reMarkable tablet.

The Toltec repository includes lots of exciting software. Take your time to go through it if you are interested.

Article Management and Document Management

The reMarkable provides a browser extension. With this extension, users can convert web pages into EPUB documents and put them on the reMarkable’s shelf with one click. It is really convenient, but it is hard for me to get used to it.

  1. The format of the EPUB document content converted by the extension looks strange.
  2. Years of using Pocket as a read-it-later application make me not plan to switch to reMarkable. And I don’t want to put all my saved web pages on the reMarkable’s shelf.

So I started automating pushing the saved pages from Pocket to reMarkable, and I recalled n8n, an open workflow automation platform.

I heard about n8n before, and I tried this time and found it was really convenient. I deployed n8n on the NAS, then created this workflow quickly. You may see that the UI of workflow on n8n is really visual and user-friendly.

Pocket 2 Google Drive
Pocket 2 Google Drive

I use a scheduler to trigger the workflow below.

  1. Get the saved timestamp of the last run, and retrieve the pages saved after the last run. The API for retrieving the saved pages has an optional parameter: since. With this parameter, Pocket will only return items modified since the given UNIX timestamp.
  2. If the list is not empty, the workflow will use the OneSimpleAPI to convert the web pages into PDF documents and upload them to Google Drive one by one.
  3. Update the saved timestamp to present.

The above workflow nodes of OneSimpleAPI and Google Drive are natively supported by the n8n and are very easy to call.

These tips may reduce some of the confusion when you are creating a similar workflow:

  1. The since parameter of Pocket API uses the last modified time as a reference. If you would like to push some outdated saved pages to Google Drive, you just need to make a slight change to them, such as tag modification and resaving it again, and these pages will be pushed to Google Drive.
  2. When you trigger a deletion of a saved page, Pocket will update the status of this page to 2 before the page is totally removed. So please ensure all the saves whose status is 2 will be filtered out to prevent unnecessary uploading.

The Google Drive node supports two authentication methods: OAuth 2 and ServiceAccount. OAuth 2 requires that your callback URL contains a domain name other than an IP. For security, my NAS blocks all direct external access and only allows VPN access, so I have not bound my NAS to any domain name. So anyone whose NAS is in the same situation as mine, please prefer ServiceAccount. Primarily the service account is not your Gmail account, so please grant the R/O permission to the Google Drive folder of your reMarkable documents to the service account.

Permissions Granted to Service Account
Permissions Granted to Service Account

Actually, I can directly push the documents onto the reMarkable shelf, but I don’t think this is a good idea. The limitation of documents’ count on the reMarkable shelf can help me focus more on the current readings before I pick new readings from Google Drive. I will not let too many documents mess up my reMarkable shelf.

As I mentioned, the shelves of KOReader and reMarkable 2 don’t share, so using Google Drive to store my pending readings can make the shelves tidier. It is also easy for KOReader and reMarkable 2 to retrieve the documents wirelessly.

Publication management

Ages before, I started to use Calibre to manage publications, such as novels, books, comics, papers, etc. Then I moved the library of Calibre to NAS and ran Calibre Web in a Docker container so that I could manage the publications from any device.

Calibre Web is not an official product of Calibre, and there is more than one fork on GitHub. I prefer the image managed by If you have never used Calibre before deploying Calibre Web, you will need a new library file (metadata.db) to initiate the configuration. You can install Calibre to create a library or download it from here.

Besides the publication management via web UI, Calibre Web also supports the OPDS catalog.

The Open Publication Distribution System (OPDS) Catalog format is a syndication format for electronic
publications based on Atom and HTTP. OPDS Catalogs enable the aggregation, distribution, discovery,
and acquisition of electronic publications.

OPDS Catalogs use existing or emergent open standards and conventions, with a priority on simplicity.

OPDS Catalog 1.2

In this way, I can search for publications from the OPDS catalog.

# curl --user {username}:{password} "http://{IP}:{port}/opds/search/{queryString}"
curl --user username:password "http://{IP of NAS}:8083/opds/search/root%20cause"Code language: Bash (bash)

If items exist, the OPDS catalog will send an XML containing publication information, including book names and links, as a response.

<?xml version="1.0" encoding="UTF-8"?>
  <link rel="self"
        href="/opds/search/root cause?"
  <link rel="start"
  <link rel="up"
  <link rel="search"
  <link type="application/atom+xml" rel="search" title="Search" href="/opds/search/{searchTerms}" />
    <title>Root Cause Analysis Handbook</title>
      <name>ABS Consulting</name>
      <name>Rothstein Publishing</name>
    <category scheme=""
              term="Business &amp; Economics"
              label="Business &amp; Economics"/>
    <summary>Are you trying to improve performance, but find that the same problems keep getting in the way? Safety, health, environmental quality, reliability, production, and security are at stake. You need the long-term planning that will keep the same issues from recurring. Root Cause Analysis Handbook: A Guide to Effective Incident Investigation is a powerful tool that gives you a detailed step-by-step process for learning from experience. Reach for this handbook any time you need field-tested advice for investigating, categorizing, reporting and trending, and ultimately eliminating the root causes of incidents. It includes step-by-step instructions, checklists, and forms for performing an analysis and enables users to effectively incorporate the methodology and apply it to a variety of situations. Using the structured techniques in the Root Cause Analysis Handbook, you will: Understand why root causes are important. Identify and define inherent problems. Collect data for problem-solving. Analyze data for root causes. Generate practical recommendations. The third edition of this global classic is the most comprehensive, all-in-one package of book, downloadable resources, color-coded RCA map, and licensed access to online resources currently available for Root Cause Analysis (RCA). Called by users &#34;the best resource on the subject&#34; and &#34;in a league of its own.&#34; Based on globally successful, proprietary methodology developed by ABS Consulting, an international firm with 50 years&#39; experience in 35 countries. Root Cause Analysis Handbook is widely used in corporate training programs and college courses all over the world. If you are responsible for quality, reliability, safety, and/or risk management, you&#39;ll want this comprehensive and practical resource at your fingertips. The book has also been selected by the American Society for Quality (ASQ) and the Risk and Insurance Society (RIMS) as a &#34;must have&#34; for their members.</summary>
    <link type="image/jpeg" href="/opds/cover/30" rel=""/>
    <link type="image/jpeg" href="/opds/cover/30" rel=""/>
    <link rel="" href="/opds/download/30/pdf/"
          length="24812876" mtime="2022-12-22T07:56:20+00:00" type="application/pdf"/>
</feed>Code language: HTML, XML (xml)

Based on this, I created the workflow below to upload the document I need to Google Drive automatically.

Query the books and upload the needed books to Google Drive.
Search for the book and upload the needed books to Google Drive.

I use the Webhook node to pass the query string to the OPDS catalog to search for the publications.


There are many functionalities worth going through on reMarkable, such as templates. I am amazed by the completion of reMarkable’s support for PDF, especially the support for the internal links. Many E-ink tablets almost don’t support internal links in PDF documents. Even to support some significant internal links such as tables of contents, they compromise toggle a menu to help users locate the pages instead of jumping during the document reading.

So we can generate templates with reCalendar. This template can help us plan and summarize in a year-month-day dimension. To prevent loading too long, the timespan of the preview below is only two months. You can also tweak the template by adding special dates, modifying the timespan, etc., with reCalendar.

Loader Loading…
EAD Logo Taking too long?

Reload Reload document
| Open Open in new tab

Here is all about reMarkable 2 I learned. I will keep digging and will share more. 😁

Talking about Device Management and Multi-computer Management: Is Wireless Always More Convenient than Wiredness?

As a former CS student and an ITer, the computer has become an inevitable part of my life. And also how to well manage the computers and peripherals is always a changing problem.

Why does this problem keep changing?

Environments Decide the Requirements

When I was in university, what I could control was just a tiny desk in the dormitory. So at that moment, I hoped all the peripherals would be slim and wireless so I could quickly put the mouse and keyboard into the drawer without unplugging the cable.

I have to say that if we forget to turn off the mouse and keyboard, the receiver drains the battery really fast 😂. There was no Bluetooth then, and the early versions of Bluetooth were unsuitable for data transmission between computers and peripherals.

One Wireless Mouse and Its Receiver
One Wireless Mouse and Its Receiver

Looking at the HUGE CRT and chassis, having a laptop became my dream then. In this way, I could take it everywhere. Especially during summer and winter vacations, I could take it home 🤭.

CRT and Chassis
CRT and Chassis

After graduating, nearly all my computers are laptops. And due to Apple, most manufacturers are simplifying the ports on the laptop, so I have to make sure most of the peripherals should support Bluetooth. Then, due to the need for confidentiality at work, I had to ensure all Bluetooth devices could memorize multiple pairs to separate my personal laptop and office laptop so that I could conveniently switch one set of peripherals between my personal laptop and office laptop.

Is Wireless Always More Convenient than Wiredness?

However, due to the requirements of my employer and myself, my device management has become incredibly complicated 🤦. I need to ensure one set of peripherals can switch smoothly across four laptops and one chassis. Obviously, Bluetooth is unable to handle this.

By the way, owning five laptops is not weird. When I was working on a mobile project at my former former company, I had more than ten cellphones, several tablets, and four computers, but of course, nearly all of them did not belong to me but my employer. At that moment, there was no cloud testing platform for mobile projects, so all the tests needed to be processed on local devices.

Let’s get back to the main topic. Luckily most of the peripherals I had were dual mode, which means supporting cable and Bluetooth; this made me figure out a compromised solution. I connected the keyboard, mouse, and display to one multiport adaptor, and I could easily switch this adaptor from the currently connected computer to another chosen one. Since the COVID situation is not so intense, I sometimes need to go to the office. When I need to go to the office, I can unplug the display and put the laptop into my backpack with the adaptor, keyboard, and mouse.

Days ago, one question popped up in my mind. If a device named HDMI switch can switch the video sources smoothly, why is there not a device that can help us conveniently switch the peripherals across the computers? Then I found it, and it is KVM Switch. This KVM is not a Kernel-based Virtual Machine; it is the abbreviation of Keyboard, Video, and Mouse.

KVM switch (with KVM being an abbreviation for “keyboard, video, and mouse”) is a hardware device that allows a user to control multiple computers from one or more sets of keyboardsvideo monitors, and mice.

From Wikipedia
KVM Switch Diagram
KVM Switch Diagram

This switch really saved my life. I don’t need to leverage more than one set of peripherals to cover all my computers or don’t need to plug in and out whenever I switch across my laptops. This switch also makes my desktop tidier, although it is still not quite tidy.

Choose the Suitable KVM Switch

The type of KVM switches varies and is not easy to choose. If you want one, keep an eye on the tech specs, especially the HDMI part.

  1. Confirm the number of devices you would like to switch across.
  2. The type of USB ports. Due to the velocity gap between USB 1 and USB 2, consider it based on your own devices, such as whether you have external high-capacity storage devices or others.
  3. The type of HDMI ports. If you have devices supporting HDMI and Dolby Vision, such as Apple TV and Xbox Series X, please check whether your chosen KVM switch supports this. And HDR has several types of video formats, such as HDR, HDR 10, HDR 10+. The same as audio, its encoding varies.
  4. High resolution and refresh rates are pretty important for video and game enthusiasts.
  5. And also, hot-swapping affects the user experiences a lot.

Hopefully, this small talk can help guys with multiple computers a little.

The Method that I Used to Improve My English Initially


Actually, this post is not suitable for English native speakers or guys that are good at English. To avoid wasting any chances to improve my written English, I still put an English version of this post here. If you are interested in the Chinese version, feel free to switch with the language switcher in the menu or widget.

Best regards and thanks,

I have worked at a company where nearly no one speaks Chinese for more than one year. During the chitchat, most colleagues seemed quite amazed when they learned that I had never worked in an English-speaking environment or studied abroad. This also tells one thing that is mute English is prominent in China.

These days some of my friends in China come to ask me to share how to improve my English. My English still sucks, many guys are excellent at English without experience working and studying abroad, and I don’t dare to claim that I can teach. However, I still decided to share the method that I used to improve my English initially, and I hope this post can help buddies who would like to lead some changes in their lives find the entry for practicing English 😄.

Open your mouth

Actually, I occasionally started my English practicing. At that moment, I had just moved from Beijing to Hangzhou, so I nearly had no friends. To make some friends not among my colleagues, I decided to have a try in some English corners.

Luckily, I found an English corner called Have Fun English Club and made several exciting friends. Here I should say thank you to these friends because I couldn’t get through an extremely dark period in my life without them. In the beginning, I am a typical minor mute English speaker. I could talk really a lot very fast in Chinese, but when I switched to English, I became a low-voice stammerer. Thanks to my thick skin, I quickly became one of them. At that moment, I told myself that mistakes were acceptable, but retreat was absolutely not allowed. 🤣 To make more friends, I applied to be a volunteer at HFEC. As a volunteer, I needed to help initiate topics for activities and act as the Group Leader during the activities. Gradually practicing English became one of my favorite things. (I will draft another post introducing how we run the English club. Our way is quite unique and one of the most popular. Some other English corners learn from our way.)

After a short while, HEFC was disbanded due to some internal issues. Suddenly we were bored when out of English club activities. To continue improving our spoken English and make more friends, we, friends known at HEFC, founded Whatever English Club. We ran it the same way as HEFC and added more game elements. It was pretty good and became popular among local English corners.

To improve spoken English, don’t give yourself too much pressure, especially in the beginning. For example, don’t care too much about the accents. If you have a chance to talk to many foreigners, you will see that there are a large number of kinds of accents around the world. You will also see that the accents can never cover their excellent English skills. Also, don’t care too much about making mistakes. We always make mistakes even when speaking in our mother tongue, so why do we need to care about making mistakes when speaking in English. Mistakes lead to rectifications which lead to improvement.

Regard yourself as a primary school student

Many friends mention that they always stumble when speaking in English because their mouths cannot catch their brains. But why the month cannot catch the brain is hard to clarify.

Once, someone told me that why Chinese are bad at speaking English is mainly due to our excessively excellent Chinese.

I think this really makes sense, and let me share my understanding. When you just started learning English, I believe whenever you would like to speak in English, firstly, you would figure out how to say it in Chinese, and secondly, you would translate that into English and speak out. But Chinese is our native Tongue, and Chinese and English belong to two totally different language families. So when you were trying to translate these beautiful Chinese lines into English, you would be stuck entirely and end with ”err…”.

Therefore my way was to force myself to become a primary school student. Whenever I would like to express sth. in English, I would use the basic subject-verb-object structure to build my line without idioms, proverbs, hymns, and other literary techniques. So that it would be much easier for me to translate the lines into English, the fewer chances I am stuck, the more confident I am, and the longer I will keep practicing.

Regard yourself as a foreigner

We may always face such a situation when speaking in English with another non-English speaker. For example, during a conversation in an English corner or during a session with my Polish colleagues. The situation is they may not be able to understand a word or a phrase we mentioned. If we don’t practice enough, the conversation will end with a long awkward silence.

So after becoming a primary school student, I began to try to make myself a foreign primary school student. I started to look up words in English-English dictionaries instead of English-Chinese dictionaries. After that, I gradually became able to explain it in another way in English to others when they could not understand what I said. In my opinion, this is a beneficial English communication skill.

By the way, I have not memorized words based on a word list for a long time, and it is much easier for me to remember new words I meet when I look them up in English-English dictionaries. Meanwhile, Lexico became one of my favorite sites.

Make yourself in a “foreign country”.

Someone always says that the environment is significant to learning English, so guys in a foreign country improve their English really fast. I may say this is half right and half wrong, cause English learning can really benefit a lot from a suitable environment. But it doesn’t mean that all the ex-pats count. Some guys that work in a team full of Chinese speakers speak only in Chinese during working hours and still talk in Chinese with family after work. The only chances that need English are shopping and dining. So their English has not been significantly improved even after years.

I watched TV series with only English subtitles to immerse myself in English. We may not understand a lot initially, but English subtitles can also help us accelerate our reading velocity. Although I also like to watch movies, I watch TV series much more than movies because the lines in TV series are closer to life than in movies. And this makes the immersion more real. If the lines are too difficult, English animation may be a better choice as a kickstart because guys talk slower with simple words in most English animation. I don’t use all but most here because there are exceptions. For example, the speed of speech and vocabulary are both terrible in Rick and Morty. After a long while, I began playing with my cellphone while watching the videos. If I couldn’t catch, I would reverse a little. I know this really made me spend more time finishing watching every episode, but it was worth trying because gradually, I was able to listen to English lines as to Chinese ones. For example, I am drafting this post while watching one of the episodes of Young Sheldon. Because when we are listening to guys chatting in Chinese, we don’t need to concentrate on that. Thanks to this practice, now I can have sessions with guys in another time zone at noon when I have a lunch box. Besides this, I also listened to English podcasts, news, TV series lines, etc., when performing things that needed less concentration, such as commuting, cooking, surfing the Internet, etc. By the way, I think listening to the news is the hardest because they are all very short and mostly have no contextual relationship to the previous one and the next one.

Let me share the milestones of improving my listening and sense of English:

  • One day, I found that I didn’t need to stare at the subtitles all the time.
  • One day, I found that I could catch the pace even though I played with my cellphone during the video play.
  • One day, I found that I could pick out the errors in the subtitles.
  • One day, I found that I could be aware of the story even though I played with my cellphone during the video play.
  • One day, I found that I could get their point when someone suddenly talked to me in English.
  • One day, I found that I could understand the whole story after watching the video without subtitles.

The change above is the process from quantitative to qualitative change based on long-term practice. In a word, do keep practicing patiently.

But I also should admit that if you stay in a foreign country and fully use this environment, your English can improve significantly. At least, my improvement here is much faster than before; of course, this also benefits from fundamentals accumulated by my long-time practice.

Result Evaluation

I worked really happily in Hangzhou but still faced some issues, so I tried several overseas companies when I just became into practicing English. As I expected, all ended due to poor communication in English. Ages later, my baby was born, and I would like to make some changes to my life. I tried four companies and came across many rounds of interviews in English with Indian, Irish, American, Italian, Japanese, Singaporean, or Chinese interviewers. And all of them issued offers to me. This really encouraged me to keep practicing my English.

Rule No. 1 to make your practicing count is that do not deceive yourself. Don’t make English learning become your excuse to be a video addict. And watching them for English learning is the key.

Do not waste any chance to practice your English.

The longer I worked in the current company, the more shortcomings in English I found. For example, my poor written English. I cannot stand my poor English mail, so Grammarly has also become one of my favorite sites. This is also one of the reasons for reopening my blog and setting this up as a bilingual site. Not sure if you have noticed that every post here has two versions of Chinese and English. And you can easily switch between versions with the language switcher in the menu item and the widget. I hope I can improve my written English by writing more. To avoid wasting any chance to practice my English, I also put an English version of this post here even though this post is not suitable for English speakers 🤣.

So much for the stories about my English learning. During English learning, practicing is a complicated and inevitable process. Don’t expect can get this immediately, and giving up too fast means you are not ready to learn English yet. I would be honored if anyone could get just a little from this post. If this post can inspire anyone to practice English, I am happy to hear that.

Hammerspoon: one Swiss Army Knife on macOS

I may believe that most computers contain unique customizations, which may be why most people hate reinstalling the operating systems or setting up a new computer.

Such as my laptop, there are a bunch of tools that improve my experience using a computer. Here is a non-exhaustive list:

SizeUpCan easily attach the windows to the sides or corners of the screen. If the screen is big enough, you may put the documentation on the left and IDE on the right.
Pap.erIt can periodically and automatically set a beautiful sightseeing image as your wallpaper.
StretchlyTimely covers your screen to make you have a rest.
Lexico.comThe official site of the Oxford dictionary.
CheatsheetIt can show you the list of the selected application’s hotkeys.
New Terminal HereOpen a terminal with the current folder path.
One non-exhaustive list of my favorite tools

Besides improving my experience in using a computer, these tools also cause a few inconveniences, especially when I need to reinstall the OS and set up a new laptop. I have to look for an alternative because sometimes one is no longer free of charge, or sometimes one no longer supports the latest OS. This didn’t bother me much until I changed my Macbook Pro thrice in half a year. So I tried to find a way to minimize the number of tools I relied on, and I found Hammerspoon. I can say this is really a Swiss Army Knife on macOS.

Actually, there are some similar tools, but Hammerspoon finds the best balance between usage simplicity and functionality complexity. The users only need a little knowledge of Lua before customizing with Hammerspoon. Under the situation of no experience in Lua, I quickly finished the customizing based on the official documentation.

We can customize with the official spoons, such as windows manipulation.

-- We can quickly implement this with the WinWin spoon

-- Check whether WinWin is loaded and bind hotkeys to different directions.
if spoon.WinWin then
  -- Supporting symbol characters in the message of Hammerspoon is quite helpful. We will talk about this later. I will talk about this later.
  -- Side
  hs.hotkey.bind({"cmd", "alt", "ctrl"}, "left", "Window ⬅", function() spoon.WinWin:moveAndResize("halfleft") end) 
  hs.hotkey.bind({"cmd", "alt", "ctrl"}, "right", "Window ➡", function() spoon.WinWin:moveAndResize("halfright") end) 
  hs.hotkey.bind({"cmd", "alt", "ctrl"}, "up", "Window ⬆", function() spoon.WinWin:moveAndResize("halfup") end) 
  hs.hotkey.bind({"cmd", "alt", "ctrl"}, "down", "Window ⬇", function() spoon.WinWin:moveAndResize("halfdown") end) 
  -- Corner
  hs.hotkey.bind({"shift", "alt", "ctrl"}, "left", "Window ↖", function() spoon.WinWin:moveAndResize("cornerNW") end) 
  hs.hotkey.bind({"shift", "alt", "ctrl"}, "right", "Window ↘", function() spoon.WinWin:moveAndResize("cornerSE") end) 
  hs.hotkey.bind({"shift", "alt", "ctrl"}, "up", "Window ↗", function() spoon.WinWin:moveAndResize("cornerNE") end) 
  hs.hotkey.bind({"shift", "alt", "ctrl"}, "down", "Window ↙", function() spoon.WinWin:moveAndResize("cornerSW") end) 
  -- Stretch
  hs.hotkey.bind({"cmd", "alt", "ctrl"}, "C", "Window Center", function() spoon.WinWin:moveAndResize("center") end) 
  hs.hotkey.bind({"cmd", "alt", "ctrl"}, "M", "Window ↕↔", function() spoon.WinWin:moveAndResize("maximize") end) 
  -- Screen
  hs.hotkey.bind({"alt", "ctrl"}, "right", "Window ➡ 🖥", function() spoon.WinWin:moveToScreen("next") end) 
  -- Other
  hs.hotkey.bind({"cmd", "alt", "ctrl"}, "/", "Window Undo", function() spoon.WinWin:undo() end) 
endCode language: PHP (php)

It is pretty easy, right? Only several hotkey bindings to functionality are enough.

We can also create spoons with the API, such as BreakTime.

To implement this, we need to periodically use a page or image to cover the whole screen to make the guys in front of the PC take a rest.

Firstly, we can quickly start a timer with hs.timer:

obj.Timer =, refresh)
obj.Timer:start()Code language: PHP (php)

Then, we can create a page covering the whole screen with hs.webview. Using a transparent image to make the page translucent is also not bad.

function makeBrowserOfBreakTime ()
  local screen = require"hs.screen"
  local webview = require"hs.webview"

  local mainScreenFrame = screen:primaryScreen():frame()
  browserFrame = {
     x = mainScreenFrame.x,
     y = mainScreenFrame.y,
     h = mainScreenFrame.h,
     w = mainScreenFrame.w

  local options = {
      developerExtrasEnabled = true,

  -- local browser =, options):windowStyle(1+2+4+8)
  local browser =, options):windowStyle(1+2+128)

  return browser
endCode language: PHP (php)

Next, we can show and remove the cover with browser:show() and browser:delete() periodically with the timer.

function refresh()

  obj.curTime = obj.curTime + 1
  if obj.curTime > obj.microbreakInterval then
    obj.curMicrobreakCount = obj.curMicrobreakCount + 1
    if obj.curMicrobreakCount > obj.microbreakCount then .. " minute break starts")

      local browser = makeBrowserOfBreakTime();
      browser:url("file://" .. hs.spoons.scriptPath() .. "BreakTime.html?time=" .. (obj.breakTime * 60 - 1)):show()
      hs.timer.doAfter(obj.breakTime * 60, function()
        if browser ~= nil then 

      obj.curMicrobreakCount = 0
    else .. " second microbreak starts")

      local browser = makeBrowserOfBreakTime();
      browser:url("file://" .. hs.spoons.scriptPath() .. "BreakTime.html?time=" .. (obj.microbreakTime - 1)):show()
      hs.timer.doAfter(obj.microbreakTime, function() 
        if browser ~= nil then 

    obj.curTime = obj.curTime - obj.microbreakInterval

endCode language: JavaScript (javascript)

Load the BreakTime spoon in the same way to load the WinWin spoon, and start it. Done!

We can also customize the taskbar menu to improve the user experience.

Take BreakTime as an example. We can show the timeline of the next break.

BreakTime's Menu
BreakTime’s Menu

Besides this, we can also show all the hotkeys defined with Hammerspoon.

Menu showing all the hotkeys
Menu showing all the hotkeys

Hammerspoon supports symbol characters quite well, so users can make the menu items more attractive. Isn’t this amazing? 😄

obj.menubar:setTooltip("Hot Key Info")

local hotkeys = hs.hotkey.getHotkeys()
local menuItem = {}
for key, value in pairs(hotkeys) do  
  local item = { title = value["msg"] }
  table.insert(menuItem, item)

obj.menubar:setMenu(menuItem)Code language: JavaScript (javascript)

Besides all the above, Hammerspoon still has much that needs going through. I am also keeping going through to make my customization more additional. Here’s mine.

BTW, not only reinstalling these tools, but I also need to reinstall all of the common applications such as VS Code, Plex, Sublime Text, VIM, etc. This is also terrible. Now I am maintaining a tap list containing the applications with homebrew. 😂

ImgCache 0.2.1 Released

I promised 12 years ago that I would enable the HTTPS support in the next release. And now, I have finally released a new version of ImgCache. I also made fun of myself for this in my first blog post. Now I have made my word and implemented this in this version. Better late than never 😂

Released ImgCache 0.2.1 after 12 years
Released ImgCache 0.2.1 after 12 years

Besides enabling the HTTPS support, I upgraded the Snoopy class, updated the code format and the README file, and fixed two interesting bugs.

The first one is about the suffix extraction of the cache images. When I coded for the HTTPS support functionality, I passed the test with PNG images. But when I tried with SVG images, the cached images didn’t show on the pages because the suffix of the cached image file was not .svg but .svg+xml.

To be honest, I could hardly remember how I confirmed the suffix in this 12-year-old ancient code. So I went through the code and found the suffix was defined based on the Content-Type inside the HTTP header fields when accessing the image’s link. The HTTP header will contain a field named Content-Type like this Content-Type: image/png when we access the image’s URL. This field helps clients confirm the MIME type of the response, so we can use the former part before / to verify whether this is an image and use the later part after / to get the suffix. Because I was the one who mostly used this plugin, I only tested with several typical image types and released it when I passed all the cases

But the Content-Type of SVG is image/svg+xml not image/svg. The cached image doesn’t show on the pages because we set .svn+xml as the suffix of the cached image file.

It says on Wikipedia that SVG is an XML file containing all the vector graphic information. That makes sense.

Scalable Vector Graphics (SVG) is an XML-based vector image format for two-dimensional graphics with support for interactivity and animation. The SVG specification is an open standard developed by the World Wide Web Consortium (W3C) since 1999.

SVG images are defined in a vector graphics format and stored in XML text files. SVG images can thus be scaled in size without loss of quality, and SVG files can be searched, indexed, scripted, and compressed. The XML text files can be created and edited with text editors or vector graphics editors, and are rendered by the most-used web browsers.

Therefore, I must split the Content-Type’s value to confirm the suffix. Actually, SVG is not the only one, and I will handle the other types in the following release.

The second bug was due to the IMG tag generated by the WordPress’ new editor. The image tags generated by the WordPress’ new editor are not closed. And there is no space between the last attribute and the tag end as below.

<meta http-equiv="content-type" content="text/html; charset=utf-8"><img src="">
Code language: HTML, XML (xml)

At that moment, in my opinion, all the HTML tags should be closed, and there must be a space between the attribute and the end of the tag as below.

<meta http-equiv="content-type" content="text/html; charset=utf-8"><img src="" />
<img src="" ></img>
Code language: HTML, XML (xml)

Based on this understanding, the REGEX for URL extraction in the previous version was not robust enough to handle this. So the URL extracted was invalid, and the plugin would stop caching this image. 😅

So much for the stories about this version. Users may be able to set customized expiration times of cached images in the next version. I used this plugin to show the Feedburner subscribers’ count images. Because the count kept changing, I set the expiration time as one hour, which is 3600 seconds in the code. Now the usage changes, a customized expiration time may make sense.

Alright! Let’s see the next release.

Blog Reopens

The blog finally reopened!

You may be aware that this is not the first time I have created a blog based on the title, and I think this is good timing for me to recall the history of my blog. Since it happened a long time ago, the timings mentioned may shift a little from reality. Here is the evolution of my blog:

Sina Blog –> Live Space –> Wordpress
Blog Service Blog Service Self-built with WordPress

The blog started to become popular in China when I was a sophomore, so most of the famous web portals released the blog services. I also registered for one on the Sina Blog service to catch the trend. But I didn’t manage it well, and I just regarded it as a notebook.

After a short while, I found that Sina Blog services set up too many limitations. As a CS student, I couldn’t stand that. Therefore I decided to transfer my blog to Live Space which Microsoft just released. There were not many posts, so I manually moved them. At that moment, I began to post more about myself on my blog and regarded it as a place where I could share my emotions other than as a notebook.

When I was a second-year graduate student, self-built blogs on VPC became the trend. Based on the recommendation from Solrex, one of my classmates, I registered a domain name and began to continue with my blog by using WordPress on Hostmonster VPC provided by Jun Gu. I choose as the domain name of my blog. I never expected that selecting a CN domain name would be really a huge failure, and I will share with you why later.

At that moment, there were lots of posts. Manually transferring them one by one was really a mission impossible for me, such a lazy guy, not to mention that I need to retain all the tags, updated times, etc. I implemented a GUI tool to move the whole blog from Live Space to WordPress to finish the transfer rapidly. I didn’t open-source this tool due to a lack of sense of open source then. And I lost the code when I switched to a new laptop once. What a pity, If I open-sourced this, this tool could help others a lot when Microsoft shut down Live Space.

Since I used WordPress, my blog changed a lot in my mind. I started to contribute a lot to manage it. I made sure that I posted once every week and quoted others’ excellent parts indicating the source instead of directly quoting the whole post. And most of the posts should be technique-related.

In comparison to other CMSs, WordPress was quite good. However it still had many issues since the version I was using was quite old, such as encoding issues, dirty DB data caused by version upgrading, backend hung due to plugin upgrading, code reverted caused by upgrading, etc. If I detailedly introduced them one by one, I could publish several more posts. 😄

RSS was once quite a popular way of subscribing to blogs, so many bloggers liked to use RSS subscriber count to show the quality and popularity of their blogs. I was also one of them. But the build-in statics of WordPress is totally a mess, so we preferred to use Feedburner to burn a feed. And Feedburner could also fix some XML syntax issues in the original RSS.

The bloggers also show the Feedburner subscriber count as below on the page.

Feedburner Subscriber Count example shown on blog
Feedburner Subscriber Count

it is pretty hard for the bloggers whose audiences are mainly in China to show this fantastic counter. This counter is inaccessible from China because Feedburner is under the Google domain, which is

To resolve this, I had to implement a plugin named ImgCache. Suppose the attribute “ref=imgcache4wordpress” is added to an <img> tag. In that case, ImgCache will automatically persist the image into the local disk and replace the link with the local path so that this image becomes accessible from China. I used this way to show images provided by Feedburner and Twitter.

The latest updated time was 12 years ago. These days I went through this plugin and really could hardly bear my poor English and coding. It shows I will resolve the known issue in the next release. So it seems nothing needs to be fixed if no newer version is released 😅. Maybe I should take some time to release a new version to fix that.

Besides ImaCache, I also implemented another plugin called Custom URL Shorter. I knew shorter should be shortener, ignore please 🤦‍♂️. The plugin name could not be updated, and it is not sure whether it can be updated now. A single slip may cause lasting sorrow. (Developers can update the plugin name now, and I have updated the name to Custom URL Shortener.)

My blog meant a lot to me, but I made a tough decision three years after I graduated from the graduate university: shut down my blog.

I kept being annoyed by these:

  1. The blacklist way of GFW: Once a site under IP outside China contained any sensitive data, that IP would be blacklisted. That was to say, all the sites using this IP would be banned from China. So I had to ask the VPS provider to change the IP repeatedly. No clue that the situation could be better.
    I was not sure whether that was due to GFW. Accessing my blog from China became unstable, but accessing from outside China is quite good.
  2. The complicated registration: the instruction for registration kept changing. The MIIT always asked for new files and documents, asked to renew the information, and asked to add further information on the pages.
    Every time one Email would be received with a very close deadline. If you could not meet the requirement in time, your site would be shut down immediately
  3. Cyber attacks: After joining an Internet company, I became swamped, so I always forgot to upgrade WordPress to apply the security patch. Therefore, my blog was attacked several times. Although I had backups, restoring still took much time.

OT in the daytime, dealing with the none technique stuff such as GFW, registration, etc., in the evening really made me tired. Finally, I gave up and chose to shut down. Shutting down my blog has always been in my mind, and it isn’t easy to erase.

Actually, I already planned to reopen the blog when I arrived in Singapore. But first time joining a foreign company delayed this plan. The arrival of my wife and baby kid delayed it again. I never thought that taking care of the baby without the support of elders would be so difficult. Finally, I have decided to reopen the blog now. Cause I have not touched this for a long time, I don’t know much about the VPS providers. Thank Xintao Lai, for recommending DigitalOcean to me.