Sunday, July 27, 2008

做個決定

人越大,反而對好多嘢猶疑左。

上網 search "decision making",有成千上萬個 methodology。有叫你畫圖分析去算盡天機的,有鼓吹憑本能「眨下眼」就做決定嘅,又有啲叫你要深思熟濾嘅… 點都好,做左「十幾廿年」人,理論上應該有番咁上下閱歷,做決定時應該越嚟越成熟兼快手先啱。

但係點解好似係現實世界係剛剛相反?身邊有朋友「一腳踏兩船」,唔知要同「二奶」遠走高飛好,定番轉頭去修保已經千瘡百孔嘅婚姻好。結果拖下拖下,瞞下瞞下,一年又一年咁過。又有朋友成日諗,究竟應該留係間穩定但係悶到發瘟公司等退休好,定係出去轉工搏一搏搵真銀好…話唔定做十年八年之後就可以唔洗撈喎。諗下諗下,不如等出左 bonus 先算喇~ 結果等下等下又過左幾年,年年都係「等出左 bonus 先」。

係人大左,遇到啲問題越嚟越複雜吖,定係經驗越多,越要多啲時間反複去諗?其實,可能只係大家都怕要承擔後果吧。

係人都有試過做錯決定…有時睇番轉頭,會諗 "what if…", 又會諗「如果當初…」等等。後悔得多,就會發現面對新問題時,做決定會越嚟越猶疑。因為,試果做錯的後果,怕怕了。

記得有次同朋友吹水,佢失驚無神爆左句:「x,有咩好後悔…你自己揀嘅!」

就咁聽落去好似冇咩「玄機」,兼有啲冷血。但諗深一層…又係喎。有時啲嘢,真係要「打落門牙和血吞」的。有時左諗又諗,問下朋友意見。啱聽嘅,只係叫就有啲心理安慰,有啲支持咁。唔啱聽嘅,反而攪到自己仲唔知點好。

其實到頭來如果發現做錯左,要承擔後果嘅,又咪係得自己。

人思考,好多時只係因為自己「想」去咁諗。因為想快樂,所以諗好唔好去搵「二奶」。因為想發達,所以諗轉工。咁諗法,齋諗一世都唔會有結果 — 直到你真係去試下先知…

不過…現實真係咁?一個人冇幾多個「十幾廿年」…錯左唔係下下都可以番轉頭…死,又有啲猶疑…

Saturday, July 26, 2008

十字架

十字架

歌手:謝安琪
作曲:周博賢
填詞:周博賢

很久的當年 媽媽天天忠告
好心交給人 總可得到好報
過去按這教導埋頭做
可惜隨年長一步 傷口隨年多一度

伸出手攙扶 遭鬆開手警告
交出心戀愛 反得傷心的控訴
厭棄我過份熱情流露
或是仁慈得恐怖 燙手我已怕碰到

彷彿背上十字架捨我救贖未算好
愈奉獻得到結局愈殘酷
教我為免傷勢再會變更槽 圍牆變更高
圍住要自己的去路 防護罩終變成墳墓
將根本的我葬下去獨自老

伸出手攙扶 遭鬆開手警告
交出心戀愛 反得傷心的控訴
厭棄我過份熱情流露
或是仁慈得恐怖 燙手我已怕碰到

彷彿背上十字架捨我救贖未算好
愈奉獻得到結局愈殘酷
教我為免傷勢再會變更槽 圍牆變更高
圍住要自己的去路 防護罩終變成墳墓
將真的我埋葬下去 哀悼裡獨個漸漸老

多想光陰退後到舊時 童年重度
多斬釘截鐵共處 態度
我對你好所以你會對我好
心裡沒墳墓 無奈這幸福的國度
已飽經災劫無寸草
今天只得我野地裡在獨舞
要怎麼的上路 祈望一天我能知道 

Monday, July 21, 2008

Bypass web proxy with SSH tunneling

For the company that I work in, the network is protected by a firewall and web proxy. We could access the web via the proxy, except those sites that are considered to be "unproductive". Most discussion forums, which are valuable when searching for technical issues, are unfortunately blocked.

