LESS Mixin for Multiple Transition Properties under Same duration, timing-function and delay

Preface

Sometimes in CSS we’d like to transition on multiple properties under the same transition duration, timing function and delay, and we’d like to transition only those specific properties so we can’t use all as transition-property. Like this, for something that we probably want transitioning effect for properties pertaining to the y axis but not for those pertaining to the x axis:

.box {
  transition: height 0.4s linear,
              background-position-y 0.4s linear,
              padding-top 0.4s linear;
}

Of course, that’s some duplicated code. One way to reduce this duplicated code is to not use the shorthand rule:

.box {
  transition-property: height, background-position-y, padding-top;
  transition-duration: 0.4s;
  transition-timing-function: linear;
}

But in this post we’ll learn how to use the shorthand rule while reducing code duplication through CSS preprocessors: The exercise today is to write a LESS mixin that takes an arbitrary number of property names and produces the shorthand rule, e.g. something like .uniform-transition(0.4s linear, height, background-position-y, padding-top);

(繼續閱讀…)

Read More

Hakuu in the making (1) — Mnjul’s Intimate Home vs-6517

Part of the post series for my process in making Hakuu.

The Overall Story

As I said in the introductory post, since its inception almost two decades ago, MIH has had roughly the same site structures: A introductory section of the site, self-introduction (“Me”), recollection of my past with my friends/family (“Cast” and “Story”), some photographs, a history of prior versions, and (in earlier versions) a guestbook:

Site menu for MIH vs-3811
Site menu for MIH vs-2121

(繼續閱讀…)

Read More

Hakuu in the making (0) — Mnjul’s Intimate Home vs-6517

This series of posts records my process in making Hakuu, the latest incarnation of my personal website series Mnjul’s Intimate Home. For those not unfamiliar with MIH: It stemmed from my shared hobby with my junior high school friends during the early 2000s, later turning into a habit: Before I started my full-time job, I had created a new version of MIH every year. Doing MIH had allowed me to self-reflect and challenge my technical abilities: MIH is usually the first playground when I want to try something new or something I’ve thought I couldn’t do, and was/is my first full-fledged PHP website, Flash website, HTML5 website.

Hakuu, being the 13th iteration of MIH, is the first full version after I became a (allow me to borrow the Japanese term) salaryman. I simply don’t have enough personal time to do what I had done as a student — when I simply started everything from scratch, and brought everything online in one go only when all sections were finished. This would include self introduction, photos, recollections about past stories/friends, background music (yes — remnant of early 2000s), and much more. As redoing all these would impose much time, for Hakuu, I went on launch the site with only two pages. This was something I’d never imagine I would do (especially forgoing background music) — but I guess, as MIH has embodied me myself throughout the years, it probably is also a prime exemplification of my transition from one-shot perfectionism to iterationism (not an English word, I know).

Aside from the changed process, Hakuu sees design and technical advancements for MIH, which are to be illustrated in the posts to come.

Before we start, I believe it helps if I refer readers to two previous versions of MIH to get a better grasp of its vibe. (Referring to older versions have been a staple in MIH, but I did without it in the first version of Hakuu too.) They are Mnjul’s Intimate Home (vs-3811) and Allodynia. The former requires Flash. Neither of the two is mobile-friendly (which Hakuu is.)

Here are the posts. The first couple were published just after the initial version of the website went live, and detail the fundamental design idea/technical framework and are more topical; as I gradually expand the website, and sometimes make design changes or technical optimizations, later posts will be more and more ad-hoc.

Part 1 – The overall story (in professional terms, “Sitemap”)
Part 2 – The first version’s design, and technical experimentation/implementation
Part 3 – More misc technical stuff
GitHub repo Manifesto – even more technical stuff (with some overlapping of the above)

Read More

In the Making of Mnjul’s Intimate Home 4931 (XII)

上一篇在這裡喔。

