Wong Liang Zan http://blog.liangzan.net Most recent posts at Wong Liang Zan posterous.com Thu, 19 Jan 2012 15:46:22 -0800 My solarized themed Arch Linux setup http://blog.liangzan.net/my-solarized-themed-arch-linux-setup http://blog.liangzan.net/my-solarized-themed-arch-linux-setup

I decided to switch to Arch Linux at the beginning of this year. After much customization work, the end result looks like this

.

The screenshots received much interest from my friends. I am going to show you how to build it. Long story short, use the same color theme for your applications.

OS: Arch Linux

Obviously only Linux or BSD gives you this much freedom to customize your desktop. I'm using Arch Linux. Other distros should yield the same result. The advantage of using Arch Linux is it gives you a blank slate to work on. If you use all-in-one distros like Ubuntu, you would have the extra work of stripping out the desktop environment.

Color theme: Solarized

There're some very good color themes available. Here're some very good ones.

Choose one which you like. I'm using Solarized. Not all color themes are created equally. Popular themes have more tooling support. For Solarized, it has been ported to vim, mutt, shell, and emacs. It makes it easier to apply the same color theme to other applications.

Font: Inconsolata

As with color themes, font is very much a personal preference. Choose a good monospaced font to use for all your apps. I'm using the Inconsolata font.

There are other good recommendations here

Window manager: XMonad

I'm using XMonad. I wanted a tiling windows manager as I wanted to maximise my screen estate. I chose XMonad because of the way it handles windows on multi monitors. Each screen shows an independent workspace. I have control over which application should appear on which screen. For example, I can show a movie on my second monitor while switching workspaces only on the laptop screen. The movie does not get affected. OS X, Windows, Gnome, KDE treats both screens as a single workspace. Nothing wrong with that. But I had to manually move apps from screen to screen and do a lot of Alt-Tab window cycling. With XMonad, I no longer need to do that. I just switch workspaces. XMonad allows you to configure apps to automatically go to designated workspaces. You get the added advantage of knowing exactly where which app is.

This repository is very well documented. My config is almost a carbon copy of it.

Status bar: Xmobar

Xmobar works well with my Window Manager(Xmonad). Configuring it is very easy. You should be able to achieve the same result with dzen2 too. Dzen has more features though. Xmobar is a plain text status bar. Here's my .xmobarrc. . THe gmail checker is a simple hand written ruby script. The colors used are picked from the solarized theme.

Termainal emulator: urxvt

I'm using urxvt as my terminal emulator. urxvt is highly customizable. I don't think the default terminal emulators that come with Gnome, KDE offer the same room for customizability as urxvt. It should not be a problem to install urxvt in your distro though. Just apply the color theme to your terminal. And it should merge nicely into the environment.

Here is my config for urxvt

Text editor: Emacs

Be it Vim or Emacs, you can easily apply a color theme for it. There's the Solarized theme for Vim as well. Just follow the instructions and install the appropriate color theme for your text editor. For emacs, you need to use the color theme package. There's a separate solarized color theme package. Install it and it'll merge perfectly with the status bar.

OS integration

To take it further, I made my wallpaper integrate into the status bar. I also used dark themes for Chrome and Firefox. Similarly for web apps like Gmail, I try to use a dark theme to merge in with the desktop. This makes the entire computing experience very pleasing to the eye.

 

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Wed, 04 Jan 2012 20:07:00 -0800 Fresh start in 2012 http://blog.liangzan.net/fresh-start-in-2012 http://blog.liangzan.net/fresh-start-in-2012

I've left sold.sg. Starting in Jan 2012, I'll be on my own as an independent developer. I'm not alone though. I'll be collaborating with Zhenyi(andadinosaur.com) for the near future. Expect to see new projects coming in the coming months. =)

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Sat, 23 Jul 2011 06:58:00 -0700 How SmugFTP came into being http://blog.liangzan.net/how-smugftp-came-into-being http://blog.liangzan.net/how-smugftp-came-into-being

SmugFTP is my side project. It has been out in the wild since this January. So its more than half a year now. Why did I build it? The reason is I find uploading painful. I wanted to scratch my own itch.

 

I signed up for Smugmug after my wedding. My wedding photos were precious. My wife and I wanted to share it with our friends and family. We wanted to back our photos up. We chose Smugmug. Everything was good. Except the uploading. An upload usually take many hours. It's common to leave you computer running overnight to complete the upload. The thing is, uploads fail. When it fails, it stops. So you have to check it periodically. If it fails, restart it. I actually felt a sense of relief and accomplishement once the uploads are complete. I wasn't happy with the web uploaders. The default uploader doesn't work. I chose the Java one. It felt clunky. The engineer in me knew that there'e got to be a better way to do this. So I went to the Smugmug wiki to find uploaders that others have written. Unfortunately there's none that look good. Feeling disappointed, I went to the Smugmug user voice page. And there it was, a suggestion for FTP uploading. I wanted FTP. I voted. That was when I thought to myself, FTP is not too hard to build, why can't I build it?

 

