近期在新聞報導常常聽到一些很大的數字,如多少百億興建高鐵,金融海嘯有關的天文數字等,令我覺得其實有多少人知道其真正「份量」?
有次在街上,聽到一母親教她的兒子數十進制:個、十、百、千、萬、十萬、百萬、千萬、億萬...我覺得愕然,為何會由千萬特跳到億萬呢?難怪現在的小孩不識理財了,因為連數數字也不懂!
我小學時學的,中國單位以萬為分位,西方則以千為分位,所以:
千萬以後是:萬萬(即億),十億,百億、千億、萬億、十萬億,百萬億、千萬億...
講起數數字,順便講一講「兆」。
中學時學十進制,知道兆是一百萬,所以電台FM頻道的兆赫是百萬Hertz。
但是台灣仍治用兆是萬億(即1012)(見維基百科 )
新聞報導員沒有加上附註,容易做成混亂!
2009-12-20
Gimp Polaroid Filter
To make my photo posting on my blog more interesting, I have usually resorted to use Gimp's "Round Corner" Script-Fu. I like this script because it drops a shadow so that my photos seems pop up from the background.
Later on, I encountered several blogs on internet like:
Gimp Making Border (in Chinese) (link)
Turn a digital photo into Polaroid with Gimp (link)
The idea is to make a digital photo resemble a photo-print and make it lay on a surface with some irregular shadows.
I very like this idea but find the steps clumsy if I have repeatedly do photo postings on my blog.
So... I start to write my first Gimp script!
Most of the Gimp macros are written in Script-Fu. It is said that it is a language called Scheme (however, I have learned Lisp before and I still cannot differentiate Scheme from Lisp because of their similarity!)
I hate Lisp because the proliferation of brackets and I have difficulties to make the opening and closing brackets match.
Anyway, after a one-day tutorial on learning the Script-Fu, my first Gimp script is born. It works as follows:
Installation steps:
Execution steps:
- open a photo, like

- run the script, which will solicit the following parameters

- the result is as follows:
Later on, I encountered several blogs on internet like:
Gimp Making Border (in Chinese) (link)
Turn a digital photo into Polaroid with Gimp (link)
The idea is to make a digital photo resemble a photo-print and make it lay on a surface with some irregular shadows.
I very like this idea but find the steps clumsy if I have repeatedly do photo postings on my blog.
So... I start to write my first Gimp script!
Most of the Gimp macros are written in Script-Fu. It is said that it is a language called Scheme (however, I have learned Lisp before and I still cannot differentiate Scheme from Lisp because of their similarity!)
I hate Lisp because the proliferation of brackets and I have difficulties to make the opening and closing brackets match.
Anyway, after a one-day tutorial on learning the Script-Fu, my first Gimp script is born. It works as follows:
- it adds a border to similar the print paper
- it creates a shadow and then use the perspective effect to make the shadow irregular
- it finally adds a background to match my blog background
Installation steps:
- download the script (link)
- put it to the script directory (in my Windows environment, it is C:\Program Files\GIMP-2.0\share\gimp\2.0\scripts)
Execution steps:
- open a photo, like

- run the script, which will solicit the following parameters

- the result is as follows:
at
下午9:01
2009-11-06
Using LINQ to retrieve XML data
Although it is like "to use a cannon to kill a mosquito", I find using LINQ to read XML has a clear advantage - to read the node like an associative array (like PHP).
I use the following VB example to illustrate:

I deliberately use a string to hold the XML content in this example, although the native constructor can be as simple as
Dim xmlTree1 As XElement =
<Root>
<Child1>1</Child1>
<Child2>2</Child2>
<Child3>3</Child3>
</Root>
I use the following VB example to illustrate:
Public Class Form1 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim xml_str As String xml_str = "<ROOT><FIELD1>VALUE1</FIELD1><FIELD2>VALUE2</FIELD2><FIELD3>VALUE3</FIELD3></ROOT>" Dim xmltree As System.Xml.Linq.XElement xmltree = XElement.Load(New System.IO.StringReader(xml_str)) Label1.Text = xmltree.Element("FIELD2").Value End Sub End Class |

I deliberately use a string to hold the XML content in this example, although the native constructor can be as simple as
Dim xmlTree1 As XElement =
<Root>
<Child1>1</Child1>
<Child2>2</Child2>
<Child3>3</Child3>
</Root>
2009-11-03
Using VB 2008 Express as client to consume SugarCRM Web service
In additional to my previous example of using AXIS as web client, I now use VB.NET as another example to consume web service. Moreover, I will just the open source SugarCRM as web service provider.
SugarCRM
The wsdl link is as follows (the host name depends on your installation. I use localhost here)
http://127.0.0.1/sugarcrm/soap.php?wsdl
as shown in the following IE screen dump