其實這兩年來沒什麼太大的更新,其一是這網站上線也五年了滿穩定的( 不過我還是有持續幫 Fragments 跟 Shards 加內容 ),其二是我現在在美國最操的軟體公司工作,實在沒什麼閒工夫。有閒工夫的時候我也想開始做下一個 Mnjul’s Intimate Home 啦!希望之後可以漸漸地把它弄上線。

  • 其實,一直以來 AJAX request 都已經不靠 jQuery 下了,所以我一直都想要把 jQuery 改成用 slim 版本。不過也因此要把 songs.xml 換成 songs.json,才能搞定。其實,當時 2012 年中是對 json 還不熟悉,如果當時就知道 json 如何操作,應該一開始就不會用 xml 了。用 xml 算是 Flash 的遺毒吧。
  • 以前曾經說過我很難決定要每放幾個 DOM element 或每隔多久就把控制權還給瀏覽器,然後說這問題根本就是需要瀏覽器給我額外的 knowledge。後來就知道有 requestIdleCallback() 這等東東!因為 callback 裡面會有機制可以問瀏覽器「我還有多少時間可以做我想做的事情?」實在太棒。
  • 順便把任何計時的功能改用 performance.now() 了。
  • 此外,也把第二階段 loader 的 box shadow 拿掉了。也把主 container 的背景顏色拿掉了。我現在的設計也確實變得越來越平面,如果可以用空間距離來表明不同的區塊的話,就不要額外再上色或用邊框啦。( 特別是這些區塊的功能差距非常明顯,使用者不太需要學。)

Read More

Private Class Members in ES6: A Complete Guide

This guide tells you how to write utility functions to facilitate private members, including properties and methods, for multiple ES6 classes with minimal code duplication, and some ideas on how we might guard against derived classes’ accessing base classes’ private members.

The final code is available as two GitHub Gists: this Gist for those who don’t care about the inheritances, and this Gist for those who do (but please definitely check the Inheritance section of this guide for caveats).

Preface

A lot of materials exist online teaching us how we can use various ES6 constructs & patterns to implement access restrictions to object properties. One common technique involves using closures and ES6 Weakmaps, like on MDN or this Stackoverflow answer. Weakmaps and the associated internal functions are great for native (or rather, syntactic sugar-coated) ES6 classes, but what I have found online is that all the code examples out there don’t tell us how we scale them. If we have multiple ES6 classes living in their own separate encompassing closures, do we want to write an explicit new WeakMap() instantiation and the internal function every time we write a class? How can we implement private instance methods with the WeakMap patterns?

(繼續閱讀…)

Read More

Creating the new mnjul.net homepage

於是我又~炸掉我的英文個人首頁,然後重做一個了。其實上一版也是一年前才做好( 算是活得最短的一個版本 ),但當時有點是為了找工作,所以急就章搞了一個也不知道到底要放什麼東西、要做什麼功能、要用什麼方式呈現、要怎樣設計的怪東西。前陣子總算有時間想 & 實際操作,就開始動工。

 

英文個人首頁,到底要放什麼東西?

自從六年前的橫向捲動的版本開始,一直以來我都把我的英文個人首頁當做 portal,放入( 幾乎是所有的 )我做的東西的連結,了不起再分門別類一下,最後加個 about me 的小 pop-up 就收工。也就是說,乍聽之下,根本就是作品集--但又是大雜匯的作品集( 姑且稱之為 meta-作品集 ):網站作品、程式碼作品、攝影作品、音樂作品、寫作作品,但又有其他亂七八糟的連結( 連到我的 Twitter 之類 );這樣胡亂攪和起來,要如何簡單扼要地呈現就成為一大難題。如果想再對每個連結都添上文字介紹,就亂糟糟了。下圖是這次被我炸掉的去年的版本:雖然有各種縮圖,但還是眼花撩亂地,沒什麼結構感、層次感。

[ 去年的版本 ]

(繼續閱讀…)

Read More

伺服器( 更多 )HTTPS 支援

最近讓這台 server 有更多 domain 支援 HTTPS 了!

其實之前 Let’s Encrypt 在 beta 的時候,我就有參加,並且也有 deploy 到我的 server 上。不過我的 deployment 一直都沒有很廣;因為我一些 domain 都額外有由 CloudFront 提供的 CDN 支援,要把 HTTPS certificate 推上去諸多麻煩。前陣子雖然 Amazon 發表了 Certificate Manager,可以快速且自動申請 certificate,但那時候 domain validation 的信一直寄不到我的 protected whois 的 proxy email address,所以我也沒辦法用。直到一兩週前我發現突然信又寄得到了,所以我就很開心地開始大幅 deploy HTTPS 啦啦啦啦!