And so I started building it. Smugmug had an API. After doing a little research, I knew FTP to Smugmug is possible. And not too hard too. The first beta release was out in a month. Immediately, there's interest from other users. Slowly, word spreaded and the project grew. It was until after 6 months or so that I felt that SmugFTP is finally stable. 

 

There're several things I learnt

 

1. Testing is very important. Try to make the tests as similar as the actual environment

 

2. Don't be ashamed to release a buggy product. SmugFTP was buggy for a good 6 months. It caused many users inconveniences. But they still forgave me. 

 

3. Be nice to your users. If you're nice, people reciprocate. I always apologised for failed uploads in the early days. And I went out of the way to fix the mess that the bugs created. All of them appreaciate it. And I had a fantastic relationship with some of my users as a result of that. 

 

4. Solve a real problem. If you're solving a painful problem, users will find you. They will stick with you, forgive you and spread word for you. I find too many people are building stuff that do not solve actual problems.

 

5. Development always take longer than you think. The production environment always have surprises for you. 

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Thu, 20 Jan 2011 17:48:00 -0800 Emacs vs Vim http://blog.liangzan.net/emacs-vs-vim http://blog.liangzan.net/emacs-vs-vim

I'm one of those who have tried both Vim and Emacs. I've always wanted to write a post to share my experiences on these 2 venerable text editors. Right now, my primry editor is Emacs. Not to say Vim is not good, but for Emacs fits my setup better. I'm typing this article on Emacs if you're curious.

First a little history. I started with Vim first. Once I got through the steep learning curve, it felt fast. I was typing faster. Vim made me saw how inefficient I was earlier. From time to time, I will see articles or comments that mention Emacs. My curiosity grew. I started trying out Emacs. When I started learning it, I forced myself to use only emacs for a week. After that week, I was able to memorise most of the basic key strokes. So after about 2 years of using Emacs, I think its the right time to summarise my opinions.

Comparing the both of them is not fair. They have a different design philosophy. When we use Vim, the mindset is 'I want to type in the shortest time, and in as few keystrokes possible'. When we use Emacs, the mindset is 'I want to use Emacs for everything'.

Key Bindings

Vim keybindings are economical. But it can be cryptic. It is designed for the fingers. Emacs is designed for the brain. Key bindings can be executed through the minor modes which maps directly to an english phrase. Like 'comment-region', 'replace-string'. For Vim that would be "+gp'. As you can see, you are unable to guess just by reading what a Vim command can do.

Placement of key bindings

A good example of the difference in philosphy is the movement buttons. Vim places them in a line, right next to each other(GHJK). Emacs use C-n, C-p, C-f, C-b. It maps to next, previous, forward and back. Vim designs for the fingers. Emacs design for the brain. For emacs you won't have to memorise as much, but your fingers suffer from stretching.

Another good thing about emacs is there're other software that correlates their default key bindings with emacs. screen, tmux, zsh, etc has very similar keybindings to emacs. It shortend the learning curve considerably.

Window management

The killer feature that made Emacs my primary editor is the window management. Emacs allows me to have multiple frames. All the frames have access to the same buffers. This allows me to switch my buffers freely between the frames. That is very helpful if you use multi monitors. I cannot replicate the same behaviour with Vim. I'm stuck with the same buffers per Vim instance.

Otherwise, both editors are about equal when it comes to customizability and functions. For me, the above are the more obvious differences

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Mon, 26 Jul 2010 10:23:23 -0700 Adding rvm to zsh prompt http://blog.liangzan.net/index.php/2010/07/26/adding-rvm-to-zsh-prompt http://blog.liangzan.net/index.php/2010/07/26/adding-rvm-to-zsh-prompt Here's a simple way to add rvm to your zsh prompt. I think it should work for bash too.

http://gist.github.com/490372

