It's been the worst day since yesterday

Sometimes, it's amazing that a song suddenly pops up in your head, then it stays for a while. "The worst day since yesterday" by Flogging Molly, I knew this song from Stargate Universe, I wasn't a SG fan. Actually, I never noticed this scifi until SGU.

I still couldn't understand how get stuck on a ancient alien ship or how a bunch of people hold projectile weapons can control—even operate technology far beyond their knowledge, could possibly have a story to write about. Yep, I know it's a scifi, but I just feel the story isn't quite convincing. Maybe I just need to catch up Stargate from the beginning.

When something happens in real life, it usually triggers some related memory, and usually a song would be played in my head. Good tune plus the motion pictures of fiction story, that's how they got embedded in me.

It's been worst day since yesterday,
it's been worst day since yesterday,
it's been worst day since yesterday.

(PS. I have a strong feeling, it wasn't my first heard from SGU. Somehow, I feel it's from Numb3rs or Chuck, but I couldn't find the proof. Might just be the false memory?)

Small bits [2010-05-30]

Resetting JavaScript RegExp [2010-05-25]

I tried to re-use regular expression in my script, but I couldn't find a way to reset their state. Now, I have it:

var RE = new RegExp('blah blah blah', 'gi');
for (idx in tests) {
  RE.lastIndex = 0; // reset
  if RE.test(tests[idx])
    console.log(tests[idx]);
  }

But I do some test:

n_re = 100;
var re_strs = [];
for (var i=0; i<n_re; i++)
  re_strs.push("(([a-zA-Z][a-zA-Z0-9+\\-.]*):)(//((([a-zA-Z0-9\\-._~%!$&\\'()*+,;=:]+)@)?([a-zA-Z0-9\\-._~%!$&\\'()*+,;]+)(:(\\d+))?))?([/a-zA-Z0-9\\-._~%!$&\\'()*+,;=:@]*)(\\?([/a-zA-Z0-9\\-._~%!$&\\'()*+,;=:@?]*))?(#([/a-zA-Z0-9\\-._~%!$&\\'()*+,;=:@?]*))?");
console.log('Number of re:', n_re);

n_test = 100;
var test_urls = [];
for (var j=0; j<n_test; j++)
  test_urls.push('http://example.com/');
console.log('Number of url:', n_test);
console.log('Number of total test:', n_re * n_test);

console.time('no precompilation');
for (var i in re_strs) {
  for (var j in test_urls) {
    var re = new RegExp(re_strs[i], 'gi');
    re.test(test_urls[j]);
    }
  }
console.timeEnd('no precompilation');

console.time('precompilation');
console.time('precompilation: compilation time');
var res = [];
for (var i in re_strs)
  res.push(new RegExp(re_strs[i], 'gi'));
console.timeEnd('precompilation: compilation time');
for (var i in re_strs) {
  for (var j in test_urls) {
    res[i].lastIndex = 0;
    res[i].test(test_urls[j]);
    }
  }
console.timeEnd('precompilation');
Number of re: 100
Number of url: 100
Number of total test: 10000
no precompilation: 1271ms
precompilation: compilation time: 3ms
precompilation: 20ms

It's not really worth precompiling if you don't have huge amount of tests in a short time.

Google Groups Picture [2010-05-25]

The background transparency issue of group picture, I always got the picture with white background even I was sure the original image was with transparent background. I had a group picture with transparency but others (made with GIMP) are not. Then, I recalled that special one was created with Inkscape, so I imported the other's picture and exported from Inkscape, that worked.

I used identify -verbose (from ImageMagick) to figure out what's the differences. Here is the diff:

--- logo_solid.txt      2010-05-25 01:54:14.000000000 +0800
+++ logo_trans.txt      2010-05-25 01:54:01.000000000 +0800
@@ -33,15 +33,9 @@
       2400: (  0,  0,  0,255) #000000 black
        200: (  0,  0,  0,127) #0000007F rgba(0,0,0,0.498039)
       3800: (255,255,255,  0) #FFFFFF00 rgba(255,255,255,0)
-  Rendering intent: Saturation
-  Gamma: 0.45455
-  Chromaticity:
-    red primary: (0.64,0.33)
-    green primary: (0.3,0.6)
-    blue primary: (0.15,0.06)
-    white point: (0.3127,0.329)
+  Rendering intent: Undefined
   Interlace: None
-  Background color: rgba(1,1,1,1)
+  Background color: white
   Border color: rgba(223,223,223,1)
   Matte color: grey74
   Transparent color: none

After a few tries in GIMP save dialog, I found out the problem was with Save Background Color, uncheck resolved the issue. Here is the new diff:

--- logo_solid.txt      2010-05-25 01:54:14.000000000 +0800
+++ logo_solid_fix.txt  2010-05-25 02:16:28.000000000 +0800
@@ -41,7 +41,7 @@
     blue primary: (0.15,0.06)
     white point: (0.3127,0.329)
   Interlace: None
-  Background color: rgba(1,1,1,1)
+  Background color: white
   Border color: rgba(223,223,223,1)
   Matte color: grey74
   Transparent color: none

The change was on Background color from rgba(1, 1, 1, 1) to white, I didn't understand how this could resolve the issue, but I am not complaining.

Emerging sys-fs/encfs [2010-05-26]

I got building error about Boost, this comment saved me. I had two Boost versions:

$ eselect boost list
Available boost versions:
  [1]   boost-1.35/default
  [2]   boost-1.41/default *

After unemerged Boost 1.35, EncFS emerged successfully. I installed it for this.

Synaptics Touchpad button only mode

My external mouse's left button has been killing me for a while, it likes to think I want to double click most of time. I don't have battery to power up another Bluetooh mouse, and wired mouse works really better. So I think why not to use the buttons on touchpad, but the problem is I can find a simple way to disable the sensing area. Finally, I came up with a trick:

synclient MaxSpeed=0
# Also need to disable all scrolls, e.g.
synclient VertTwoFingerScroll=0 HorizTwoFingerScroll=0

You can still keep those scrolling methods, they are more easier to use than mousewheel to me.

Circular slide text

Let it slide!

See what between here moving and here
See what between here moving and here

I made this script because someone posted a gig on Craiglist. Start to them!

Source

Left @Twitter

After 918 days of being a Twitter user, 114 days with my second account, 9605 tweets1, now I have left Twitter.

The reason is quite simple: it took me too much and I couldn't really make something useful out of 140s.

About two weeks ago, I started to use FriendFeed to post my updates. I got much less responses on FriendFeed than on Twitter, but I still think FriendFeed is a better place for me. I don't want to be limited by 140 rules with only plain text. I want to have a close pattern to real discussion, not just the @reply mess or the RT mess.

The last week, I have been more productive, I almost posted one posting a day, coded everyday, buried in bugs. I read more and thought more and deeper. Time was still not enough but I was using time, not wasting time. I pressed F5 less and stayed in Vim (text editor) more. I used to do system update less than every 24 hours because I was too bored for waiting tweets show up, now I rarely noticed that I didn't update yet.

Please don't get me wrong, it's not as if Twitter is a bad or poor service. It's just what Twitter is is not for me anymore and I am not a person have good self-control power, my willpower is pretty weak. It's easy to be distracted and too many tweets to read them all. I only had followed 20 users, I felt that already. I think following people's organized thoughts might be better, such as blogs.

However, I am not totally leaving actually, because I still have some unfinished business on Twitter, but I don't read tweets anymore, at least not those without me being mentioned.


  1. 4399 tweets from @livibetter plus 5206 tweets from @lyjl at the moment I tweeted I am leaving. ^

YouTube Favorites simple search

Important note: if you enter Query, it is actually more like a filter on results of a page, meaning? For example, you click on search button with number of results is 20, YouTube will use that querying string to filter first 20 videos of all videos before returns the results. If all 20 videos are not matched, it returns no videos. Say, the 21st video, which is paged in second page, is matched, you have to click next page for second page, so you can get that video in results. My 2 cents: I have no idea what the YouTube developers were thinking about the definition of querying, probably the reason q is not supported in verson 2 API.

I made this because sometimes I need to find a video I have favored but I couldn't recall the exact name. I used to go through all my favorites and still couldn't find one. With this, it could be a little bit easier.

If I use HTML5 database to download all favorites, I get rid of the problem mentioned in the note above, but I'm lazy.

Basm - A Bash client for stereomood

stereomood - emotional internet radio

I recently discovered this online radio, stereomood, it seems to have indie music mostly. Most of them are not bad. After I checked up their api documentation, I decided to write a Bash client.

This client has three Bash scripts:

  • OAuth.sh - Bash OAuth library
  • StereomoodOAuth.sh - stereomood Bash OAuth library
  • Basm.sh - The main script

The first two are libraries, they are not complete but enough for Basm.sh to play music. It requires mplayer for main script, OpenSSL and Perl for libraries.

You have to run with two required parameters as follows:

$ ./Basm.sh -q happy -t mood

or you can specify library path in PATH environment if you put them altogether:

$ PATH=$PATH:/path/to/two_oauth_libs /path/to/Basm.sh -q happy -t mood

If you run Basm.sh with these two libraries in the same directory, but Basm.sh still couldn't find the libraries, try:

$ PATH=$PATH:$PWD /path/to/Basm.sh -q happy -t mood

Basm.sh only has two parameters and they both are required.

  • -t: Type of the radio, it could be "mood", "activity", or "site".
  • -q: Querying text, e.g. "happy" for mood, "relax" for activity.

You probably need to check up on stereomood, so you can know what querying text you can use.

You must have to have an account on stereomood, that's the requirement for using APIs. In your first run of the script, you have to authorize the script, just follow the link and enter the PIN code.

The songs will be played randomly, there is no like button or ban button for you yet1. It's a little different than on stereomood.

There are few keys you can use:

  • P - Pause
  • A - Add to library
  • N - Next song
  • Q - Quit

Here is a screenshot:

The last line from screenshot actually is the output of mplayer.


  1. A developer from stereomood told me the corresponding APIs would be released in September or October. ^

Bash OAuth

I have used a Python OAuth library for a few of my scripts. Some of my scripts are Bash scripts, I didnt want to rewrite them using Python. A little wild idea came up in my mind, I decided to use Bash to write a library and make those Bash scripts work with that library.

So, OAuth.sh was born.

After I finished this library, it actually is not too complicated. However this library still needs two external programs, one is Perl for percent-encoding1, the other is OpenSSL for HMAC-SHA1. I think its possible that Bash can do these two jobs, but that might take a lot of extra efforts to make so.

Now, I will show you how to use this library. Basically, I will use Twitters Authenticating Requests (3-legged OAuth) as template, only focus on how to get the values not the OAuth specification. I use it here because Twitter is what I written this library for. I want to update my profile image from shell, I used to use one curl to update, but now its a little different.

I have also made a script, test_OAuth.sh, so you can run it to see the calculated values for real.

Acquiring a request token

First, we have the following variables:

oauth_consumer_key=GDdmIQH6jhtmLUypg82g
oauth_consumer_secret=MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98
oauth_signature_method=HMAC-SHA1
oauth_version=1.0
oauth_nonce=QP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk
oauth_timestamp=1272323042
oauth_callback=http://localhost:3005/the_dance/process_callback?service_provider_id=11

We need to create an array to specify what are needed to be used for signing:

params=(
  $(OAuth_param oauth_consumer_key "$oauth_consumer_key")
  $(OAuth_param oauth_signature_method "$oauth_signature_method")
  $(OAuth_param oauth_version "$oauth_version")
  $(OAuth_param oauth_nonce "$oauth_nonce")
  $(OAuth_param oauth_timestamp "$oauth_timestamp")
  $(OAuth_param oauth_callback "$oauth_callback")
  )

localStorage, primitive types, and JSON

localStorage is a feature of HTML5s webstorage. You can store or retrieve as the followings:

localStorage[key] = value;
value = localStorage[key];
delete localStorage[key];

localStorage.setItem(key, value);
value = localStorage.getItem(key);
localStorage.removeItem(key);

localStorage.key = value;
value = localStorage.key;
delete localStorage.key;

You can list:

for (key in localStorage)
  console.log(key, localStorage[key]);

You can clean up at once:

localStorage.clear();

You can put every thing in but you might not get what you put in, because

The setItem(key, value) method must first create a structured clone of the given value. If this raises an exception, then the exception must be thrown and the list associated with the object is left unchanged. If constructing the stuctured clone would involve constructing a new ImageData object, then throw a NOT_SUPPORTED_ERR exception instead.

jQuery plugin jk navigation

I had thought about a jQuery plugin for jk binding navigation for a while and I finally wrote it. This jQuery plugin actually is my first plugin.

Updated on 2010-09-20: I have removed jknav from this blog, please check out the demo page, instead.

Here is what you can try to see how it works on this blog: Press h and l to navigate between posts; j and k to navigate between sections.

I have the following code installed:

<script src="http://lilbtn.yjl.im/js/jquery/jquery.jknav.min.js"></script>
<script>
$('h3').jknav();
$.jknav.init({up: 'l', down: 'h', reevaluate: true});

$('h3,h4,h5,h6').jknav(null, 'all-headers');
$.jknav.init({name: 'all-headers', reevaluate: true});
</script>

It actually has two navigation settings, jk and hl.

Basically, you use jQuery to select what element should be navigated to by calling jknav(), then init() to set up some variable that plugin needs and the keyup event handler, done. That's all. You can call jknav() as many times as your like, and the selectors don't have to be the same, you can mix tag names. This plugin will sort them by their position on page, top to bottom, left to right.

You can read the documentation and check out this demo page, which uses callback.

Brainfuck

Brainfuck is a programming language. And its what it says in its name Brainfuck.

Only 8 instructions:

Cmd  Effect                               
---  ------                               
+    Increases element under pointer      
-    Decrases element under pointer       
>    Increases pointer                    
<    Decreases pointer                    
[    Starts loop, flag under pointer      
]    Indicates end of loop                
.    Outputs ASCII code under pointer     
,    Reads char and stores ASCII under ptr

Now take a look at the Hello World (You can run it in this JavaScript Interpreter:

+++++ +++++             initialize counter (cell #0) to 10
[                       use loop to set the next four cells to 70/100/30/10
    > +++++ ++              add  7 to cell #1
    > +++++ +++++           add 10 to cell #2 
    > +++                   add  3 to cell #3
    > +                     add  1 to cell #4
    <<<< -                  decrement counter (cell #0)
]                   
> ++ .                  print H
> + .                   print e
+++++ ++ .              print l
.                       print l
+++ .                   print o
> ++ .                  print  
<< +++++ +++++ +++++ .  print W
> .                     print o
+++ .                   print r
----- - .               print l
----- --- .             print d
> + .                   print !
> .                     print \n

Any idea? Im not smart enough so I have to read the explanation.

Anyway, I decided to try to write one (and its the only one, I have ever written) to print out:

*
**
***
****
*****

Weekly users chart of Keep Last Two Tabs using Flot

Updated 2010-06-03: Now I use Google Docs to record the number, see this doc. It's easier to add a data point, the only problem is it's too ugly.

The chart below is the weekly users of Keep Last Two Tabs, a Chrome Extension of mine. This extension does what it claims, it's silly and amazingly to see the number of users is actually growing up.

A week ago, I stumbled upon Flot, a pure JavaScript plotting library for jQuery. It produces nice and pretty chart comparing to Google Visualization API's Annotated Time Line, a Flash based. Here is a post I used it.

I feel Annotated Time Line is more easier (or less customizable) to use because you don't need some functions, but Flot is more comprehensive library (and it's Open Source), you can have more types of chart and make the chart do whatever you want if you know JavaScript.

A: It's a nipple. B: Damn you! Now I can't unsee it.

Are you an Arch Linux user? Have you ever noticed something strange about Arch Linux? I didn't until I read this conversation on forums.

sand_man: It's a nipple.

Fingel: Damn you! Now I can't unsee it.

I tried to see that nipple in replies but I couldn't see one from any of those images until I scrolled the page to top and I saw:

Hover Here to See the Nipple!
If you read this, please go to [Arch Linux](http://www.archlinux.org/) and look at top-left corner of the page.

If this doesn't work, just go to Arch Linux and look at top-left corner of the page.

Now I can't unsee it, either. :D

@font-face and cross-domain (cross-origin)

This blog uses external1 fonts, which are served from http://www.yjl.im/font/. Chromium (5.0) is my main browser and it renders with those fonts correctly. Some time ago, I noticed that Firefox (3.6) didnt render with those fonts but it did download them. I couldnt figure out why Chromium and Opera (10.10) works fine but Firefox doesnt, and its not as if Firefox cant render with fonts because it uses fonts at http://www.yjl.im/. (Internet Explorer (7) doesnt, either, its same reason. But I dont really care about IE)

I suddely had a guess, a cross-domain thing. So I googled and found the answer, it refers to Web Font linking and Cross-Origin Resource Sharing, my guess was comfirmed.

Short story: you cant use a font (in Firefox) which is not at same domain (origin). I think its right for a browser to have such behavior. Some people like stealing stuff.

Anyway, the solution is to add a response header Access-Control-Allow-Origin:

<FilesMatch "\.(ttf|otf|eot)$">
  <IfModule mod_headers.c>
    Header set Access-Control-Allow-Origin "*"
  </IfModule>
</FilesMatch>

If you uses Apache and you do know how to configure your server, the code above is right for you.

However, many people do not have a webserver, if they do, they probably would host a WordPress blog already and wouldnt encounter this issue. Moreover, Google Sites is probably some peoples file hosting options if they user Blogger, you have no way to add a header. So a normal blogger without skill or knowledge or money, probably wouldnt have a chance to use @font-face. Say what? Data URI? For Greens sake, dont use that to serve a font.

As for me, I use Google App Engine at http://www.yjl.im (source code, BSD License). You only need to write a code2. font.py does the job, the following code is the main part:

jackd watchdog: timeout - killing jackd

I tried to make JACK running on my Gentoo for a day or two, but I kept getting this

$ jackd -v -R -d alsa 
jackd 0.118.0 
Copyright 2001-2009 Paul Davis, Stephane Letz, Jack O'Quinn, Torben Hohn and others. 
jackd comes with ABSOLUTELY NO WARRANTY 
This is free software, and you are welcome to redistribute it 
under certain conditions; see the file COPYING for details 

getting driver descriptor from /usr/lib64/jack/jack_dummy.so 
getting driver descriptor from /usr/lib64/jack/jack_net.so 
getting driver descriptor from /usr/lib64/jack/jack_alsa.so 
JACK compiled with System V SHM support. 
server `default' registered 
registered builtin port type 32 bit float mono audio 
registered builtin port type 8 bit raw midi 
clock source = system clock via clock_gettime 
loading driver .. 
start poll on 3 fd's 
new client: alsa_pcm, id = 1 type 1 @ 0x608fc0 fd = -1 
creating alsa driver ... hw:0|hw:0|1024|2|48000|0|0|nomon|swmeter|-|32bit 
control device hw:0 
configuring for 48000Hz, period = 1024 frames (21.3 ms), buffer = 2 periods 
ALSA: final selected sample format for capture: 32bit integer little-endian 
ALSA: use 2 periods for capture 
ALSA: final selected sample format for playback: 32bit integer little-endian 
ALSA: use 2 periods for playback 
new buffer size 1024 
registered port system:capture_1, offset = 4096 
registered port system:capture_2, offset = 8192 
registered port system:playback_1, offset = 0 
registered port system:playback_2, offset = 0 
++ jack_sort_graph 
++ jack_rechain_graph(): 
+++ client is now alsa_pcm active ? 1 
client alsa_pcm: internal client, execution_order=0. 
-- jack_rechain_graph() 
-- jack_sort_graph 
5485 waiting for signals
[Ten seconds later]
6624 waiting for signals 
jackd watchdog: timeout - killing jackd

I googled it and found a lot are about realtime, but it's not my case. After many tries, I still couldn't solve my problem so I asked for help, and someone's reply helped me indirectly.

By default, JACK would try to open two ports, one for playback, the other for capture. The problem was on capture, I guess jackd couldn't receive data, so it times out. I have to enable Capture in alsamixer or only use the playback by specifying -P. If I don't do either, the timeout always occurs.

I also tried to use TiMidity++ to create a virtual MIDI device, but there is a problem

$ timidity -iA -Oj -B2,7
TiMidity starting in ALSA server mode
ALSA lib seq_hw.c:457:(snd_seq_hw_open) open /dev/snd/seq failed: No such file or directory
error in snd_seq_open

modprobe snd-seq loads the kernel module TiMidity++ needs. Put it into /etc/modules.autoload.d/kernel-2.6 would be helpful for loading at boot time.

emerge -j JOBS and MAKEOPTS in make.conf

They have nothing to do with each other, I just learned about an hour ago by RTFM. I was watching video and found there were still two compilers running at the same time, that got my attention.

For a year1, I mistakenly assumed that emerge -j JOBS would override MAKEOPTS in make.conf, the JOB is the maximum concurrent package emerging tasks, not the maximum concurrent compilation tasks using make command.

And MAKEOPTS is more than just for specifying the number compilation tasks -jJOBS for make, I should have thought about that, so I wouldn't make a false assumption.

Anyway, if you want to override, e.g. I have MAKEOPTS=-j2 in make.conf, I want to keep one core (my CPU is a dual core) available for me, I run

[sudo] MAKEOPTS=-j1 emerge [options] atom

That does what I really want.


  1. I am just an one-year Gentoo user, 1 year and 17 days to be precise. 

A-B Repeat, EQ, auto-zoom, and fullscreen using SMPlayer

SMPlayer is my favorite frontend for MPlayer. There are some other frontends, such as MPlayer's own GUI (depreciated), GNOME MPlayer, or KMPlayer. But SMPlayer is the best. You probably use VLC or Totem or something I have never heard, I can say 99% MPlayer is the best. So MPlayer + SMPlayer is the best combination in my opinion.

Weeks ago, I found this Auto zoom (Shift+W) feature, it fills up the gap of video (and the gap of my life as well). You won't see any blank area if the video doesn't contain blank border. You can use Alt+Arrow keys to pan the zoomed area. There is only a slight problem, the OSD on top-left corner, likely would be cut off. I don't have a resolution for this issue, and I haven't tried to ask for one yet.

I usually play a playlist of YouTube videos. Some (indie videos) have introduction part, so I use A-B Section (Repeat) to play only the main part. If a video's sound level is too low or too high, I use Equalizer to adjust.

For what I have done to a video, the changes (not including panning) are memorized by SMPlayer. That's the most awesome feature, it will always play a video (or audio) in a way you want.

Two things I want to add: 1) Because of SMPlayer, I know there is a hack to boost performance in MPlayer, -vo gl:yuv=2:force-pbo:ati-hack (For ATI cards only). 2) Don't forget to turn off Repeat mode (not the one in Playlist window), it means single track repeat mode when you play a playlist.

On The Rocks and Lady Gaga Bad Romance synced playback

I watched this On The Rocks' (new) version about two days ago, I had heard of Lady Gaga's Bad Romance (Who hasn't?), but I hadn't watched her music video at that moment. Later, I checked the MV out, I decided to make this synchronous playback.

It's not perfect, definitely out of sync, but you still can LOL! Enjoy! (If the following Play button doesn't work, play Lady Gaga first and count for 9 seconds, then play On The Rocks)

Updated on 2010-09-16: The old video has been taken down, replaced with another. First half of replacement has better timing, but then completely out of sync.

Updated on 2010-09-23: I replaced with another video which is same as the original one.