Saturday, 31 December 2011

激情和爱情

今天在开心网上看到的帖子,觉得说的不错,记录下来。

有朋友问到区分激情和爱情,其实很好区分的,当你不见她时茶饭不思,是激情。老想见到她,想和她一起玩,一起上床,一起做白日梦,是激情。每天短信电话多的没完,是激情。为了生日节日费尽心思想浪漫的点子,是激情。当你和她在一起时脑子里不自觉的规划实实在在的将来,是爱情。当你们争吵到很凶,火很大时,也不忍心说一句伤害她的话,是爱情。当你们有分歧时,你总是能清楚的知道她是怎么想的,能理解她的初衷,是爱情。 

Thursday, 29 December 2011

Java profiler

jvisualvm is a Java virtual machine monitoring, troubleshooting and profiling tool. It comes with Sun Java 6 JDK and works out of the box. It works pretty well on Ubuntu so far for me.

Tuesday, 20 December 2011

Kinect statistics

Depth full resolution: 640 x 480 pixels
Device max depth: 10,000
Depth sensitivity: 11-bit, 2,048 levels
The depth sensor has a range limit of about 0.5m - 5m with a resolution of 1.5mm at 0.5m and 5cm at 5m.

Monday, 19 December 2011

Eat your way to better skin

1. Avoid sugar

Sugar has been associated with increasing aging. In a process called glycation, sugar molecules bind to proteins, such as collagen, causing it to become less effective and show signs of aging more quickly.

2. Snack on anti-oxidant-rich fruits or vegetables instead of sugar treats. These include blueberries.

3. Take oil supplements, such as omega-3 (fish or flaxseed oil) supplements, to keep skin hydrated. Omega-3 rich foods include salmon, flax and linseed oil. Linoleic acid - an essential omega-6 fatty acid - in particular can help dry skin too. The body doesn't make linoleic acid (which is found in grape seed, sunflower and other oils), but can be obtained through diet or in skin products.

3. For anti-aging purpose, we should take supplements that have vitamin C and E, lycopene (found in tomatoes), and lutein (common in spinach and kale). The help prevent wrinkles. We should also seek foods that contain beta-carotene, along with vitamins A and B.

Friday, 2 December 2011

偶然在网上看到的一段话,很有共鸣。

"我们都认为婚姻里的不忠,不仅仅是爱与不爱的区别,而是人品问题。你欺骗了这个世界上你最亲密的人,背叛了这个与你相互依偎,将走过一生的人。你还有什么值得信任呢?"

Ruby IO

Output
puts writes its arguments with a newline after each; print also writes its arguments but with no newline. printf works similar as C. The p method prints out an internal representation of an object.

Monday, 14 November 2011

Installation guide for several ruby gems

typhoeus
In order to install the typhoeus gem, you need to have the curl library installed. You can do this by:
sudo apt-get install libcurl4-openssl-dev


linecache19
linecache19 requires vm_core.h which needs to be included when installing ruby-debug19
sudo gem install ruby-debug19 -- --with-ruby-include=/src_file_paht_with_vm_core.h

Friday, 11 November 2011

Git remote related commands

Changing a remote's URL
git remote set-url example git://github.com/user/test.git will set the URL of the remote named “example” to git://github.com/user/test.git.


Tracking remote branch
Tracking when creating a new branch:
The full syntax is:
$ git checkout -track -b [local branch] [remote]/[tracked branch]
Simpler version is:
$ git checkout -t origin/branch
Setting up tracking for an existing branch:
$ git branch --set-upstream branch upstream/branch
Setting upstream when push
$ git push -u [remote] [branch]

Saturday, 5 November 2011

Show table of contents in Mendeley

If you want to view the table of contents of pdfs in Mendeley, you can start the application with the following option:
mendeleydesktop --pdf-toc
To make a shortcut in your launcher in Ubuntu 11.10, you can open the Main Menu application and add a new item with the command to start Mendeley. Note that if Main Menu does not respond after clicking the buttons, it is possible that the gnome-desktop-item-edit binary is missing. You can confirm this by running alacarte from the terminal and see if there are any errors. To install gnome-desktop-item-edit, you can run the following command:
sudo apt-get install --no-install-recommends gnome-panel

You can find the icon for Mendeley in /usr/share/icons/hicolor/. Choose the appropriate resolution you want for the icon. I used 48x48.

Friday, 4 November 2011

OpenNI updates

Recently I updated the OpenNI library to version 1.3.4.3 in the unstable branch, but playing from recorded files doesn't work after that. Then I switch back to  the latest version (1.3.3.6) in the master branch which works for playing recorded files.


The OpenNI developers are not very responsive to pull requests. In particular, the bug that I mentioned in the earlier post that is related to the wrong use of memcpy has not been fixed. So I forked the project and added the fix. I also added a method copyToBuffer to wrapper/OpenNI.java/src/org/OpenNI/Map.java so that we only need to allocate the buffer for the depth or image map once.

Friday, 28 October 2011

Explanation of POWMOD pseudocode

The following is a brute-force algorithm for computing B to the power of E mod M, assuming all the input numbers have N digits with base 256.

Explanation:

Wednesday, 26 October 2011

Using Kinect with OpenNI on Ubuntu 11.10

I recently upgraded to Ubuntu 11.10 and then my Kinect stopped working. I'm using OpenNI library for getting data from the Kinect.

At the beginning, when I ran the sample program NiViewer from the OpenNI libaray, I got the following error:

Open failed: failed to set USB interface.

I found the solution on OpenNI Google group discussion. You need to remove the gspca_kinect kernel module that comes with the upgrade by doing:
rmmod gspca_kinect
It seems to work even though it says "cann't find the module gspca_kinect". However, every time you restart the computer or replugin the Kinect USB, the module will be loaded again. To permanently remove the module, you can change the name of the module file:
sudo mv /lib/modules/3.0.0-12-generic/kernel/drivers/media/video/gspca/
gspca_kinect.ko /lib/modules/3.0.0-12-generic/kernel/drivers/media/video/gspca/gspca_kinect.ko.BAK

A better way may be blacklisting the module as suggested by this post. In this way, even after a kernel upgrade, the module will not be loaded.
$sudo gedit /etc/modprobe.d/blacklist.conf
Then add the following line to the end of the file and reboot:
blacklist gspcs_kinect