VB
The set up is a little bit tricky, as the initial menu does not have any web service item. The steps are as follows:
(1) Project > Add Service Reference

(2) Click the "Advanced" button (Do not type the WDSL link yet)

(3) Click the "Add Web Reference" button

(4) Type the WSDL link and press "Go" button. The web service description will be displayed. Then choose a reference name you like (I use SugarCRM) and press "Add Reference"

(5) You will find VB has added the WS reference in the Solution Explorer

(6) Ironically, VB will now have the "Add Web Referebce" menu item available in the Project menu

7) Now you can start to write codes to consume the web service. Since my example just illustrate the principle, I have hard-coded many things. The logic is there is a Button1. If I click this button, it will call the login method of SugarCRM. The session id returned will be displayed as Label1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim soapservice As New SugarCRM.sugarsoap
Dim credential As New SugarCRM.user_auth
Dim opensession As New SugarCRM.set_entry_result
credential.user_name = "admin"
credential.password = getMd5Hash("password")
credential.version = "1.0"
opensession = soapservice.login(credential, "SugarCRM")
Label1.Text = opensession.id
End Sub
The convenience of using VB is its IntelliSense which can enumerate the available options.

I have declared three objects
soapservice - the client stub
credential - the first argument of the service, containing the user id, md5 of the password and the version.
openssion - the returned result of the service. One of the most important field is the session ID
The result is shown below
SugarCRM
The wsdl link is as follows (the host name depends on your installation. I use localhost here)
http://127.0.0.1/sugarcrm/soap.php?wsdl
as shown in the following IE screen dump

VB
The set up is a little bit tricky, as the initial menu does not have any web service item. The steps are as follows:
(1) Project > Add Service Reference

(2) Click the "Advanced" button (Do not type the WDSL link yet)

(3) Click the "Add Web Reference" button

(4) Type the WSDL link and press "Go" button. The web service description will be displayed. Then choose a reference name you like (I use SugarCRM) and press "Add Reference"

(5) You will find VB has added the WS reference in the Solution Explorer

(6) Ironically, VB will now have the "Add Web Referebce" menu item available in the Project menu

7) Now you can start to write codes to consume the web service. Since my example just illustrate the principle, I have hard-coded many things. The logic is there is a Button1. If I click this button, it will call the login method of SugarCRM. The session id returned will be displayed as Label1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim soapservice As New SugarCRM.sugarsoap
Dim credential As New SugarCRM.user_auth
Dim opensession As New SugarCRM.set_entry_result
credential.user_name = "admin"
credential.password = getMd5Hash("password")
credential.version = "1.0"
opensession = soapservice.login(credential, "SugarCRM")
Label1.Text = opensession.id
End Sub
The convenience of using VB is its IntelliSense which can enumerate the available options.

I have declared three objects
soapservice - the client stub
credential - the first argument of the service, containing the user id, md5 of the password and the version.
openssion - the returned result of the service. One of the most important field is the session ID
The result is shown below
at
下午6:23
2009-10-23
CTI (Computer Telephony Integration) for SugarCRM
Recently I come across SugarCRM. It has a Community Edition which I do not need to pay. Moreover, since it is open-source, I can realize some customization easily.
I have experience in CTI (Computer Telephony Integration). But what I can search around SugarCRM is its integration with Asterisk, which is also an open source telephony project.
Because I have already an Avaya installation base, I study whether I can do some quick start work easily.
What I need are two functions:
(1) Screen Pop
To pop up the SugarCRM screen based on the Calling Line Identity (CLI)
(2) Click to Dial
Turn the phone number in the SugarCRM screen to a link that is clickable and activate automatic phone dialling
For those readers which are familar with CTI, these are just very basic features. But it is achievable for SugarCRM, this is already a great time-saver for the CRM users.
I tackle the problem in the following ways:
(1) Screen Pop
Since SugarCRM is web-based, I can simply ask the browser to navigate to a specific link.
The first question is what the link is.
In SugarCRM, I make a search with a phone number. Then I get the following screen.

Great, I find the URL is
Therefore in .NET code, I use:
(2) Click to Dial
I find SugarCRM has Skype integration, in which it will convert a phone number to a clickable link. First you need to turn this feature on in the Administration screen, as follows:

After the feature activation, you will find that when you put a mouse pointer over a phone number, you can find it the associated link is :
callto://5551234/

In Windows, each URL protocol can be managed by the "Folder Option" in the Windows Explorer. (Someone suggested registry hack. But I prefer the conventional way.)

After pressing the "Advanced" button and then the "Edit" button, you can set your preferred program to handle this protocol. In my case, I have
written a program called "qcallto.exe". Windows will pass the link a program parameter to it.

Finally, a point of SugarCRM hack. As shown in the SugarCRM adminstration screen, it requires a phone number to conform to certain format (e.g. prefixed with a plus sign). I do not like this convention. Why cannot SugarCRM simply treat all the phone number clickable?
Thanks to the PHP open sources, I find that in "c:\Inetpub\wwwroot\sugarcrm\include\utils.php" (the actual directory depends on your installation), there is a php function will determine whether a phone number is clickable:
Original:
function skype_formatted($number){
if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
return false;
}
else {
return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' ||
substr($number, 0, 2) == '011';
}
}
I change it to
function skype_formatted($number){
if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
return false;
}
else {
return 1;
}
}
Some final words... Although my implemented solution is Avaya-based, it is easily portable to other platforms (even for a modem connected phone line) easily.
I have experience in CTI (Computer Telephony Integration). But what I can search around SugarCRM is its integration with Asterisk, which is also an open source telephony project.
Because I have already an Avaya installation base, I study whether I can do some quick start work easily.
What I need are two functions:
(1) Screen Pop
To pop up the SugarCRM screen based on the Calling Line Identity (CLI)
(2) Click to Dial
Turn the phone number in the SugarCRM screen to a link that is clickable and activate automatic phone dialling
For those readers which are familar with CTI, these are just very basic features. But it is achievable for SugarCRM, this is already a great time-saver for the CRM users.
I tackle the problem in the following ways:
(1) Screen Pop
Since SugarCRM is web-based, I can simply ask the browser to navigate to a specific link.
The first question is what the link is.
In SugarCRM, I make a search with a phone number. Then I get the following screen.

Great, I find the URL is
http://127.0.0.1/sugarcrm/index.php?module=Home&query_string=test&advanced=true&action=UnifiedSearch&search_form=false&query_string=5551888&search_mod_Contacts=true5551888 is the phone number I have typed.
Therefore in .NET code, I use:
url_str = "http://127.0.0.1/sugarcrm/index.php?action=UnifiedSearch&search_form=false&advanced=false&query_string=" _Here, SkpSock1.CLID is my CTI object to collect the CLID (Calling Line Identity) property.
& SkpSock1.CLID & "&search_mod_Contacts=true"
System.Diagnostics.Process.Start(url_str)
(2) Click to Dial
I find SugarCRM has Skype integration, in which it will convert a phone number to a clickable link. First you need to turn this feature on in the Administration screen, as follows:

After the feature activation, you will find that when you put a mouse pointer over a phone number, you can find it the associated link is :
callto://5551234/

In Windows, each URL protocol can be managed by the "Folder Option" in the Windows Explorer. (Someone suggested registry hack. But I prefer the conventional way.)

After pressing the "Advanced" button and then the "Edit" button, you can set your preferred program to handle this protocol. In my case, I have
written a program called "qcallto.exe". Windows will pass the link a program parameter to it.