Here is how setup a SSH tunnel to bypass the firewall. Basically, it requires to create a SSH connection to a server (e.g. your home pc) outside the company firewall via the company proxy. At the same time, configure the SSH connection to do a port forwarding from your workstation at work to a free proxy server on the Internet (better yet, point it to a proxy server at home).

First, make sure that the SSH daemon on the server has enabled the TCP forwarding option. For OpenSSH, it is the AllowTcpForwarding option.

On the workstation at work, use Putty to connect to the SSH server.




At the Proxy option, set it to use the company proxy to pass through the firewall.



Then the tricky part. Setup a port forwarding rule to forward a port on the workstation to another machine and port on the Internet. Here, this example is forwarding the port 8080 on the workstation to the port 8888 on host proxy.pcathome.com



Click on the Add button to add the rule.



Click Open to connect to the server. Login as usual.

Then change the proxy setting of the browser on the workstation to point it to localhost and port 8080. From now on, web browsing will go through the proxy (for the above example, the proxy.mypcathome.com) outside the company and all restrictions are gone!

Notes:

  1. Since the connection is via a HTTP proxy, connection will timeout when there is not data going through. Either execute a run-forever command on the terminal (e.g. top) or let Putty sends null packets periodically (under the Connection option)

辦公室躲懶術(一)

係辦公室工作咁多年,對於「躲懶」呢門學問點都有d心得。特意係到交流一下,歡迎指點~

不過,話說在前:「躲懶」並不等於唔做野!一日十個八個鐘頭係 office,總唔可能 100% 工作吧?有時點都要上網 check 下 email,去 forum 搵下料,msn 同朋友吹下水…簡單d講:處理下私人事務o者,唔係咁都唔得下話!

言歸正傳,先講下電腦桌面o既「佈陣」。常見初心者會咁樣做:




即係:將一個工作用o既 application 放到最大,然後再開一個小小 window 係到上網或者做自己野。原意係,當發現有咩風吹草動時,可以好快咁用 alt-tab 轉番去後面個 application 到… -_-

但係…大佬~!係「老年」咁遠睇見呢個陣,就算睇唔到你做緊咩,都知你鬼鬼祟祟有d野喇~!試問,當你真係做緊野o既時候,會唔會將背後個 window 放到鬼咁大,反而前面做緊野個 window 縮到睇得個兩行字先?!

計我話,應該要以打亂敵人視線為重點…例如:



用於「躲懶」o既 window 照樣縮小,但係同一時間就開多四五個「疑似」工作 window 亂放係到。咁就算俾人遠遠「目及」到自己個 mon,都冇咁礙眼先啦!只要記得放其中一個「疑似」工作 window 同「躲懶」 window 重疊,咁咪一樣可以用 alt-tab 去救命。 道行再高 d o既,可以 set 到條 active 同 non-active o既 title bar 一樣顏色…咁人地「沖沖一瞥」時都唔知你用緊邊個 window 喇(不過可能到真係做野時攪到自己都唔知用緊邊個… @_@)

Wednesday, July 2, 2008

Writing assembly in Java

Not really assembly language... but byte code instead.

I read an article on dynamic code generation with C# a few days ago and was wondering if similar thing can be done with Java. After some Google searches, the (expected) answer is yes!

The benefit of dynamic code generation is performance, esp. when the logic involved has to be executed many times. This article has a good example on using dynamic programming on a stack-based calculator.

For example, to a stack-based calculator, the expression "2 $0 * $1 /" means:

  • push the value 2 to the stack
  • push parameter 0 to the stack
  • execute the multiple calculation by popping two values from the stack and store the result back to the stack
  • push parameter 1 to the stack
  • execute the divide calculation by popping two values from the stack and store the result back to the stack

That is: (2 * $0) / $1.

Using the plain old Java, it is easy to implement the logic. All we need to do is tokenize the expression and push/pop values from the Stack class for calculation.