After this, the program could run, but I only got the RGB image data and the depth image was blank. Someone find out that this is due to the wrong use of memcpy in the OpenNI library. The line of code that causes the problem is in "/Source/OpenNI/Linux-x86/XnUSBLinux-x86.cpp" function "XN_THREAD_PROC xnUSBReadThreadMain(XN_THREAD_PARAM pThreadParam)" around line 1057. Instead of using memcpy, it should be:
memmove(pTransfer->buffer + nTotalBytes, pBuffer, pPacket->actual_length);
The difference between memcpy and memmove is that with memcpy, the destination cannot overlap the source at all, while with memmove, it can. For example, memcpy might always copy addresses from low to high. If the destination overlaps after the source, this means some addresses will be overwritten before copied. memmove would detect this and copy in the other direction - from high to low - in this case. However, checking this and switching to another (possibly less efficient) algorithm takes time.

The previous version of memcpy in libc6 may not make the difference so distinct, but in the new updated version of libc6 version 2.13, it might copy memory backward in some conditions, which causes issues if the source and destination overlap. You can read more about the changes in the new version in "/usr/share/doc/libc6/NEWS.Debian.gz".

Saturday, 22 October 2011

Update ruby to 1.9.2 on Ubuntu 11.10

$sudo apt-get remove ruby rubygems ruby1.8 ruby1.8-dev ruby1.8-full
$sudo apt-get install ruby1.9.1-full
$sudo update-alternatives --set ruby /usr/bin/ruby1.9.1
$sudo env REALLY_GEM_UPDATE_SYSTEM=1 gem update --system

Tuesday, 4 October 2011

Desktop Recorder for Ubuntu and Conversion