It'll only show when rvm is in use. And here's how it looks. [URL=http://img252.imageshack.us/i/rvmzshprompt.png/][IMG]http://img252.imageshack.us/img252/1047/rvmzshprompt.png[/IMG][/URL]

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Wed, 07 Apr 2010 07:13:30 -0700 Test for blank elements with Culerity-Cucumber http://blog.liangzan.net/index.php/2010/04/07/test-for-blank-elements-with-culerity-cucumber http://blog.liangzan.net/index.php/2010/04/07/test-for-blank-elements-with-culerity-cucumber When you need to test for blank elements on Culerity, it is better to parse the html. Using Celerity helper methods such as $browser.button will return a Culerity::RemoteObjectProxy object. It does not tell you if it found an element or not. It is a limitation of Culerity. To work around it try this:

http://gist.github.com/358616

You can use the above code in the step definitions.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Tue, 09 Mar 2010 03:46:31 -0800 How to shoot yourself in the foot using a functional programming language http://blog.liangzan.net/index.php/2010/03/09/how-to-shoot-yourself-in-the-foot-using-a-functional-programming-language http://blog.liangzan.net/index.php/2010/03/09/how-to-shoot-yourself-in-the-foot-using-a-functional-programming-language While preparing for a presentation on Scala, I added some jokes on the functional languages. Here's the original version and the new editions Erlang You create a dozen clones of youself, pass the gun to one another in turn to shoot at each other's foot Python You have to align your foot 10 steps below the gun for it to work Ruby You pull the trigger to find popcorns popping out of the gun. Someone somewhere has just made all guns shoot popcorns. Haskell Close your eyes and picture a gun in your mind. Think about the foot being shot. Open your eyes. You found your foot shot. No sound. No smell. No one else even noticed. Scala You pull the trigger and you got shot. You stab your foot with the gun and you got shot.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Tue, 12 Jan 2010 09:43:39 -0800 Selectively load Ruby Facets modules http://blog.liangzan.net/index.php/2010/01/12/selectively-load-ruby-facets-modules http://blog.liangzan.net/index.php/2010/01/12/selectively-load-ruby-facets-modules Ruby facets has a lot of useful libraries. Sometimes you only want to load the ones that you need. Here's a little snippet that you can use

http://gist.github.com/275055

Rails won't load facets as the 'lib' param is false. We then load the libraries manually through initializers. This helps when facets unwittingly clobbers some of the other gems you are using.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Fri, 11 Dec 2009 08:42:41 -0800 Testing PDFs with Celerity-Culerity and Cucumber http://blog.liangzan.net/index.php/2009/12/11/testing-pdfs-with-celerity-culerity-and-cucumber http://blog.liangzan.net/index.php/2009/12/11/testing-pdfs-with-celerity-culerity-and-cucumber Here're the code to test the content of the pdfs. But first you need the pdf-reader gem.

http://gist.github.com/254067

The feature file is above.

http://gist.github.com/254065

Add the code above as a helper file.

http://gist.github.com/254064

And lastly, the steps. Remember to add a @pdf tag to your feature files.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Mon, 31 Aug 2009 15:23:45 -0700 Using Cucumber to test Paperclip file attachments http://blog.liangzan.net/index.php/2009/08/31/using-cucumber-to-test-paperclip-file-attachments http://blog.liangzan.net/index.php/2009/08/31/using-cucumber-to-test-paperclip-file-attachments I was using thoughtbot's paperclip to attach files. I realised that paperclip only provide shoulda macros for test::unit. No cucumber macros? In the end, I got to write it. Its very simple. The feature is shown here:

http://gist.github.com/178507

Define your steps:

http://gist.github.com/178505

As celerity does not have an attach_file method, I got to write my own. You could see it's not hard at all. Remember to define the browser variable. Last, we have some hooks to clean up the test upload files. Remember to place an @upload tag in your scenario.

http://gist.github.com/178501

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Thu, 20 Aug 2009 06:47:41 -0700 Email_Spec Integrated with Action_Mailer_Cache_Delivery http://blog.liangzan.net/index.php/2009/08/20/email_spec-integrated-with-action_mailer_cache_delivery http://blog.liangzan.net/index.php/2009/08/20/email_spec-integrated-with-action_mailer_cache_delivery For people using the action mailer cache delivery plugin, you can now add the email_spec plugin. The email_spec plugin provides many wonderful helpers to test your emails. Both plugins are now integrated. To use them you need to install both my forks of the plugins: Install them as plugins following the same instructions from the README. Don't forget to change the git url!

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Wed, 10 Jun 2009 06:45:21 -0700 Troubleshooting an Eclipse PDE Build http://blog.liangzan.net/index.php/2009/06/10/troubleshooting-an-eclipse-pde-build http://blog.liangzan.net/index.php/2009/06/10/troubleshooting-an-eclipse-pde-build

In this post, I'll share what I've learnt trying to run an Eclipse PDE build. The specific version is Eclipse 3.2. This took me a while to get right(a few months in fact!). The key to getting it right is getting The Dependencies right. So let's dive in!

Setting up

I'm following the example by J Aaron Farr. His example works and is simple enough.

The example code and screencast can be downloaded here.

If you are following Farr's steps, you should end up with 3 directories: builder, features, plugins. You should place all your plugins in the plugins folder, and the features in the features folder. The builder folder can be copied from Farr's example. One thing to note is inside the builder folder is a target folder. That contains a copy of Eclipse which is used to build. Make sure that copy has the dependencies(plugins/features) you need.

The checklist

There're lots of things that can go wrong in an Eclipse PDE build. Most times the error messags don't tell you clearly what's wrong. In my experience, the problems are usually found in the configuration. And it always is a dependency problem.

Product

The product file is found from your launching plugin.

  • Does the product contain all of your plugins and their dependencies? Only those plugins/features listed in the product are packaged. So make sure all the things you need are there
  • Does the build.properties file point to the correct product file?
  • Does the product contain the features necessary for testing? You need these 2 features org.eclipse.rcp(for launching eclipse) and org.eclipse.test(for testing). Add them as one of the features in the product.
  • Does the product configuration correct? There's the fields like name, id, application, useFeatures found in the attriute line of the product declaration. Make sure these are correct.

build.properties

This is one of the configuration files found under builder directory. It is meant for build.xml.

  • Are the paths correct? Use the full path to make sure everything works first. Switch to relative paths after which.
  • Is it forward slash or back slash? Ans: its "/"
  • What if I have spaces in the path? Ans: Use double quotes ""

For a better explanation, you can try the eclipse wiki

customTarget.xml

This is one of the configuration files found under builder directory. It is meant for adding your own ant targets to the build process.

  • Are u running junit tests? If you do, have you added an ant target task? Is the path correct?

allElements.xml

This is one of the configuration files found under builder directory.

  • Is the name of your feature correct?

Deployment target

This is the eclipse that you usually use to build against.

  • Does it have all the plugins features necessary for the build?
  • Does it contain only 1 copy of the plugin/feature?(eclipse will always take the newest version of the same plugin. it'll cause problems if your build needs the older version)

Build target

This is the eclipse target found under builder > target.

  • Does it have all the plugins features necessary for the build?
  • Does it contain only 1 copy of the plugin/feature?(eclipse will always take the newest version of the same plugin. it'll cause problems if your build needs the older version)

feature.xml for the plugins

This is the feature.xml for the feature that contains your plugins.

  • Is the id correct?
  • Does it contain all the plugins of your project
  • Does it have the dependencies listed?

feature.xml for the test plugins

This is the feature.xml for the feature that contains your test plugins.

  • Does it have the required dependency org.apache.ant?
  • Does it contain the test plugins?
  • Does it contain org.apache.ant and org.eclipse.core.runtime.compatibility?

General

  • Is the compiler version correct?
  • Is Ant and Java configured correctly?

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Sun, 09 Nov 2008 15:02:11 -0800 Fly away - Corrinne May Guitar Chords http://blog.liangzan.net/index.php/2008/11/09/fly-away-corrinne-may-guitar-chords http://blog.liangzan.net/index.php/2008/11/09/fly-away-corrinne-may-guitar-chords

This is a sad sad song. Well it happened to be my best friend's favourite. Reminds her of her Mom. Anyway this is for you MF!

F major, capo 1

F                 Am
"When will you be home?" she asks
      F                     Am
as we watch the planes take off
   F                 Am                 Dm
We both know we have no clear answer to where my dreams may lead
      F               Am
She's watched me as i crawled and stumbled
F                      Am
As a child, she was my world
    Am                           Dm
And now to let me go, I know she bleeds
                    Am
and yet she says to me


        Dm
You can fly so high
          F
Keep your gaze upon the sky
        Am                          Dm
I'll be prayin every step along the way
     F                   Am                     Dm          Bb
Even though it breaks my heart to know we'll be so far apart
Bb         Am                   Dm
I love you too much to make you stay
Dm             F
Baby fly away

F                  Am
Autumn leaves fell into spring time and
F              Am
Silver-painted hair
  F               Am                 Dm
Daddy called one evening saying "We need you. Please come back"
       F              Am
When I saw her laying in her bed
F             Am
Fragile as a child
  Am                           Dm
Pale just like an angel taking flight
                Am
I held her as I cried


        Dm
You can fly so high
          F
Keep your gaze upon the sky
        Am                          Dm
I'll be prayin every step along the way
     F                   Am                     Dm          Bb
Even though it breaks my heart to know we'll be so far apart
Bb         Am                   Dm
I love you too much to make you stay
Am             F
Baby fly away
Dm
ohh...

Bb         Am                   Dm
I love you too much to make you stay
Dm             F
Baby fly away

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Thu, 23 Oct 2008 09:15:58 -0700 Setting up a basic project infrastructure with Redmine, Hudson, VSFTP http://blog.liangzan.net/index.php/2008/10/23/setting-up-a-basic-project-infrastructure-with-redmine-hudson-vsftp http://blog.liangzan.net/index.php/2008/10/23/setting-up-a-basic-project-infrastructure-with-redmine-hudson-vsftp Here I would like to share with you the steps to set up the basic project infrastructure. For a project, there're a few tools which are absolutely necessary to function
  • File Server
  • Project Wiki
  • Continuous Integration Server
  • Bug/Issue Tracking
  • Source Control
With these features in mind, I have identified the software necessary to provide all these functionality.
  • Subversion - Source Control
  • Redmine - wiki, issue tracking, forums, repository viewing
  • Hudson - continuous integration
  • VSFTP - FTP file server
Ubuntu is chosen cos Linux is more stable, its free, its much easier to install stuff in it. But the real reason is cos I'm a Linux geek.

What do you need to learn?

All the work is done on the command line. So you need to be familiar with UNIX shell commands. Another thing is you'll be editing text files most of the time. Therefore you have to learn one of the UNIX text editors. Basic UNIX commands

Unix text editors

What tools do you need?

Setting up the server OS

Redmine Issue Tracking Server

Subversion

VSFTP FTP Server

Hudson Continuous Integration Server

Maven

Static Code Analysis Tools

Continuous feedback devices

How-Tos

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Sat, 18 Oct 2008 03:21:04 -0700 Plucking patterns for 让夜轻轻落下 http://blog.liangzan.net/index.php/2008/10/18/plucking-patterns-for-%e8%ae%a9%e5%a4%9c%e8%bd%bb%e8%bd%bb%e8%90%bd%e4%b8%8b http://blog.liangzan.net/index.php/2008/10/18/plucking-patterns-for-%e8%ae%a9%e5%a4%9c%e8%bd%bb%e8%bd%bb%e8%90%bd%e4%b8%8b This is a very old song. Its from the 'Xinyao' era in '80s Singapore where its a mini Renaissance of local Chinese music. I love songs from that era. Here is one of them. You can catch the original song here. The plucking patterns are improvised by me. For those new to guitar music notation: p = thumb(duh...) i = index finger(2nd finger) m = middle finger(3rd finger) a = ring finger(4th finger) 让夜轻轻落下 词曲:梁文福 Original Key: Bb Capo:3, play G Pattern 1: p i m a m i Pattern 2: p i m Pattern 3: p i m a m i m a
1          1          2      2    2 2
       G          Bm         C      D7   G G7
等着黑夜轻轻轻轻落下,将你我来覆盖,等着黎明的安排。

2     2        2    2       3       3
C     D7       Bm   Em     Am7      D7
过去已经过去,未来未必存在,让我们继续相信现在。

1     3         3         3
G     Em7       Bm7
对你从来不改变,千种柔情说着一种语言。

   3         3         3           3
   C         G        Am7          D7
昙花的笑靥,星光的乍现,是我羞涩散乱的思念。

1     3         3         3
G     Em7       Bm7
你也从来不改变,一种沉默说着千种亏欠。

   3         3         3            3
   C         G        Am7           D7
紧紧拥抱我,轻轻放开我,像放开无处安放的依眷。

   1      3        3           3
   G      D        Em          Bm
曾经我将无助的爱情,静静枕在你的臂弯里。

2    2    2     2    3           3
C    D7   Bm    Em   Am7         D7
以为它将为我阻挡风雨,共我面对寂寞的潮汐。

      1        3        3           3
      G        D        Em          Bm
可是在你宽阔温暖的胸怀里,总是听到冷冷的叹息。

2    2    2   2    3          3   2  2
C    D7  Bm  Em    Am         D7  G G7
你那不屑说谎的眼睛,始终教我自己回避。

1     3         2    2      2 2
C     Bm        C    D7     G G7
也许已经不是爱,只是一种坚持的情怀。

1     3           3           3
C     Bm          C           D7
也许依然还有爱,也许是慢慢生长的悲哀。

       1          1          2      2    2 2
       G          Bm         C      D7   G G7
等着黑夜轻轻轻轻落下,将你我来覆盖,等着黎明的安排。

2     2        2    2       3       3
C     D7       Bm   Em     Am7      D7
过去已经过去,未来未必存在,让我们继续相信现在。

      1        3        3           3
      G        D        Em          Bm
可是在你宽阔温暖的胸怀里,总是听到冷冷的叹息。

2    2    2  2     3          3   2  2
C    D7  Bm  Em    Am         D7  G G7
你那不屑说谎的眼睛,始终教我自己回避。

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Mon, 06 Oct 2008 14:03:58 -0700 Guitar Chords for The Birthday Song - Corrinne May http://blog.liangzan.net/index.php/2008/10/06/guitar-chords-for-the-birthday-song-corrinne-may http://blog.liangzan.net/index.php/2008/10/06/guitar-chords-for-the-birthday-song-corrinne-may The Birthday Song - Corrinne May Here's another set of self written chords. I wrote this cos someone wanted to play this song for her best friend. And I thought that's a worthy cause. So here goes...
G
Don't worry about that extra line
       Em
That's creeping up upon your face
     G
It's just a part of nature's way
   Em                        D
To say you've grown a little more
G
Trees have rings and thicker branches
Em
Kids shoes get a little tighter
      G                            Bm
Every year we're getting closer to who we're gonna be
     G                              Bm                    D
It's time to celebrate the story of how you've come to be

      G                  D  
Happy birthday my friend
          Bm
Here's to all the years we've shared together
Em                D
All the fun we've had
              G
You're such a blessing
       D7
Such a joy in my life
        G
May the good Lord bless you
        D                        G
And may all your dreams come true

G
So light a candle on your cake
    Em
For every smile you've helped create
    G
For every heart and every soul
       Em                     D
You've known to grow a little more
  G
A few more pounds, a little more grey
      Em
Don't count the years just count the way
   G                              Bm   
It takes a little time to go from water into wine
      G                           Bm                D
Don't ever lose the wonder of the child within your eyes

      G                  D  
Happy birthday my friend
          Bm
Here's to all the years we've shared together
Em                D
All the fun we've had
              G
You're such a blessing
       D7
Such a joy in my life
        G
May the good Lord bless you
        D                        G
And may all your dreams come true

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Thu, 18 Sep 2008 03:11:41 -0700 Comparing payment gateways for an e-commerce store in Singapore http://blog.liangzan.net/index.php/2008/09/18/comparing-payment-gateways-for-an-e-commerce-store-in-singapore http://blog.liangzan.net/index.php/2008/09/18/comparing-payment-gateways-for-an-e-commerce-store-in-singapore In this post I hope to share the nuts and bolts of setting up an e-commerce website from scratch. The topic of e-commerce is too broad to broach upon in 1 post. So let's focus on the payment gateway. What is a payment gateway? Why do I need it?  And the more important question: Where to find a payment gateway in Singapore?

What is a payment gateway? Why do I need it?

The payment gateway is that magic link between your website and the banks. It is how people pay you from the Internet. Without it, you can't make any monetary transactions. No transactions means you can't sell. Simply put, you must have a payment gateway if you were to sell things online.

E-Commerce Features

Amongst payment gateways, they offer many different pricing plans and different features. Here're some of the major features that you should take into consideration.
  1. Virtual terminal
  2. Virtual terminal is a virtual credit card swipe machine. It means you can make purchases manually by keying in the credit card details through the virtual terminal. It is helpful in cases when you sell your goods in person. The customer can still pay you by credit card though you don't have a swipe machine. But from a customer's perspective, I don't feel comfortable letting a stranger know my credit card number. Besides, isn't your website supposed to be up 24/7? Well, I feel that this feature is helpful but largely non essential.
  3. Support
  4. Support is that helping hand when things don't work. For example, you have problems integrating. Or the payment gateway is down, and you don't know why. Different plans have different support arrangements. It can range from email support to phone to 24/7 phone support. Though the terms may say 24/7 phone support, it may be an empty promise. If support is important to you, do seek out current customers and find out how's their customer service experience.
  5. Hosted/Non hosted
  6. Hosted solutions is when your customers is transferred to the payment gateway's website to make payment. While non-hosted solutions means the entire payment process is completed on your website. The main difference is the question of user interface. When your customers are redirected to another website, they're facing a completely different user interface. It may make them uncomfortable. Some people feel that it looks unprofessional. Is this a turn off significant enough? Well, it is subjective. If a simple redirect is enough to turn off your customers, doesn't that reveal how much they want to buy your product? Rather than working on your interface, why not spend your energy on things that matter?
  7. Credit card
  8. Visa, Mastercard, Discover, etc There're a multitude of credit cards available. Not all cards are supported by the gateways. Do check with them. In essence think which credit cards do your customers use. As long as you support the cards they have, you're fine.
  9. Need a merchant account?
  10. Usually, non-hosted solutions would require you to have a merchant account. A merchant account is a bank account that is electronically linked to the payment gateway. It means when someone makes payment, the money goes into this merchant account. You will need to pay fees for it. Banks usually impose a setup fee, plus transaction fees plus monthly fees. Don't forget you still need to pay the payment gateways.
  11. E-Commerce Technology
  12. Payment gateways offer different ways to integrate with their servers. Some may let you integrate via web services. While some may force you to use JSP(they told they've never heard of Rails before). So ask your programmer to check out the technologies available before you commit to a payment gateway

What are the payments gateways available in Singapore?

It is at times like this that you realise that the Internet is very US centric. Many of the well known payment gateways like Authorize.net, Braintree, Google Checkout operate exclusively in the United States. The choices are pretty limited if you're not in US. Available Options in Singapore For Paypal Payflow Gateway, the condition is you need to have a volume of S$5 million a year. If you qualify, congratulations! Visit a Citibank branch to open a merchant account and link it to the Payflow Gateway. It took me 2 months, a wasted trip to Paypal office in Singapore(where I got chased away), over 10 emails, almost 20 calls to Paypal(including overseas calls to UK and US) just to find this out. Banks do have e-commerce services. But Singapore banks are geared towards servicing brick and mortar companies aiming to build an internet store. They're not start-up friendly. What do I mean by that? It is required that you go through an application process, where you fill up many forms, and wait. And in fact, their e-commerce service providers are either E-Nets or E-Clearing. So please save yourself trouble and possible middleman fees by approaching the payment gateways directly. For overseas payment gateways, they usually offer their services through E-Nets. That is the case for Payment Express which is based in New Zealand.

Cost Comparison

World Pay Enets Paypal Payment express
Set up fees S$250 S$200 Free S$150
Annual fees S$650 S$450 Free S$600
Transaction fees 4.50% 4.50% 3.4% + S$0.50 100 free transactions, S$0.50 per transaction thereafter

Final Decision?

Eventually, we decided to use Paypal Website Payment Standard. Why? First, the cost is the lowest. There're no set up fees or monthly fees. You only pay when there're purchases. Second, the process is easy to set up. All I needed is a credit card. Applying for a merchant account at the banks is a hassle in comparison. There is processing time, and added charges for the set up can be quite hefty.

How to build an e-commerce cart?

There're all sorts of technologies available. It depends on the person coding it. If you're using Rails, I highly recommend the following blog post from fortytwo. Good luck on your e-commerce endeavours!

Update - Jan 2010

I've found out that Cybersource offers an API for direct integration on your website. Their prices is reasonable too. They have a Singapore office. It's best to call them directly. Their emails keep bouncing. Another option that is coming is 2C2P. They will link to local banks on March 1st 2010. They also have an API.

Update - Apr 2010

Another option is Payvision. They have a local office. Their sales staff can be annoying. They want to see your website before further discussion. With Payvision, you can use CheddarGetter for recurring payments

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Mon, 07 Jul 2008 03:27:20 -0700 Persistent Cookie Authentication Gem Documentation http://blog.liangzan.net/index.php/2008/07/07/persistent-cookie-authentication-gem-documentation http://blog.liangzan.net/index.php/2008/07/07/persistent-cookie-authentication-gem-documentation

Media_httpliangzannet_cemld

What are persistent cookies? What are persistent cookies used for?

A persistent cookie is no different from other cookies. What is different is that it is used to identify users. With identification, it enables a website to remember you on subsequent visits, speeding up or enhancing your experience of services or functions offered. For example, a website may offer its contents in different languages. On your first visit, you may choose to have the content delivered in French and the site may record that preference in a persistent cookie set on your browser. When you revisit that site it will use the cookie to ensure that the content is delivered in French.

Why do I need it?

The biggest advantage is we can skip the registration step. We use persistent cookies to identify users. Users can be anonymous first time visitors or registered users. When we're able to identify them(especially anonymous users), we can keep data like what items the user has placed on her cart. For e-commerce sites, you may not want to force the first time anonymous users to register when they try to place items in the cart. Some may be turned off and go away. By using persistent cookies to identify them, we can save which items they want without making them go through the registration process. You can make them register when its time to make payment.

How do I use them?

To use persistent cookies effectively, we're segregating the web site into 3 levels of access.
  • Public - anyone can go in. Examples would include your index page and FAQ
  • Protected - cookie authenticated.
  • Private - user must log in.
In your controllers, place a before_filter to identify which actions is private/protected
before_filter :cookie_required, :only => [:some_actions]
before_filter :login_required, :only => [:some_actions]
Use :cookie_required for protected actions, and :login_required for private areas.

How do I identify the users?

If you have seen through the code, there're actually 3 models controlling the authentication system: identity, login_cookies and users.
  • Identity - the unique identifier used to identify users. All users only have one identity, be it anonymous or registered users.
  • Login_cookie - the cookies used for identifying the users.
  • User - for identifying registered users.
One unique identity can have many Cookies, but only one User. So when you want to link to the user, use the Identity model instead. For example, you want to create a relationship where a user has many books:
class Identity 
Whenever your controllers need to link to the user, do it through the identity instead.

@identity.user
What if the user's browser did not enable cookies?
Good question. If that happens, we will treat the protected region as private automatically. There's no need for you to handle it. The code is created to degrade gracefully.
Implementation of persistent cookie authentication
The implementation is as suggested by Barry Jaspan and Charles Miller. In fact, Drupal's Persistent Login Module follows this set of implementation.
Special cases
There's a special case you need to take note. For example, an anonymous user comes to your site, and place a few items on the cart. And then she registers as a new user. Will the data in her shopping cart be lost?  The gem will ensure that her cookie entry and her newly registered user entry will be transferred to the same identity. But as I do not know how your website will be implemented, I did not implement the merging of the data from her cart. You'll need to add your code to transfer the data to her new identity. An example of the implementation is here. You'll need to modify the merge_identity function from user_controller.rb  From app/controllers/user_controller.rb

def mergeIdentity(anonymousCookieValue, knownIdentityID)
if anonymousCookieValue == nil || knownIdentityID == nil
return false
end

return false if !LoginCookie.isAnonymous(anonymousCookieValue)
loginValue = LoginCookie.getCookieLogin(anonymousCookieValue)

#getting the both anonymous user's identity and the known identity
anonymousCookie = LoginCookie.find(:first, :conditions => ["login = ?", loginValue])
anonymousIdentity = anonymousCookie.identity
knownIdentity = Identity.find(knownIdentityID)
return false if anonymousIdentity == nil || knownIdentity == nil

#transferring the cookies
anonymousIdentity.login_cookies.each { |cookie|
cookie.identity_id = knownIdentity.id
cookie.save
}

#transferring the cards
anonymousIdentity.cards.each { |card|
card.identity_id = knownIdentity.id
card.save
}

#finally send the identity to its grave
anonymousIdentity.destroy

return true

end
This is about all you will need to know to implement the persistent cookie authentication system effectively. Any bugs or unclear points, feel free to contact me.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Sun, 06 Jul 2008 22:38:35 -0700 Persistent Cookie Authentication Generator http://blog.liangzan.net/index.php/2008/07/06/persistent-cookie-authentication-generator http://blog.liangzan.net/index.php/2008/07/06/persistent-cookie-authentication-generator

Media_httpliangzannet_bqgjj

This is a Rails gem that I wrote, or rather extracted from the codebase from hushyhushy.com. OK, what is PersistentCookie Authentication Generator? This gem is a code generator.  This generator creates an authentication system with persistent cookie management. Feature include
  • a model which uses SHA1 encryption and salted hashes for passwords
  • a controller with signup, login, welcome and logoff actions
  • gmail smtp server integration
  • account creation that requires account verification via email
  • supports forgotten and changed passwords
  • a mixin which lets you easily add advanced authentication features to your abstract base controller
  • extensive unit and functional test cases to make sure nothing breaks.
  • token based authentication
  • persistent cookie management that allows anonymous users to be authenticated via cookies
Actually the code is heavily modified from another well known gem: salted hash login generator To put it simply, it is

persistent_cookie_authentication = salted_hash_login - localization + persistent_cookie_management

The code is written with an emphasis on simplicity. No effort is made from me to write clever or DRY(don't repeat yourself) code. The intention is to dumb it down so that people using it could understand it. As Joel says, abstraction is bad.

Media_httpliangzannet_cdozo

Here's the installation instructions: To install, run this line on the shell
gem install persistent_cookie_authentication_generator
From the directory of your Rails app, run this from the shell
ruby script/generate persistent_cookie_authentication
Change your config/database.yml settings. Then update your database by running
rake db:migrate
From app/controllers/application.rb, add this within application.rb
include UserSystem
Example application.rb From config/environment.rb, add this at the end of the file
require 'environments/user_environment'
require 'smtp_tls'
Example environment.rb From config/environments/, add this to the end of both development.rb and production.rb
ActionMailer::Base.smtp_settings = {:address => "smtp.gmail.com",
:port => "587",
:domain => "localhost.localdomain",
:authentication => :plain,
:user_name => "yourgmailusername",
:password => "yourgmailpassword"
}
Example development.rb From config/initializers/inflections.rb, modify your inflections.rb to look like this
Inflector.inflections do |inflect|#   inflect.plural /^(ox)$/i, '1en'
#   inflect.singular /^(ox)en/i, '1'
#   inflect.irregular 'person', 'people'
#   inflect.uncountable %w( fish sheep )
inflect.irregular 'LoginCookie', 'LoginCookies'
end
To test, run this from your shell
rake db:test:clone
rake test
From config/user_environment.rb, change the name of your Rails app to your liking That's it. Another post will cover how to use persistent login cookies. Bug reports please contact me directly at my email address. *Update: Here's the slides I've presented at the Singapore Ruby Meeting

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan
Sun, 29 Jun 2008 03:58:33 -0700 InvalidAuthenticityToken and Session Expiry http://blog.liangzan.net/index.php/2008/06/29/invalidauthenticitytoken-and-session-expiry http://blog.liangzan.net/index.php/2008/06/29/invalidauthenticitytoken-and-session-expiry This is something that I've discovered as I was building hushyhushy. After I upgraded to Rails 2, I began using authenticity tokens. So far so good. But in the course of testing the app, I would encounter the infamous 'InvalidAuthenticityToken Error'. That's weird! It usually happened in the middle of testing the app, and after some time too. It means that my authentication token was working fine, but somehow or rather it just failed in mid air. Then I realised the reason after some investigation. The reason is that my session expired. The session id changed. The authentication token is tied to the session id. So it became invalid. I did set my sessions to expire. I hope this helps for those who encountered the same problems as me. The obvious solutions that I can think of is:
  • prevent the session from expiring
  • lengthen the session expiration time
  • reset the authentication token
Here's how you would set the session expiration time in config/environment.rb
ActionController::Base.session_options[:session_expires] = 10.minutes.from_now
The best solution is to reset the authentication token. I tried doing that with form_authentication_token(), but I wasn't too successful. I'll try again and update this post if I am successful.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/831285/3793ee83f08ce6cb19b42df6316ef383.jpeg http://posterous.com/users/4xgetJYqvofT liangzan liangzan