......
                char opchar = tok.charAt(0);
                int  op = "+-*/".indexOf(opchar);

                if (op == -1)
                {
                    // not an operator
                    stk.push(Double.valueOf(tok));
                }
                else
                {
                    double arg2 = (stk.pop()).doubleValue();
                    double arg1 = (stk.pop()).doubleValue();

                    switch(op)
                    {
                        case 0:
                            stk.push(arg1 + arg2);
                            break;

                        case 1:
                            stk.push(arg1 - arg2);
                            break;

                        case 2:
                            stk.push(arg1 * arg2);
                            break;

                        case 3:
                            stk.push(arg1 / arg2);
                            break;

                        default:
                            throw new RuntimeException(
                                "unknown parameter(" + i + "): " + tok);
                    }

                }
......


When tested for performance, this implementation can compute the expression "2 $0 * $1 / 1 + $2 -" a million times in less than 3 seconds. Not bad. But it could be improved.

Using dynamic code generation, we can actually create a method (or a Java class) on-the-fly for each expression. This eliminates all the unnecessary testing and branching logic in the loop. For comparison, the above mentioned test can finish in less than 20ms when using dynamic code generation. (yes... finishing the one million calculation in less than twenty millisecond!!).

Here are the details on the dynamic code generation. First, go get the Byte Code Engineering Library (BCEL). It simplifies the way to write byte code logic.

Create a new ClassGen class as the template for the new Calculator
        ClassGen gen = new ClassGen(
            dynClassName,  // fully qualified class name
            "java.lang.Object",  // fully qualified superclass name
            "",  // source file name
            Constants.ACC_PUBLIC | Constants.ACC_SUPER,  // access qualifiers
            new String[]
                {"net.clarenceho.calc.Calculator"}  // implemented interfaces
            );


Then, define methods for the class. We need to define a constant pool and an instruction list of each method. The logic is similar to writing assembly language. We will be pushing/popping values from the operand stack and call arithmetic/logic operations to do the work. e.g.

......
                int op = "+-*/".indexOf(tok.charAt(0));

                switch(op)
                {
                    case -1:
                        // not an operator
                        double val = Double.parseDouble(tok);
                        il.append(new PUSH(cp, val));
                        break;

                    case 0:
                        il.append(InstructionConstants.DADD);
                        break;

                    case 1:
                        il.append(InstructionConstants.DSUB);
                        break;

                    case 2:
                        il.append(InstructionConstants.DMUL);
                        break;

                    case 3:
                        il.append(InstructionConstants.DDIV);
                        break;

                    default:
                        throw new RuntimeException(
                            "unknown parameter: " + tok);
                }
......

il is the instruction list for the method. the DADD, DSUB etc are the arithmetic logic for double values. Refer to the BCEL apidoc for details.

Following the above mentioned article, I also implemented the logic for fun. The only different is that my implementation takes doubles instead of integers. Full source can be found below.


Interface for the Calculator:
package net.clarenceho.calc;

public interface Calculator
{
    double calc(double[] param);
}


Implementation using traditional Java logic:
package net.clarenceho.calc;

import java.util.StringTokenizer;
import java.util.Stack;
import java.util.ArrayList;

public class SimpleCalculator implements Calculator
{
    private ArrayList<String> lst = new ArrayList<String>();

    public SimpleCalculator(String exp)
    {
        StringTokenizer st;
        st = new StringTokenizer(exp, " ");
        while (st.hasMoreTokens())
        {
            lst.add(st.nextToken());
        }
    }

    public double calc(double param[])
    {
        Stack<Double> stk = new Stack<Double>();

        for (int i=0; i < lst.size(); i++)
        {
            String tok = lst.get(i);
            if (tok.startsWith("$"))
            {
                // a parameter
                int pos = Integer.parseInt(tok.substring(1));
                stk.push(param[pos]);
            }
            else
            {
                char opchar = tok.charAt(0);
                int  op = "+-*/".indexOf(opchar);

                if (op == -1)
                {
                    // not an operator
                    stk.push(Double.valueOf(tok));
                }
                else
                {
                    double arg2 = (stk.pop()).doubleValue();
                    double arg1 = (stk.pop()).doubleValue();

                    switch(op)
                    {
                        case 0:
                            stk.push(arg1 + arg2);
                            break;

                        case 1:
                            stk.push(arg1 - arg2);
                            break;

                        case 2:
                            stk.push(arg1 * arg2);
                            break;

                        case 3:
                            stk.push(arg1 / arg2);
                            break;

                        default:
                            throw new RuntimeException(
                                "unknown parameter(" + i + "): " + tok);
                    }

                }
            }
        }

        return (stk.pop()).doubleValue();
    }
}