A good desktop recording software for Ubuntu is gtk-recordMyDesktop. Installation and usage instructions can be found here. To select a portion of the desktop to record, click Select Window button. Next click the mouse, hold and drag to select the portion in the preview window (note you don't do this on the actual desktop). It may be easier to instead right-click on the red circle in the system tray and click Select Area On Screen. In this way, you can select the portion actually on the desktop.

The video produced is in .ogv format. To convert the video format, you can use mencoder. You can install it using the command:
$ sudo apt-get install mencoder
To convert the recorded out.ogv file to recorded.avi of AVI format, you can use the following command:
$ mencoder out.ogv -o recorded.avi -oac mp3lame -ovc lavc
-ovc sets the video encoder. lavc refers to libavcodec.

Tuesday, 20 September 2011

NiViewer


Today I ran NiViewer provided by OpenNI again on Captured_08_22_11.oni, and observed vertical lines on the depth image. The vertical lines also shift with time.

The default coloring of the depth image is according to linear histogram. MAX_DEPTH is set to be 10000. The histogram is calculated according the following steps (in Draw.cpp, line 549, calculateHistogram()):
  - Count the number of pixels with the same depth_value and store it in depthHist[depth_value].
  - Calculate the accumulative frequency.
  - Invert the accumulative frequency.

In this way, pixels with greater depth values will have darker color. The use of histogram is good because the color is not scaled linearly with depth but with the frequency of the occurrences of the depth values.

Sunday, 18 September 2011

Ruby and Python boolean expressions compared

Ruby:

Only false and nil are treated as being false in a boolean context. All other values are treated as being true.

and, &&, or, and || all return operands. Bot and and && return their first argument if it is false. Otherwise, they evaluate and return their second argument. Similarly, both or and || return their first argument unless it is false, in which case they evaluate and return their second argument.

The word forms of the logical operators (and, or and not) have a lower precedence than the corresponding symbol forms (&&, ||, and !).

Equality testing:
Ruby has three main equality test methods, ==, eql? and equal?. They are defined in the Object class and in the Object class, all three methods do exactly the same thing, they test if two objects are exactly the same object. However, in other classes, they are usually redefined with different semantics:
  • == Test for equal value
  • eql? True if the receiver and argument have both the same type and equal values. 1 == 1.0 returns true, but 1.eql?(1.0) is false.
  • equal? True if the receiver and argument have the same object ID.
Ruby also has a case equality operator ===, which is used to compare each of the items with the target in the when clause of a case statement. The === operator is defined in Class to test whether the argument is an instance of the receiver or one of its superclasses. So you can use it to test the class of objects.

Python:

More values are considered false in Python:
  • None
  • False
  • zero of any numeric type, for example, 0, 0L, 0.0, 0j.
  • any empty sequence, for example, '', (), [].
  • any empty mapping, for example, {}.
  • instances of user-defined classes, if the class defines a __nonzero__() or __len__() method, when that method returns the integer zero or bool value False.
Python only has word forms of the logical operators. They return their operands in the same way as in Ruby.

In Python, == is similar to == in Ruby for numeric types and different string types (str and unicode) in that it only compares the values, but not the types, e.g. 1 == 1.0 returns True. But for objects of other types, == is similar to eql? in Ruby because both types and values have to be equal for it to return True. The object identity test is is the same to equal? in Ruby.

To check if an object is an instance of a type (class), use isinstance(object, type_name).

Monday, 12 September 2011

XHR2

Recently I used XHR2 for the CSSA new website. Basically, XHR2 enhances XHR with new features, such as cross-origin requests. This means you can make an XHR request across domains, but only if the server you're connecting to allows it.

This means the server needs to respond with a CORS (Cross-Origin Resource Sharing) header. For PHP, you can add the following lines at the beginning of the .php file:

<?php
header('Access-Control-Allow-Origin: *');
?>

'*' means it allows any origin to access the resource.

References:
https://developer.mozilla.org/en/HTTP_access_control#Access-Control-Allow-Origin
http://html5doctor.com/methods-of-communication/

Tuesday, 30 August 2011

Ruby: strings

Single-quoted strings only support two escape sequences: two consecutive backslashes are replaced by a single backslash, and a backslash followed by a single quote becomes a single quote.

Double-quoted strings support more escape sequences, like "\n". It also allows string interpolation #{expr}. If the code is just a global variable, a class variable, or an instance variable, you can omit the braces.

%q and %Q start delimited single- and double-quoted strings as well.
%q/general single-quoted string/
%Q!general double-quoted sting!
%{Seconds/day: #{24 * 60 * 60}} # => Q can be ommitted.


You can also construct a string using a here document:
string = <<END_OF_STRING
    The body of the string
    is the input lines up to 
    one starting with the same
    text that followed the '<<'
END_OF_STRING

Normally, the terminator of the here document must start in the first column. However if you put a minus sign after the << characters, you can indent the terminator:
string = <<-END_OF_STRING
    The body of the string
    is the input lines up to 
    one starting with the same
    text that followed the '<<'
    END_OF_STRING

To initialize an array of strings, you can use %w:
%w(foo bar) # => ["foo", "bar"]

Installing rubygems

Installing rubygems on Ubuntu 11.04 takes several steps:

$ sudo apt-get install rubygems rubygems-update
$ gem env | grep EXECUTABLE
// cd to the executable directory
$ update_rubygems 
// now rubygems will be installed in the correct directory.

Saturday, 27 August 2011

Remote Accessing Ubuntu Desktop

Today my Macbook Pro didn't boot up with stripes on the initial gray screen. I took it to the Apple Store and the technician told me that it is a specific failure on the Main Logic Board. However the replacement is covered even thought it is already out of warranty, so I don't need to pay anything for the replacement. :D

But I'll be without my laptop for 5-7 days. :( I have a Chrome notebook with Ubuntu installed on it, but I'm afraid it's going to be laggy if I run Eclipse on it, so I looked into remote accessing my desktop in my lab. I tried the default Remote Desktop Viewer application that came with Ubuntu, but it didn't work: my notebook doesn't refresh the screen after I clicked something on the remote display. I also tried the guide on using x11vnc, but was also out of luck. I used TightVNC's vncviewer. It asked for a password and I wasn't sure what password to use. I tried a few, but all failed.

Finally, I installed the NX free edition and client and it works pretty well. The installation and configuration are very easy too.

Thursday, 18 August 2011

Java ArrayList copy constructor

The copy constructor of ArrayList in Java provides a shallow copy of the elements in the list. This is kind of expected, but I stilled wrote a test to verify this.

public class Test {
  public static void main(String[] args) {
    ArrayList<Point> list1 = new ArrayList<Point>();
    list1.add(new Point(1, 2));
    System.out.println("list1: " + list1);
    ArrayList<Point> list2 = new ArrayList<Point>(list1);
    list2.get(0).x = 3;
    list2.get(0).y = 4;
    System.out.println("list1: " + list1);
    System.out.println("list2: " + list2);
  }
}

Output:
list1: [java.awt.Point[x=1,y=2]]
list1: [java.awt.Point[x=3,y=4]]
list2: [java.awt.Point[x=3,y=4]]

Cloning an array of primitives, like int, is deep cloning. For example:
public class Test {
  public static void main(String args[]) {
    int[] a = {1, 2, 3, 4};
    int[] b = a.clone();
    b[0] = 5;
    System.out.println("a = " + Arrays.toString(a));
    System.out.println("b = " + Arrays.toString(b));
  }
}

The output is:
a = [1, 2, 3, 4]
b = [5, 2, 3, 4]

Friday, 12 August 2011

Notes on Robert Martin interview by the Pragmatic Bookshelf

Podcast: http://pragprog.com/podcasts/show/32

1. Programming is a craft and you do it for the shear love of it. Why would you want to do anything else? Why don't you perfect it. If you love doing it, why changing to another field like management?

2. Learn a new language every year. Clojure is an interesting language to know. Learn functional languages.

3. Corporate languages like Java and C# will become legacies.

4. SOLID: principles of organizing objects in a object oriented language: what should be in a class and what the relationships between objects ought to be.
Single responsibility, Open closed, Liskov substitution principle, Dependency inversion, interface segregation

5. TDD

6. The Structure and Interpretation of Computer Programs - by Abelson and Sussman

Wednesday, 20 July 2011

燕子呢喃之烧鸡公 (Chongqing Spicy Chicken)


材料:
鸡块,烧鸡公调料


步骤:
1. 热锅中倒入200克油,旺火加热到7成熟后,倒入鸡块2斤左右,翻炒加热到皮紧。

2. 倒入160克调料,翻炒至调料均匀。
3. 倒入水至盖过鸡块,旺火烧10分钟,小火焖20分钟,至烧烂为止。

Ingredients:
Chicken (cut into pieces), Chongqing spicy chicken sauce.

Steps:
1. Add 200g oil to the wok. Heat under high heat until 70% cooked. Add the chicken and stir until the skin is tight.
2. Add the sauce and stir until well-mixed.
3. Add water until it covers the chicken. Heat under high heat for 10 mins and low heat for 20 min until the chicken is tender.

Friday, 8 July 2011

燕子呢喃之酒糟木耳猪蹄 (Fungus and pork feet)


材料:
猪蹄, 木耳,葱姜,料酒,酒糟。




步骤:
1. 猪蹄洗净焯水。取出后将猪蹄冲洗干净。

2. 再将猪蹄、葱姜放入水中,大火煮沸7-8分钟,加料酒。
3. 将洗净的木耳去根,稍切小。
4. 加入木耳,转至小火焖煮1小时。当肉煮烂后,加入盐和鸡精适量。
5. 再略煮片刻后取出,冷却2个小时左右后加酒糟。

Ingredients:
Pork feet, fungus, onion, ginger, cooking wine, distiller's grains.

Steps:
1. Wash the pork feet and put them into boiling water. Take them out when it boils again and wash again.
2. Put pork feet, onion, ginger into water, boil for 7-8 mins under high heat. Then add cooking wine.
3. Remove the root of the fungus and cut it into smaller pieces.
4. Add the fungus and turn to low heat and cook for 1 hour. When the meat becomes tender, add some salt.
5. Take out the feet after a few minutes. Add the distiller's grains after cooling for 2 hours.

燕子呢喃之茄汁鳝筒 (Eel with tomato sauce)

这道菜荤素搭配,营养丰富。黄鳝鲜嫩,酸中带甜。热量低,是理想的减肥菜肴。

材料:
主料:黄鳝500克,番茄2个。
配料:蒜头1个,红椒3个,葱姜若干。

步骤:
1. 黄鳝焯水,去腥味和粘液。取出后切断。
        


2. 煸炒配料,煸出香味后,加入黄鳝,再煸炒一下。放冷水大火烧滚2-3分钟,然后调小火焖烧10分钟。然后放入盐、鸡精和料酒少许。


3. 把去皮的番茄切丁,放入油锅中煸炒成番茄酱。

4. 将炒好的番茄酱放入黄鳝中翻炒几下即可上盆。

Ingredients:
Main: 500g eels, 2 tomatoes.
Side: 1 garlic, 3 chili peppers, ginger and scallion

Steps:
1. Put eels in the boiling water and take out when it boils again to remove smell. Chop the eels.
2. Fry the side ingredients, and then add the eels and fry again. Add cold water and boil for 2-3mins under high heat. Turn to low heat and cook for 10mins. Then add salt and cooking wine.
3. Remove the skin of the tomatoes. Chop the tomatoes into small pieces. Fry the tomatoes in a pan with some oil to make tomato sauce.
4. Add tomato sauce to the eels. Stir for a bit and it's done.

Thursday, 7 July 2011

OpenCV naming convensions


  • Matrix data types:
    CV_[bit_depth](S|U|F)C[number_of_channels]
    S = Signed integer
    U = Unsigned integer
    F = Float 
    
    E.g.: CV_8UC1 means an 8-bit unsigned single-channel matrix,
            CV_32FC2 means a 32-bit float matrix with two channels.

  • Image data types:
    IPL_DEPTH_[bit_depth](S|U|F)
    E.g.: IPL_DEPTH_8U means an 8-bit unsigned image.
            IPL_DEPTH_32F means a 32-bit float image.
Note that in the image data types, the depth and number of channels are specified separately.

Meat ball soup(肉丸汤)

图片来源:心食谱

Ingredients:
Ground meat, 1 tomato, 1 egg, water 1L, salt 2 1/2 teaspoons, starch powder 2 tablespoons, soy sauce 2 1/2 teaspoons, ginger (small amount, optional).

Steps:
1. Defrost the ground meat in the microwave for 4 mins (choose defrost on the microwave).
2. Cut the tomato into pieces. Optional: cut the ginger into very small pieces.
3. Add 1 teaspoon of salt, ginger pieces (optional), egg and 1 teaspoon of soy sauce to the ground meat. Stir in one direction. Add the starch powder and stir further.
4. Boil the water under high heat. When the water boils, turn to low heat. Use the green measuring spoon to scoop the meat, making it approximately ball shape. Put the meat balls into the water.
5. When the meat balls float on the water (almost cooked), add tomato, salt and soy sauce.
6. When the water boils again, it's done.

Original recipe:

材料:
猪肥瘦肉250克(可选猪绞肉,但是自己剁的肉要筋斗些),大番茄1个,黄豆芽100克,鸡蛋1个,鲜汤或清水1升,精盐21/2茶匙,生姜5克,姜末11/2茶匙,水豆粉2汤匙,味精21/2茶匙(可选),酱油21/2茶匙


做法:
1.将葱切成葱花,番茄切成厚片,生姜拍破,黄豆芽洗净待用。
2.猪肉剁茸,加1茶匙精盐、姜末、鸡蛋、1茶匙酱油及少量清水向一个方向搅拌均匀,再加水豆粉搅拌均匀待用。
3.汤锅置旺火上,加入鲜汤或清水、破姜烧沸,将火关至小火,将肉馅用小汤勺舀成圆形,每个约呈2厘米的直径,逐一放入锅中煮熟至肉丸浮出汤面时,加黄豆芽,番茄片、精盐、酱油、味精烧沸后,捡去破姜,盛入汤碗中即成。

Wednesday, 6 July 2011

Wireless adapter on Compaq Presario V2000

Today, I was trying to use wireless network connection on the Compaq Presario V2030US laptop. It didn't work initially. The wireless button didn't light up when I pressed it.

In device manager, the network adapter Intel (R) PRO/Wireless 2200BG Network Connection is listed with a red cross on the icon. I tried to update the driver automatically and it appears to install some files from the system folder. In the end, it says the driver is not compatible with the platform. I'm guessing it's because the driver comes with the original installation is for XP Home and now the OS is XP Professional. Maybe there's some incompatibility.

So I went to find the driver for the wireless adapter online and installed it. It works now. :)

Monday, 4 July 2011

Ants climbing the hill(蚂蚁上树)

照片来源:心食谱


Ingredients:
Rice noodle (1 bundle), ground meat, hot chili sauce

Steps:
1. Boil the rice noodle in a pot with water. Take out the noodle when it's soft. Run the noodle through cold water in a sieve (the orange one in the kitchen drawer) to cool the noodle and get rid of the water.

2. While boiling the noodle, defrost the ground meat in the microwave (choose defrost, for about 4min).

3. In a pan, heat up 2 teaspoons of oil under high heat. When the oil is warm, turn to low heat. Add ground meat and stir. Add hot chili sauce and stir more until the meat is almost cooked.

4. Add the noodle to the pan and stir for about 3 to 5 min. Add some salt and soy sauce, and it's done.

Optional:
Can add some vegetables, like green peppers, tomatoes, carrots if you like. Add them after the meat, but before the noodle.

Original recipe: 

材料:

粉条,肉末50克,蒜蓉

步骤:
1.粉丝先在开水中煮至八成熟后,捞出;过冷水,沥干水份,备用。
2.油锅烧热,下蒜蓉,爆香;加入肉末,炒至肉粒呈金黄颜色。
3.倒入已煮过,沥干水份的粉丝,与肉末一齐翻炒三至五分钟;此时加适量精盐,以及生抽,上色并调味;即可出锅。

Saturday, 2 July 2011

If by life you were deceived...

If by life you were deceived... - Alexander Pushkin

If by life you were deceived,
Don't be sad or mad at it!
On a gloomy day, submit:
Trust - fair day will come , why grieve you?

Heart lives in the future, so
What if gloom pervade the present?
All is fleeting, all will go;
What is gone will then be pleasant.

假如生活欺骗了你 - 普希金


假如生活欺骗了你,
不要忧郁,也不要愤慨!
不顺心时暂且克制自己,
相信吧,快乐之日就会到来。


我们的心儿憧憬着未来,
现今总是令人悲哀:
一切都是暂时的,转瞬即逝,
而那逝去的将变得可爱。

Александр Сергеевич Пушкин


Если жизнь тебя обманет,
Не печалься, не сердись!
В день уныния смирись:
День веселья, верь, настанет.


Сердце в будущем живет;
Настоящее уныло:
Все мгновенно, все пройдет;
Что пройдет, то будет мило.


I loved you - Pushkin

I loved you; and perhaps I love you still,
The flame, perhaps, is not extinguished; yet
It burns so quietly within my soul,
No longer should you feel distressed by it.
Silently and hopelessly I loved you,
At times too jealous and at times too shy.
God grant you find another who will love you
As tenderly and truthfully as I.


我曾经爱过你 普希金


爱情,也许
在我的心灵里还没有完全消亡,
但愿它不会再打扰你,
我也不想再使你难过悲伤。
我曾经默默无语、
毫无指望地爱过你,
我既忍受着羞怯,
又忍受着嫉妒的折磨,
我曾经那样真诚、
那样温柔地爱过你,
但愿上帝保佑你,
另一个人也会象我爱你一样。


Я вас любил...


Я вас любил: любовь еще, быть может
В душе моей угасла не совсем;
Но пусть она вас больше не тревожит;
Я не хочу печалить вас ничем.
Я вас любил безмолвно, безнадежно,
То робостью, то ревностью томим;
Я вас любил так искренно, так нежно,
Как дай вам бог любимой быть другим.

Friday, 1 July 2011

Java int and short casting

Did some test on Java int and short casting. I'm interested to see how it behaves when the integer overflows short.

public class CastingTest {
  public static void test(int a) {
    System.out.println("a = " + a + " (" + getBits(a) + ")");
    short b = (short) a;
    System.out.println("b = " + b + " (" + getBits(b) + ")");
    int c = b;
    System.out.println("c = " + c + " (" + getBits(c) + ")");
    int d = b & 0xffff;
    System.out.println("d = " + d + " (" + getBits(d) + ")");
  }
  
  public static String getBits(int v) {
    StringBuffer sb = new StringBuffer(32 + 3);
    for (int i = 1; i <= 32; i++) {
      int mask = 1 << 31;
      int bit = (v & mask) == 0 ? 0 : 1; 
      sb.append(bit);
      if (i % 8 == 0 && i != 32)
        sb.append(' ');
      v <<= 1;
    }
    return sb.toString();
  }
  
  public static String getBits(short v) {
    StringBuffer sb = new StringBuffer(16 + 1);
    for (int i = 1; i <= 16; i++) {
      int mask = 1 << 15;
      int bit = (v & mask) == 0 ? 0 : 1; 
      sb.append(bit);
      if (i % 8 == 0 && i != 16)
        sb.append(' ');
      v <<= 1;
    }
    return sb.toString();
  }
  
  public static void main(String[] args) {
    test(65535);
    test(65536);
    test(-65535);
  }
}

Output:

a = 65535 (00000000 00000000 11111111 11111111)
b = -1 (11111111 11111111)
c = -1 (11111111 11111111 11111111 11111111)
d = 65535 (00000000 00000000 11111111 11111111)

a = 65536 (00000000 00000001 00000000 00000000)
b = 0 (00000000 00000000)
c = 0 (00000000 00000000 00000000 00000000)
d = 0 (00000000 00000000 00000000 00000000)

a = -65535 (11111111 11111111 00000000 00000001)
b = 1 (00000000 00000001)
c = 1 (00000000 00000000 00000000 00000001)
d = 1 (00000000 00000000 00000000 00000001)

This shows that, when converting int to short, jvm just takes the lower two bytes, even if the number overflows short.

Friday, 24 June 2011

Working with PrimeSense's Nite Middleware

Today when I tried to run the sample program in the Nite package, I got an error saying "One or more of the following nodes could not be enumerated:" It worked before, so I wondered why. Eventually I solved the problem by reinstalling the Nite package.

1) Go to the downloaded Nite package directory.
2) Use the following commands to reinstall:
$ sudo ./uninstall.sh
$ sudo ./install.sh
When prompted, enter the licence key: 0KOIk2JeIBYClPWVnMoRKn5cdY4=