( 我這台 server 放了一~堆 domain,所以 HTTPS 都透過 SNI 處理 )

大部分的 domain 其實都還滿好操作的,就執行一下 Let’s Encrypt command line( 我用 --standalone ),然後把 apache conf 改一下;再去 ACM 申請一下 certificate,放到 CloudFront,就可以 deploy 了。不過我以前寫的網頁,很多外連結或資源都沒有用 protocol relative URL,瀏覽器就會吐 error 或 warning( 當然身為程式設計師,後者是不用管的 ),所以還得把一些 http:// 的東西換成 //

除了之前的 mnjul.net 跟 purincess.tw ,這次一口氣做了這些 domain:

  • (cdn.)allodynia.mnjul.net:一些 protocol relative 的東西要戳。
  • (cdn.)home.mnjul.net:意外地完全不用改任何 Flash 的 code,所以很好弄。
  • (cdn.)albums.purincess.tw:這個也滿簡單的。另外,piwigo 還有一個 CDN 外掛,所以就算裡面的照片要丟給 CDN serve,也不會太麻煩。這次還順便更新了很久沒更新的 piwigo。
  • hopperlive.mnjul.net:雖然沒在用,不過因為 charlie_su1986 大神幫我做的網站,實在捨不得拿下來,就…。
  • wretchalbum.purincess.tw:雖然沒在用了,但因為不用改任何 code( 包括 Flash 也不用改 ),所以很快可以搞定,就順便。
  • (cdn.)blogs.purincess.tw:這個就有點麻煩了。首先,apache conf 有一些額外要複製的東西。再者 wordpress 對於 base url 好像不太有 protocol relative 的概念。然後有些 theme/plug-in 沒有 protocol relative,得自己去戳檔案。然後還要去把資料庫文章裡面的一些網址改成 protocol relative:UPDATE wp_posts SET post_content = REPLACE(post_content, 'http://cdn.blogs.purincess.tw', '//cdn.blogs.purincess.tw'); 之類。

有一些不太能在這裡公開的 domain 就不特別說了。不過我現在只是初步開始支援 HTTPS,並沒有真的要做成 HTTPS first。大概還要之後很有空才能繼續弄吧。

Read More

Singleton Boto Client Wrappers In a Multi-Threaded Environment

Note: The “license notice” in this blog’s sidebar does not apply for this post; all rights are reserved for this post.

Well, the title already sounds thrilling, I know. But that’s the deal today.

Here at Plurk, we use AWS DynamoDB to store some key-value things. This includes, for example, mapping from a single plurk’s ID into its database shard ID, and maintaining global (cross-shard) atomic counters. And we use boto to communicate with DynamoDB. Since boto3 wasn’t available (or rather, wasn’t declared as stable) when we transitioned to AWS, we use boto2. We probably would’ve needed less threading library constructs if we could utilize boto3 sessions!

Indeed, in our codebase, boto library calls are wrapped in our customized modules to expose semantically meaningful data/field accessors. Conventionally, most of our modules are singleton utilities (I’m personally not sure of exactly why, though). For example, if we want to dig out a user’s ID from their username, we’ll do a user_id = Users().get_id_from_name(username), with Users class extending (or rather, mixing-in) the Singleton base class.

 
Preface: (Thread-Safe) Singletons

For sake of completeness, here’s the implementation of that Singleton class:

(For brevity, imports are omitted, or things are used as were imported into the current namespace with from ... import ...)

class Singleton(object):
  __it_lock__ = threading.Lock()
  __it__ = None

  def __new__(cls, *args, **kwargs):
    if not cls.__it__:
      with cls.__it_lock__:
        if not cls.__it__:
          it = object.__new__(cls)
          it.init(*args, **kwargs)
          cls.__it__ = it
    return cls.__it__

  # Don't use __init__() because an instance returned
  # by __new__() will have its __init__() called
  # automatically every time __new__() is called. 
  @overridable
  def init(self, *args, **kwargs):
    pass