Implementation using dynamic code generation:
package net.clarenceho.calc;

import java.lang.Thread;
import java.lang.Class;
import java.lang.ClassLoader;
import java.util.StringTokenizer;
import java.util.Stack;

import org.apache.bcel.Constants;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.InstructionConstants;
import org.apache.bcel.generic.PUSH;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.Type;

public class DynamicCalculator extends ClassLoader implements Calculator
{
    Calculator dynCalc = null;

    public DynamicCalculator(String exp)
    {
        String dynClassName = "net.clarenceho.calc.DynamicCalculator_" +
            Thread.currentThread().getId() + "_" +
            System.currentTimeMillis();

        ClassGen gen = new ClassGen(
            dynClassName,  // fully qualified class name
            "java.lang.Object",  // fully qualified superclass name
            "",  // source file name
            Constants.ACC_PUBLIC | Constants.ACC_SUPER,  // access qualifiers
            new String[]
                {"net.clarenceho.calc.Calculator"}  // implemented interfaces
            );

        // need to manually add an empty constructor
        gen.addEmptyConstructor(Constants.ACC_PUBLIC);
        // add member function to the class;
        this.addMethod(gen, exp);

        // create a new instance of the dynamic class
        byte[] data = gen.getJavaClass().getBytes();
        Class theClass = this.defineClass(dynClassName, data, 0, data.length);
        try
        {
            this.dynCalc = (Calculator)theClass.newInstance();
        }
        catch (Exception e)
        {
            throw new RuntimeException(e.getMessage());
        }
    }


    private void addMethod(ClassGen cgen, String exp)
    {
        // each method has a constant pool and an instruction list
        ConstantPoolGen cp = cgen.getConstantPool();
        InstructionList il = new InstructionList();

        StringTokenizer st = new StringTokenizer(exp, " ");

        while (st.hasMoreTokens())
        {
            String tok = st.nextToken();

            if (tok.startsWith("$"))
            {
                // a parameter
                int pos = Integer.parseInt(tok.substring(1));

                // load and store the array reference to the operand stack
                il.append(InstructionConstants.ALOAD_1);
                // store the array index to the operand stack
                il.append(new PUSH(cp, pos));
                // load and store array item
                il.append(InstructionConstants.DALOAD);
            }
            else
            {
                int op = "+-*/".indexOf(tok.charAt(0));

                switch(op)
                {
                    case -1:
                        // not an operator
                        double val = Double.parseDouble(tok);
                        il.append(new PUSH(cp, val));
                        break;

                    case 0:
                        il.append(InstructionConstants.DADD);
                        break;

                    case 1:
                        il.append(InstructionConstants.DSUB);
                        break;

                    case 2:
                        il.append(InstructionConstants.DMUL);
                        break;

                    case 3:
                        il.append(InstructionConstants.DDIV);
                        break;

                    default:
                        throw new RuntimeException(
                            "unknown parameter: " + tok);
                }
            }
        }

        // return a double
        il.append(InstructionConstants.DRETURN);

        MethodGen mgen = new MethodGen(
            Constants.ACC_PUBLIC,  // access qualifiers
            Type.DOUBLE,  // return type
            new Type[] {Type.getType("[D")},  // argument types
            new String[] {"param"},  // argument names
            "calc",  // name of method
            cgen.getClassName(),  // class name containing this method
            il,  // instruction list associated with this method
            cp  // constant pool
            );

        // compute the max stack size
        mgen.setMaxStack();
        // compute the max number of local variables
        mgen.setMaxLocals();

        cgen.addMethod(mgen.getMethod());
    }

    public double calc(double[] param)
    {
        if (this.dynCalc != null)
        {
            return this.dynCalc.calc(param);
        }
        else
        {
            throw new RuntimeException(
                "problem creating dynamic calculator");
        }
    }
}