Wednesday, 22 June 2011

Adding printers at CSAIL on Ubuntu

1. Go to Printing and click "Add".
2. Under Network Printer, choose LPD/LPR Host or Printer.
Host: cups.csail.mit.edu
Queue: [Printer Queue Name] (i.e. xerox2)
3. Choose the option to provide the driver yourself. You can download the driver here.

Friday, 27 May 2011

C++ tips: use forward declaration when possible

Found a good explanation of forward declaration in C++ header files here. Basically, if a class A is only used as a reference or a pointer, it should only need to be included as:
class A;
//#include <A.h> // Not like this

Monday, 23 May 2011

Eclipse crashes when having CDT projects

This seems to be a problem since Oracle Java 6 update 23. I have update 24, and still have the same problem. The work around is adding -XX:-UseCompressedOops to the eclipse.ini file in the eclipse directory. This disables compressed oops.

In Java HotSpot VM, options that are specified with -XX are not stable and are not recommended for casual use. Such options, if they are boolean, can be turned on with -XX:+[option] and turned off with -XX:-[optoin].

What is compressed oops then? "Oop" means "ordinary object pointer". In HotSpot parlance, it is a managed pointer to an object. Compressed oops represent managed pointers as 32-bit values which must be scaled by a factor of 8 and added to a 64-bit base address to find the object they refer to. Some details can be found here. According to this bug report, the crash is not due to a compressed oops bug per se but an existing bug that could only be triggered under the object layout that results from compressed oops.