Alright, hope this metaclass-flavor singleton implementation is not too ugly, because this is actually more than a typical one — this singleton implementation is thread safe, guarded by double-checked locking. Why do we need thread safety? Because we use CherryPy as our HTTP server, where each HTTP request is served by a different thread, to attain the best possible throughput. So, when our server just launches, it immediately gets lots of requests, and there’s gonna be some occasion where singletons for the same class are almost simultaneously being requested (attribute that “almost” to Python’s GIL) — and we want to make sure only one has been instantiated in the end.

 
Wrapping Boto (and Failing)

Back to our main topic. To wrap our boto calls, taking the plurk mapping and atomic counter examples above, this was the first version of the modules I wrote…

class _DDBBase(Singleton):
  @override
  def init(self, *args, **kwargs):
    self._conn = boto.dynamodb2.connect_to_region(
      config.DYNAMODB_REGION,
      awesomes_access_key_id=config.DYNAMODB_ACCESS_ID,
      aws_secret_access_key=config.DYNAMODB_ACCESS_KEY
    )

class DDBPlurksMap(_DDBBase):
  @override
  def init(self, *args, **kwargs):    
    super(DDBPlurksMap, self).init(*args, **kwargs)
    self._ddb_plurks_map = DDBTable(config.DYNAMODB_TABLE_PLURKS_MAP, connection=self._conn) # from boto.dynamodb2.table import Table as DDBTable

  def get_shard_id(self, plurk_id, strong_consistent=False):
    try:
      item = self._ddb_plurks_map.get_item(consistent=strong_consistent, id=plurk_id)
    except ItemNotFound: # from boto.dynamodb2.exceptions import ItemNotFound
      return None
    else:
      return int(item['shard_id'])

class DDBAtomicCounters(_DDBBase):
  def _inc_and_get(self, key_name):
    res = self._conn.update_item(config.DYNAMODB_TABLE_ATOMIC_COUNTERS, {'name': {'S': key_name}}, {'number': {'Action': 'ADD', 'Value': {'N': '1'}}}, return_values='UPDATED_NEW')
    return int(res['Attributes']['number']['N'])

  def next_magic_id(self):
    return self._inc_and_get('magic_counter')

Looks properly abstracted? Yeah, it turned out this code worked… most of the time, but not always: These pieces of codes were not thread-safe, because boto2 was not thread-safe due to its use of httplib. So, as all my threads shared only one DynamoDBConnection instance stored at _DDBBase._conn, I was perfectly on my way to all the (not so) nice racing conditions down the road. (The dynamodb2.table instance using that connection was also shared, and was probably in peril, too).

 
Thread-Local Storage to the Rescue (Not Really, Yet)

To solve this with boto2, I’d need one connection for each thread. To do that, I needed a thread-local storage. Uhm… I tried writing something like this.

class _DDBBase(Singleton):
  @override
  def init(self, *args, **kwargs):
    self._tls = threading.local() # <- here it is
    self._tls.conn = boto.dynamodb2.connect_to_region(
      config.DYNAMODB_REGION,
      awesomes_access_key_id=config.DYNAMODB_ACCESS_ID,
      aws_secret_access_key=config.DYNAMODB_ACCESS_KEY
    )

class DDBPlurksMap(_DDBBase):
  @override
  def init(self, *args, **kwargs):    
    super(DDBPlurksMap, self).init(*args, **kwargs)
    self._tls.ddb_plurks_map = DDBTable(config.DYNAMODB_TABLE_PLURKS_MAP, connection=self._tls.conn)

  def get_shard_id(self, plurk_id, strong_consistent=False):
    try:
      item = self._tls.ddb_plurks_map.get_item(consistent=strong_consistent, id=plurk_id)
    except ItemNotFound:
      return None
    else:
      return int(item['shard_id'])