Sunday, June 29, 2008

No One - Alicia Keys



I just want you close
Where you can stay forever
You can be sure
That it will only get better

You and me together
Through the days and nights
I don't worry 'cause
Everything's going to be alright
People keep talking they can say what they like
But all i know is everything's going to be alright

No one, no one, no one
Can get in the way of what I'm feeling
No one, no one, no one
Can get in the way of what I feel for you, you, you
Can get in the way of what I feel for you

When the rain is pouring down
And my heart is hurting
You will always be around
This I know for certain

You and me together
Through the days and nights
I don't worry 'cause
Everything's going to be alright
People keep talking they can say what they like
But all i know is everything's going to be alright

No one, no one, no one
Can get in the way of what I'm feeling
No one, no one, no one
Can get in the way of what I feel for you, you, you
Can get in the way of what I feel

I know some people search the world
To find something like what we have
I know people will try try to divide something so real
So till the end of time I'm telling you there ain't no one

No one, no one, no one
Can get in the way of what I'm feeling
No one, no one, no one
Can get in the way of what I feel for you, you, you
Can get in the way of what I feel for you

oh oh oh oh oh oh oh oh oh oh oh oh oh oh oh oh

Sunday, June 22, 2008

反樸歸真?




本來冇諗住又去呢個位到影相,事關呢個位已經影過無數咁多次,有d悶。不過今日實在太好天,兼且又順路,所以帶部傻瓜機去影下。

八、十年前冇咩人會特登去呢個位影,最多只係遊客經過用傻瓜機影下留念。今日上到去,見到幾十人係到等日落影相,仲要九成人都係用DSLR…真係勁!反觀我自己用傻瓜機但係配鬼死咁大枝o既 Gitzo 腳,有d攪笑~




太陽能電筒?



係太陽能燈先真。日間吸收太陽光為電池差電,夜間就著燈發光。

太陽能燈本身冇咩特別,但係佢又好有創意咁張盞燈放係一個半透明 jar 入面…出黎效果就好似捉左d瑩火蟲入去咁…好正!

之前係某網上商店見過有得賣,不過好貴(幾十蚊成本,但係賣成幾百蚊!)想 DIY,不過又懶。早兩日經某網友提起,今日經過某店時終於忍唔住要敗家… orz

Monday, June 2, 2008

Don't shoot! Let them burn!!

為早幾日的「是日金句」解下畫。

事源忽然又諗起 Saving Private Ryan 中,一句我覺得幾震撼的對白…

套戲開場後第一場戰爭場面,就係盟軍登陸諾曼第一役。一幕幕子彈及血肉橫飛的場面。開始時由於德軍有地利,所以盟軍方面傷亡慘重。

Tom Hanks 一隊人幾經辛苦,終於打到高地,攻到德軍的 bunker。為左避免強攻入 bunker 而令到自己一方有傷亡,佢地用當時常用的一招:炸開 bunker 的入口後,係外面用噴火槍向內噴火,將入面o既德軍連人同 bunker 一齊燒左佢。

咁當入面d德軍個個著曬火,係另一面跳出 bunker 碌落山坡時,外面有個盟軍回頭大聲向同袍叫:

   Don't shoot! Let them burn!!

意思即係,唔好開槍殺左呢d德軍,如果唔係就便宜左佢地。由得佢地活生生燒死…

睇完套戲之後,句 "let them burn"久唔久就會係我腦袋中浮出來。

原來憎一樣野時,你係唔會由佢走得咁爽的說。 @_@

Sunday, June 1, 2008

平到冇朋友

之前試用 QuickTime 將高清片轉俾 PS3 用,發覺部舊 notebook 得o個 1G ram 真唔多夠。於是趁今日出城,順手買兩條 1G ram 換左用開o個兩條 512M。 唔洗四舊水攪掂,依家d ram 真係平到冇朋友。不過問題係:就算 upgrade 左 ram,呢部舊 notebook 仲可以玩幾耐?

PS. 現有 2x 512M DDR2-667 SODIMM 多左,有冇邊個親朋戚友有用?