Friday, 20 May 2011

Recovering grub boot-loader after installing Windows

Installing Windows after Ubuntu will wipe out the boot-loader. To recover the boot-loader, follow the instructions here:
https://help.ubuntu.com/community/RecoveringUbuntuAfterInstallingWindows

This worked great for me, except once. After doing the steps in that website, it directly booted into Ubuntu without listing Windows. Then I typed the following command, and it worked:
$ sudo update-grub

Wednesday, 18 May 2011

4-Projector Display under Ubuntu 11.04

For my tabletop interaction research project, I need to create a large extended display with 4 projectors in a 2x2 configuration. I could not make all 4 projectors to display at the same time with the original 2 Nvidia GeForce 8600GT graphics cards. Turns out it is especially hard to do this, if not impossible. Also, the Nvidia cards are kind of old, so I switched to a new graphics card, ATI Radeon HD 6870 with two DVI ports, 2 Mini DisplayPorts and 1 HDMI port.

After connecting the projectors to the 2 DVI ports and 2 Mini DisplayPorts, all 4 projectors can display now, however the displayed areas are not well-aligned as before. Specifically, the two displays from the projectors connected to the DVI ports are smaller with black area around them.

The problem is with underscan. The Catalyst Control Center does have the underscan and overscan option for HDMI but it doesn't always show up. It is supposed to be under "Display Manager" -> <a particular projector/monitor> -> Adjustment, but the "Adjustment" tab does not always appear. For me, it appears for one projector and I changed the scaling to 0% underscan. This did expand the displayed area for that projector. But I couldn't do the same for the other projector.

Finally, what worked is using the command line to disable underscan:
sudo aticonfig --set-pcs-val=MCIL,DigitalHDTVDefaultUnderscan,0

Sunday, 8 May 2011

The Unbearable Lightness of Being

Part 1.1 (p4)
... the idea of eternal return implies a perspective from which things appear other than as we know them: they appear without the mitigating circumstance of their transitory nature. The mitigating circumstance prevents us from coming to a verdict. For how can we condemn something that is ephemeral, in transit?

... the profound moral perversity of a world that rests essentially on the nonexistence of return, for in this world everything is pardoned in advance and therefore everything cynically permitted.

Part 3.3 (p91)
But what is betrayal? Betrayal means breaking ranks. Betrayal means breaking ranks and going off in the unknown. Sabina knew of nothing more magnificent than going off into the unknown.