Finally, a point of SugarCRM hack. As shown in the SugarCRM adminstration screen, it requires a phone number to conform to certain format (e.g. prefixed with a plus sign). I do not like this convention. Why cannot SugarCRM simply treat all the phone number clickable?
Thanks to the PHP open sources, I find that in "c:\Inetpub\wwwroot\sugarcrm\include\utils.php" (the actual directory depends on your installation), there is a php function will determine whether a phone number is clickable:
Original:
function skype_formatted($number){
if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
return false;
}
else {
return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' ||
substr($number, 0, 2) == '011';
}
}
I change it to
function skype_formatted($number){
if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
return false;
}
else {
return 1;
}
}
Some final words... Although my implemented solution is Avaya-based, it is easily portable to other platforms (even for a modem connected phone line) easily.
at
下午7:19
Labels:
Computer Telephony Integration,
CTI,
SugarCRM
2009-10-12
Why DC cannot shoot a picture with shallow depth of field
I carry an Optio S3 to make ad hoc photography.
According to the specification, the tiny camera has an aperture f2.6 - f4.8
However, even at an aperture f2.6, I can never shoot a picture with sufficient shallow depth of field (DOF), except in macro mode of course.
I start to ask why.
The most authoritative reference (but hard to understand) about Depth of Field is at Wiki (link http://en.wikipedia.org/wiki/Depth_of_field)
It gives complicated formula to show the relation of DOF vs. format size (though roughly speaking, DOF is inversely proportional to format size). Since my DC has a small CCD, the DOF is less shallow than the conventional SLR.
However, I try to associate the problem with APS-C or Four Thirds or micro Four Thirds.
In these cases, usually, we will use a crop factor to represent the effective focal length at full-frame (FF, at 35mm) format size . For instance, even you use a lens with 18mm on DSLR with crop factor 1.6, its effective angle of view is just same as 28.8mm at FF.
Please note that aperture is actually stated in F-number (the ratio of focal length to effective aperture diameter).
Then why not use similar the crop factor to calculate the effective DOF?
For instance, my Optio S3 has the focal length 5.8mm (equivalent to 35mm at FF). This means that the crop factor is about 6X.
Then even at aperture f2.6, the "equivalent" aperture at FF is already 6x2.6 = 15.6
This explains why I cannot shoot at shallow DOF even with the largest aperture (smallest F-number) because its FF-equivalent aperture at 15.6!
According to the specification, the tiny camera has an aperture f2.6 - f4.8
However, even at an aperture f2.6, I can never shoot a picture with sufficient shallow depth of field (DOF), except in macro mode of course.
I start to ask why.
The most authoritative reference (but hard to understand) about Depth of Field is at Wiki (link http://en.wikipedia.org/wiki/Depth_of_field)
It gives complicated formula to show the relation of DOF vs. format size (though roughly speaking, DOF is inversely proportional to format size). Since my DC has a small CCD, the DOF is less shallow than the conventional SLR.
However, I try to associate the problem with APS-C or Four Thirds or micro Four Thirds.
In these cases, usually, we will use a crop factor to represent the effective focal length at full-frame (FF, at 35mm) format size . For instance, even you use a lens with 18mm on DSLR with crop factor 1.6, its effective angle of view is just same as 28.8mm at FF.
Please note that aperture is actually stated in F-number (the ratio of focal length to effective aperture diameter).
Then why not use similar the crop factor to calculate the effective DOF?
For instance, my Optio S3 has the focal length 5.8mm (equivalent to 35mm at FF). This means that the crop factor is about 6X.
Then even at aperture f2.6, the "equivalent" aperture at FF is already 6x2.6 = 15.6
This explains why I cannot shoot at shallow DOF even with the largest aperture (smallest F-number) because its FF-equivalent aperture at 15.6!
at
下午5:56
2009-10-09
Using COM objects in VB.NET
I am an old-fashioned guy and right now even though I uses VB.NET for my new programming, I still need to resort to old COM objects sometimes.
I find there is not much references to facilitate the process (e.g. I do not like command line tools). If I have a VB6 project orginally, the Studio Express can import it automatically. But if I starts a new .NET project, I find the following procedures is the quickest:
(1) Add the COM reference in the "Tools" | "Choose Toolbox Items" menu, so that the object is selectable in the left Toolbox

(2) Choose the COM Components Tab. If your object has been registered before hand, it is listed. Otherwise, click the Browse button to include it in the list

(3) Then you will find the Componet will appear in the left Toolbox. You then can drag it into your form.

(4) You will find VB.NET will automatically add appropriate references in your Project Properties, as in the following screen dump. In my cases, VB.NET add two references: one is the Interop and one is the AxInterop

I find there is not much references to facilitate the process (e.g. I do not like command line tools). If I have a VB6 project orginally, the Studio Express can import it automatically. But if I starts a new .NET project, I find the following procedures is the quickest:
(1) Add the COM reference in the "Tools" | "Choose Toolbox Items" menu, so that the object is selectable in the left Toolbox

(2) Choose the COM Components Tab. If your object has been registered before hand, it is listed. Otherwise, click the Browse button to include it in the list

(3) Then you will find the Componet will appear in the left Toolbox. You then can drag it into your form.

(4) You will find VB.NET will automatically add appropriate references in your Project Properties, as in the following screen dump. In my cases, VB.NET add two references: one is the Interop and one is the AxInterop

at
上午10:17
2009-08-24
高清無用!
當人人都「講」高清時,我發看很多人其實都將Windows的display解像度set得比native低(可能使用者有老花?),見MSDN Blog Follow-up on High DPI resolution

從圖可見,只有55%的人用native resolution,可悲!

從圖可見,只有55%的人用native resolution,可悲!
at
下午12:54
2009-08-06
Quick Building a Web service client using Axis
After some studies, to my surprise, building a web service client using the Axis library (not the web service itself) is in fact very easy. I would like to summarize my experience in this blog.
- Download Axis from the Apache web site and expand the zip file (Remark: in fact the whole package includes the server code. To build a client, only the jar files are needed. But for simplicity and because of the limited extra hard disk space, I recommend to expand the whole package).
In my example, I have downloaded Axis version 1.1 and put it at /home/craft/whc/axis-1-1 - Download the WSDL file of the web service. In this case, I have chosen the free stock quote example at webservicex at http://www.webservicex.net/stockquote.asmx?wsdl and store it in /home/craft/whc/StockQuote.wsdl
- Use the WSDL2Java tool from Axis to crate the stub codes. Since we need to refer to the jar files in the Axis, I have built a script with classpath set appropriately
The resultant files will be created at /home/craft/whc/NET/webserviceX/www#!/bin/sh
java -classpath "/home/craft/whc/axis-1_1/lib/axis.jar:
/home/craft/whc/axis-1_1/lib/log4j-1.2.8.jar:
/home/craft/whc/axis-1_1/lib/commons-logging.jar:
/home/craft/whc/axis-1_1/lib/commons-discovery.jar:
/home/craft/whc/axis-1_1/lib/wsdl4j.jar:
/home/craft/whc/axis-1_1/lib/jaxrpc.jar:
/home/craft/whc/axis-1_1/lib/saaj.jar"
org.apache.axis.wsdl.WSDL2Java StockQuote.wsdl - Create the simple client code (StockClient.java) as follows (I have hard-coded MSFT (Microsoft) for the stock code)
import java.net.URL;
import org.apache.axis.client.Service;
import org.apache.axis.client.Call;
public class StockClient {
public static void main(String[] args) throws Exception {
NET.webserviceX.www.StockQuote service = new NET.webserviceX.www.StockQuoteLocator();
NET.webserviceX.www.StockQuoteSoap port = service.getStockQuoteSoap();
String result = port.getQuote("MSFT");
System.out.println("Result = "+result);
}
} - Compile the client code with a script as follows (Please note that I have deliberately omitted the wsdl4j.jar because the wsdl file is no longer processed at run time and ass a dot (current directory in the classpath)
#!/bin/sh
javac -source 1.5 -classpath "/home/craft/whc/axis-1_1/lib/axis.jar:
/home/craft/whc/axis-1_1/lib/log4j-1.2.8.jar:
/home/craft/whc/axis-1_1/lib/commons-logging.jar:
/home/craft/whc/axis-1_1/lib/commons-discovery.jar:
/home/craft/whc/axis-1_1/lib/jaxrpc.jar:
/home/craft/whc/axis-1_1/lib/saaj.jar:." StockClient.java - Run the complied class file (again, I have used a script to add the classpath. Moreover, since we need a http proxy to access the internet, I have defined these properties in during invoking the JVM using the -D switch
#!/bin/sh
java -classpath "/home/craft/whc/axis-1_1/lib/axis.jar:
/home/craft/whc/axis-1_1/lib/log4j-1.2.8.jar:
/home/craft/whc/axis-1_1/lib/commons-logging.jar:
/home/craft/whc/axis-1_1/lib/commons-discovery.jar:
/home/craft/whc/axis-1_1/lib/jaxrpc.jar:
/home/craft/whc/axis-1_1/lib/saaj.jar:." -Dhttp.proxySet=true -Dhttp.proxyHost="10.36.250.25" -Dhttp.proxyPort=8080 StockClient
The result is follows:
[craft:/home/craft/whc (465)] run_client.sh
Result = <StockQuotes><Stock><Symbol>MSFT</Symbol><Last>23.81</Last><Date>8/5/2009</Date><Time>4:00pm</Time><Change>+0.04</Change><Open>23.93</Open><High>24.25</High><Low>23.79</Low><Volume>53310240</Volume><MktCap>212.2B</MktCap><PreviousClose>23.77</PreviousClose><PercentageChange>+0.17%</PercentageChange><AnnRange>14.87 - 28.50</AnnRange><Earns>1.619</Earns><P-E>14.68</P-E><Name>Microsoft Corpora</Name></Stock></StockQuotes>
at
下午2:06
訂閱:
文章 (Atom)