For sure, this didn't work: Since Singleton.init() was called only once for a class across the Python process's entire life time, only one thread --- the one that successfully acquired the singleton lock and executed that init() --- had the DynamoDBConnection instance (and the dynamodb2.table instance in DDBPlurksMap's case) in its thread local storage. All other threads, while having their own thread-local storage as self._tls, didn't get those instances constructed and stored, and would hit an AttributeError once they tried to access the instances.

 
Ugly Solution

Indeed, I could write something like the following...

class _DDBBase(Singleton):
  @override
  def init(self, *args, **kwargs):
    self._tls = threading.local()
    self.reinit()

  @overridable
  def reinit(self):
    self._tls.conn = boto.dynamodb2.connect_to_region(
      config.DYNAMODB_REGION,
      awesomes_access_key_id=config.DYNAMODB_ACCESS_ID,
      aws_secret_access_key=config.DYNAMODB_ACCESS_KEY
    )

...and have subclasses check for the need to reinit() whenever a method was called...

class DDBPlurksMap(_DDBBase):
  @override
  def init(self, *args, **kwargs):    
    super(DDBPlurksMap, self).init(*args, **kwargs)

  @override
  def reinit(self):
    if not hasattr(self._tls, 'conn'):
      super(DDBPlurksMap, self).reinit()
    self._tls.ddb_plurks_map = DDBTable(config.DYNAMODB_TABLE_PLURKS_MAP, connection=self._tls.conn)

  def get_shard_id(self, plurk_id, strong_consistent=False):
    if not hasattr(self._tls, 'ddb_plurks_map'):
      self.reinit()
    # other things

  def get_shard_ids(self, plurk_ids, strong_consistent=False):
    if not hasattr(self._tls, 'ddb_plurks_map'):
      self.reinit()     
    # other things

  def delete_plurk_id(self, plurk_id):
    if not hasattr(self._tls, 'ddb_plurks_map'):
      self.reinit()
    # other things

  def set_shard_id(self, plurk_id, shard_id):
    if not hasattr(self._tls, 'ddb_plurks_map'):
      self.reinit()
    # other things

This would work, of course, but looking at the duplicated code (even after being converted into a decorator, which is omitted here) made me think of Dr. Chuen-Liang Chen, professor of my design pattern class back in school, who would definitely graded the code with an F.

Well, I would grade my code with an F too, so the quest for a better solution continued...

 
Subclassed Thread-Local Storage to the Rescue

At this point, I knew what I needed --- a thread-local storage that could automagically initialize its contents when they were requested for the first time (or, when the thread was first spawned --- but as I couldn't modify thread spawning, this was a no-go). Fortunately, Python's threading.local does provide such construct: a threading.local instance's __init__() is called if its thread-local attribute dict, a threading.local-internal data structure, has not been constructed when someone accesses the attribute dict. Such calling of __init__() can be long after the threading.local instance is apparently created in the source code, taking place only when new threads are spawned and those threads' threading.local instance's attributes accessed. Now, there's the big addendum: overriding __init__() in subclasses of threading.local will also be called.

Therefore, my auto-magic was actually simple:

class _DDBBase(Singleton):
  class _TLS(threading.local):
    def __init__(self):
      self.conn = boto.dynamodb2.connect_to_region(
        config.DYNAMODB_REGION,
        aws_access_key_id=config.DYNAMODB_ACCESS_ID,
        aws_secret_access_key=config.DYNAMODB_ACCESS_KEY
      )

  @override
  def init(self, *args, **kwargs):
    self._tls = _DDBBase._TLS()

  def get_api_ver(self):
    return self._tls.conn.APIVersion # automagic!

There, whenever I called _DDBBase().get_api_ver(), the conn attribute would be looked up in self._tls. If at this moment, the thread-local attribute dict had not been constructed as per threading.local's internal implementation, _DDBBase._TLS.__init__() would be called upon that self._tls --- and this would properly construct the conn attribute and tuck it into the thread-local storage. This would happen once (and only once) per thread, and only when actually needed, so it's all perfect.

Now, as DDBPlurksMap also needed to store its own data into the thread-local storage, I needed to be able to customize _TLS.__init__()'s behavior too. Here's the complete piece of codes:

class _DDBBase(Singleton):
  @hidable
  class _TLS(threading.local):
    def __init__(self):
      self.conn = boto.dynamodb2.connect_to_region(
        config.DYNAMODB_REGION,
        aws_access_key_id=config.DYNAMODB_ACCESS_ID,
        aws_secret_access_key=config.DYNAMODB_ACCESS_KEY
      )

  @override
  def init(self, *args, **kwargs):
    self._tls = self.__class__._TLS()

class DDBPlurksMap(_DDBBase):
  @hide
  class _TLS(_DDBBase._TLS):
    def __init__(self, *args, **kwargs):
      super(DDBPlurksMap._TLS, self).__init__(*args, **kwargs)
      self.ddb_plurks_map = DDBTable(config.DYNAMODB_TABLE_PLURKS_MAP, connection=self.conn)

  def get_shard_id(self, plurk_id, strong_consistent=False):
    try:
      item = self._tls.ddb_plurks_map.get_item(consistent=strong_consistent, id=plurk_id)
    except ItemNotFound:
      return None
    else:
      return int(item['shard_id'])

  def get_shard_ids(self, plurk_ids, strong_consistent=False):
    result_set = self._tls.ddb_plurks_map.batch_get(consistent=strong_consistent, keys=[{'id': plurk_id} for plurk_id in set(plurk_ids)])
    # other things

  def delete_plurk_id(self, plurk_id):
    self._tls.ddb_plurks_map.delete_item(id=plurk_id)

  def set_shard_id(self, plurk_id, shard_id):
    self._tls.ddb_plurks_map.put_item(data={'id': plurk_id, 'shard_id': shard_id}, overwrite=True)

# nothing really to customize, so it's pretty clean for this module
class DDBAtomicCounters(_DDBBase):
  def _inc_and_get(self, key_name):
    res = self._tls.conn.update_item(config.DYNAMODB_TABLE_ATOMIC_COUNTERS, {'name': {'S': key_name}}, {'number': {'Action': 'ADD', 'Value': {'N': '1'}}}, return_values='UPDATED_NEW')
    return int(res['Attributes']['number']['N'])

  def next_magic_id(self):
    return self._inc_and_get('magic_counter')

Well, things are again getting metaclassy here, so let me do a quick step-by-step on what would happen if we call DDBPlurksMap().set_shard_id(1, 2) for example:

  1. For the DDBPlurksMap() part, Singleton.__new__() is called on the DDBPlurksMap class.

    • If an instance of DDBPlurksMap has ever been constructed in the whole Python process, nothing really happens except for us getting that instance.
    • Otherwise, the instance is constructed, and since DDBPlurksMap has no init() defined, _DDBBase.init() is called upon that instance, which creates an instance of our subclassed thread-local storage. Note that self.__class__ is DDBPlurksMap, so we'll be properly constructing an instance of DDBPlurksMap._TLS, instead of that of _DDBBase._TLS.
  2. Now, inside set_shard_id(), the ddb_plurks_map attribute is requested from self._tls.

    • If at this moment, the subclassed thread-local storage for this thread has been constructed, which means DDBPlurksMap._TLS.__init__() has been called, ddb_plurks_map will be a dynamodb2.table instance, local to the current thread, parameterized by a DynamoDBConnection instance (i.e. conn), also local to the current thread. These two instances would have been constructed within DDBPlurksMap._TLS.__init__() and _DDBBase._TLS.__init__(), respectively (in the reversed order for sure).
    • If not, then threading.local's internal implementation calls DDBPlurksMap._TLS.__init__(), which calls _DDBBase._TLS.__init__() to create and store a DynamoDBConnection instance into the thread-local storage. And then, DDBPlurksMap._TLS.__init__() creates and store a dynamodb2.table instance into the thread-local storage. Those instances are only visible to the current thread, no racing!
  3. Either way, a thread-local dynamodb2.table instance will be returned by the __getattr__() call on the thread-local storage for the ddb_plrurks_map attribute, and everything is good! Not many duplicated codes!

 
Afterwords
Really, as Greg Weng, my former colleague at Mozilla, puts it, threads might be too heavy a weapon to maximize request throughput by working around I/O blockage. In the future, we should really begin investigating into those state-of-the-art async I/O constructs such as coroutines and futures and the like. Too bad we're still stuck in Python 2.7, though...

Read More