Part 3.4 (p98)
She had an overwhelming desire to tell him, like the most banal of women, Don't let me go, hold me tight, make me your plaything, your slave, be strong! But they were words she could not say.

The only thing she said when he released her from his embrace was, "You don't know how happy I am to be with you." That was the most her reserved nature allowed her to express.

Part 4.8 (p142)
What is flirtation? One might say that it is behavior leading another to believe that sexual intimacy is possible, while preventing that possibility from becoming a certainty. In other words, flirting is a promise of sexual intercourse without a guarantee.

Part 4.28 (p169)
But the fragile edifice of their love would certainly come tumbling down. For that edifice rested on the single column of her fidelity, and loves are like empires: when the idea they are founded on crumbles, they, too, fade away.

Part 5.23 (238)
He suddenly recall the famous myth from Plato's Symposium: People were hermaphrodites until God split them in two, and now all the halves wander the world over seeking one another. Love is the longing for the half of ourselves we have lost.

Tuesday, 26 April 2011

A selection of gesture interactions using Kinect




CSS good practices

Found two interesting slides about good CSS practices from Nicole Sullivan. Here are some points about examining our best practices myths rationally that I think are really nice:
Myths Rational Rethink
Don't add any extra elements Add non-semantic elements judiciously
Use descendant selectors exclusivelyKeep specificity as low as possible
Use specificity to define your architecture
Don't add classes (Classitis)Abstract repeating visual patterns into class


A video of her presentation on this topic at WebStock.



Two main principles of object oriented CSS:
1. Separate structure and skin
2. Separate container and content: break the dependency between the container module (contour blocks, background blocks) and the content objects (headings, paragraphs, lists, headers, footers, buttons, etc) it contains.

Best practices:
1. Build HTML from component library
2. Extend objects by applying multiple classes to an element
3. Use classes for style. Save ids for JavaScript
4. Be flexible: extensible height and width -> Grids control width; content control height
Nicole Sullivan's original blog post.

Sunday, 24 April 2011

Romanian

Useful phrases:
La mulți ani: Happy Birthday!
Noapte bună: Good night!
Bună dimineața: Good morning!
Bună ziua: Hello!

Tuesday, 19 April 2011

Java: compare different methods for copying BufferedImage

Tested with copying a 640x480 RGB image.
// Fastest method (0-1ms).
public void copy1(BufferedImage src, BufferedImage dst) {
  int[] srcArray = ((DataBufferInt) src.getRaster().getDataBuffer()).getData();
  int[] dstArray = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData();
  System.arraycopy(srcArray, 0, dstArray, 0, srcArray.length);
}

// Second fastest (7-8ms).
public void copy1(BufferedImage src, BufferedImage dst) {
  int[] srcArray = ((DataBufferInt) src.getRaster().getDataBuffer()).getData();
  dst.setRGB(0, 0, dst.getWidth(), dst.getHeight(), srcArray, 0, dst.getWidth());
}

// Slowest method (18-19ms).
public void copy1(BufferedImage src, BufferedImage dst) {
  dst.setData(src.getData());
}

Java object reference is passed by value

Today I spent a whole afternoon debugging a piece of Java code. The code is something like this:

public void captureNow(BufferedImage image) {
  try{  
    image = ImageIO.read(new File(getRecordeDir() + files[index++])); // only changes the local variable image.
  } catch (IOException ioe) {
    System.err.println(e.getMessage());
  }
}

BufferedImage bi = new BufferedImage(width, height, type);
captureNow(bi); // bi does not change.

After calling captureNow(bi), bi didn't get the image that supposed to be read. The problem here is I got confused with C++. Even though Java is pass by reference, it does not mean the same thing as in C++. Here in Java, the local variable image got the address of bi. In side the method, image is assigned another address, but this does not affect bi. In C++, a reference is automatically dereferenced to point to the actual object. Hence, an assignment will affect the actual object passed.

Edit:
As a reader pointed out, here is a good explanation about Java's pass by value.

Monday, 18 April 2011

Setting permissions of a Windows partition in Ubuntu

My Windows partition is in NTFS format which does not support chmod or chown for changing file permissions and ownership. These are set at the time of mounting. If I click the partition icon to mount it, the default permission does not allow execution. To change the mount settings, you need to edit the /ect/fstab file which is a system configuration file and is used to tell the Linux kernel which partitions (file systems) to mount and where on the file system tree.

Here is an example of a configuration to add to the fstab file:
/dev/sda4 /media/WinData ntfs uid=<user_name>,exec,fmask=037,dmask=027 0 0

fmask and dmask change the permissions of files and directories respectively. The numbers represent the permissions to turn off, and  4, 2, 1 represents read, write and execute respectively.

After setting this, the partition needs to be mounted by root using mount command line.

For more details, see this post: http://ubuntuforums.org/showthread.php?t=283131

Sunday, 10 April 2011

Ruby: metaprogramming

Definitions
Singleton method: a method defined on a particular object
Singleton class: the anonymous class created in which a singleton method is defined

Object Model
  • Instance variables live in objects, and methods live in classes.
    • You can get a list of object's methods by calling obj.methods.
    • For a class, you can call klass.methods to see what class methods are available, and klass.instance_methods to know the instance methods. klass.instance_methods(false) returns methods defined by the class and not inherited.
  • Classes themselves are nothing but objects, and have their own class called Class.
    • All classes ultimately inherit from Object.
      "hello".class # => String
      String.class # => Class
      Class.instance_methods(false) # => [:allocate, :new, :superclass]
      # :superclass is only a method a class, not an object. 
      String.superclass # => Object
      
  • The methods of an a class are the instance methods of Class.
Self
  • Every line of Ruby code is executed inside an object - the so-called current object. The current object is also known as self.
  •  In a class or module definition, the role of self is taken by the class or module.
Singleton Methods
  • Class methods are Singleton Methods of a class.
  • Introspection methods:
    • singleton_methods returns all the singleton methods for the object (also the ones in included modules).
    • singleton_methods(false) returns all the singleton methods for the object, but not those declared in included modules.
    • methods(false) supposedly returns the singleton methods by calling singleton_methods, but it also passes the parameter false to it.
      String.methods(false) == String.singleton_methods(false) # => true

Saturday, 9 April 2011

Convert ogv to wmv

Yesterday, I was trying to insert a video clip into a PowerPoint presentation. The video was recorded using recordMyDesktop under Ubuntu and is a .ogv file. PowerPoint does not support this format. So I need to convert it to either AVI or WMV format.

.ogv is one of the extensions used for files whose content use the Ogg container format. In particular, .ogv is used for video with or without sound. As PowerPoint supports AVI format and I can also play AVI file in Ubuntu, so I converted the .ogv file to .avi file using ffmpeg using the following command:

$ ffmpeg -i shutter.ogv -vcodec mpeg4 -acodec libmp3lame -sameq shutter.avi

However, when I opened the .avi file in Windows XP, it doesn't play in PowerPoint or in the DivX player. I thought there may be some incompatibility in the file made in Ubuntu, so I tried to convert the .ogv file to .avi or .wmv in Windows XP. I tried several software including ffmpeg and WinFF for Windows but the resulted file's quality is very bad. In the end, what worked is converting the .avi file I made in Ubuntu to .wmv using WinFF.

Tuesday, 22 March 2011

Change primary display in Ubuntu 10.10

My desktop at my office doesn't use NVidia graphics card, but uses ATI Radeon. So I don't have the monitor setting application from NVidia I usually use for my laptop. So I searched a bit, and found a way to do it through command line.

The command to use is xrandr. It is the command line interface to the RandR X extension which is used to configure which display ports are enabled, and to configure display modes and properties such as orientation, reflection and DPI.

Usage:
# To query what screens are connected, type the following:
$ xrandr -q
# Using the name of the output from the query, you can set 
# a display output as the primary display:
$ xrandr --output CRT2 --primary
To make this run at the startup, go to System=>Preferences=>Startup Applications
Click Add
Name: XRANDR
Command: xrandr --output CRT2 --primary
Source: http://www.thinkwiki.org/wiki/Xorg_RandR_1.2

Monday, 21 March 2011

Ruby: block

Blocks can be closures
In computer science, a closure is a first-class function with free variables that are bound in the lexical environment. Blocks are closures, which means variables in the surrounding scope that are referenced in a block remain accessible for the life of that block and the life of and Proc object created from that block.

Example:
def n_times(thing)
  lambda {|n| thing * n}
end

p1 = n_times(23)
p1.call(3) # => 69
p1.call(4) # => 92

Compare with Python closures:
def generate_power_func(n):
  def nth_power(x): 
    return x**n
  return nth_power
end

raised_to_4 = generate_power_func(4)
raised_to_4(2)
Blocks can be objects
Block can be converted to an object of class Proc. There are several ways where blocks are converted to objects.
  • If the last parameter in a method definition is prefixed with an ampersand (such as &action), Ruby looks for a code block whenever that method is called. 
  • Use lambda or its alternative -> form. For example:
    bo = lambda { |param| puts "You called me with #{param}" }
    bo.call 99
    bo.call "cat"
    # produces:
    # You called me with 99
    # You called me with cat
    
    lam = ->(p1, p2) { p1 + p2 }
    lam.call(4, 3) # => 7
    Compare this with the "bound function operator" in CoffeeScript:
    callback = (message) => @voicement.push message
    
  • Use Proc.new

  • The call method on a proc object invokes the code in the original block.

The Symbol.to_proc trick
Ruby implements the to_proc for objects of class symbol.
names = %w{ant bee cat}
result = names.map {|name| name.upcase}
result = names.map {&:upcase}
The last line means: apply the upcase method to each element of names. This works by relying on Ruby's type coercion. When you say names.map(&xxx), you're telling Ruby to pass the Proc object in xxx to the map method as a block. If xxx isn't already a Proc object, Ruby tries to coerce it into one by sending it a to_proc message. If it was written Ruby, it would look something like this:
def to_proc
  proc { |obj, *args| obj.send(self, *args) } # same as lambda
end
It's an incredibly elegant use of coercion and of closures. However, the use of dynamic method invocations mean that the version of code that uses &:upcase is about half as fast as the more explicitly coded block. This doesn't matter so much unless in the performance-critical section of your code.

Sunday, 20 March 2011

Depth of field

Hyperfocal distance (超焦距)
The hyperfocal distance is the nearest focus distance at which the DOF extends to infinity; focusing the camera at the hyperfocal distance results in the largest possible depth of field for a given f-number.  Let f be the lens focal lengthN be the lens f-number, and c be the circle of confusion for a given image format. The hyperfocal distance H is given by
H \approx \frac {f^2} {N c} \,.

Formula for DOF:
\mathrm {DOF} \approx \frac {2 N c f^2 s^2} {f^4 - N^2 c^2 s^2} \,.
This means:
  • DOF increases as f-stop increases or aperture decreases
  • DOF increases as subject distance (distance at which the camera is focused) increases
  • DOF increases as focal length decreases. 

Monday, 14 March 2011

JNI header file generation using Eclipse


Here is an example of using the External Tools Configuration in Eclipse to generate the JNI header file under WindowXP.

1) Choose External Tools Configuration in the tool bar:


2) Under the Main tab of a new configuration, setup the following parameters:
Location: [location of javah.exe (e.g. C:\Program Files\Java\jdk1.6.0_14\bin\javah.exe)]
Working Directory: [project directory (e.g. ${workspace_loc:/camera})]
Arguments:
-jni
-classpath .;[directory of the .class file (e.g. ${workspace_loc:/camera}/bin)]
-o [output file name (e.g. ${workspace_loc:/camera}/pointgrey_trigger/pointgrey_trigger/firefly_driver_jni.h)] [java file with the native methods declaration (e.g. edu.mit.yingyin.camera.WebcamDriverFirefly)]

Note that in *nix OS, the classpaths are concatenated using ":".

Friday, 11 March 2011

Making jar file using ant

Today I tested with making a jar file using ant according to a tutorial. Below are the simple build.xml I used and it works.


  
    
  
  
    
  


But I wasn't sure what "**" means in the includes file pattern. Turns out that this is a special feature in the ant syntax which makes it possible to match multiple directory levels. This can be used to match a complete directory tree, or a file anywhere in the directory tree. To do this, ** must be used as the name of a directory. When ** is used as the name of a directory in the pattern, it matches zero or more directories. For example: /test/** matches all files/directories under /test/, such as /test/x.java, or /test/foo/bar/xyz.html, but not /xyz.xml. Details can be found here.

Thursday, 10 March 2011

RESTful Web Services

How the HTTP methods are typically used to implement a web service:
Resource GET PUT POST DELETE
Collection URI List the URIs and perhaps other details of the collection's members. Replace the entire collection with another collection. Create a new entry in the collection. The new entry's URL is assigned automatically and is usually returned by the operation. Delete the entire collection.
Element URI Retrieve a representation of the addressed member of the collection, expressed in an appropriate Internet media type. Replace the addressed member of the collection, or if it doesn't exist, create it. Treat the addressed member as a collection in its own right and create a new entry in it. Delete the addressed member of the collection.


Difference between GET and POST as form submission methods
  • GET: With the HTTP "GET" method, the form data set is appended to the URI specified by the action attribute (with a question-mark ("?") as separator) and this new URI is sent to the processing agent.
  • POST: With the HTTP "POST" method, the form data set is included in the body of the form and sent to the processing agent.
The "GET" method should be used when the form is idempotent (i.e. causes no side-effects). Many database searches have no visible side-effects and make ideal applications for the "GET" method. Note. The "GET" method restricts form data set values to ASCII characters. Only the "POST" method is specified to cover the entire character set.

 Sources: http://en.wikipedia.org/wiki/Representational_State_Transfer#RESTful_web_services
http://www.w3.org/TR/html401/interact/forms.html#h-17.13.1

Monday, 7 March 2011

On generative and discriminative models

In a supervised learning problem, we want to find the function f: X -> Y, or P(Y|X). Discriminative models directly estimate P(Y|X). It is given the name because given X, we can directly discriminate (or determine) the value of the target Y. Generative models, on the other hand, estimate the joint probability P(Y, X) by finding P(X|Y) and P(Y). It is called generative because given the parameters P(X|Y) and P(Y), we can generate observable samples from the model.

Discriminative models include: logistic regression, conditional random fields, support vector machine
Generative models include: HMM, naive Bayes, Gaussian mixture models.

For solving a classification problem, a discriminative classifier is almost always preferred because discriminative models do not need to model the distribution of the observed variables, and they can generally express more complex relationships between the observed and target variables. However, Ng et al. also demonstrated in their experiments that generative methods may also converge more quickly to its (higher) asymptotic error as number of training examples increases. The generative model may also approach its asymptotic error with a number of training examples that is only logarithmic, rather than linear, in the number of parameters. This means that with smaller number of training examples, generative models may do better.

Sunday, 6 March 2011

Libraries needed for RoR development

For a RoR project that has a Gemfile, you can install all the required gems using the bundle command. You need to install bundler first. You may also install some other apps/libraries by using the following commands:
sudo apt-get install build-essential ruby1.8-dev
sudo apt-get install mysql-server mysql-client libmysqlclient-dev
sudo apt-get install sqlite3 libsqlite3-dev
sudo gem update --system 
sudo gem install bundler

Saturday, 5 March 2011

Clutter

We made Clutter, a Chrome extension that allows you to view multiple websites in the same tab. You can find it in Google's webstore:  http://bit.ly/eBIPZW

We attended the Chrome hackathon on February 19 at HubSpot's office in Cambridge. Jan Kleinert from Google gave us a tutorial on Chrome extension and then we began the hacking.

We decided what extension to make before the hackathon. Victor came up with the idea and it was inspired by the small hack he did during the IAP. During our Battlecode hacking, he made a split-pane display to show three websites (Pandora, google doc, and IRC chat) in the same tab as a dashboard and projected it. This is especially useful for the Chrome notebook because all it has is a browser window, and you cannot have multiple windows.

The one he made was a static layout, what we added, in addition to making it a Chrome extension, is allowing adding and removing panes at whatever position you want. We won the hackathon in the end and Jan wrote a blog post about this event as well.

Friday, 4 March 2011

Command to remove all .svn folders

find ./ -name ".svn" | xargs rm -Rf
Explanations:
xargs is used to build and execute command lines from standard input. It breaks list of arguments into sublists small enough to be acceptable.

Monday, 28 February 2011

User Study

I'm reading a CHI paper recently and noticed some techniques and terminologies in it that may be useful for my future user studies.

Counterbalancing
Definition: a within-subjects design involves changing the order in which treatment conditions are administered from one participant to anther so that the treatment conditions are matched with respect to time. The goal is to use very possible order of treatments with an equal number of individuals participating in each sequence. The purpose of counterbalancing is to eliminate the potential for confounding by disrupting any systematic relationship between the order of treatments and time-related factors [1].

Sources:
1. Gravetter. F., and Forzano L.. Research Methods for the Behavioral Science. 259.

Sunday, 27 February 2011

祝爸爸生日快乐!

今天(苏州是昨天)是爸爸60岁大寿,我做了可爱的兔子,马和猪(我们一家三口,muhaha)还有寿桃为爸爸祝寿。马比较难做,只能发挥想像了。用牙签做的4条腿是Victor的主意,因为马的腿比兔子和猪要长的多,所以可以突出这点来区分他们。还是比较成功的,站得也挺稳。马的头上还有鬃毛,是木耳。

这是做生日快乐字样的模板,这比做latte art简单多了,不需要手上的技巧,但是也挺好看的。:)

爸爸妈妈自己也小小庆祝了一下,天梭的表是我送给爸爸的生日礼物,去年十一月回去的时候带回去的。


Sunday, 20 February 2011

CSS Layout: Positioning

Yesterday, during the Google Chrome Hackathon, I was trying to replace the text on a button with an image, for example, replacing "Go" in the button below with an arrow image.


I can certainly add a background image for the button, but the text will still be seen above the background. Due to the lack of time, I just deleted the text in the html file. However, I feel that replacing the text with an image is really a styling choice rather than semantic.

Today, I started to read the book "Pro CSS and HTML Design Patterns" to improve my css skills. It actually mentions about the Text Replacement design pattern in the first chapter. It requires the use of css layout positioning to achieve the effect.

First, a recap on the positioning models:
  • Position an element by setting position to something other than static.
  • Use left, right, top and bottom to change the default position.
  • You can use position: static to "unposition" an element.
position 
In flow 
Positioning
static
yes
according to the flow
relative 
ghost
relative to the flow position 
absolute 
no
offset from its nearest positioned ancestor     
fixed
no
screen coordinate space

Text Replacement

Replace "Go" with this image:

Result:


Method: (Taken from p209 of the book.)
HTML
 TEXT 
CSS
#UNIQUE-ID { 
  position:relative; 
  padding:0; 
  overflow:hidden;
  width:IMAGE_WIDTH;
  height:IMAGE_HEIGHT; 
}
#UNIQUE-ID span { 
  position:absolute; 
  left:0; 
  top:0; 
  margin:0;
  width:IMAGE_WIDTH;
  height:IMAGE_HEIGHT;
  background-image:url("FILE.EXT");
  background-repeat:no-repeat; 
}

Initially, when I was testing with this, I found that the Chrome browser includes the border width in the height and width of the content size. By inspecting the element, I found that box-sizing is set to border-box. By setting it back to content-box, it behaves normally.