<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6288624699880009928</id><updated>2012-01-23T01:34:12.080+09:00</updated><category term='ruby'/><category term='linux'/><category term='tools'/><category term='operation'/><category term='finance'/><category term='java'/><category term='resume-developer'/><category term='jopr'/><category term='Oracle'/><category term='tiếng Việt'/><category term='leisure'/><category term='agile'/><category term='git'/><category term='python'/><category term='rails'/><category term='kernel'/><category term='dsl'/><category term='jboss'/><category term='pattern'/><category term='exception'/><category term='career'/><category term='vim'/><category term='jruby'/><category term='writing'/><category term='c++'/><category term='mumps'/><category term='resume-admin'/><category term='chef'/><category term='database'/><title type='text'>Le Huy on software design, pattern, DSL and distributed system</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default?start-index=101&amp;max-results=100'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>122</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-975370236567706130</id><published>2011-08-10T05:22:00.010+09:00</published><updated>2011-08-10T06:24:38.907+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='chef'/><title type='text'>Craft a solid chef-server</title><content type='html'>The out of box chef server installation is enough to support large scale deployment . To handle hundreds of nodes we need to craft it a bit. I highlight here some configuration tweaks  
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;1. Run multi instances with Apache or Nginx http server as front end.&lt;/span&gt; &lt;br&gt;
chef-server-api and chef-server-webui is single process, the only way to scale them are run multi instances of them behind the front end reverse http proxy server. &lt;br&gt;
Also the front end http server can be configured to perform ssl encryption making communication between nodes and chef-server-api secure. Note that chef-server-webui is also chef-client, so use URL of the reverse proxy server to communicate with chef-server-api.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;2. Use ruby 1.9&lt;/span&gt;&lt;br&gt;
chef server components are hungry to CPU, use ruby 1.9 can boost performance as much as twice comparing to ruby 1.8.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;3. Couchdb  and big hard disk&lt;/span&gt;&lt;br&gt;
Avoid un necessary headache by installing latest version of  Couchdb. The version that comes with OS is usually old, buggy, often crashes under high load with hundred GB database. Hard disk is cheap, keep space for Couchdb data files, log files always free around 30%. &lt;br&gt;
Also learn Erlang a bit so you can look and understand crash dump file from Couchdb as well as change its configuration.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;4. Solr server&lt;/span&gt;&lt;br&gt;
Chef-solr is de facto Solr server for full text search, The default config is pretty small for any serious operation. As it is java application based on Lucene, we need increase java heap size. You also need  modify the Solr config (see &lt;a href="http://www.elevatedcode.com/articles/2009/01/14/speeding-up-solr-indexing/"&gt;this tip&lt;/a&gt;) to make full text index run faster. Believe me , you will have to rebuild solr index more than you think and proper solr config will save days of frustrated waiting.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;5. Rabbitmq-server&lt;/span&gt;&lt;br&gt;
Follow the same advice as for Couchdb. Rabbitmq-server is also Erlang application. It need enough memory to work reliably. Give it few GB of RAM if you do not want it crash and then will have to rebuild solr index.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;6. Not enough&lt;/span&gt; &lt;br&gt;
Distribute load by running chef-client at different deterministic time avoiding run chef-client of all nodes at the same time.  &lt;br&gt;
Consider running each of chef-server component on separate box even one component in many boxes. But don't do it if you have not try all above options as the more complex configuration, the more time you have to spend on it and you end up to serve the chef instead of it serves your infrastructure.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;7. Put chef-server configuration in a cookbook&lt;/span&gt;&lt;br&gt;
Create your own cookbook to automate all the changes you make on chef-server so you can recreate exact new chef-server using chef-solo in matter of minute (when needed). At the end, who will believe that you will be able to automate the infrastructure if you can not automate your own stuff.
 

 &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-975370236567706130?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/975370236567706130/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=975370236567706130&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/975370236567706130'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/975370236567706130'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2011/08/configure-solid-chef-server.html' title='Craft a solid chef-server'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-1595230203770086228</id><published>2011-07-31T23:55:00.006+09:00</published><updated>2011-08-01T00:02:53.770+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>How a packet travels from 3COM NIC to udp socket</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-K2gneJm0-kg/TjVtVxcVVxI/AAAAAAAAAqQ/YMGQCyKRXDw/s1600/receive-data-from-udp-socket.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 196px;" src="http://4.bp.blogspot.com/-K2gneJm0-kg/TjVtVxcVVxI/AAAAAAAAAqQ/YMGQCyKRXDw/s400/receive-data-from-udp-socket.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5635530729540900626" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-1595230203770086228?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/1595230203770086228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=1595230203770086228&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/1595230203770086228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/1595230203770086228'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2011/07/how-data-is-delivered-to-udp-socket.html' title='How a packet travels from 3COM NIC to udp socket'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-K2gneJm0-kg/TjVtVxcVVxI/AAAAAAAAAqQ/YMGQCyKRXDw/s72-c/receive-data-from-udp-socket.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-7851233596153877217</id><published>2011-05-25T14:38:00.024+09:00</published><updated>2011-08-03T14:10:59.380+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='chef'/><title type='text'>Migrate configuration to Chef</title><content type='html'>One of big headache in implementation Chef or any automate configuration management tool is migration. We usually have to face with a large legacy configuration that is poorly designed and implemented, which make thing worse.
&lt;br&gt;  
I want to share some of our own experiences in doing migration of a relatively large configuration in term of both scale and complexity. 
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;The tools and techniques&lt;/span&gt; 
&lt;br&gt;
They are
&lt;br&gt;
1. a decent, fast and rock solid version control system: I recommend git. 
&lt;br&gt;
2. semantic diff tools: diff of text file is OK, but not enough, depending on format of your configuration (XML, properties, yaml, JSON), you may need to write your own semantic diff, that is able to make intelligent diff  of these formats.
&lt;br&gt;
3. source code of these applications that use these configuration: the migration involve legacy applications, access to source code is absolute need to order to do a refactoring.
&lt;br&gt;
4. collaboration: with the new tool developers need to change/cleanup the code that access configuration data, operation people need to change their practices, we all need to learn how to use, what to trust, where we need to pay attention.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Shadow configuration file&lt;/span&gt; 
&lt;br&gt;
In order to minimize impact existing system, at the beginning we let chef to create shadow configurations, which then are verified with existing configuration using diff tools. The shadow configuration generated by chef will replace the actual one only after we make sure that they are semantically the same from the point of view of the program using it.
&lt;br&gt;
In shadow configuration we can have a configuration file with different prefix/postfix or different directory. e.g. if the actual configuration file is &lt;code&gt;/etc/hosts&lt;/code&gt; then the shadow one will be &lt;code&gt;/etc/hosts.chef&lt;/code&gt; or &lt;code&gt;/etc-chef/hosts&lt;/code&gt; or &lt;code&gt;/root-chef/etc/hosts&lt;/code&gt;. I personally prefer the complete shadow directory because it is easier to check, remove when needed.
&lt;br&gt;
The cookbook need to have one attribute (can be name of directory where we are going to generate configuration files) saying if we are going to generate shadow or actual configuration.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Conflicting changes&lt;/span&gt; 
&lt;br&gt;
In ideal world, we just has one configuration management system and one administrator  who modify the system. But reality is different. There are usually more actors that make the change. So there is potential conflict. E.g. Chef modify one file and then an administrator or scripts or other configuration system don't know and also modify it. The worst case is that everyone assume that the file has the content he expect and thing get broken. These scripts that work for many years suddenly fails. 
&lt;br&gt;
How to minimize the conflict?.  Communicate well with other team  members what are managed by Chef, which they should  modify through Chef and not manually or by other tools.  Various methods can be used e.g. a) wiki pages, b) put a clear notice as comment at the beginning of all files managed by Chef such as "This file is generated by Chef, you shall not modify it as it will be overwritten" c) notify all people each time a file is modified by Chef.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Top-down vs. bottom-up&lt;/span&gt; 
&lt;br&gt;
There is basically two approaches to start the migration project 1)  top-down and 2) bottom-up. 
&lt;br&gt;
1. In top-down approach, you start with create a cookbook/recipe for one configuration item (e.g. syslog-ng, the cookbook will be fairly generic so it is usable by all environments) . Then extract specific data (e.g. ip of syslog server, source of log) from configuration file from each server and put them as attributes into a role. After finishing one configuration item, you continue with other until you have all you need in Chef.
&lt;br&gt;
2. With bottom-up approach, we first create one generic cookbook/recipe per server role (e.g. middleware)  then you add all configuration files from servers of all environments to it.  The structure of  cookbook files can be like 
&lt;pre&gt;
      middleware/files/default   # files that are same for all hosts of all env.
      middleware/files/default/dev   #  files that are same for all hosts of development env.
      middleware/files/default/dev/host1   # files that are specific for host1 of evelopment env. 
      middleware/files/default/dev/host2
      middleware/files/default/qa
      middleware/files/default/pro
&lt;/pre&gt;
The recipe can be easily developed to copy these configuration files to a server depending on environment and hostname (node[:hostname]). After everything are in Chef and  work well, we will start refactor and split this  big generic cookbook to many smaller cookbooks, adding more roles and make thing easily to reuse. This step is kind of continual improvement process aiming at making our chef repository better and better.
&lt;br&gt;
&lt;br&gt;
In our project we have taken the first approach because it seems more naturally at first sight, however later we change to the second one, which I think have many benefits. 
&lt;br&gt;
With the second approach, after we put all things in the Chef (can be done pretty quickly), we can announce that from now all changes has to be done through Chef. The very first result is seen immediately:  a) there is single point of making change b) change is well audited and communicated as Chef repository is under version control system  c)conflicting changes is minimized&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-7851233596153877217?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/7851233596153877217/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=7851233596153877217&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7851233596153877217'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7851233596153877217'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2011/05/migra.html' title='Migrate configuration to Chef'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-2117522838669055000</id><published>2011-05-22T04:06:00.006+09:00</published><updated>2011-05-22T05:08:45.865+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='chef'/><title type='text'>Chef - Different between method defined in recipes and libraries</title><content type='html'>There is one thing that need an attention when developing a recipe. If we create a method in recipe then that method is not available inside resource block's parameter. I will show it in the following example using  Shef, the Chef interactive Ruby console.
&lt;pre&gt;
[root@localhost gems]# shef

Ohai2u root@localhost!
chef &gt; recipe
chef:recipe &gt;   # here we are inside of a recipe
chef:recipe &gt; def account(path) # create a method
chef:recipe ?&gt;    return 'nobody' if File.dirname(path) == '/tmp'
chef:recipe ?&gt;    return 'root'
chef:recipe ?&gt; end
 =&gt; nil 
chef:recipe &gt; file "/tmp/file.test" do
chef:recipe &gt;      action :create
chef:recipe ?&gt;     owner account(name) # try to use this method inside the block and we got a error
chef:recipe ?&gt; end
NoMethodError: undefined method `account' for Chef::Resource::File
 from /usr/lib/ruby/gems/1.8/gems/chef-0.9.8/lib/chef/resource.rb:84:in `method_missing'
&lt;/pre&gt;
One way to workaround is to call the method outside of resource block's parameter
&lt;pre&gt;
chef:recipe &gt; fname = "/tmp/file.test"
 =&gt; "/tmp/file.test" 
chef:recipe &gt; account_val = account(fname)
 =&gt; "root" 
chef:recipe &gt; file fname do
chef:recipe &gt;   action :create
chef:recipe ?&gt;  owner account_val
chef:recipe ?&gt; end
chef:recipe &gt;
&lt;/pre&gt;
Other way is to define it as library (put it inside the directory libraries), in shef we would do like that
&lt;pre&gt;
chef:recipe &gt; exit 
 =&gt; :recipe
chef &gt;  # here we are in top context, in which libraries are loaded 
chef &gt; def account(dirname)
chef ?&gt;    return 'nobody' if File.dirname(path) == '/tmp'
chef ?&gt;    return 'root'
chef ?&gt; end
 =&gt; nil 
chef &gt; recipe
chef:recipe &gt;   # here we are inside of a recipe
chef:recipe &gt; file "/tmp/file.test" do
chef:recipe &gt;    action :create
chef:recipe ?&gt;   owner account(name) # now it is OK
chef:recipe ?&gt; end
chef:recipe &gt;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-2117522838669055000?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/2117522838669055000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=2117522838669055000&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2117522838669055000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2117522838669055000'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2011/05/chef-different-between-method-defined.html' title='Chef - Different between method defined in recipes and libraries'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-6365136607813175688</id><published>2011-04-22T23:05:00.053+09:00</published><updated>2011-05-10T15:46:05.395+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='chef'/><title type='text'>Some experiences in using Opscode Chef</title><content type='html'>I am reaching the end of our Chef's implementation project, in which Chef is deployed to manage hundreds of Apache and Jboss servers (Redhat) hosting complex and dynamic banking application.&lt;br&gt;
So it is worth-wise to  recap some issues, problems encountered and solutions employed during  the course of implementation. &lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Chef vs other tools&lt;/span&gt;
&lt;br&gt;
The project actually started from around Aug/Sep last year with the decision to start with Chef instead of other tools Puppet, CF Engine. I choose Chef because CF Engine is just too old while Puppet is too complex, both require to learn new language for expressing configuration and they missed GUI.  Other quite subjective reason is that I know Ruby better comparing to other.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;The challenges&lt;/span&gt;
&lt;br&gt;
The technical challenges include the complexity of the configuration being migrated to Chef as well its ever changing nature during the course of implementation. As Chef represents paradigm's shift to what we called infrastructure as code, the most difficult part is to persuade the team to change their habit and to adopt software development practices in their work.   
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Refactoring&lt;/span&gt;
&lt;br&gt;
Our environment is complicated and legacy. It was created over years by  different guys manually with a bundle of shell scripts, that are far from good in quality from software engineering perspective (consistency, less duplication, good naming).  So the implementation also mean refactoring the environment to something more viable in order to automate. 
&lt;br&gt;
Cookbooks, roles are developed in parallel with renaming of configuration files/directories, cleaning up obsolete stuffs while adding support for new developed applications, environments, at the same time making sure not to break any things. 
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Single vs multi instances&lt;/span&gt;
&lt;br&gt;
At the beginning of the project there is no environment supported in Chef so there is two options a) maintain separate Chef instance per environment b) embed environment's information into role. As we have too many environments (development, preproduction, quality assurance, training, laboratory, DRS, production), it would be less work to select second option.
&lt;br&gt;
Cookbooks are developed and shared between all environment while roles are created per environment. I use e.g. the following naming convention for role: &lt;code&gt;dev_apache_internet_os&lt;/code&gt; to denote role containing attributes for OS related cookbooks of Apache server in Internet zone.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Roles as Ruby code&lt;/span&gt;
&lt;br&gt;
We have nearly hundred of roles, a server is assigned to at least 2 roles one of OS and other of application specific. That is for separate the concern. OS role will has attributes more less related to OS e.g. pam, ssh, hosts, dns, ntp, postfix, route while application specific are e.g. Apache, Java, Tomcat, Jboss, log4j, etc. 
&lt;br&gt;
To make it easy to manage; a subdirectory is created for each environment and roles are placed in it. The role format is Plain Old Ruby instead of JSON. This is because comparing to JSON format, the Ruby one is easier to spot error saving a lot of time. When we have hundred lines in a Role's file, it is quite possible that we make some typing errors.   
&lt;br&gt;
The other reason is that we can do some sort of programming in Role file e.g. it is more convenient using a loop to create mod_jk config that route request to dozen of servers. 
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;One layer above roles&lt;/span&gt;
&lt;br&gt;
As the number if roles grows,  I have seen that many roles of different environments share common attributes. At OS level e.g. we use same DNS and NTP for both production and non production just in case of DRS there is different. Such examples are endless. These attributes are mostly not same in all environments, they are just same in some so  it is not wise to put them in attributes's file of relevant cookbooks. Therefore we have created additional layer to support reduce such kind of duplication. These attributes  and their values are kept together with applicable environments e.g. in separate file
&lt;pre&gt;
set_config_item(:item=&gt;"dns",:env=&gt;["dev","pre","qa"],:value=&gt;["192.168.0.1","192.168.0.2"])
&lt;/pre&gt;
and in the Role' file, we fetch the relevant attributes value. e.g.
&lt;pre&gt;
"dns"=&gt;get_config_item(:item=&gt;"dns",:env=&gt;"dev")
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Call Attribute#to_hash in recipe&lt;/span&gt;
&lt;br&gt;
Cookbooks are commonly used in all environments. Beside infrastructure, we also create cookbooks that maintain our application specific setting such as URL of external partner systems that we communicate with. The fundamental structure are instances and application modules. Many different application modules can be deployed in single instance and the same application module can be deployed in different instances to support of different versions of the same module and dedicate instance per customer delivery channel.
&lt;br&gt;
Recipe of a cookbook get data from a role to define resources (file, directory, permission, etc.). As we want make role simple, easy to create and modify, I put more logic in recipe. Some recipes are real programming stuff that need to iterate over structure of a role to get desire data. The autovivify feature of attribute sometime causes problem, in order to avoid it we have to call &lt;code&gt;to_hash&lt;/code&gt; for attribute before doing any iteration over it.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Avoid putting big binary in a cookbook&lt;/span&gt;
&lt;br&gt;
We initially tried to put all files required by a recipe in its cookbook.  It turn out to be a bad idea to keep e.g. 200 MB of Jboss installation in Couchdb of Chef. Both knife and Chef-client runs very slow and un reliably. At the end we decided to keep these big binary (more than 20 MB) outside Chef cookbook and setup an Apache for handling these files. The recipe then has to be written to handle checksum, downloading (we use wget) and installation.    
&lt;br&gt;
We do not have to do it in case of software packages available as rpm, because chef &lt;code&gt;package&lt;/code&gt; resource supports their installation.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Make sure that there is no non-ascii character in /etc/passwd,group&lt;/span&gt;
&lt;br&gt;
 chef-client use ohai to parse certain OS configuration files e.g. /etc/password to JSON, if these files contain non-ascii characters, it can causes a problem because JSON lib can not cope with that. So it is better to remove non-ascii from OS configuration files when migrating existing machine to chef.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Disable SELinux&lt;/span&gt;
&lt;br&gt;
SELinux se store security context per files &amp; directories. When chef-client modify configuration files , it may not retain that information making some daemon not working properly. Chef does not support SELinux so we need to disable it  to avoid problem.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Start multi chef-server-api instances for better performance&lt;/span&gt;
&lt;br&gt;
A default chef-server can not support hundreds of clients, so we installed front end Apache that handles SSL encryption for chef-client as well as balances request to 4 instances of chef-server-api, which we start using option &lt;code&gt;-c 4&lt;/code&gt;. 
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;run chef-client as root in crontab&lt;/span&gt;
&lt;br&gt;
We run chef-client on our non production environments, this is because we want to avoid possible problem with long running ruby process and to reduce the chance that chef-client at many machines run at one moment causing high load to chef-server.
&lt;br&gt;
Using crontab we can easily specify time when they will run for each group of machines or even machine. Time to run chef-client can be further generated automatically using hash of machine name to achieve a fair distribution of load.  
&lt;br&gt;
For user, group management chef-client uses unix command lines, so chef-client must run as root with appropriate path to locations of useradd, groupadd, … (e.g. /usr/sbin,/usr/bin,/bin, /sbin).
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;The flow of change&lt;/span&gt;
&lt;br&gt;
The chef-client does not run automatically in production one. This is because in production we want more control as well as due to our change management policy.  It is also safer taking into consideration that modification of cookbook can potentially impact  production. 
&lt;br&gt;
The flow of change in production (after cookbook being modified and tested in other environments) involes 1) modify relevant production role, 2) take one production machine from service, 3) execute chef-client on that machine, 4) verify that it work as per expectation, 5) execute chef-client in all remain servers and put all into service. 
&lt;br&gt;
To execute the chef-client command on a group of machines, we can use sort of Command Control system (e.g. rundesk, control tier, ..) or simple knife.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Hacking, Notification and improvement&lt;/span&gt;
&lt;br&gt;
To increase safety in the context of missing noop option in chef-client, I have create a monkey patch for certain providers so when chef-client modify a file it notify us by sending output of diff between new and  old file by e-mail.  The custom notification also send alert to certain group of people depending of nature of change and affected environment. 
&lt;br&gt;
Beside that, we have create new resources and change behavior of fews existing one to suit more our need.  The code base of our cookbook, roles is now reaching 20K line of Ruby code and we continually adding more thing as well improve it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-6365136607813175688?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/6365136607813175688/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=6365136607813175688&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6365136607813175688'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6365136607813175688'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2011/04/some-experiences-in-using-opscode-chef.html' title='Some experiences in using Opscode Chef'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-8418257552168977434</id><published>2011-02-15T12:20:00.004+09:00</published><updated>2011-02-15T12:50:31.824+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>chroot - Change Root</title><content type='html'>I have recently closed a year old ticket that has some thing to do with chroot. For security reason, we use chroot (in modsecurity) to restrict our Apache process to access only to a desired directory tree. As per chroot document, a program that is re-rooted to another directory cannot access or name files outside that directory, and the directory is called a "chroot jail".  &lt;br&gt;

We make sure that chroot is called after Apache process complete it' initialization in order to not break anything, Because otherwise Apache will not be able to access needed share lib, log files, pid file located in various system directories. &lt;br&gt;

However there is  a wrong access time the log produced by our Apache. It is always GMT not local time as we want. We have opened ticket with vendor, searching over internet, looking at source code but could not figure out why. The worse thing is that, for first few requests , the access time is correct (local time) but then it gets change to GMT.  &lt;br&gt;

Yesterday I have found the reason. I remember that when I ran the strace with the Apache process being chrooted, I saw Apache try to open some files but could not find it. We see a lot of file not found when running strace because various libraries intend to open some file and if it is not found then try others. But in that case the file is /etc/localtime. So it turns out that when logging Apache use apr lib, which call gmtime and mktime, which need to access /etc/localtime. So missing this file in "chroot jail" causes a problem with access time. Without file /etc/localtime gmtime and mktime consider that the machine is in GMT time zone.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-8418257552168977434?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/8418257552168977434/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=8418257552168977434&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8418257552168977434'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8418257552168977434'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2011/02/chroot-change-root.html' title='chroot - Change Root'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-4051481872447145765</id><published>2011-01-01T17:15:00.013+09:00</published><updated>2011-01-01T17:44:34.820+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Using debuginfo packages in Redhat</title><content type='html'>Redhat provide debuginfo packages but not tell us so much how to use it. Here is a simple instruction to use debuginfo packages.
&lt;br&gt;
First this is important to know that a debuginfo package contains only debug symbol not the executable. Therefore we need to install both normal package and the corresponding debuginfo and of course their version must be matched.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Installation&lt;/span&gt; 
&lt;br&gt;
Make sure that repository of debuginfo package is configured properly as follows
&lt;pre&gt;
[root@localhost ~]# cat /etc/yum.repos.d/rhel-debuginfo.repo 
[rhel-debuginfo]
name=Red Hat Enterprise Linux $releasever - $basearch - Debug
baseurl=ftp://ftp.redhat.com/pub/redhat/linux/enterprise/$releasever/en/os/$basearch/Debuginfo/
enabled=0
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release
&lt;/pre&gt;
To install debuginfo package, we have to specify &lt;code&gt;--enablerepo rhel-debuginfo&lt;/code&gt; as yum option
&lt;pre&gt;
root@localhost ~]#yum install --enablerepo rhel-debuginfo httpd-debuginfo

root@localhost ~]#yum install httpd

[root@localhost ~]# rpm -q -a | grep httpd
httpd-debuginfo-2.2.3-43.el5_5.3
httpd-2.2.3-43.el5_5.3
&lt;/pre&gt; 

&lt;span style="font-weight:bold;"&gt;Usage&lt;/span&gt;
&lt;br&gt;
To get use just start gdb session with a normal executable
&lt;pre&gt;
[root@localhost ~]# gdb /usr/bin/ab
GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-23.el5_5.2)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later &lt;http://gnu.org/licenses/gpl.html&gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu".
For bug reporting instructions, please see:
&lt;http://www.gnu.org/software/gdb/bugs/&gt;...
Reading symbols from /usr/bin/ab...Reading symbols from /usr/lib/debug/usr/bin/ab.debug...done.
done.
(gdb) break main
Breakpoint 1 at 0x7402: file /usr/src/debug/httpd-2.2.3/support/ab.c, line 1900.
(gdb) run
Starting program: /usr/bin/ab 
[Thread debugging using libthread_db enabled]

Breakpoint 1, main (argc=114424, argv=0x0) at /usr/src/debug/httpd-2.2.3/support/ab.c:1900
1900 {
(gdb) l
1895 
1896 /* ------------------------------------------------------- */
1897 
1898 /* sort out command-line args and call test */
1899 int main(int argc, const char * const argv[])
1900 {
1901     int r, l;
1902     char tmp[1024];
1903     apr_status_t status;
1904     apr_getopt_t *opt;
(gdb) 
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-4051481872447145765?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/4051481872447145765/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=4051481872447145765&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4051481872447145765'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4051481872447145765'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2011/01/using-debuginfo-packages-in-redhat.html' title='Using debuginfo packages in Redhat'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-525693438925995885</id><published>2010-12-12T17:46:00.013+09:00</published><updated>2010-12-13T00:44:13.540+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mumps'/><title type='text'>M Language Tutorial - The cryptic style</title><content type='html'>In order to save typing at cost of readability, every command and built in function of M has abbreviation/shortcut.
&lt;br&gt;
The following examples are perfectly valid
&lt;pre&gt;
f i=1:1:9 s sqtable(i)=i*i; 'f' stand for 'for' and 's' for 'set'
&lt;/pre&gt;
and
&lt;pre&gt;
s i="" f  s i=$o(sqltable(i)) q:i=""  w i," ",sqltable(i),!;'q' stand for 'quit' '$o' for '$order', 'w' for 'write'
&lt;/pre&gt;
As we spend most of our time reading code written by others, modern programming style does care much about naming thing. The abbreviated style of most if M code is really pain especially for novices.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-525693438925995885?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/525693438925995885/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=525693438925995885&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/525693438925995885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/525693438925995885'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2010/12/cryptic-style.html' title='M Language Tutorial - The cryptic style'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-570756325326448132</id><published>2010-11-20T17:00:00.020+09:00</published><updated>2010-12-08T17:53:10.630+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mumps'/><title type='text'>M Language Tutorial -  for and Array</title><content type='html'>&lt;span style="font-weight:bold;"&gt;for command&lt;/span&gt;
&lt;pre&gt;
GTM&gt;for i=1:1:5 write i,!
1
2
3
4
5
&lt;/pre&gt;
The above &lt;code&gt;for&lt;/code&gt; loop a variable &lt;code&gt;i&lt;/code&gt; from 1 to 5, increasing by 1 in each iteration.
&lt;br&gt;
This one will loop over a list of arguments
&lt;pre&gt;
GTM&gt;for i="hello","world","bye","moon" write i,!
hello
world
bye
moon
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;array&lt;/span&gt;
&lt;br&gt;
In M array is stored as sparse B-tree structure, index or subscript can be anything and can be in any number
&lt;pre&gt;
GTM&gt; 
GTM&gt;set a(1)="hello",a(2)="world" 
GTM&gt;write a(1)," ",a(2)
hello world
GTM&gt;
GTM&gt;write a(3)         
%GTM-E-UNDEF, Undefined local variable: a(3)
&lt;/pre&gt;
the index of an Array can be any thing so it is like hash/dictionary in other language.
&lt;pre&gt;
GTM&gt;set a("hello")=1

GTM&gt;set a("world")=2

GTM&gt;write a("hello")
1
GTM&gt;write a("world")
2
GTM&gt;write a("moon") 
%GTM-E-UNDEF, Undefined local variable: a(moon)
&lt;/pre&gt;
We can use any number of subscripts
&lt;pre&gt;
GTM&gt;set a(1,2)="moon"

GTM&gt;set a(1,1)="world"

GTM&gt;write a(1,1)
world
GTM&gt;write a(1,2)
moon
GTM&gt;write a(1,0)
%GTM-E-UNDEF, Undefined local variable: a(1,0)
&lt;/pre&gt;
built-in function &lt;code&gt;$order&lt;/code&gt; is used to get index/subscript of an element of an Array, that is particularly useful for traversal over an Array. 
&lt;pre&gt;
GTM&gt;set b(3)="hello",b(5)="world",b("hello")=1,b("world")=2

GTM&gt;write $order(b("")); with empty string we get a subscript of the first element of an Array
3
GTM&gt;write $order(b(3)); passing one element we get a subscript of next element  
5
GTM&gt;write $order(b(5))
hello
GTM&gt;write $order(b("hello"))
world
GTM&gt;write $order(b("world")); passing the last element we get empty string 
&lt;/pre&gt;
If array is multi dimensional, &lt;code&gt;$order&lt;/code&gt; will return subscript of an element in one dimension
&lt;pre&gt;
GTM&gt;set a("h",1)="hello",a("w",1)="world"

GTM&gt;write $order(a("")); return subscript in the first dimension of first element 
h
GTM&gt;write $order(a("h")); return subscript in the first dimension of second element 
w
GTM&gt;write $order(a("w"))

GTM&gt;write $order(a("h","")); return subscript in the second dimension of first element  
1
GTM&gt;write $order(a("h",1)) 

GTM&gt;write $order(a("w","")); return subscript in the second dimension of second element 
1
GTM&gt;write $order(a("w",1)) 

&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;traversal over a array&lt;/span&gt;
&lt;br&gt;
&lt;code&gt;for&lt;/code&gt; is typical command used to traversal an array
&lt;pre&gt;
GTM&gt;kill a for i=1:1:10 set a(i)=i*i
&lt;/pre&gt;
We use &lt;code&gt;kill&lt;/code&gt; to erase content of the variable &lt;code&gt;a&lt;/code&gt; if exists and a &lt;code&gt;for&lt;/code&gt; to create 10 elements.
&lt;pre&gt;
GTM&gt;set i="" for  set i=$order(a(i)) quit:i=""  write i," ",a(i),!; two SPACE after for and two SPACE after quit:i=""
1 1
2 4
3 9
4 16
5 25
6 36
7 49
8 64
9 81
10 100
&lt;/pre&gt;
Here, the argument-less For repeats until stopped by a terminating quit. This line prints a table of i and a(i)
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;block of multi line of codes under for&lt;/span&gt;
&lt;br&gt;
M support execute multi line of code under for  in the routine
&lt;pre&gt;
GTM&gt;zedit "nested"
finish
 for name="ivan","john","janes" do
 . if name]"jo"; the operator ] test if name follows string "jo"
 . else  write name,!
 quit

GTM&gt;zlink "nested"

GTM&gt;do finish^nested
ivan
janes
GTM&gt;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-570756325326448132?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/570756325326448132/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=570756325326448132&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/570756325326448132'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/570756325326448132'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2010/11/m-language-tutorial-for-loop.html' title='M Language Tutorial -  for and Array'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-2768082508375578054</id><published>2010-11-15T01:14:00.040+09:00</published><updated>2010-12-18T17:54:59.063+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mumps'/><title type='text'>M Language Tutorial - if, else and boolean condition</title><content type='html'>M language has no concept of structure that are familiar in other programming languages. In M all are commands including &lt;code&gt;if,else,for&lt;/code&gt;.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;if and else commands&lt;/span&gt;
&lt;pre&gt;
GTM&gt;set x=1

GTM&gt;if x=1 write "boom"; if condition is satisfied
boom
GTM&gt;if x=2 write "bang";  if condition is not satisfied
&lt;/pre&gt;
The &lt;code&gt;if&lt;/code&gt; command support AND , OR, NOT condition
&lt;pre&gt;
GTM&gt;set x=1,y=2

GTM&gt;if x=1,y=1 write "bang" ; we use , to denote AND

GTM&gt;if x=1,y=2 write "bang"
bang

GTM&gt; if (x=1)&amp;(y=2) write "bang"; other way to express AND is to use &amp;
bang

GTM&gt;if x=1!y=1 write "boom"; we use ! to denote OR 
boom
GTM&gt;if 1=0 write "oh" 

GTM&gt;if '1=0 write "oh"; we use '  to denote a negation
oh
&lt;/pre&gt;
Internally, &lt;code&gt;if&lt;/code&gt; set a special value &lt;code&gt;$TEST&lt;/code&gt; to 1 (TRUE) or 0 (FALSE) depending on whether the condition is satisfied or not. &lt;code&gt;$TEST&lt;/code&gt; is set to 1 at the start of gtm. The &lt;code&gt;if&lt;/code&gt; command without condition will use &lt;code&gt;$TEST&lt;/code&gt; as condition.
&lt;pre&gt;
$gtm
GTM&gt;write $TEST
1
GTM&gt;if 1=0

GTM&gt;write $TEST
0
GTM&gt;if  write "hello"! note two SPACEs after if

GTM&gt;if $TEST=1 write "hello"! equivalent to above

GTM&gt;if 1=1

GTM&gt;write $TEST
1
GTM&gt;if  write "hello"; note two SPACEs after if
hello
GTM&gt;if $TEST=1 write "hello"; equivalent to above
hello
&lt;/pre&gt;
&lt;code&gt;else&lt;/code&gt; is command that perform the command followed it if the &lt;code&gt;$TEST&lt;/code&gt; variable is 0
&lt;pre&gt;
GTM&gt;set x=1

GTM&gt;if x&gt;1 write "world"

GTM&gt;else  write "moon"; note two SPACES after else
moon
GTM&gt;if $TEST=0  write "moon"; equivalent to above
moon
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;command's postcondition&lt;/span&gt;
&lt;br&gt;
execution of almost all commands can be controlled by following it with a colon and a truthvalue expression. 
&lt;pre&gt;
GTM&gt;set n=1
GTM&gt;write:n&gt;0 "hello"
hello
GTM&gt;write:n&gt;1 "world"
GTM&gt; 
&lt;/pre&gt;
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;block of multi line of codes under if,else&lt;/span&gt;
&lt;br&gt;
M support execute multi line of code under if,else, for  in the routine
&lt;pre&gt;
GTM&gt;zedit "nested"
start(x,who)
 if x=1 do  ;two SPACE after do
 . write "hello",!
 . write who
 else  do  ;two SPACE after else and do
 . write "bye",!
 . write who
 quit

GTM&gt;zlink "nested"

GTM&gt;do start^nested(1,"world")
hello
world
GTM&gt;do start^nested(0,"world")
bye
world
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;operators for string' comparison &lt;/span&gt;
&lt;br&gt;
These operators are a little bit strange comparing to other languages
&lt;pre&gt;
GTM&gt;WRITE "A"="B"; compare if two string are equal
0
GTM&gt;WRITE "C"="C"
1
GTM&gt;WRITE "A"["B"; this is same as contains in other language
0
GTM&gt;WRITE "ABC"["C"
1
GTM&gt;WRITE "A"]"B"; this is same as &gt; in other language
0
GTM&gt;WRITE "B"]"A"
1
&lt;/pre&gt;
NOT operator can applied to either expression or other operator
&lt;pre&gt;
GTM&gt;write "A"="B" 
0
GTM&gt;write '("A"="B")
1
GTM&gt;write "A"'="B"
1
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-2768082508375578054?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/2768082508375578054/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=2768082508375578054&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2768082508375578054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2768082508375578054'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2010/11/m-language-tutorial-if-else-for.html' title='M Language Tutorial - if, else and boolean condition'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-2522720549605131515</id><published>2010-11-05T05:58:00.031+09:00</published><updated>2010-11-07T18:49:14.041+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mumps'/><title type='text'>M Language Tutorial - routines</title><content type='html'>Divide and conquer is the technique used to counter complexity from the  beginning of software development history, A complex system in M language comprise of many files called routines. 
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;label, quit and function&lt;/span&gt;
&lt;br&gt;
In general each line of code in a routine contains of one or no label following by a SPACE or TAB and then M command, other M code can make a call to any line of the routine that has a label at start of the file. Let create a file &lt;code&gt;display.m&lt;/code&gt; in one of these paths specified in env. variable &lt;code&gt;gtmroutines&lt;/code&gt; using any editor.
&lt;pre&gt;
start
 write "display",!
 quit
other 
 write "other",!
nothing
 write "no",!
&lt;/pre&gt;
Now start gtm and try to make some call
&lt;pre&gt;
$gtm
GTM&gt;zlink "display"
GTM&gt;do ^display
display
GTM&gt;do start^display
display
GTM&gt;do start+1^display
display
&lt;/pre&gt;
The name after ^ is name of routine same as filename without extension &lt;code&gt; .m&lt;/code&gt;. Without any label, GTM will execute the code starting from line 1 of the routine. It does exactly the same with label &lt;code&gt;start&lt;/code&gt;. Making a call to a line 1 from the label &lt;code&gt;start&lt;/code&gt; mean start the execution from line 2 of the file. The execution terminate at command &lt;code&gt;quit&lt;/code&gt;.
&lt;pre&gt;
GTM&gt;do start+3^display
other
no
GTM&gt;do other^display  
other
no
GTM&gt;do nothing^display
no
&lt;/pre&gt;
Calling a line 3 from label &lt;code&gt;start&lt;/code&gt; is the same as calling label &lt;code&gt;other&lt;/code&gt;. Because there is no &lt;code&gt;quit&lt;/code&gt; command, GTM continues the execution at the end of file.
&lt;br&gt;
There is good practice always structure a routines as series of sections starting with a label and ending with a &lt;code&gt;quit&lt;/code&gt; command. That way we can consider each label as a function name when making a call. Using offset from a label is considered a bad practice as it decrease readability of the code.
&lt;br&gt;
When calling a function within the same routine, we can remove the ^filename
 &lt;pre&gt;
talkto(who)
 do say("Hello",who); call a function in the same routine
 write "bla bla",!
 do say("Byte",who)
 quit

say(what,who)
 write what," ",who,!
 quit
GTM&gt;zlink "stuff"

GTM&gt;do talkto^stuff("John")
Hello John
bla bla
Byte John
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;calling function, passing parameters, return value&lt;/span&gt;
&lt;br&gt;
We pass parameters when calling M routine in parentheses  separated by comma, the leading period &lt;code&gt;.&lt;/code&gt; is used to indicate a parameter being passed as reference that is used to store the output of function.
&lt;pre&gt;
$gtm
GTM&gt;zedit "calc"
calc(a,b,ret)
 set ret=(2*a)+(3*b)
 quit
&lt;/pre&gt;
Now make a call
&lt;pre&gt; 
GTM&gt;zlink "calc"
GTM&gt;do ^calc(1,2,.result)
GTM&gt;write result
8
&lt;/pre&gt;
M provides a facility called Extrinsic Variable to create a function that return value so it can be used in a expression 
&lt;pre&gt;
$gtm
GTM&gt;zedit "calc"
calc(a,b,ret)
 set ret=(2*a)+(3*b)
 quit

othercalc(a,b)
 quit (2*a)+(3*b); the function must put return value  after quit command

GTM&gt;zlink "calc"
GTM&gt;write $$othercalc^calc(1,2); put $$ before the name of function when calling
8
GTM&gt;set x=$$calc^calc(2,3)     
%GTM-E-QUITARGREQD, Quit from an extrinsic must have an argument
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-2522720549605131515?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/2522720549605131515/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=2522720549605131515&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2522720549605131515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2522720549605131515'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2010/11/m-language-tutorial-routines.html' title='M Language Tutorial - routines'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-8819680489149570461</id><published>2010-11-02T02:28:00.053+09:00</published><updated>2010-11-21T18:50:41.146+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mumps'/><title type='text'>M Language Tutorial - Getting started</title><content type='html'>I am learning &lt;a href="http://en.wikipedia.org/wiki/MUMPS"&gt;MUMPS/M language&lt;/a&gt; to understand one of our systems, that has  been implemented using M. I feel, there is  a lack of a documentation in form of quick start and tutorial, so I put some notes here hoping that it will be useful for someone.
&lt;br&gt;
For a thorough listing of  the M language commands, operators, functions and special variables, see &lt;a href="http://71.174.62.16/Demo/AnnoStd?Frame=Main&amp;Page=a100006"&gt;MUMPS by Example&lt;/a&gt;
&lt;br&gt; 
One of M implementations available as open source is GTM from FIS, we can download it from &lt;a href="http://sourceforge.net/projects/fis-gtm/"&gt;http://sourceforge.net/projects/fis-gtm/&lt;/a&gt;. The documentation is available from &lt;a href="http://fisglobal.com/Products/TechnologyPlatforms/GTM/UserDocumentation/index.htm"&gt;here&lt;/a&gt; 
&lt;br&gt;
Setup a environment to start some test is fairly simple, just unzip the downloaded file, run configure and answer few questions, then we can start 
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;setting env. for running GTM&lt;/span&gt;
&lt;pre&gt;
$source ./gtmprofile
&lt;/pre&gt;
This shell will set various env, variables required by GTM also create a global directory and a default datafile, that is actually M database. M is a language with built in persistence.  The global directory is kind of control file in Oracle. 
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;start gtm - the interpreter&lt;/span&gt;
&lt;pre&gt;
$gtm
GTM&gt;
GTM&gt;write "hello world"
hello world
GTM&gt;halt
&lt;/pre&gt;
M use &lt;code&gt;write&lt;/code&gt; command to output some thing to a console, in Ruby we would use &lt;code&gt;puts&lt;/code&gt; in Python, this is &lt;code&gt;print&lt;/code&gt;.
The command &lt;code&gt;halt&lt;/code&gt; is used to quit the gtm.
&lt;br&gt;
For a beginner of any language, the ability to write something out to see and to exit are the two most important commands.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;string and numbers&lt;/span&gt;
&lt;br&gt;
String is enclosed by " as in C, Java, Python, Ruby, to concatenate two or more string we use operator &lt;code&gt;_&lt;/code&gt;, not that common any more.
&lt;pre&gt;
GTM&gt;set x="hello"
GTM&gt;set y="world"
GTM&gt;set z=x_" "_y
GTM&gt;write z
hello world
&lt;/pre&gt;
The command &lt;code&gt;set&lt;/code&gt; set these local variables, these variables are created automatically if not exist.
&lt;br&gt;
&lt;pre&gt;
GTM&gt;set a=10
GTM&gt;set b=20
GTM&gt;set c=(a+b)*5/10
GTM&gt;write c
15
&lt;/pre&gt;
For number, this is quite straightforward, no surprise.
&lt;br&gt;

&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;create and run the first program&lt;/span&gt;
&lt;pre&gt;
$export gtmroutines=/home/gtm/samples
$source ./gtmprofile
$gtm
GTM&gt;write $ZROutines
/home/gtm/samples
&lt;/pre&gt;
this  &lt;code&gt;gtmroutines&lt;/code&gt; env. variable specifies where GTM is going to store and search for its routines, inside GTM however it is kept in variable &lt;code&gt;$ZROutines&lt;/code&gt;. The concept routine in GTM is synonym for a single file containing M code.
&lt;br&gt;
&lt;pre&gt;
GTM&gt;zedit "hello"
&lt;/pre&gt;
This will popup a vi editor with opened file &lt;code&gt;/home/gtm/samples/hello.m&lt;/code&gt;. Create the following content, save and quit vi editor.
&lt;br&gt;
&lt;pre&gt;
hello(who)
  write "Hello ",who,!
  quit
&lt;/pre&gt;
In the routine &lt;code&gt;hello.m&lt;/code&gt; we see a label &lt;code&gt;hello(who)&lt;/code&gt;, which is calling entry point. GTM's routine can have many labels and the general syntax of calling a section of code in the routine is &lt;code&gt;label^routine&lt;/code&gt;. 
The label &lt;code&gt;hello&lt;/code&gt; will take one parameters. The &lt;code&gt;write&lt;/code&gt; above command takes 3 parameters separated by comma where &lt;code&gt;!&lt;/code&gt; means new line. It is possible to write the above code in a single line
&lt;pre&gt;
hello(who) write "Hello ",who,! quit
&lt;/pre&gt; 
The &lt;code&gt;quit&lt;/code&gt; at the end is important in case other labels are added below if we want a label to behave as a function, which mean that the execution flow in the routine terminates at &lt;code&gt;quit&lt;/code&gt; command .
&lt;pre&gt;
GTM&gt; zlink "hello"
&lt;/pre&gt;  
The &lt;code&gt;zlink&lt;/code&gt; compiles and link &lt;code&gt;hello.m&lt;/code&gt; to GTM image so we can call this routine in GTM environment
&lt;pre&gt;
GTM&gt;do hello^hello("Moon")
Hello Moon
&lt;/pre&gt;
If we do not specify a label then the code will be executed from the first line. 
&lt;pre&gt;
GTM&gt;do ^hello("World")
Hello World
&lt;/pre&gt;
If we look closely to &lt;code&gt;gtm&lt;/code&gt;, we will see that &lt;code&gt;gtm&lt;/code&gt; is shell script that call the binary &lt;code&gt;mumps&lt;/code&gt; in direct mode (with parameter &lt;code&gt;-direct&lt;/code&gt;). 
&lt;br&gt;
We can run the routine &lt;code&gt;hello.m&lt;/code&gt; from command line as follow
&lt;br&gt;
&lt;pre&gt;
$export gtmroutines="/home/gtm/samples/ ."
$mumps -run %XCMD 'do ^hello("World")'
&lt;/pre&gt;
The  &lt;code&gt;%XCMD&lt;/code&gt; is in fact a routine  &lt;code&gt;_XCMD.m&lt;/code&gt; located in distribution directory of GTM, that is why we need add "." into &lt;code&gt;gtmroutines&lt;/code&gt; env. variables, so &lt;code&gt;mumps&lt;/code&gt; knows where to find the files being executed.
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;language syntax&lt;/span&gt;
&lt;br&gt;
M syntax is very strict, SPACE characters between M statements are significant. A single space separates a command from its argument, COMMA ","  is used to separate one argument from other of these commands taking more than one arguments.  
&lt;br&gt;
A SPACE, or newline, separates the command's arguments from others. Commands which take no arguments (e.g., ELSE) require two following spaces. 
&lt;br&gt;
Character &lt;code&gt;;&lt;/code&gt; is used to indicate start of a comment, that runs until end of line.
&lt;pre&gt;
GTM&gt;write  "hello"; two SPACES after write
%GTM-E-EXPR, Expression expected but not found
 write  "hello"
       ^-----
GTM&gt;write "hello"; single SPACE after write
hello
GTM&gt;set x=1,y=2 write "x=",x,",y=",y !set and write commands are on the same line separated by SPACE
x=1,y=2
GTM&gt;set x=1 + 2; SPACE surrounding + 
%GTM-E-CMD, Command expected but not found
 set x=1 + 2
         ^-----
GTM&gt;set x=1+2; no SPACE in expression
GTM&gt;write x
3
GTM&gt;set x= 9 ; SPACE after =  
%GTM-E-EXPR, Expression expected but not found
 set x= 9
       ^-----
GTM&gt;set x=9; no SPACE after=
GTM&gt;write x
9
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Math expression&lt;/span&gt;
&lt;br&gt;
Comparing to other language, math operator has no order precedences, a expression is evaluated from left to right 
&lt;pre&gt;
GTM&gt;write 1+2*3
9
GTM&gt;write (1+2)*3
9
&lt;/pre&gt;
Parentheses has to be used to make thing work as expecting.
&lt;pre&gt;
GTM&gt;write 1+(2*3)
7
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-8819680489149570461?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/8819680489149570461/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=8819680489149570461&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8819680489149570461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8819680489149570461'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2010/11/m-language-tutorial.html' title='M Language Tutorial - Getting started'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-5049055544567008423</id><published>2010-06-30T20:12:00.003+09:00</published><updated>2010-07-21T05:35:35.080+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='operation'/><title type='text'>Velocity conference 2010</title><content type='html'>&lt;a href="http://en.oreilly.com/velocity2010"&gt;Velocity conference 2010 Site&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.youtube.com/view_play_list?p=D1D3B0B233F2AD66"&gt;Videos&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-5049055544567008423?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/5049055544567008423/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=5049055544567008423&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5049055544567008423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5049055544567008423'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2010/06/velocity-conference-2010.html' title='Velocity conference 2010'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-1996303164980044011</id><published>2010-03-20T05:59:00.005+09:00</published><updated>2010-03-20T21:23:09.008+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Automatically dump your Thread´s StackTrace whenever something get wrong</title><content type='html'>JVM either from SUN or IBM has features that allows us to do heap dump and thread stack trace dump. They can even do it automatically when there is OutOfMemory error. &lt;br&gt;

But there is plenty of others situations that StackTrace of Threads can be useful e.g. when your application code enter into infinite loop or it forgets to free some resources or all threads of its thread pools are busy. In such cases Thread´s StackTrace are extremely valuable in root cause analysis. &lt;br&gt;

Create StackTrace dump is also much cheaper and faster than Heap dump so that is why we should do it automatically in many situation when we suspect that something gets wrong. &lt;br&gt;

The most easy way to do it to write a script that trigger a Thread´s StackTrace dump by invoking kill -3 jvm_pid (or jstack jvm_pid) when something happen( e.g. JVM use more then 90% CPU).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-1996303164980044011?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/1996303164980044011/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=1996303164980044011&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/1996303164980044011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/1996303164980044011'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2010/03/automatically-dump-your-threads.html' title='Automatically dump your Thread´s StackTrace whenever something get wrong'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-2702047339385324566</id><published>2010-01-23T18:31:00.008+09:00</published><updated>2010-01-23T19:15:06.273+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>6 months in ING Direct Spain</title><content type='html'>Today marks 6 months of my tenure in ING Direct Spain. So it is helpful to have some reflections. 
&lt;br&gt;
1. My job is primarily administrative. During the time, I was involved in a couple of troubleshooting issues, for which we are able to find out a root cause and proposed a conclusive solution. 
&lt;br&gt;
&lt;br&gt;
2. The second thing is my effort to refactor our JBoss infrastructure and to use git to track and manage the change. One lesson I learned from that is not matter what sophisticated we are using, the key of success is ability a) to figure out what is specific and what is common and b) to reduce number of configuration items. 
&lt;br&gt;
At the beginning I tried to track configuration items on each machine as one git branch but it turns out into a horror of hundreds of un-manageable branches. At the end I thrown it and start to divide the monolithic configuration into smaller parts, parametrize them for reuse. After that using git or any other VCS for tracking them is just as walk in a rose's garden.    
&lt;br&gt;
&lt;br&gt;
3. The third thing I have started is documentation of our infrastructure, I decided to use wiki for doing it. It turned out to be a good choice. The document is very up to date and practical because I use the document during my daily work so whenever I find a gaps between the document and the reality, I correct it.  Update documentation is not separated task but a part of my day-to-day activities.
&lt;br&gt;
&lt;br&gt;
4. An the last thing is my research to look for a central authentication solution for our unix farm of mix LINUX, AIX and Solaris. I have tested PAM &amp;  Open LDAP combination for a while but at the end I have selected and recommended Likewise with the existing Active Directory as authentication server due to a lower cost of installation and operation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-2702047339385324566?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/2702047339385324566/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=2702047339385324566&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2702047339385324566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2702047339385324566'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2010/01/6-months-in-ing-direct-spain.html' title='6 months in ING Direct Spain'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-2465355207405307635</id><published>2010-01-18T02:57:00.004+09:00</published><updated>2010-01-18T03:20:35.056+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='operation'/><title type='text'>java.lang.OutOfMemoryError Out of swap space?</title><content type='html'>I have encountered this error in one of our Hotspot JVMs. Googling for a while without definitive result, I decided to look at source code of Hotspot VM (happily the source code is available in Sun website).
&lt;br&gt;
Within few minutes, with very little effort, I found that JVM print out this message when got NULL from calling malloc. So it turns out to find why malloc fails.  
&lt;br&gt;
When OS does not have RAM to satisfy malloc, it may try to swap out unused real memory to disk and if the swap space is configured too small, the error appears. But this is just one cause. 
&lt;br&gt;
Other more likely cause is that JVM run out of memory address space and this is our case. It can happen when we run 32 bit JVM and total memory used by the JVM exceeds magical limit of 3 GB (on 32 bit kernel LINUX).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-2465355207405307635?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/2465355207405307635/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=2465355207405307635&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2465355207405307635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2465355207405307635'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2010/01/javalangoutofmemoryerror-out-of-swap.html' title='java.lang.OutOfMemoryError Out of swap space?'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-4937062973560890816</id><published>2009-11-23T04:33:00.004+09:00</published><updated>2009-11-23T05:07:30.885+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='operation'/><title type='text'>Bringing more development practices to the world of administration</title><content type='html'>In tradition software development and system administration tends to be separated. So useful practices in software development are not known by many administrators. I would say that the world of system administrations lack very much behind software development's world.  
&lt;br&gt;
While using Version Control System (VCS) is obvious thing in any software project, not many administrator use this very useful tool during their daily work. The result is a dirty environment where a configuration's file is backup manually by renaming before making change. Also there is difficult to perform a rollback and reason and time of change is not well maintained.
&lt;br&gt;
Other often well encouraging software principles are to achieve re-usability, readability, explicitness as well as to avoid duplication. On the other hand an administrator cares much less about them. I have seen an environment where there are hundreds of scripts poorly written, repetitive, difficult to understand and maintained. I do thing that by using technique as re-factoring the situation can be improved significally.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-4937062973560890816?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/4937062973560890816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=4937062973560890816&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4937062973560890816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4937062973560890816'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/11/bringing-more-development-practices-to.html' title='Bringing more development practices to the world of administration'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-1126833057808067504</id><published>2009-08-23T04:43:00.010+09:00</published><updated>2009-10-25T18:52:40.268+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='operation'/><title type='text'>Articles about deployment and operation are rare</title><content type='html'>Deploy and run a software is a vital part of the full picture "make value from the software". However does not draw much attentions from community.I listed here links to few blogs and websites talking about this subject matter.
&lt;br&gt;
&lt;a href="http://www.build-doctor.com"&gt;http://www.build-doctor.com&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.agileweboperations.com/"&gt;http://www.agileweboperations.com/&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://en.oreilly.com/velocity2009"&gt;http://en.oreilly.com/velocity2009&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://reductivelabs.com/trac/puppet/wiki/FrequentlyAskedQuestions"&gt;http://reductivelabs.com/trac/puppet/wiki/FrequentlyAskedQuestions&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://ganglia.info/"&gt;http://ganglia.info/&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.cfengine.com/"&gt;http://www.cfengine.com/&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://trac.mcs.anl.gov/projects/bcfg2"&gt;http://trac.mcs.anl.gov/projects/bcfg2&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://automateit.org/"&gt;http://automateit.org/&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://wiki.opscode.com/display/chef/Home"&gt;http://wiki.opscode.com/display/chef/Home&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-1126833057808067504?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/1126833057808067504/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=1126833057808067504&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/1126833057808067504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/1126833057808067504'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/08/blogs-about-deployment-and-operation.html' title='Articles about deployment and operation are rare'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-7616194854438991132</id><published>2009-08-08T15:10:00.005+09:00</published><updated>2009-08-08T15:31:44.025+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>Joining to ING Direct Spain</title><content type='html'>ING Group decided not to launch ING Direct Operation in Japan, as result I moved to ING DIRECT Spain. As for non European citizen, the visa process take long time for me. But finally I landed to Spain Office at the end of July. 
&lt;br&gt;
This is logical step in my career, I want to stay with ING DIRECT and the job market has still very tough. I returned to Europe after 12 years, I moved from Prague to Hanoi in July, 1997.
&lt;br&gt;
The first two weeks in the Spain Office is exciting, people are friendly, HR is supportive, office is nice, lunch is free, job is interesting. But like you got marry and went to honeymoon, this period does not last forever. Back to reality, I have to be pragmatic, find the way to integrate to the team and the community, be helpful and continue the journey in my career path.
&lt;br&gt;
Weather is Spain in this season is good especially in the morning, drop me a call or a message whenever you go Madrid, I would love to meet you for a drink, tapas.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-7616194854438991132?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/7616194854438991132/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=7616194854438991132&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7616194854438991132'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7616194854438991132'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/08/joining-to-ing-direct-spain.html' title='Joining to ING Direct Spain'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-4071270323806729451</id><published>2009-07-12T17:58:00.007+09:00</published><updated>2009-07-12T21:03:58.913+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='resume-admin'/><title type='text'>My Resume - SUMMARY of SKILLS</title><content type='html'>&lt;hr/&gt;
&lt;h4&gt;System administration, support and maintenance&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
Responsible for large scale WebSphere Application Server ND and WebSphere MQ infrastructure used by  iFlex (Oracle Flexcube) retail banking system for a leading consumer bank. 
&lt;/li&gt;
&lt;li&gt;
Led a team, that provide remote and onsite support 24/7 distributed critical J2EE application based on WebLogic and Oracle Database for immigration control. 
&lt;/li&gt;
&lt;li&gt;
Directly involved in identification and analysis critical problems, was interface point with vendors, customers, and management in incident handling, problems solving process
&lt;/li&gt;
&lt;li&gt;
Well versed in using scripting language (RUBY, PYTHON) to automate all kinds of administrative activities including software installation, update; configuration management; application deployment, update; testing; monitoring; and log file management
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Java and J2EE Application Server&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
More than 5 years experience with JAVA platform and J2EE framework particularly Websphere, WebLogic. Directly involved in capacity planning, application packaging,  deployment, monitoring, troubleshooting that includes sizing memory, thread pools, setting transaction's timeout, maintaining resource pool, etc..
&lt;/li&gt;
&lt;li&gt;
Well understood internal JVM and its assembler language (byte code). Hands-on experience in tools and technique for identifying JVM and J2EE problem such as analyzing heap dump, core dump, garbage collector, decompile byte code, injection tracing code into application and container code.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Messaging System&lt;/h4&gt;
&lt;ul&gt; 
&lt;li&gt;
More then 7 years in design and implementation of software systems that communicate with each other using asynchronous messages. Understand message creation and processing patterns (Enterprise Integration Patterns) and their applications in real world systems. 
&lt;/li&gt;
&lt;li&gt;
Responsible for deployment IBM MQ as message backbone for many applications. The responsibility includes interfacing with development team for planning and configuration, testing, trial run, installation, monitoring and troubleshooting
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
Database System 
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
More then 10 years extensive working experience on RDBMS Oracle in both administrator and developer role. Obtained certification on Oracle DBA in 1999, hand-on experiences in large site capacity planning, performance tuning, high availability using Real Application Cluster (RAC) and Data Guard.
&lt;li&gt;
Involved in database design for many enterprise projects, assisted  implementation team in evolving database schema, data migration and cleansing.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Operating System and Hardware&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
More than 10 years experience in design, installation, administration and troubleshooting complex IT infrastructure including UNIX clustering system, IBM FC and iSCSI SAN, CISCO router and PIX firewall
&lt;/li&gt;
&lt;li&gt;
Hand-on experience in AIX administration including HACMP. Obtained certification on AIX administration in 1999. Performed installation, configuration, tuning many AIX based systems(s), making them ready for deployment Oracle Database and J2EE application server.
&lt;li&gt;
Involved in technical pre-sale activities including sizing a system, proposal preparation, technical presentation and alike.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Software Development&lt;/h4&gt; 
&lt;ul&gt;
&lt;li&gt;
More than 15 years experience in developing software products with deep knowledge of architecture / design of multi-tiered client-server systems based on middleware including Tuxedo, J2EE (WebSphere, WebLogic) and other emerging Web framework as Ruby on Rails. 
&lt;/li&gt;
&lt;li&gt;
Skillful in many programming languages including C/C++, JAVA, SQL, PL/SQL, RUBY. Passionate for the simple and easy to understand software with rich domain model. Well versed in OOP, design patterns (Design Patterns - GoF, Pattern for Enterprise Application Architecture - PEAA, Domain Driven Design). 
&lt;/li&gt;
&lt;li&gt;
Strong knowledge of algorithms and data structures and their applications in writing a high performance, time critical system for complex business domain.
&lt;/li&gt;
&lt;li&gt;
Extensive experience with state of art software development practices such as pair programming, Test Driven Development (TDD), refactoring, continuous integration.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Business Analysis and Leadership&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
Able to attract, retain and lead people. Led team up to 25 developers, responsible for task planning, technical direction, risk management, code inspections, quality control, performance reviews, staff development. Understood how to create working environment to keep people happy, motivated, creative and productive. 
&lt;/li&gt;
&lt;li&gt;
Solid presentation skill, proven in communication with customers, understanding problems, capturing domain knowledge and turning it into high level requirements in suitable form for development team and other stakeholders
&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-4071270323806729451?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/4071270323806729451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=4071270323806729451&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4071270323806729451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4071270323806729451'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/07/my-resume-summary-of-skills.html' title='My Resume - SUMMARY of SKILLS'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-4770394435796225850</id><published>2009-06-05T17:49:00.011+09:00</published><updated>2009-06-12T09:37:14.742+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='jboss'/><title type='text'>Context root of single war's web applicaton in JBoss</title><content type='html'>Context root of web application is usually specifiedin &lt;code&gt;META-INF/application.xml&lt;/code&gt; in ear file (or a vendor specific jboss-web.xml inside war ) e.g. 
&lt;br&gt;
&lt;pre&gt;
...
  &amp;lt;module&amp;gt;
    &amp;lt;web&amp;gt;
      &amp;lt;web-uri&gt;app.war&amp;lt;/web-uri&amp;gt;
      &amp;lt;context-root&amp;gt;/jsfejb3&amp;lt;context-root&amp;gt;
    &amp;lt;/web&amp;gt;
  &amp;lt;/module&amp;gt;
..
&lt;/pre&gt;
However if we drop a single war file without vendor specific descriptor (jboss-web.xml) into JBoss &lt;code&gt;deploy&lt;/code&gt; directory then context root is implicitly the name of the war file without extension. 
&lt;br&gt;
e.g. 
&lt;br&gt;
Web application jmx-console residing in &lt;code&gt;default/deploy/jmx-console.war&lt;/code&gt; has context root &lt;code&gt;jmx-console&lt;/code&gt;
&lt;br&gt;
Web application groovy-scripts residing in &lt;code&gt;default/deploy/groovy-script.war&lt;/code&gt; has context root &lt;code&gt;groovy-script&lt;/code&gt; and can be accessible via http://localhost:7080/groovy-script&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-4770394435796225850?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/4770394435796225850/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=4770394435796225850&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4770394435796225850'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4770394435796225850'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/06/context-root-of-single-wars-web.html' title='Context root of single war&apos;s web applicaton in JBoss'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-6602655016249930430</id><published>2009-05-31T08:54:00.007+09:00</published><updated>2010-12-08T17:51:57.121+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Centralized Management Tools</title><content type='html'>&lt;a href="http://www.nagios.org/"&gt;Nagios&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.quest.com/bigbrother/"&gt;Big Brother&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.hyperic.com/"&gt;Hyperic HQ&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.jboss.org/jopr/"&gt;JOPR&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.industry.siemens.de/ito/business-process-monitoring/EN/INDEX.HTM"&gt;@ctiveFriend&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.oracle.com/technology/products/oem/index.html"&gt;OEM&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.opennms.org/"&gt;OpenNMS&lt;/a&gt;
&lt;br&gt;
There is a great presentation of monitoring tools &lt;a href="http://www.slideshare.net/tomdc/open-source-monitoring-tools-shootout?type=presentation"&gt;here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-6602655016249930430?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/6602655016249930430/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=6602655016249930430&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6602655016249930430'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6602655016249930430'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/05/centralized-management-softwares.html' title='Centralized Management Tools'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-667841000488205291</id><published>2009-05-16T09:11:00.002+09:00</published><updated>2009-05-16T09:16:45.292+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jopr'/><title type='text'>Testing JOPR 2.2.0 - Basic configuration</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Modify JBoss server startup options to include JVM as child resource of JBoss Server in JOPR&lt;/span&gt;
&lt;pre&gt;
#$JBOSS_HOME/bin/run.conf
JAVA_OPTS="$JAVA_OPTS -Djboss.platform.mbeanserver"
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Remove an uninterested resource from management a.k.a uninventory&lt;/span&gt;
&lt;br&gt;
Browse &lt;code&gt;Resources-&gt;Servers&lt;/code&gt;, select uninterested one, hit uninventory button&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-667841000488205291?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/667841000488205291/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=667841000488205291&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/667841000488205291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/667841000488205291'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/05/jopr-basic-configuration.html' title='Testing JOPR 2.2.0 - Basic configuration'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-7791857157447576187</id><published>2009-05-02T10:23:00.057+09:00</published><updated>2009-05-16T09:16:25.065+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='jopr'/><title type='text'>Testing JOPR 2.2.0 - Installation</title><content type='html'>&lt;span style="font-weight:bold;"&gt;What is JOPR, RHQ, JBoss ON &lt;/span&gt;
&lt;br&gt;
JOPR is an open source project from Redhat to develop complex management platform. JOPR is agent based JAVA/J2EE system, where  agent is standalone JAVA running and server runs on top of JBOSS Application Server(AS). It can be used to manage JBOSS AS, Tomcat, Apache as well as Oracle, and any IT resources.
&lt;br&gt;
&lt;br&gt;
JBoss Operations Network (JBoss ON) is commercial offer of JOPR in form of support service by Redhat. 
&lt;br&gt;
&lt;br&gt;
JOPR is developed on top of RHQ project. RHQ serves as an maven upstream project for JOPR. RHQ consists of GUI management console, agent container and a set of agent plugins for management of common IT resources. 
&lt;br&gt;
JOPR extends RHQ by adding additional plugins for JBoss App Server, Tomcat Web Server, etc. . JOPR version 2.2.0 is corresponding with RHQ version 1.2.0.
&lt;br&gt;
&lt;br&gt;
The original of RHQ is &lt;a href="http://www.hyperic.com/"&gt;Hyperic HQ&lt;/a&gt;. Redhat and Hyperic work together to extract common reusable parts of Hyperic HQ and maintain it as RHQ. The aim is to create a common infrastructure for developing management's application. That is why the project named RHQ, where R stand for Redhat. 
&lt;br&gt;
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Install JOPR Server&lt;/span&gt;
&lt;br&gt;
Download JOPR binary from &lt;a href="http://www.jboss.org/jopr/"&gt;JOPR website&lt;/a&gt; 
&lt;br&gt;
Follow instruction in &lt;a href="http://www.redhat.com/docs/en-US/JBoss_ON/2.2/html/Installation_Guide/index.html"&gt;Installation Guide&lt;/a&gt; to prepare database server for JOPR server
&lt;br&gt;
Change working directory to jopr-server-2.2.0 and type 
&lt;pre&gt;
bin/rhq-server.sh start
&lt;/pre&gt; 
then open web browser and point to &lt;code&gt;http://localhost:7080&lt;/code&gt;
&lt;br&gt;
Follow instructions in screen to set database driver, url, username/password to correct values. After that verify database connection.
&lt;br&gt;
Hit button &lt;code&gt;Install JOPR server&lt;/code&gt; to complete installation process
&lt;br&gt;
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Modify JOPR server properties file for agent communication&lt;/span&gt;
&lt;br&gt;
Modify rhq-server.properties file
&lt;pre&gt;
# jopr-server-2.2.0/bin/rhq-server.properties
rhq.communications.connector.transport=servlet
rhq.communications.connector.bind-address=&amp;lt;jopr-server-ip-address&amp;gt;
rhq.communications.connector.bind-port=7080
&lt;/pre&gt;
Restart JOPR server
&lt;pre&gt;
bin/rhq-server.sh stop
bin/rhq-server.sh start
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Login to JOPR console and watch its log file&lt;/span&gt;
&lt;br&gt;
Pointing Web browser to &lt;code&gt;http://localhost:7080/Dashboard.do&lt;/code&gt;
&lt;br&gt;
Login use default &lt;code&gt;rhqadmin/rhqadmin&lt;/code&gt; as initial username/password
&lt;br&gt;
JOPR log file is located in &lt;code&gt;jopr-server-2.2.0/logs/rhq-server-log4j.log&lt;/code&gt;
&lt;br&gt;
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Install JOPR Agent &lt;/span&gt;
&lt;br&gt;
This shall be done in all machines that we want JOPR to manage .
&lt;br&gt;
Download agent from &lt;code&gt;http://&amp;lt;jopr-server-hostname&amp;gt;:7080/agentupdate/download&lt;/code&gt; 
&lt;br&gt;
Install JOPR Agent by typing
&lt;pre&gt;
java -jar rhq-enterprise-agent-1.2.0.jar --install
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Modify JOPR Agent configuration file&lt;/span&gt;
&lt;pre&gt;
#rhq-agent/conf/agent-configuration.xml

# ask jopr agent not to ask for configuration during startup
&amp;lt;entry key="rhq.agent.configuration-setup-flag" value="true" /&amp;gt;

&amp;lt;entry key="rhq.agent.name" value="&amp;lt;jopr-agent-hostname&amp;gt;"/&amp;gt;

&amp;lt;entry key="rhq.agent.server.bind-address" value="&amp;lt;jopr-server-ip-address&amp;gt;" /&amp;gt;

# ask jopr agent to listen to on particular ip
&amp;lt;entry key="rhq.communications.connector.bind-address" value="&amp;lt;jopr-agent-ip-address&amp;gt;" /&amp;gt;
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Start RHQ Agent and watch its log file&lt;/span&gt;
&lt;br&gt;
change working directory to rhq-agent and run
&lt;pre&gt;
bin/rhq-agent.sh -c conf/agent-configuration.xml 
&lt;/pre&gt;
If we reinstall JOPR server then agent's local data and server'data is not in sync. In that case we shall ask agent to clean it's local data when start by using
&lt;pre&gt;
bin/rhq-agent.sh -l -c conf/agent-configuration.xml 
&lt;/pre&gt;  
The most recent agent's log file is located in &lt;code&gt;rhq-agent/logs/agent.log&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-7791857157447576187?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/7791857157447576187/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=7791857157447576187&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7791857157447576187'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7791857157447576187'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/05/using-jboss-opertation-management-on.html' title='Testing JOPR 2.2.0 - Installation'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-6723233367295969512</id><published>2009-04-30T19:48:00.007+09:00</published><updated>2009-05-05T10:03:35.271+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>Develop an international career - Recruiters</title><content type='html'>Recruiters (a.k.a Head Hunters) play a vital role in the job market. Many big companies use services of recruiters when they need to hire someone (they do not recruit directly). I myself and a lot of my colleagues got a job by a recruiter.  
&lt;br&gt;
Below is a list of the most well known recruiters
&lt;br&gt;
- &lt;a href="www.roberthalf.com"&gt;Robert Half&lt;/a&gt;
&lt;br&gt;
- &lt;a href="http://www.robertwalters.com/default.do"&gt;Robert Walters&lt;/a&gt;
&lt;br&gt;
- &lt;a href="www.hays.com"&gt;Hays&lt;/a&gt;
&lt;br&gt;
- &lt;a href="http://www.wallstreetglobalcareers.com/"&gt;Wall Street&lt;/a&gt;
&lt;br&gt;
- &lt;a href="http://hudson.com"&gt;Hudson&lt;/a&gt;
&lt;br&gt;
There are many smaller but also very good recruiters, who are constantly looking for a good candidate in all countries over the world. If you are somehow visible and your skill fit a opening position, they will contact you. 
&lt;br&gt;
I got my first job via placement of a smaller recruiter named Juno located in New York.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-6723233367295969512?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/6723233367295969512/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=6723233367295969512&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6723233367295969512'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6723233367295969512'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/04/develop-international-career-recuiter.html' title='Develop an international career - Recruiters'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-6681774687544910627</id><published>2009-04-29T17:45:00.010+09:00</published><updated>2009-06-24T19:01:44.290+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='jopr'/><category scheme='http://www.blogger.com/atom/ns#' term='jboss'/><title type='text'>JBoss resources</title><content type='html'>&lt;a href="http://www.mastertheboss.com/en/jboss-application-server.html"&gt;JBOSS configuration and tunning articles from Master the Boss&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://blogs.adobe.com/livecycle/2006/10/running_multiple_jboss_instanc.html"&gt;Running Multi JBoss Instances&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.learntechnology.net/content/main.jsp"&gt;Good examples of EJB 2.1, EJB 3 from Learn Technology&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.redhat.com/docs/en-US/JBoss_Enterprise_Application_Platform/"&gt;JBoss Official Docs &amp; Examples from Redhat&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.redhat.com/docs/en-US/JBoss_ON/"&gt;JBoss Operation Network (ON), a.k.a JOPR - Documents&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.redhat.com/docs/en-US/JBoss_ON/html/FAQs/index.html"&gt;JBoss ON - FAQ&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://support.rhq-project.org/display/RHQ/Home"&gt;RHQ project, upon it JOPR depends&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.jboss.org/jopr/"&gt;JOPR project&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://management-platform.blogspot.com/"&gt;A blog on RHQ, JOPR, JBoss ON&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-6681774687544910627?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/6681774687544910627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=6681774687544910627&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6681774687544910627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6681774687544910627'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/04/jboss-links.html' title='JBoss resources'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-7114627986157347845</id><published>2009-04-25T09:09:00.012+09:00</published><updated>2009-05-01T08:07:37.871+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>Develop an international career - Make yourself visible</title><content type='html'>No matter how good and skilled you are,it is useless if no one know about it. So make yourself visible, post your resume to professional websites and social networks, create your own blog, subscribe to interested user groups, participate in an online discussion.
&lt;br&gt;
Keep in mind that all these techniques only work if you keep your data up to date. When a recruiter doing executive search and find your resume within dozens of others,he/she will easily exclude you if your resume is 2 years old.
&lt;br&gt;
&lt;br&gt;
Few years back I created my blog. It has only professional content and I decided to keep it in English because my intention is not to have many readers but the right one. Those are recruiters, potential employers and colleagues. I believe, that it helps me to get my first and also second job. Looking at site analytic of the blog, I don't see much traffic but I can identify those coming from area where I received a job offer or where my recruiter is located.
&lt;br&gt;
&lt;br&gt;
&lt;a href="http://www.linkedin.com/"&gt;Linked In&lt;/a&gt; is great social networking site for professionals, so I would recommend to register and put your career information there.
&lt;br&gt;
&lt;br&gt;
Again, don't expect anything happened over night, it will take time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-7114627986157347845?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/7114627986157347845/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=7114627986157347845&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7114627986157347845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7114627986157347845'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/04/develop-international-career-make.html' title='Develop an international career - Make yourself visible'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-840818863502194500</id><published>2009-04-22T13:50:00.017+09:00</published><updated>2009-05-01T16:56:55.390+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>Develop an international career - Resume</title><content type='html'>This post is created (based on my own experiences) for people who want to work out of their home countries and therefore develop their career internationally. It can be used as an advice.
&lt;br&gt;
You have generally only one career, so don't let it goes based on some unexpected events. If you really want to work abroad in developed countries, be prepared that it will take time to get a job. It can be two years or more depending on many factors. During this time, you may need take many actions to move into that direction. 
&lt;br&gt;
&lt;br&gt;
Resume (a.k.a CV) is your ticket for entering job market. Write your resume with care and update it gradually and of course it should be in English. During last few years, I spend many hours to re-write many time my resume as well as to ask friends, colleagues and career's adviser for my resume's correction. I have to admit that I am still not satisfied with my resume as there is a lot of things to improve.
&lt;br&gt;
&lt;br&gt;
I also spend time to read resume of others, who work in the same industries and/or share a similar knowledge and career path. It help me a lot to get know how others present themselves, so I can adjust my resume to highlight my strength. 
&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-840818863502194500?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/840818863502194500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=840818863502194500&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/840818863502194500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/840818863502194500'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/04/develop-your-international-career-value.html' title='Develop an international career - Resume'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-990926664080342793</id><published>2009-04-01T11:29:00.008+09:00</published><updated>2009-06-08T09:55:08.431+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='jboss'/><title type='text'>Java Class Loader's links</title><content type='html'>&lt;a href="http://impalablog.blogspot.com/2008/10/using-threads-context-class-loader-in.html"&gt;Impala blog post - Thread Context Class Loader &lt;/a&gt; 
&lt;br&gt;
&lt;a href="http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html"&gt;Java World - Class Loader article&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.onjava.com/pub/a/onjava/2005/01/26/classloading.html"&gt;On Java - Internals of Java Class Loading&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.jboss.org/community/docs/DOC-10290"&gt;Advanced JBoss Class Loading&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://wiki.eclipse.org/index.php/Context_Class_Loader_Enhancements"&gt;Equinox OSGi Context Class Loader Enhancements&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-990926664080342793?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/990926664080342793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=990926664080342793&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/990926664080342793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/990926664080342793'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/04/java-class-loader.html' title='Java Class Loader&apos;s links'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-8079072760512266494</id><published>2009-03-03T14:05:00.004+09:00</published><updated>2009-07-12T17:53:16.739+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='resume-admin'/><category scheme='http://www.blogger.com/atom/ns#' term='resume-developer'/><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>My resume - LANGUAGE</title><content type='html'>&lt;hr
 /&gt;&lt;ul
&gt;&lt;li
  &gt;Vietnamese, English, Czech&lt;/li
  &gt;&lt;/ul
&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-8079072760512266494?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/8079072760512266494/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=8079072760512266494&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8079072760512266494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8079072760512266494'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/03/language.html' title='My resume - LANGUAGE'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-5035153110480318425</id><published>2009-03-03T14:04:00.004+09:00</published><updated>2009-07-12T17:54:05.624+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='resume-admin'/><category scheme='http://www.blogger.com/atom/ns#' term='resume-developer'/><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>My resume - EDUCATION</title><content type='html'>&lt;hr
 /&gt;&lt;p
&gt;Charles University Prague, Czech Republic&lt;/p
&gt;&lt;ul
&gt;&lt;li
  &gt;MS in Computer Science (data engineering specialization) - 1997&lt;/li
  &gt;&lt;li
  &gt;BS in Computer Science - 1994&lt;/li
  &gt;&lt;/ul
&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-5035153110480318425?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/5035153110480318425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=5035153110480318425&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5035153110480318425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5035153110480318425'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/03/education.html' title='My resume - EDUCATION'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-2535836758028458785</id><published>2009-02-14T23:09:00.009+09:00</published><updated>2009-03-02T09:13:02.275+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Using CINT - C/C++ Interpreter - An experiment with vector</title><content type='html'>Let do something with vector
&lt;pre&gt;
cint.exe&gt; L vector
cint.exe&gt; {vector&amp;lt;int&amp;gt; temps;}
cint.exe&gt; {temps.push_back(6);}
cint.exe&gt; {temps.push_back(4);}
cint.exe&gt; {temps.push_back(5);}
cint.exe&gt; {temps.size();}
(const unsigned int)3
cint.exe&gt; {temps[0];}
(int)6
cint.exe&gt; {temps[1];}
(int)4
cint.exe&gt; {temps[2];}
(int)5
cint.exe&gt;
&lt;/pre&gt;
So it works well, now there is time to try some algorithm
&lt;pre&gt;
cint.exe&gt; L algorithm
cint.exe&gt; {sort(temps.begin(),temps.end());}
Error: Template Function value_type(first) is not defined in current scope  algo.h(735)
!!!Dictionary position rewound... !!!Error recovered!!!
cint.exe&gt;
&lt;/pre&gt;
It seems that there is some problem with STL lib coming with CINT in Windows. Looking at STL header files, I found that Function &lt;code&gt;value_type&lt;/code&gt; is declared in &lt;code&gt;_iterator.h&lt;/code&gt; surrounded by a condition for whatever reason
&lt;pre&gt;
#if (G__GNUC&gt;=3)

#if (G__GNUC_VER&gt;=3001) 
...
template &lt;class T&gt; 
inline T* value_type(const vector&lt;T&gt;::iterator&amp;) {return (T*)(0);}
..
#endif
#endif
&lt;/pre&gt;
To fix it is fairly simple
&lt;pre&gt;
d:\cint-5.16.19\cint.exe
cint : C/C++ interpreter  (mailing list 'cint@root.cern.ch')
   Copyright(c) : 1995~2005 Masaharu Goto (gotom@hanno.jp)
   revision     : 5.16.19, March 16, 2007 by M.Goto

No main() function found in given source file. Interactive interface started.
'h':help, 'q':quit, '{statements;}' or 'p [expr]' to evaluate

cint.exe&gt; {#define G__GNUC 4}
cint.exe&gt; {#define G__GNUC_VER 4001}
cint.exe&gt; L vector
cint.exe&gt; L algorithm
cint.exe&gt; {vector&amp;lt;int&amp;gt; temps;}
cint.exe&gt; {temps.push_back(6);}
cint.exe&gt; {temps.push_back(4);}
cint.exe&gt; {temps.push_back(5);}
cint.exe&gt; {temps.size();}
(const unsigned int)3
cint.exe&gt; {temps[0];}
(int)6
cint.exe&gt; {temps[1];}
(int)4
cint.exe&gt; {temps[2];}
(int)5
cint.exe&gt; {sort(temps.begin(),temps.end());}
cint.exe&gt; {temps[0];}
(int)4
cint.exe&gt; {temps[1];}
(int)5
cint.exe&gt; {temps[2];}
(int)6
cint.exe&gt;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-2535836758028458785?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/2535836758028458785/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=2535836758028458785&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2535836758028458785'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2535836758028458785'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/02/using-cint-cc-interpreter-first-attempt.html' title='Using CINT - C/C++ Interpreter - An experiment with vector'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-6841766158013041400</id><published>2009-02-14T22:21:00.010+09:00</published><updated>2009-03-02T09:13:29.934+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Using CINT - C/C++ Interpreter - Basic Commands</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Load,Unload,files&lt;/span&gt; &lt;br&gt;
&lt;code&gt;L&lt;/code&gt; that load files into interpreter, and &lt;code&gt;file&lt;/code&gt; that list these loaded files.
&lt;pre&gt;
cint.exe&gt; L iostream
cint.exe&gt; files
  0 fp=0x781c1bd0 lines=13   file="iostream"
  1 fp=0x781c1bf0 lines=479  file="iostream.h"
  2 fp=0x781c1c10 lines=11  *file="iosenum.h"
  3 fp=0x781c1c30 lines=34   file="bool.h"
  4 fp=0x781c1c50 lines=173 *file="_iostream"
&lt;/pre&gt;
If we use &lt;code&gt;#include&lt;/code&gt; in curly bracket, we will get the same result
&lt;pre&gt;
cint.exe&gt; {#include &amp;lt;iostream&amp;gt;}
cint.exe&gt; files
  0 fp=0x781c1bf0 lines=13   file="iostream"
  1 fp=0x781c1c10 lines=479  file="iostream.h"
  2 fp=0x781c1c30 lines=11  *file="iosenum.h"
  3 fp=0x781c1c50 lines=34   file="bool.h"
  4 fp=0x781c1c70 lines=173 *file="_iostream"
&lt;/pre&gt;
&lt;code&gt;U&lt;/code&gt; command unload a file, a C/C++ header file can include other header files, which in turn can include additional header files and so all. CINT is good enough and maintain this dependencies so if we unload one file, others referenced files may get unloaded also.
&lt;pre&gt;
cint.exe&gt; L string
cint.exe&gt; files
  0 fp=0x781c1bd0 lines=11   file="string"
  1 fp=0x781c1bf0 lines=72   file="_string"
  2 fp=0x       0 lines=0    file="string.dll"
  3 fp=0x781c1c10 lines=13   file="iostream"
  4 fp=0x781c1c30 lines=479  file="iostream.h"
  5 fp=0x781c1c50 lines=11  *file="iosenum.h"
  6 fp=0x781c1c70 lines=34   file="bool.h"
  7 fp=0x781c1c90 lines=173 *file="_iostream"
cint.exe&gt; U string
cint.exe&gt; files
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;reset&lt;/span&gt; &lt;br&gt;
&lt;code&gt;reset&lt;/code&gt; reset interpreter environment and unload all files
&lt;pre&gt;
cint.exe&gt; {int a=1;}
cint.exe&gt; {a;}
(int)1
cint.exe&gt; reset
cint.exe&gt; {a;}
Error: Symbol a is not defined in current scope  (tmpfile)(1)
!!!Dictionary position rewound... !!!Error recovered!!!
cint.exe&gt; L vector
cint.exe&gt; files
  0 fp=0x781c1bd0 lines=11   file="vector"
  1 fp=0x781c1bf0 lines=18   file="_vector"
  2 fp=0x       0 lines=0    file="vector.dll"
  3 fp=0x       0 lines=0    file="vectorbool.dll"
  4 fp=0x781c1c10 lines=313  file="_vector.h"
  5 fp=0x781c1c30 lines=282  file="function.h"
  6 fp=0x781c1c50 lines=34   file="bool.h"
  7 fp=0x781c1c70 lines=235  file="algobase.h"
  8 fp=0x781c1c90 lines=55   file="_pair.h"
  9 fp=0x781c1cb0 lines=17   file="_iterator"
 10 fp=0x781c1cd0 lines=668  file="_iterator.h"
 11 fp=0x781c1cf0 lines=6    file="stddef.h"
 12 fp=0x781c1d10 lines=479  file="iostream.h"
 13 fp=0x781c1d30 lines=11  *file="iosenum.h"
 14 fp=0x781c1d50 lines=173 *file="_iostream"
 15 fp=0x781c1d70 lines=177  file="defalloc.h"
 16 fp=0x781c1d90 lines=34   file="new.h"
 17 fp=0x781c1db0 lines=34   file="stdio.h"
 18 fp=0x       0 lines=0    file="stdfunc.dll"
 19 fp=0x781c1dd0 lines=14   file="stdlib.h"
 20 fp=0x  476800 lines=19   file="limits.h"

-- Press return for more -- (input [number] of lines, Cont,Step,More)
cint.exe&gt; reset
cint.exe&gt; files
cint.exe&gt;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-6841766158013041400?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/6841766158013041400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=6841766158013041400&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6841766158013041400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6841766158013041400'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/02/using-cint-cc-interpreter-basic.html' title='Using CINT - C/C++ Interpreter - Basic Commands'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-6970513901817489966</id><published>2009-02-11T19:22:00.017+09:00</published><updated>2009-03-02T09:13:50.770+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Using CINT - C/C++ Interpreter - Getting Started</title><content type='html'>One of things I favor scripting languages (Ruby, Python) over none scripting (JAVA, C/C++) is there is no need to follow time consuming cycle of write-compile-run. Even with the best IDE, I still feels the pain of typing command, hit key combination, waiting for computer doing.  This is especially true when I need to explore some API, test some ideas.

So when I discovered &lt;a href="http://root.cern.ch/drupal/content/cint"&gt;CINT&lt;/a&gt;, a C/C++ Interpreter, I gave it a try. With CINT, we can type C/C++ code directly in it's interactive CINT console and get the result. CINT is available for Windows and many UNIX platform(s) some LINUX clone has CINT pre-installed.
We start CINT console by type e.g. (on Windows)
&lt;pre&gt;
d:\cint-5.16.19\cint.exe
cint.exe&gt;{#include &amp;lt;iostream&amp;gt;
cint.exe&gt;{cout &lt;&lt; "Hello World\n";}  
Hello World (class ostream)2085223112 
&lt;/pre&gt;

C/C++ code shall be type inside curly bracket &lt;code&gt;{...}&lt;/code&gt;, CINT doesn't allow to define function in interactive console
&lt;pre&gt;
&gt; { int func999() {return 999;} }
Limitation: Function can not be defined in a command line or a tempfile
You need to write it in a source file (tmpfile)(1)
!!!Dictionary position rewound... !!!Error recovered!!!
&lt;/pre&gt;
So we have to create separate file e.g.
&lt;pre name="code" class="Cpp"&gt;
# func999.cpp
int func999() {
return 999;
}
&lt;/pre&gt;
,load it in the console and call a function inside
&lt;pre&gt;
cint.exe&gt;L func999.cpp
cint.exe&gt;{func999();}
&lt;/pre&gt;
Some of the most frequently used commands includes
&lt;pre&gt;
L &lt;filename&gt; - load file in to the console
U &lt;filename&gt; - unload the file
file - show which files are currently loaded
reset - reset memory of CINT console to initial state,unload all files
q - quit CINT console
&lt;/filename&gt;&lt;/filename&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-6970513901817489966?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/6970513901817489966/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=6970513901817489966&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6970513901817489966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6970513901817489966'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/02/using-cint-cc-interpreter.html' title='Using CINT - C/C++ Interpreter - Getting Started'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-4850451187492369428</id><published>2009-01-12T15:32:00.009+09:00</published><updated>2009-04-22T16:13:15.530+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>Retrospective 2008</title><content type='html'>Year 2008 was marked by an important event of my life and my career. I have joined ING Direct Japan (INGDJ) and moved to Tokyo in September. So far I feel OK.  Within last 4 months, I have done a couple of things. Technically
&lt;br&gt;
1. Learned how to manage WebSphere Application Server and MQ infrastructure in a complex IT environment for banking business.
&lt;br&gt;
2. Write a bundle of ruby scripts to perform administrative activities related to WebSphere including system monitoring, log management and application deployment.
&lt;br&gt;
3. Learned JVM internal stuff like GC, heap dump, core dump analysis tools, JAVA decompiler and JVM assembler language
&lt;br&gt;
4. Use VIM (as primary editor) and GIT
&lt;br&gt;
5. Learned Python and it's Java implementation Jython primarily and use it for WebSphere Application Server scripting&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-4850451187492369428?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/4850451187492369428/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=4850451187492369428&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4850451187492369428'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4850451187492369428'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2009/01/retrospective-2008.html' title='Retrospective 2008'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-7140935795413651666</id><published>2008-11-28T22:56:00.019+09:00</published><updated>2008-11-29T14:48:00.003+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='vim'/><title type='text'>Using VIM in troubleshooting JAVA application</title><content type='html'>After trying many Text Editor available on Windows as TexPad, UltraEdit, Wordpad, Notepad, etc. , finally I decided to use vim, an enhanced version of unix vi. Vim is never been an easy choice but once you master it, it is wonderful, it give you high productivity. Also it is free.&lt;br&gt;
Some basic vi commands can be found in  &lt;a href="http://www.cs.uiuc.edu/class/fa07/cs225/calendar/vim.pdf"&gt;http://www.cs.uiuc.edu/class/fa07/cs225/calendar/vim.pdf&lt;/a&gt;. &lt;br&gt;
During my daily work, I often have to troubleshoot complex JAVA application. Sometime I get exception with full JAVA stack printout, but the application is provided by vendor without source code so there is very difficult to find a root cause. &lt;br&gt; 
There is a tool called JAD that can decompile JAVA classes. Because my primary editor is VIM so I decided to integrate the JAD into VIM. Googling a while, I found vim JAD plugin, that display decompiled java class whenever we open the class file. However JAVA application(s) are mostly provided in form of several jar, zip, ear package so it is not so convenient. &lt;br&gt;
There is luckily zip plugin that is part of vim installation and can browse zip, jar, ear package and display content of selected file inside the package when we hit enter. Modify just few lines of this plugin, I am able to browse content of jar, zip file and view a decompiled inside JAVA class.&lt;br&gt;
The steps is as follows (for version 7.2, that was installed in D:\Vim\)&lt;br&gt;&lt;br&gt;
1. open D:\Vim\vim72\autoload\zip.vim and change 
&lt;pre&gt;
fun! zip#Read(fname,mode)
...
  exe "silent r! ".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fname,1)
...
endfun
&lt;/pre&gt;
to
&lt;pre&gt;
fun! zip#Read(fname,mode)
...
 if fname =~ '.class$'
   exe "silent r! ".g:zip_unzipcmd." -o -- ".s:Escape(zipfile,1)." ".s:Escape(fname,1)
   exe "silent r! jad -lnc -p ".s:Escape(fname,1)
 else
   exe "silent r! ".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fname,1)
 endif
...
endfun
&lt;/pre&gt;

2. download unzip.exe, jad.exe and put them in the PATH
&lt;br&gt;
3. start vim and open a jar file, a list of files inside the jar file will be displayed
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hSKkcklzwTU/STDR57qViKI/AAAAAAAAAHA/K8WzTfPqf74/s1600-h/browse-jar.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 287px;" src="http://3.bp.blogspot.com/_hSKkcklzwTU/STDR57qViKI/AAAAAAAAAHA/K8WzTfPqf74/s400/browse-jar.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5273945956848863394" /&gt;&lt;/a&gt;

&lt;br&gt;
4. select one class file and hit ENTER
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hSKkcklzwTU/STDRuJiFWjI/AAAAAAAAAG4/w2tjT4461dQ/s1600-h/view-class.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 287px;" src="http://4.bp.blogspot.com/_hSKkcklzwTU/STDRuJiFWjI/AAAAAAAAAG4/w2tjT4461dQ/s400/view-class.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5273945754413914674" /&gt;&lt;/a&gt;
The '-lnc' option of JAD display line number of original source code as comment on the left side of decompiled code so it can be used to identify which part of code cause an exception.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-7140935795413651666?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/7140935795413651666/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=7140935795413651666&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7140935795413651666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7140935795413651666'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2008/11/switch-to-vim.html' title='Using VIM in troubleshooting JAVA application'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_hSKkcklzwTU/STDR57qViKI/AAAAAAAAAHA/K8WzTfPqf74/s72-c/browse-jar.PNG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-5314808624434372877</id><published>2008-11-08T08:03:00.043+09:00</published><updated>2011-05-24T15:04:23.678+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Simple Python Syntax</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Start interpreter and print out something then exit &lt;/span&gt;
&lt;br&gt;
&lt;pre&gt;
C:\python
ActivePython 2.5.2.2 (ActiveState Software Inc.) based on
Python 2.5.2 (r252:60911, Mar 27 2008, 17:57:18) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; print 'hello world'
hello world
&gt;&gt;&gt; print 1+2+3
6
&gt;&gt;&gt; exit()
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Run a script in the interpreter &lt;/span&gt;
&lt;br&gt;
To run a script within Python interpreter use execfile(path), it is useful for people who use Jython, because startup time of JVM is horrible . e.g
&lt;pre&gt;
&gt;&gt;execfile('sample.py')
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Create string from a template&lt;/span&gt;
&lt;br&gt;
This is one of my most frequently used statement, Python follow style of C printf function &lt;br&gt;
&lt;pre&gt;
&gt;&gt;&gt; "my name is %s, my age is %d" % ("Goto",30)
'my name is Goto, my age is 30'
&gt;&gt;&gt;
&lt;/pre&gt;
Ruby has the same function 
&lt;pre&gt;
irb(main):004:0&gt; "my name is %s, my age is %d" % ["Goto",30]
=&gt; "my name is Goto, my age is 30"
irb(main):005:0&gt;
&lt;/pre&gt;
but there is nicer way to do it
&lt;pre&gt;
irb(main):005:0&gt; name,age = "Goto",31
=&gt; ["Goto", 31]
irb(main):006:0&gt; "my name is #{name}, my age is #{age}"
=&gt; "my name is Goto, my age is 31"
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Create a substring from a string&lt;/span&gt;
&lt;br&gt;
Python has nice methods get a substring from string
&lt;pre&gt;
&gt;&gt;&gt; s='hello world'
&gt;&gt;&gt; s[0]
'h'
&gt;&gt;&gt; s[0:10] #substring from a position(inclusive) until other (non inclusive)
'hello worl'
&gt;&gt;&gt; s[2:] #substring to end of string
'llo world'
&gt;&gt;&gt; s[:2] #substring from start until other (non inclusive)
'he' 
&gt;&gt;&gt; s[-2:] #negative position indicates position from end of the string
'ld'
&lt;/pre&gt;
The equivalent in Ruby would be
&lt;pre&gt;
$ irb
&gt;&gt; s="hello world"
=&gt; "hello world"
&gt;&gt; s[0]
=&gt; 104
&gt;&gt; s[0..0]
=&gt; "h"
&gt;&gt; s[0..(10-1)] #unlike Python, Ruby includes the end position
=&gt; "hello worl"
&gt;&gt; s[2..-1] # -1 indicate relative position from end
=&gt; "llo world"
&gt;&gt; s[0..(2-1)]
=&gt; "he"
&gt;&gt; s[-2..-1]
=&gt; "ld"
&lt;/pre&gt;
Unlike Ruby, Python still throw &lt;code&gt;out of range&lt;/code&gt; exception for single indice operation
&lt;pre&gt;
&gt;&gt;&gt; s[20]
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
IndexError: string index out of range
&gt;&gt;&gt; s[20:30] # this is OK as it consider as slice operation
''
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;String is immutable&lt;/span&gt;
&lt;br&gt;
Unlike Ruby, Python string can not be changed directly 
&lt;pre&gt;
&gt;&gt;&gt; s[0:5]
'hello'
&gt;&gt;&gt; s[0:5]="bye"
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
TypeError: 'str' object does not support item assignment
&gt;&gt;&gt; s1 = "bye" + s[5:] # to achieve the same goal we need create string from other string 
&gt;&gt;&gt; print s1
bye world
&lt;/pre&gt;
In Ruby we can do
&lt;pre&gt;
&gt;&gt; s[0..4]="bye"
=&gt; "bye"
&gt;&gt; print s
bye world=&gt; nil
&lt;/pre&gt;
As string is considered value object, create new string instead of changing an existing express that concept more clearly. 
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;List and tuple&lt;/span&gt;
&lt;br&gt;
Python has tuple and list for representation of variable size array of items. Tuple is immutable array while list is mutable. People think that list is intended for homogeneous while tuple is for non-homogeneous, but this is convention only is not enforced by the language. However some api accept only tuple as argument e.g. String format %, that sometime lead to a confusion. In contras Ruby has only Array. &lt;br&gt;
example of tuple
&lt;pre&gt;
&gt;&gt;&gt; y=('a',2)
&gt;&gt;&gt; y[1]=1
Traceback (most recent call last):
  File "&amp;lt;stdin&amp;gt;", line 1, in &amp;lt;module&amp;gt;
TypeError: 'tuple' object does not support item assignment
&gt;&gt;&gt; y
('a', 2)
&lt;/pre&gt;
example of list
&lt;pre&gt;
&gt;&gt;&gt; x=['a',2]
&gt;&gt;&gt; x[1]=1
&gt;&gt;&gt; x
['a', 1]
&lt;/pre&gt;
iterate over list or tuple
&lt;pre&gt;
&gt;&gt;&gt; items = ('a','b',2)
&gt;&gt;&gt; for e in items:
...   print e
...
a
b
2
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Hash aka dictionary &lt;/span&gt;
&lt;br&gt;
Python has hash structure called dictionary
&lt;pre&gt;
&gt;&gt;&gt; h = {1:'a',2:'b',3:'c'}
&gt;&gt;&gt; h.__class__
&amp;lt;type 'dict'&amp;gt;
&gt;&gt;&gt; h[3] = 'z'
&gt;&gt;&gt; h
{1: 'a', 2: 'b', 3: 'z'}
&gt;&gt;&gt;
&lt;/pre&gt;
iterate over dictionary
&lt;pre&gt;
&gt;&gt;&gt; for k,v in h.iteritems():
...   print "%d=&gt;%s" % (k,v)
...
1=&gt;a
2=&gt;b
3=&gt;z
&lt;/pre&gt;
&lt;code&gt;h.items()&lt;/code&gt; also works well 
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Class, Object, method&lt;/span&gt;
&lt;br&gt;
Class is defined using class keyword, name of a class can start lower case or upper case character, which is different from Ruby. Ruby requires name of class start with upper case character. &lt;br&gt;
However the convention is that, name of built-in class as string, unicode, list, tuple start with lower case character while user-defined class starts with upper case.
&lt;br&gt;
example of built-in class
&lt;pre&gt;
&gt;&gt;&gt; y = ('a',2)
&gt;&gt;&gt; y.__class__
&amp;lt;type 'tuple'&amp;gt;
&gt;&gt;&gt; y.__class__ == tuple
True
&gt;&gt;&gt; z = tuple(y)
&gt;&gt;&gt; z
('a', 2)
&lt;/pre&gt;
example of user defined class
&lt;pre&gt;
&gt;&gt;&gt; class Foo:
...   def m(self):
...     print self.__class__
...
&gt;&gt;&gt;
&gt;&gt;&gt; Foo().m()
__main__.Foo
&gt;&gt;&gt;
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Module&lt;/span&gt;
&lt;br&gt;
Every Python script store in a file is a module, the name of the file is module name. 
&lt;pre&gt;
$ cat hello.py
def say(whom):
  return "hello %s" % whom
&lt;/pre&gt;
To use method defined in a module, just import the module and call the function preceding by the module name plus '.'
&lt;pre&gt;
&gt;&gt;&gt; import hello
&gt;&gt;&gt; hello.say('world')
'hello world'
&lt;/pre&gt;
It is also common to mix module methods into current name space, so we can call method without typing module name 
&lt;pre&gt;
&gt;&gt;&gt; from hello import *
&gt;&gt;&gt; say('moon')
'hello moon'
&gt;&gt;&gt;
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Parameters&lt;/span&gt;
&lt;br&gt;
Beside normal position based parameters, Python has two extra forms of passing parameters to a function &lt;code&gt;*params&lt;/code&gt; and &lt;code&gt;**params&lt;/code&gt;. 
&lt;br&gt;
The first form is argument list, in which caller pass a list parameters and calling function receives them in form of an array.
&lt;pre&gt;
 def foo(*numbers):
      return sum(numbers)
 
print foo(23, 42)        # prints: 65
&lt;/pre&gt;
The second form is name based, in which caller pass a list name,value pairs and calling function receives then as a hash map.&lt;pre&gt;
def bar(**options):
  if "verbose" in options and options["verbose"]:
     print "verbose is ON"
  else:
     print "verbose is OFF"

bar(verbose=True) # print: "verbose is ON"
bar(verbose=False) # print: "verbose is OFF"
bar(force=True) # print: "verbose is OFF"

&lt;/pre&gt;
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Closures&lt;/span&gt;
&lt;br&gt;
&lt;a href="http://ivan.truemesh.com/archives/000392.html"&gt;Python closures&lt;/a&gt;
&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-5314808624434372877?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/5314808624434372877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=5314808624434372877&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5314808624434372877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5314808624434372877'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2008/11/run-script-within-python-interpreter.html' title='Simple Python Syntax'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-784666359915149016</id><published>2008-10-30T20:36:00.008+09:00</published><updated>2011-01-01T17:37:58.827+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Where to download RPM  package(s) for RedHat Linux</title><content type='html'>If you are looking for RPM package(s) for LINUX, then you should look at this site &lt;a href="http://linuxsoft.cern.ch/"&gt;http://linuxsoft.cern.ch/&lt;/a&gt;. The binary rpm package are built from source SRPM available in &lt;a href="http://ftp.redhat.com/pub/redhat/linux/enterprise/"&gt;http://ftp.redhat.com/pub/redhat/linux/enterprise/&lt;/a&gt;. They are well organized, complete and updated. The slc4X directory is equivalent to RedHat ES/AS 4 while slc5X to RedHat ES/AS 5. &lt;br&gt;
If you have not RedHat Linux media in hand for what ever reason, this is definitely a good help.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-784666359915149016?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/784666359915149016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=784666359915149016&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/784666359915149016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/784666359915149016'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2008/10/source-of-rpm-package-for-redhat-linux.html' title='Where to download RPM  package(s) for RedHat Linux'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-2059978635188687541</id><published>2008-09-09T12:39:00.007+09:00</published><updated>2009-04-22T16:12:58.804+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>First few days in ING Direct Japan</title><content type='html'>The first day was just for formality. I was given temporary access card (RFID card), seat and account to access the company computer. Then a lady from IT team took me to the local ward office for alien card registration and to local bank (Shinsei) to open a account to which the company can pay me. &lt;br&gt;
The second day is workshop on kind corporate value and culture , they called it Orange value, where we listened to the CEO speed of ING group system of value, did self introduction, play game, conduct group discussion organized by external consultant.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-2059978635188687541?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/2059978635188687541/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=2059978635188687541&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2059978635188687541'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2059978635188687541'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2008/09/first-few-days-in-ing-direct-japan.html' title='First few days in ING Direct Japan'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-4795620457037352776</id><published>2008-09-04T18:11:00.067+09:00</published><updated>2009-03-09T17:20:26.015+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>Testing Oracle Real Application Cluster</title><content type='html'>Installation and configuration of Oracle RAC is always challenging task even for an experienced dba. &lt;br&gt;
I read a story saying that a database administrator will laugh at you if you ask him to create a workable RAC of 2 nodes within a week. &lt;br&gt;
Oracle RAC is definitely complex environment but is it so difficult and time consuming to deploy ? &lt;br&gt;
To find an answer, I decided to try install Oracle RAC 10.2 on my small computer with 2 GB RAM. I used VMWARE server to create the environment of 2 linux nodes, that concurrently access shared database on cluster file system OCFS2. &lt;br&gt;
I took me not one week but nearly 4 day(s), during which, I have solved various encountered problems. Below are some notes that you need to consider before attempting similarly &lt;br&gt; &lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Documentation&lt;/span&gt;&lt;br&gt;
&lt;a href="http://www.oracle-base.com/articles/rac/ArticlesRac.php"&gt;http://www.oracle-base.com/articles/rac/ArticlesRac.php&lt;/a&gt; &lt;br&gt;
&lt;a href="http://www.dbasupport.com/oracle/ora10g/index_RAC.shtml"&gt;http://www.dbasupport.com/oracle/ora10g/index_RAC.shtml&lt;/a&gt;
These two freely available resources are quite good, concise and practical beside &lt;a href="http://metalink.oracle.com"&gt;metalink&lt;/a&gt; and official manual. &lt;br&gt; &lt;br&gt;

&lt;span style="font-weight:bold;"&gt;Summary of problems&lt;/span&gt;&lt;br&gt;
Believe or not, the fact is that most of problems are rooted from &lt;br&gt;
- mis-configuration of hardware and OS: without time synchronization between nodes, Clusterware misbehaves  &lt;br&gt;
- not install latest patch: many things suddenly work after installing latest patch&lt;br&gt;
Oracle RAC document is generally not good &lt;br&gt;
- it is huge and verbose: the Oracle Clusterware and Oracle Real Application Clusters Administration and Deployment Guide 10g Release 2 (P/N: B14197-08) is 400 pages thick &lt;br&gt;
- knowledge is split across many metalink notes making it difficult in orientation: to understand why we need proper setting of default gateway for a public network interface and its role, we need search metalink more than once &lt;br&gt;
- It is usually difficult and expensive to create environment for practical testing &lt;br&gt;&lt;br&gt;

&lt;span style="font-weight:bold;"&gt;The RAC software stack&lt;/span&gt;&lt;br&gt;
RAC Software stack consists of 2 layers sitting on top of OS &lt;br&gt;
a. RDBMS: Oracle RDBMS with RAC as Option &lt;br&gt;
b. Clusterware: CRS – Cluster Ready Service &lt;br&gt;
c. Operating System: Linux, Windows, AIX &lt;br&gt;
By implementing CRS component to play a role of Clusterware, Oracle wants to remove dependency of RAC from Clusterware traditionally provided OS and third party vendor. &lt;br&gt;
CRS need two device(s)/file(s) to store it's data; voting disk and oracle cluster registry - OCR . Because only one CRS is needed to support multi database(s), it is good to keep voting disk and OCR in a location independent from location for a database files. &lt;br&gt;
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;VMWARE Server configuration&lt;/span&gt;&lt;br&gt;
To experiment with Oracle Clusterware, also called Cluster Ready Service (CRS) and RAC, we need VMWARE Server. VMWARE Workstation does not work because it does not support concurrent access to a share disk. &lt;br&gt;
The config file (*.vmx) of each node shall be specially modified to disable disk locking and cache. By doing it, a hard disk created as file on host system can be safely attached to 2 VMWARE nodes. An example of special setting is taken from &lt;a href="http://www.oracle-base.com/articles/10g/OracleDB10gR2RACInstallationOnCentos4UsingVMware.php"&gt;Oracle RAC Installation on VMWARE article&lt;/a&gt; given below &lt;br&gt;
&lt;pre&gt;
...
...
disk.locking = "FALSE"
diskLib.dataCacheMaxSize = "0" 
diskLib.dataCacheMaxReadAheadSize = "0" 
diskLib.dataCacheMinReadAheadSize = "0" 
diskLib.dataCachePageSize = "4096" 
diskLib.maxUnsyncedWrites = "0"

scsi1.present = "TRUE"
scsi1.virtualDev = "lsilogic" 
scsi1.sharedBus = "VIRTUAL"
...
...
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Network setting&lt;/span&gt;&lt;br&gt;
RAC requires at least 2 NIC per node, one for private network and one for public network. Private network is used for communication between nodes while public network is for serving clients. &lt;br&gt;
In case of public network RAC does not use the host IP address for client communication but what it calls service or virtual IP address (VIP). In the public network, the VIP address has the same netmask as the host IP address, it is managed (assigned/un-assigned to the NIC) by Cluster Ready Service - CRS so in case of failure of one node, the VIP address of the fail node will be move to surviving one by CRS. 
&lt;br&gt;
It is good to follow some naming convention for host name. Example is given below
&lt;pre&gt;
/etc/hosts
# public
190.2.4.100             rac1 rac1-en0
190.2.4.101             rac2 rac2-en0

# private
9.2.4.100               rac1-priv rac1-en1
9.2.4.101               rac2-priv rac2-en1

# virtual
190.2.4.200             rac1-vip
190.2.4.201             rac2-vip
&lt;/pre&gt;
CRS need a gateway assigned to a public network interface in order to reliably detect failure of NIC and node. It is important to use a IP of a live machine reachable from all nodes but it is not necessarily a gateway. &lt;br&gt; &lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Enabling remote shell (RSH) and login (RLOGIN)&lt;/span&gt;&lt;br&gt;
Oracle Universal Installer (OUI) uses RSH and RLOGIN to install software on multi nodes, which means we run OUI only on one node and it will automatically copy the software (CRS and RAC) and configure on other nodes. Other configuration programs as VIPCA, NETCA and DBCA also work similarly and depend on RSH and RLOGIN to perform remote operation.&lt;br&gt;
Therefore we need to enable RSH and RLOGIN on all nodes before running installation program. The example below demonstrate how to enable RSH and RLOGIN. &lt;br&gt;
Configure RSH
&lt;pre&gt;
[root@rac1 ~]# rpm -q -a | grep rsh
rsh-0.17-25.4
rsh-server-0.17-25.4

[root@rac1 ~]# cat /etc/xinetd.d/rsh
# default: on
# description: The rshd server is the server for the rcmd(3) routine and, \
#       consequently, for the rsh(1) program.  The server provides \
#       remote execution facilities with authentication based on \
#       privileged port numbers from trusted hosts.
service shell
{
        disable = no
        socket_type             = stream
        wait                    = no
        user                    = root
        log_on_success          += USERID
        log_on_failure          += USERID
        server                  = /usr/sbin/in.rshd
}
&lt;/pre&gt;
Configure RLOGIN
&lt;pre&gt;
[root@rac1 ~]# cat /etc/xinetd.d/rlogin
# default: on
# description: rlogind is the server for the rlogin(1) program.  The server \
#       provides a remote login facility with authentication based on \
#       privileged port numbers from trusted hosts.
service login
{
        disable = no
        socket_type             = stream
        wait                    = no
        user                    = root
        log_on_success          += USERID
        log_on_failure          += USERID
        server                  = /usr/sbin/in.rlogind
}
&lt;/pre&gt;
Start RSH and RLOGIN
&lt;pre&gt;
[root@rac2 ~]# chkconfig rsh on
[root@rac2 ~]# chkconfig rlogin on
[root@rac2 ~]# service xinetd reload
&lt;/pre&gt;
Create oracle account and enable RSH and RLOGIN for oracle on node rac1 and rac2
&lt;pre&gt;
#Create the /etc/hosts.equiv file as the root user.
[root@rac2 ~]# touch /etc/hosts.equiv
[root@rac2 ~]# useradd oracle
[root@rac1 ~]# useradd oracle

[root@rac[1,2] ~]# cat /etc/hosts.equiv
+rac1 oracle
+rac2 oracle
+rac1-priv oracle
+rac2-priv oracle
+rac1-vip oracle
+rac2-vip oracle

[root@rac[1,2] ~]# chmod 600 /etc/hosts.equiv
[root@rac[1,2] ~]# chown root:root /etc/hosts.equiv
&lt;/pre&gt;
Verify RSH and RLOGIN
&lt;pre&gt;
[oracle@rac2 ~]$ rsh rac1 “uname –a”
[oracle@rac1 ~]$ rsh rac2 “uname –a”
[oracle@rac1 ~]$ rlogin rac2
[oracle@rac2 ~]$ rlogin rac1
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Configure Network Time Protocol - NTP&lt;/span&gt;&lt;br&gt;
&lt;br&gt;
Oracle clusterware CRS use time from nodes for it activities, so keeping time synchronized on all nodes is required. The clock synchronization method on unix is using NTP services, in which a machine contact other with preciser clock a reference clock, on regular interval to retrieve time and update its own clock. &lt;br&gt;
In the following example, node rac1 is used as reference clock while rac2 use rac1 as it's reference clock. Sometime this configuration does work well due to the reason that VMWARE hypervisor provide very bad clock implementation, therefore it is recommended to use an external physical server as reference clock , if we can have connection to Internet then use one of available real reference clocks.
&lt;pre&gt;
[root@rac1 ~]# more /etc/ntp.conf
server  127.127.1.0     # local clock
fudge   127.127.1.0 stratum 10 refid LCL

[root@rac1 ~]# /etc/init.d/ntpd restart
Shutting down ntpd:                                        [  OK  ]
Starting ntpd:                                             [  OK  ]
[root@rac1 ~]# chkconfig ntpd on

[root@rac2 ~]# more /etc/ntp.conf
server  rac1     # remote clock

[root@rac2 ~]# /etc/init.d/ntpd restart
Shutting down ntpd:                                        [  OK  ]
Starting ntpd:                                             [  OK  ]

[root@rac2 ~]# chkconfig ntpd on

[root@rac2 ~]# /usr/sbin/ntpdate -v -d rac1 # verify reference clock rac1

&lt;/pre&gt;

&lt;span style="font-weight:bold;"&gt;Turn off firewall&lt;/span&gt;&lt;br&gt;
&lt;br&gt;
CRS communication between nodes happens via TCP and UDP, so it is important to turn off firewall in all nodes to allow inter nodes traffic.
&lt;pre&gt;
[root@rac1 ~]# /etc/init.d/iptable stop
[root@rac1 ~]# chkconfig iptable off
[root@rac2 ~]# /etc/init.d/iptable stop
[root@rac2 ~]# chkconfig iptable off
&lt;/pre&gt;

&lt;span style="font-weight:bold;"&gt;Install, configure cluster file system - OCFS2 &lt;/span&gt;&lt;br&gt;
&lt;br&gt;

RAC use shared disk architecture, in which all nodes have to access  (for both read and write) to a same collection of database and others files located in a external hard disk. There are few options, one is to keep these files on raw devices, which is usually quite painful due to it's complex administration ranging from creation to maintenance. Other option is store them on file system, because traditional unix file system don't allow access from multi nodes, we need a special one, a cluster file system. There are different cluster file system available for different OS, e.g. GFS on AIX, Oracle has implemented a cluster file system on LINUX called OCFS2. &lt;br&gt;

Install OCFS2 is fairly simple and easy

&lt;pre&gt;
[root@rac1 ~]# rpm -q -a | grep ocfs2
ocfs2-2.6.9-42.ELsmp-1.2.9-1.el4
ocfs2-tools-1.2.7-1.el4
ocfs2console-1.2.7-1.el4

[root@rac2 ~]# rpm -q -a | grep ocfs2
ocfs2-2.6.9-42.ELsmp-1.2.9-1.el4
ocfs2-tools-1.2.7-1.el4
ocfs2console-1.2.7-1.el4
&lt;/pre&gt;

To create a configuration run ocfs2console and follow GUI menu
&lt;pre&gt;
[root@rac2 ~]# /usr/sbin/ocfs2console
&lt;/pre&gt;

Define a configuration of two nodes rac1, rac2 using IP on private NIC en1 and specified port &lt;br&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hSKkcklzwTU/SbSGd_poJfI/AAAAAAAAAT0/kHgWrdUxKi8/s1600-h/ocfs1.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 289px;" src="http://2.bp.blogspot.com/_hSKkcklzwTU/SbSGd_poJfI/AAAAAAAAAT0/kHgWrdUxKi8/s400/ocfs1.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5311017710437017074" /&gt;&lt;/a&gt;

Propagate the configuration to other node &lt;br&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hSKkcklzwTU/SbSGzrkKO3I/AAAAAAAAAT8/4ClhlAWTnyw/s1600-h/ocfs2.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 289px;" src="http://3.bp.blogspot.com/_hSKkcklzwTU/SbSGzrkKO3I/AAAAAAAAAT8/4ClhlAWTnyw/s400/ocfs2.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5311018083002497906" /&gt;&lt;/a&gt;

Create and format cluster file system, note that we shall create a cluster filesystem on a  shared disk, that is accessible from both nodes. &lt;br&gt;
&lt;pre&gt;
[root@rac1 ~]#fdisk /dev/sdb
...  #create single partition sdb1
...
&lt;/pre&gt;
Use ocfs2console=&gt;task=&gt;format /dev/sdb1 &lt;br&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hSKkcklzwTU/SbSIl3LBp4I/AAAAAAAAAUE/arYlb58-8OE/s1600-h/ocfs3.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 289px;" src="http://3.bp.blogspot.com/_hSKkcklzwTU/SbSIl3LBp4I/AAAAAAAAAUE/arYlb58-8OE/s400/ocfs3.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5311020044623390594" /&gt;&lt;/a&gt;
Start OCFS2 services and mount cluster file system at startup &lt;br&gt;
&lt;pre&gt;
[root@rac[1,2] ~]#chkconfig --add o2cb
[root@rac[1,2] ~]#chkconfig --add ocfs2
[root@rac[1,2] ~]#/etc/init.d/o2cb configure

[root@rac[1,2] ~]#cat /etc/fstab:
...
/dev/sdb1  /u02  ocfs2    rw,_netdev,datavolume,nointr,heartbeat=local 0 0

[root@rac[1,2] ~]#mkdir /u02
[root@rac[1,2] ~]#mount /u02
&lt;/pre&gt;

Verify cluster file system by creating a directory on one node and check if it appears on other node.

&lt;pre&gt;
[root@rac1~]#mkdir –p /u02/crsdata
[root@rac1~]#mkdir –p /u02/oradata
[root@rac2~]#ls –l /u02
crsdata
oradata
&lt;/pre&gt;

&lt;span style="font-weight:bold;"&gt;Modify LINUX kernel setting to meet OCRS,and ORACLE requirements &lt;/span&gt;&lt;br&gt;
For the first node
&lt;pre&gt;
[root@rac1]~]# vi /etc/sysctl.conf
kernel.shmall = 2097152
kernel.shmmax = 2147483648
kernel.shmmni = 4096
# semaphores: semmsl, semmns, semopm, semmni
kernel.sem = 250 32000 100 128
fs.file-max = 65536
net.ipv4.ip_local_port_range = 1024 65000
net.core.rmem_default=262144
net.core.rmem_max=262144
net.core.wmem_default=262144
net.core.wmem_max=262144
[root@rac1~]# sysctl -p
[root@rac1]~]# vi /etc/modprobe.conf
options hangcheck-timer hangcheck_tick=30 hangcheck_margin=180
&lt;/pre&gt;
For the second node
&lt;pre&gt;
[root@rac2~]# vi /etc/sysctl.conf
kernel.shmall = 2097152
kernel.shmmax = 2147483648
kernel.shmmni = 4096
# semaphores: semmsl, semmns, semopm, semmni
kernel.sem = 250 32000 100 128
fs.file-max = 65536
net.ipv4.ip_local_port_range = 1024 65000
net.core.rmem_default=262144
net.core.rmem_max=262144
net.core.wmem_default=262144
net.core.wmem_max=262144
[root@rac2~]# sysctl -p
[root@rac2]~]# vi /etc/modprobe.conf
options hangcheck-timer hangcheck_tick=30 hangcheck_margin=180
&lt;/pre&gt;

&lt;span style="font-weight:bold;"&gt;Install Oracle Cluster Ready Service - CRS &lt;/span&gt;&lt;br&gt;

Create the new groups and users.
&lt;pre&gt;
[root@rac[1,2]~]#useradd oracle
[root@rac[1,2]~]#groupadd oinstall 
[root@rac[1,2]~]#groupadd dba 
[root@rac[1,2]~]#usermod -g oinstall -G dba oracle 
&lt;/pre&gt;
Create Oracle Cluster Registry - OCR and votedisk on cluster file system
&lt;pre&gt;
[root@rac1~]#mkdir –p /u02/crsdata
[root@rac1~]#touch /u02/crsdata/ocr.dbf
[root@rac1~]#touch /u02/crsdata/votedisk.dbf
[root@rac1~]#chown –R oracle /u02
&lt;/pre&gt;

Copy installation software
&lt;pre&gt;
[root@rac1~]#mkdir –p /u02/setup/clusterware10.2.0.1
[root@rac1~]#mkdir –p /u02/setup/oracle10.2.0.1
[root@rac1~]#mkdir –p /u02/setup/patch10.2.0.4
&lt;/pre&gt;
Create home directory for crs and oracle
&lt;pre&gt;
[root@rac1~]#mkdir –p /u01/crs
[root@rac1~]#mkdir –p /u01/oracle
[root@rac1~]#chown –R oracle /u01
&lt;/pre&gt;

Run Oracle Universal Installer - OUI as oracle 
&lt;pre&gt;
[oracle@rac1~]$/u02/setup/clusterware/runInstaller
&lt;/pre&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hSKkcklzwTU/SbS2hiV2F0I/AAAAAAAAAUU/8f86Rmla7uc/s1600-h/crs1.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 289px;" src="http://3.bp.blogspot.com/_hSKkcklzwTU/SbS2hiV2F0I/AAAAAAAAAUU/8f86Rmla7uc/s400/crs1.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5311070547847026498" /&gt;&lt;/a&gt;
Follow instructions and  &lt;br&gt;
- add node rac2 to make sure that there are two nodes in the cluster
- for each node specify public node name (rac1, rac2), virtual host name (rac1-vip, rac2-vip) and private node name (rac1-priv, rac2-priv), this is also important to specify an IP of a reliable host of the same public network as gateway. &lt;br&gt;
- specify public network for public and virtual IP and private network for private IP &lt;br&gt;
- specify u02/crsdata/ocr.dbf as OCR and /u02/crsdata/votedisk.dbf as voting disk location and external redundancy
OUI will perform installation on one node then using RSH to copy to other node, during final phase of the installation process, script root.sh shall be invoked manually as root on each node. &lt;br&gt;
At the end, OUI will run virtual IP configuration assistant - VIPCA, that create and persist configuration of VIP, ONS and GSD etc. as resource in OCR. &lt;br&gt;
If for any reason (e.g. mis typing, incorrect IP) VIPCA fails, we can re run it under root after correction.
&lt;br&gt;
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Install Oracle Database Software and create a database &lt;/span&gt;&lt;br&gt;

The installation of Oracle Database Software is similar as for non-RAC version, only different is after completion on one node, the OUI will copy the software to other node. &lt;br&gt;

At the end of this process two configuration programs  will be invoked&lt;br&gt;
- a database configuration assistant - DBCA for database creation and &lt;br&gt;
- a network configuration assistant - NETCA for listener and tnsname configuration &lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-4795620457037352776?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/4795620457037352776/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=4795620457037352776&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4795620457037352776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4795620457037352776'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2008/09/testing-oracle-real-application-cluster.html' title='Testing Oracle Real Application Cluster'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_hSKkcklzwTU/SbSGd_poJfI/AAAAAAAAAT0/kHgWrdUxKi8/s72-c/ocfs1.PNG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-4341783107641056181</id><published>2008-08-28T09:50:00.019+09:00</published><updated>2008-09-04T17:13:16.723+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='finance'/><title type='text'>Difference between Remittance and Transfer</title><content type='html'>In financial industries, 'Remittance' refers to an action of sending money from an individual to other not being resulted from either sale and transfer of good and funds. 'Transfer' generally refers to an action of sending money from a party to other as payment for a good or service. &lt;br&gt;
E.g. CitiBank Japan have different &lt;a href="http://www.citibank.co.jp/en/cbol/charge/index.html"&gt;charge&lt;/a&gt; for remittance and transfer
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hSKkcklzwTU/SL-Ye5-b-NI/AAAAAAAAAEU/kPFe3hUj75E/s1600-h/cb.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_hSKkcklzwTU/SL-Ye5-b-NI/AAAAAAAAAEU/kPFe3hUj75E/s400/cb.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5242076148008745170" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-4341783107641056181?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/4341783107641056181/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=4341783107641056181&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4341783107641056181'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4341783107641056181'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2008/08/difference-between-remittance-and.html' title='Difference between Remittance and Transfer'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_hSKkcklzwTU/SL-Ye5-b-NI/AAAAAAAAAEU/kPFe3hUj75E/s72-c/cb.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-3652227383807904202</id><published>2008-08-08T19:54:00.008+09:00</published><updated>2009-02-13T21:27:48.926+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='jruby'/><title type='text'>Calling RMI from EJB Stateless Session Bean</title><content type='html'>I have to analyze one of our J2EE application(s), that call RMI from a Stateless Session Bean. I originally think that it could be a problem, because our Session Bean use remote object as singleton and the rule said that Session Bean shall be programed in thread safe manner because its methods run concurrently within container's threads. To confirm that I decided to do some experiments. &lt;br&gt;
I create a sample RMI server
&lt;pre name="code" class="Java"&gt;
/* SampleServer.java */
import java.rmi.*;

public interface SampleServer extends Remote
{
  public int sum(int a,int b) throws RemoteException;
}

import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;

/* SampleServerImpl.java */
public class SampleServerImpl extends UnicastRemoteObject
                             implements SampleServer
{
  SampleServerImpl() throws RemoteException
  {
     super();
  }

  public int sum(int a,int b) throws RemoteException
  {
     try {
       Thread.sleep(5000);
     } catch (InterruptedException e){
       e.printStackTrace();
     }

     return a + b;
  }

  public static void main(String args[])
  {
    try
      {
        SampleServerImpl sampleServer = new SampleServerImpl();

        Registry registry = LocateRegistry.createRegistry(8989);
        registry.rebind("Sample", sampleServer);

        System.out.println("Server waiting.....");
      }
    catch (RemoteException e)
      {
         e.printStackTrace();
      }
  }
}
&lt;/pre&gt;
I compile these classes compile and run using JDK1.5 with jmx enabled according &lt;a href="http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html"&gt;jconsole article&lt;/a&gt;
&lt;pre&gt;
$ javac SampleServer.java SampleServerImpl.java
$ rmic SampleServerImpl
$ java -Dcom.sun.management.jmxremote SampleServerImpl
&lt;/pre&gt;
I decide to use JRUBY to create and run a 20 thread(s), each issue a call RMI server
&lt;pre&gt;
$jirb
&gt; import java.rmi.Naming  
&gt; sample = Naming.lookup("//127.0.0.1:8989/Sample")
&gt; (1..20).each { Thread.new { puts sample.sum(3,7)} }
&gt;
&lt;/pre&gt;
Then I run jconsole supplied in JDK1.5 and watch thread pool of the RMI server
&lt;pre&gt;
$jconsole
&lt;/pre&gt;
The result is everything is OK, for each incoming call request, RMI server create a separate thread to handle it and the thread is dropped after it completion.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-3652227383807904202?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/3652227383807904202/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=3652227383807904202&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/3652227383807904202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/3652227383807904202'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2008/08/calling-rmi-from-ejb-stateless-session.html' title='Calling RMI from EJB Stateless Session Bean'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-5709171372013890574</id><published>2008-07-09T09:00:00.007+09:00</published><updated>2009-04-22T16:11:25.127+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>Joining ING Direct Japan</title><content type='html'>I have given a resignation letter to the CEO of CSE, the company that I worked for 11 years. Officially I will join ING Direct Japan at the end of August and will move to Tokyo. &lt;br&gt;

Taking such decision is not easy, CSE is not just my workplace, it is part of my life, where I put a lot of my desire and hope. These past 11 years was rewarding and I never regret of the decision to move from Prague to Hanoi in 1997. But it is time to change. &lt;br&gt;

If anyone have chance to be in Tokyo, don't forget to drop me a e-mail, I will be pleased to go with you for a drink.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-5709171372013890574?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/5709171372013890574/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=5709171372013890574&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5709171372013890574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5709171372013890574'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2008/07/joining-ing-direct-japan.html' title='Joining ING Direct Japan'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-279994839882636521</id><published>2008-05-10T11:55:00.005+09:00</published><updated>2008-05-10T12:10:36.986+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='jruby'/><title type='text'>Faster jruby startup</title><content type='html'>One of issue with JRuby and Java in general is long startup time. As the result, a lot of peoples including myself use MRI when developing application and then use JRuby to test and run the application. &lt;br&gt;
Recent change is jruby shell script have improved startup time at significantly by putting JRuby library into java boot classpath (using -Xbootclasspath/a:) instead of normal classpath to bypass java class verification, however it still so slow compare to MRI. &lt;br&gt;
Below is a simple test on machine &lt;br&gt;
&lt;b&gt;1. jruby lib in classpath&lt;/b&gt; &lt;br&gt;
&lt;pre&gt;
huy@huy-desktop:/u01/jruby-1.1.1/bin$ time jruby -e "puts 'hello world'"
hello world

real    0m2.934s
user    0m2.604s
sys     0m0.136s

&lt;/pre&gt;
&lt;b&gt;2. jruby lib in boot classpath&lt;/b&gt; &lt;br&gt;
&lt;pre&gt;
huy@huy-desktop:/u01/jruby-1.1.1/bin$ time jruby -e "puts 'hello world'"
hello world

real    0m1.124s
user    0m0.896s
sys     0m0.072s
&lt;/pre&gt;
&lt;b&gt;3. MRI&lt;/b&gt; &lt;br&gt;
&lt;pre&gt;
huy@huy-desktop:/u01/jruby-1.1.1/bin$ time ruby -e "puts 'hello world'"
hello world

real    0m0.060s
user    0m0.004s
sys     0m0.004s

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-279994839882636521?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/279994839882636521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=279994839882636521&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/279994839882636521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/279994839882636521'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2008/05/faster-jruby-startup.html' title='Faster jruby startup'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-8018266472297604168</id><published>2008-04-15T17:10:00.006+09:00</published><updated>2008-04-15T17:53:10.937+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Why Python</title><content type='html'>I known &lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt; during the time I read the book "Test-Driven Development By Example". It is dynamic programming language like Ruby. However I don't like that language as Ruby because of it's syntax, missing open classes, having difficult meta programming style, etc..
&lt;br&gt;
I get attention of Python after recent release of &lt;a href="http://code.google.com/appengine/"&gt;Google AppEngine&lt;/a&gt;, a combination of web framework  written in Python with hosting service. Google AppEngine allows us to develop application in our machine then upload to Google hosting service and benefit from Google Infrastructure including identity management, Google datastore, scalability on demand, etc. . Google AppEngine is now available only for Python developers, they are many so within few hours from announcement of Google AppEngine, the first free 10,000 accounts has gone. 
&lt;br&gt;
Python has additional good characteristics to be considered as language on new projects: &lt;br&gt;
- Python can compile program to byte code so it has reputation of better performance then Ruby. &lt;br&gt;
- In addition to C implementation, Python has already quite mature .Net and Java implementation, which can be very strong arguments in any integration projects.&lt;br&gt;
- Python has proven track on scalable web site like Google or framework as Django , Zope or application as ERP5
&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-8018266472297604168?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/8018266472297604168/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=8018266472297604168&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8018266472297604168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8018266472297604168'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2008/04/why-python.html' title='Why Python'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-323321226381532312</id><published>2008-02-22T09:21:00.003+09:00</published><updated>2008-02-22T09:23:01.913+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>Agile Reading List</title><content type='html'>link to &lt;a href="http://www.thekua.com/atwork/2008/01/21/the-essential-agile-reading-list/"&gt; essential list &lt;/a&gt; &lt;br&gt;
link to &lt;a href="http://www.thekua.com/atwork/2008/02/20/the-extended-agile-reading-list/"&gt;extended list &lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-323321226381532312?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/323321226381532312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=323321226381532312&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/323321226381532312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/323321226381532312'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2008/02/agile-reading-list.html' title='Agile Reading List'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-6802893776626771147</id><published>2008-01-20T15:17:00.019+09:00</published><updated>2011-07-04T04:29:32.786+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Using git for newbie</title><content type='html'>I am doing some experiment with Rubinius code base, which uses distributed SCM git. Comparing with Subversion, Git is a little bit more difficult, so It takes me a while to understand its commands and find the proper way to work with it. Without commit right, here are typical commands I use in my work flow.&lt;br&gt;&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Clone a remote repository into the local disk&lt;/span&gt; - repository is create as a clone of the remote repository identified by a given url
&lt;pre&gt;
git clone git://git.rubini.us/code 
cd code # goto directory containing local repository 
git config user.name "le huy"  #configure your name 
git config user.email "lehuy20@gmail.com" #and email that will be used when committing
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Sample .git/config&lt;/span&gt; - git create a .git directory to store it's data, file .git/config contains configuration data including remote repository, which remote branch is link with which local one
&lt;pre&gt;
cat .git/config 
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
[remote "origin"]
        url = git://github.com/evanphx/rubinius.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[gui]
        geometry = 885x450+5+65 399 192
[branch "master"]
        remote = origin
        merge = refs/heads/master
[branch "cpp"]
        remote = origin
        merge = refs/heads/cpp
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Submodule&lt;/span&gt; - git submodule is used to link to external repository (equivalent to subversion extern)
&lt;pre&gt;
cat .gitmodules
[submodule "mspec"]
        path = mspec
        url = git://github.com/brixen/mspec.git
[submodule "spec/frozen"]
        path = spec/frozen
        url = git://github.com/brixen/rubyspec.git
&lt;/pre&gt;
init and update submodule from external repository
&lt;pre&gt;
git submodule init # init submodule repository based on .gitmodules
git submodule update
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Show current branch &lt;/span&gt; - show which branch we are working on, switch between them
&lt;pre&gt;
git branch # will show us local branches 
* cpp
  master

git branch -a # will show us all branches including local and remote 
* cpp
  master
  origin/cmakebuild
  origin/cpp
  origin/fusion-experiment
  origin/instance_eval
  origin/master
  origin/wilson64

git checkout master # switch to branch named 'master'
git checkout dev # switch to branch named 'dev'
&lt;/pre&gt;
We can sometime create new branches in addition to 'master' to work concurrently on many features &lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Create new branch&lt;/span&gt;
&lt;pre&gt;
git branch working  # create branch 'working' 
git checkout working # switch to branch named 'working'
git branch dev --track origin/dev # create local branch 'dev' that track the remote branch origin/dev
&lt;/pre&gt;
The current working branch is now 'working' &lt;br&gt;&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Delete branch&lt;/span&gt; - we can remove unused branch if it is no longer needed
&lt;pre&gt;
git branch -d working # delete 'working' branch
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Update from remote repository&lt;/span&gt; - e.g. wait until someone commit the patch to the main trunk then update changes from git://git.rubini.us/code 
&lt;br&gt;
git pull will perform merge change on remote branch to local branch
&lt;pre&gt;
git pull
&lt;/pre&gt;
git rebase will save local changes away, update from remote branch, and then reapply them
&lt;pre&gt;
git rebase master 
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Push change to remote repository&lt;/span&gt;
&lt;pre&gt;
git push # push will update a --track branch in remote repository,
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Edit source code&lt;/span&gt; - do some source code editing
&lt;pre&gt;
gedit kernel/core/kernel.rb
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Show modification &lt;/span&gt; - show what I have modify without committing change
&lt;pre&gt;
git diff HEAD # HEAD is symbol for latest/head version of current branch
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Revert back&lt;/span&gt; -when recognizing that there is something wrong, we can undo the modification, all changes are lost  
&lt;pre&gt;
git reset --hard HEAD
&lt;/pre&gt; 
&lt;span style="font-weight:bold;"&gt;Edit source code &lt;/span&gt; - Do some source code editing again
&lt;pre&gt;
gedit kernel/core/module.rb
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Commit changes &lt;/span&gt; - commit change in current branch
&lt;pre&gt;
git commit -a -s # vi editor will be popped up for entering committing message
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Create patch&lt;/span&gt; - create patch containing changes between 2 branches local 'master' and remote 'origin/master'
&lt;pre&gt;
git checkout master # switch to branch 'master'
git format-patch origin/master --stdout # to standard output
git format-patch origin/master -o ../patch # create formated patch as a file and store in directory ../patch
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Create a ticket&lt;/span&gt; - goto in http://rubinius.lighthouseapp.com/m create a ticket and attach a patch file to it&lt;br&gt;&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Revert change&lt;/span&gt; - switch to branch named 'master' and revert back directory tree in original state, all changes are lost
&lt;pre&gt;
git checkout master
git reset --hard HEAD 
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Resolve conflict&lt;/span&gt; - if there is a conflict on file, git stop doing and ask for manually resolve, to inform that the conflict has been resolved on e.g. kernel/core/module.rb, use
&lt;pre&gt;
gedit kernel/core/module.rb # after manually resolve conflict
git add kernel/core/module.rb # inform git that conflict on file kernel/core/module.rb is resolved
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Apply patch&lt;/span&gt;
&lt;pre&gt;
git-apply ../patch/0001-Fixes-for-Class-include-and-Class-extend-to-handle-c.patch
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Apply patch partly&lt;/span&gt; - if a patch contains modification of multi files and there are conflict with some of them during patching, then use --reject option to modify only non-conflicted files and create filename.rej for those conflicted  
&lt;pre&gt;
git-apply --reject ../patch/0001-Fixes-for-Class-include-and-Class-extend-to-handle-c.patch 
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;Remove file from stage&lt;/span&gt;
Making change into git repository actually happens in two steps, 1) add the new/modified file into stage area 2) commit stage area. If for some reason, we want to revert the step 1) we can do as follow
&lt;pre&gt;
$git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached &lt;file&gt;..." to unstage)
#
# new file: dict_parser/tests/dict_tests.py
#
$ git rm --cached dict_parser/tests/dict_tests.py
rm 'dict_parser/tests/dict_tests.py'
$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add &lt;file&gt;..." to include in what will be committed)
#
# dict_parser/
&lt;/pre&gt;
Git getting popular now when many open source projects moved from subversion to git, Zack Rusin has done very nice git cheat sheet summarizing git usage scenarios below
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hSKkcklzwTU/SAQq6JQRiaI/AAAAAAAAACQ/QVDtYc6e2k4/s1600-h/git-cheat-sheet-medium.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_hSKkcklzwTU/SAQq6JQRiaI/AAAAAAAAACQ/QVDtYc6e2k4/s400/git-cheat-sheet-medium.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5189319849042610594" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-6802893776626771147?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/6802893776626771147/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=6802893776626771147&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6802893776626771147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6802893776626771147'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2008/01/using-git-for-newbie.html' title='Using git for newbie'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_hSKkcklzwTU/SAQq6JQRiaI/AAAAAAAAACQ/QVDtYc6e2k4/s72-c/git-cheat-sheet-medium.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-592713716617980479</id><published>2007-12-21T18:06:00.001+09:00</published><updated>2007-12-21T18:07:52.671+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Ruby Virtual Machine's Implementation</title><content type='html'>link to &lt;a href="http://antoniocangiano.com/2007/12/03/the-great-ruby-shootout/"&gt;The Great Ruby Shootout&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-592713716617980479?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/592713716617980479/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=592713716617980479&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/592713716617980479'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/592713716617980479'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/12/ruby-virtual-machines-implementation.html' title='Ruby Virtual Machine&apos;s Implementation'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-4314321354188094210</id><published>2007-12-09T13:21:00.000+09:00</published><updated>2007-12-09T13:23:07.960+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>rails-2.0 released summary of features</title><content type='html'>link to &lt;a href="http://ryandaigle.com/articles/2007/12/7/rails-2-0-final-released-summary-of-features"&gt;rails-2.0 released summary of features&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-4314321354188094210?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/4314321354188094210/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=4314321354188094210&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4314321354188094210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4314321354188094210'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/12/rails-20-released-summary-of-features.html' title='rails-2.0 released summary of features'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-8766621658916454656</id><published>2007-11-24T11:10:00.000+09:00</published><updated>2007-11-24T11:11:49.046+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dsl'/><title type='text'>Martin Fowler DSL Book</title><content type='html'>link to &lt;a href="http://martinfowler.com/dslwip/"&gt;DSL Book work in progress&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-8766621658916454656?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/8766621658916454656/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=8766621658916454656&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8766621658916454656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8766621658916454656'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/11/martin-fowler-dsl-book.html' title='Martin Fowler DSL Book'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-5574250393418734245</id><published>2007-11-17T19:38:00.002+09:00</published><updated>2008-02-21T09:42:55.438+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='jruby'/><title type='text'>Nice test code sample using mocha</title><content type='html'>link to &lt;a href="http://blog.floehopper.org/articles/2007/11/29/mock-object-injection"&gt;Mock Object Injection&lt;/a&gt;&lt;br&gt;
link to &lt;a href="http://memeagora.blogspot.com/2007/10/mocking-jruby.html"&gt;Mocking Jruby&lt;/a&gt; &lt;br&gt;
link to &lt;a href="http://www.infoq.com/news/2008/01/boost-java-test"&gt;Boost your Java Test with Ruby and JtestR&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-5574250393418734245?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/5574250393418734245/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=5574250393418734245&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5574250393418734245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5574250393418734245'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/11/nice-code-to-test-java-program-using.html' title='Nice test code sample using mocha'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-2644168839893554692</id><published>2007-10-13T11:04:00.000+09:00</published><updated>2007-10-13T11:11:21.023+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Useful unix tricks</title><content type='html'>link touseful unix tricks from Paul Gross &lt;br&gt;
&lt;a href="http://www.pgrs.net/2007/9/6/useful-unix-tricks"&gt;part 1&lt;/a&gt; &lt;br&gt;
&lt;a href="http://www.pgrs.net/2007/10/8/useful-unix-tricks-part-2"&gt;part 2&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-2644168839893554692?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/2644168839893554692/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=2644168839893554692&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2644168839893554692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2644168839893554692'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/10/useful-unix-tricks.html' title='Useful unix tricks'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-8426334222209484297</id><published>2007-10-02T09:22:00.000+09:00</published><updated>2008-12-11T16:35:55.862+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='leisure'/><title type='text'>Sea Fish</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hSKkcklzwTU/RwiEZ-tXbNI/AAAAAAAAACI/ahWTWTYckds/s1600-h/fishs.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_hSKkcklzwTU/RwiEZ-tXbNI/AAAAAAAAACI/ahWTWTYckds/s400/fishs.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5118486558371441874" /&gt;&lt;/a&gt;

This picture named 'Sea Fish' is from Le Ngoc Mai, my 8 year old daughter.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-8426334222209484297?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/8426334222209484297/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=8426334222209484297&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8426334222209484297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8426334222209484297'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/10/fish.html' title='Sea Fish'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_hSKkcklzwTU/RwiEZ-tXbNI/AAAAAAAAACI/ahWTWTYckds/s72-c/fishs.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-4743500313394837466</id><published>2007-09-11T21:27:00.000+09:00</published><updated>2007-09-11T21:28:11.414+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>How to organize Rails model</title><content type='html'>Link to &lt;a href="http://errtheblog.com/post/5"&gt;How to organize Rails model&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-4743500313394837466?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/4743500313394837466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=4743500313394837466&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4743500313394837466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4743500313394837466'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/09/how-to-organize-rails-model.html' title='How to organize Rails model'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-6232091445629290542</id><published>2007-09-07T08:44:00.000+09:00</published><updated>2007-10-22T20:12:11.337+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jruby'/><title type='text'>Calling Java from JRuby</title><content type='html'>Current JRuby is lack of detail documentation with regard to Java integration, so in certain cases it take me and my colleague a while to figure out how to do.&lt;br&gt;
&lt;b&gt;String to/from Java byte's array&lt;/b&gt;&lt;br&gt;
In our recent application, we need to pass image from Ruby to image processing method written in Java. The Java method accept byte array and has result as byte array also. So we need convert Ruby String to Java byte[] and back.&lt;br&gt;
The &lt;code&gt;require 'java'&lt;code&gt; add two methods to Ruby String class 
&lt;pre&gt;
String#to_java_bytes # instance method return Java byte[] 
String::from_java_bytes # class method return Ruby string from Java byte[]
&lt;/pre&gt;
The below code snippet demonstrate it.
&lt;pre&gt;
require 'java'
include_class 'net.csetech.sq.image.ImageHelper'

File.open('duongpl.jpg') do |f|
  f.binmode
  @original = f.read
end

@reduced_j = ImageHelper.reduce_to_fix_size(@original.to_java_bytes,15000)
@reduced_r = String.from_java_bytes(@reduced_j)

File.open('duongpl-15k.jpg','w') do |f|
  f.binmode
  f.write(@reduced_r)
end
&lt;/pre&gt;
&lt;b&gt;Ruby Array to Java Array&lt;/b&gt;&lt;br&gt;
Other example, that we may need is to convert Ruby Array to Java Array. The &lt;code&gt;require 'java'&lt;/code&gt; add method &lt;code&gt;Array::to_java(Symbol)&lt;/code&gt;, that convert Ruby Array to Java Array, where Symbol represent Java Class of the Array's elements. If it is omitted, the result is Java Object[].
&lt;pre&gt;
['a','b'].to_array(:String) # return Java String[]
['a','b'].to_array # return java Object[]
&lt;/pre&gt;
More about method &lt;code&gt;to_array&lt;/code&gt; is on &lt;a href="http://www.headius.com/jrubywiki/index.php/JRuby_Cookbook"&gt;JRuby Cookbook&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-6232091445629290542?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/6232091445629290542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=6232091445629290542&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6232091445629290542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6232091445629290542'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/09/convert-string-tofrom-java-bytes-array.html' title='Calling Java from JRuby'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-3355835546671513718</id><published>2007-09-01T13:41:00.000+09:00</published><updated>2007-09-01T13:44:32.779+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pattern'/><category scheme='http://www.blogger.com/atom/ns#' term='dsl'/><title type='text'>API design</title><content type='html'>Link to &lt;a href = "http://www.acmqueue.com/modules.php?name=Content&amp;pa=printer_friendly&amp;pid=488&amp;page=1"&gt; API: Design Matters&lt;/a&gt;&lt;br&gt;
Link to &lt;a href="http://www.scribd.com/doc/33655/How-to-Design-a-Good-API-and-Why-it-Matters"&gt;
How to Design a Good API &amp; Why it Matters&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-3355835546671513718?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/3355835546671513718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=3355835546671513718&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/3355835546671513718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/3355835546671513718'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/09/api-design.html' title='API design'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-8646283589176442343</id><published>2007-09-01T13:01:00.001+09:00</published><updated>2009-03-09T18:53:56.153+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>ActiveRecord-JDBC 0.5 can not insert object with pre-assigned Id into Oracle Database</title><content type='html'>If you encountered problem when try to insert object with pre-assigned Id into Oracle Database in JRuby 1.0.1 with ActiveRecord-JDBC 0.5, here is quick fix
&lt;pre&gt;
module ::JdbcSpec
  module Oracle
     def insert(sql, name = nil, pk = nil, id_value =nil, sequence_name = nil) #:nodoc:
      if pk.nil? || id_value
        execute sql, name
      else # Assume the sql contains a bind-variable for the id
        id_value = select_one(
        "select #{sequence_name}.nextval id from dual")['id'].to_i 
        log(sql, name) {
          @connection.execute_id_insert(sql,id_value)
        }
      end
      id_value
    end
  end
end
&lt;/pre&gt;
The problem is on compatibility of Oracle JDBC driver and &lt;code&gt;execute_insert&lt;/code&gt; method of java class &lt;code&gt;JdbcAdapterInternalService&lt;/code&gt;. The fix simply remove the usage of &lt;code&gt;execute_insert&lt;/code&gt; method. Verification code is below
&lt;pre&gt;
require 'rubygems'
gem 'ActiveRecord-JDBC','0.5'
require 'jdbc_adapter'
require 'active_record'

ActiveRecord::Base.establish_connection(
 :adapter  =&gt; 'jdbc',
 :driver   =&gt; 'oracle.jdbc.driver.OracleDriver', 
 :url      =&gt; 'jdbc:oracle:thin:@localhost:1521:DEV',
 :username =&gt; "scott",
 :password =&gt; "tiger",
)

class Emp &lt; ActiveRecord::Base
  set_table_name 'emp'
  set_primary_key 'empno'
end

emp = Emp.new
emp.id = 9999
emp.save
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-8646283589176442343?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/8646283589176442343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=8646283589176442343&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8646283589176442343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8646283589176442343'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/09/activerecord-jdbc-05-can-not-insert.html' title='ActiveRecord-JDBC 0.5 can not insert object with pre-assigned Id into Oracle Database'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-4968788227062258157</id><published>2007-08-19T12:02:00.002+09:00</published><updated>2009-02-13T21:31:26.346+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Ruby require idiom</title><content type='html'>Ruby Kernel#require(filename) read and execute the specified file only once regardless how many time we call it as opposite to Kernel#load(filename) which reload the file each time.

With application having many files, each depend on others without this behavior of Kernel#require(filename), a single file will be read executed multi time, which may not desired from  functional and performance's perspective.


The Kernel#require(filename) however has an issue, after loading it puts path of a file required in global array &lt;code&gt;$"&lt;/code&gt; and does not know if we refer to the same file using different path. e.g.

&lt;pre name="code" class="Ruby"&gt;
#file : lib/foo.rb
puts "loading #{__FILE__}"

#file : lib/bar.rb
require File.dirname(__FILE__) + '/foo'
puts "loading #{__FILE__}"

#file : app/runme.rb

require File.dirname(__FILE__) +'/../lib/foo'
require File.dirname(__FILE__) +'/../lib/bar'
puts $"
&lt;/pre&gt;
Then run
&lt;pre&gt;
ruby app/runme.rb

loading ./app/../lib/foo.rb
loading ./app/../lib/foo.rb
loading ./app/../lib/bar.rb
["app/../lib/foo.rb", "./app/../lib/foo.rb", "app/../lib/bar.rb"]
&lt;/pre&gt;

There are basically few well known techniques to deal with this problem &lt;br&gt;

1. Using absolute path &lt;br&gt;

2. Modifying $LOAD_PATH &lt;br&gt;

3. Using defined? &lt;br&gt;&lt;br&gt;



&lt;span style="font-weight: bold;"&gt;USING ABSOLUTE PATH&lt;/span&gt;&lt;br&gt;


In this variant we always call  Kernel#require with  a absolute path, the File::expand_path will be used to remove '..' symbol representing parent directory  e.g
&lt;pre name="code" class="Ruby"&gt;
#file : lib/bar.rb
require File.expand_path(File.dirname(__FILE__)) + '/foo'
puts "loading #{__FILE__}"

#file : app/runme.rb
require File.expand_path(File.dirname(__FILE__)+'/../lib')+'/foo'
require File.expand_path(File.dirname(__FILE__)+'/../lib')+'/bar'
puts $"
&lt;/pre&gt;
run
&lt;pre&gt;
ruby app/runme.rb

loading D:/huy/rubyapp/require_1/lib/foo.rb
loading D:/huy/rubyapp/require_1/lib/bar.rb
["D:/huy/rubyapp/require_1/lib/foo.rb", "D:/huy/rubyapp/require_1/lib/bar.rb"]
&lt;/pre&gt;
This method is described in post &lt;a href="http://ghouston.blogspot.com/2007/05/ruby-require-idiom.html"&gt;ruby require idiom&lt;/a&gt;
&lt;br&gt;&lt;br&gt;
&lt;span style="font-weight: bold;"&gt;MODIFYING $LOAD_PATH&lt;/span&gt; &lt;br&gt;


The second quite popular technique is to modify $LOAD_PATH directly e.g.

&lt;pre name="code" class="Ruby"&gt;
#file : lib/bar.rb

libpath=File.expand_path(File.dirname(__FILE__)+'/lib')
$LOAD_PATH.unshift(libpath) unless $LOAD_PATH.first==libpath

require 'foo'
puts "loading #{__FILE__}"

#file : app/runme.rb

libpath=File.expand_path(File.dirname(__FILE__)+'/lib')
$LOAD_PATH.unshift(libpath) unless $LOAD_PATH.first==libpath

require 'foo'
require 'bar'
puts $"
&lt;/pre&gt;

In the previous mentioned techniques, the File#expand_path method is used to get absolute path of either file or directory, the same file or directory is kept only once in a relevant global variable. &lt;br&gt;&lt;br&gt;

&lt;span style="font-weight: bold;"&gt;USING defined?&lt;/span&gt; &lt;br&gt;

This technique is very old and frequently used by C programmers to guard header file to include multiple e.g.
&lt;pre name="code" class="Cpp"&gt;
#file foo.h

#ifdef __FOO_H

#define __FOO_H

...

#endif
&lt;/pre&gt; 
In Ruby, I have seen this technique being applied using Kernel#defined? e.g.
&lt;pre name="code" class="Ruby"&gt;

#file : lib/foo.rb
unless defined?(FooDefined)
   FooDefined=true
   puts "loading #{__FILE__}"
end

#file : lib/bar.rb
unless defined?(BarDefined)
  BarDefined=true
  require File.dirname(__FILE__) + '/foo'
  puts "loading #{__FILE__}"
end

#file : app/runme.rb

require File.dirname(__FILE__)+'/../lib/foo'
require File.dirname(__FILE__)+'/../lib/bar'
puts $"
&lt;/pre&gt;
&lt;span style="font-weight: bold;"&gt;UPDATE on 26-12-2007&lt;/span&gt; &lt;br&gt;
The new &lt;a href="http://eigenclass.org/hiki/Changes+in+Ruby+1.9#l6"&gt;Kernel#require in Ruby 1.9&lt;/a&gt; store full path in $" make this article obsolete.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-4968788227062258157?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/4968788227062258157/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=4968788227062258157&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4968788227062258157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4968788227062258157'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/08/ruby-require-idiom.html' title='Ruby require idiom'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-22117750134661243</id><published>2007-07-28T20:35:00.000+09:00</published><updated>2007-07-28T20:40:18.886+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Turn off color in output of ls command</title><content type='html'>Output of &lt;code&gt;ls&lt;/code&gt; command in color mode sometime causes a problem to my eyes. Turn it off is simple, just put 
&lt;pre&gt;
unalias ls
&lt;/pre&gt;
in .bash_profile or .bashrc (in case of Ubuntu Feisty)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-22117750134661243?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/22117750134661243/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=22117750134661243&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/22117750134661243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/22117750134661243'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/07/turn-off-color-in-ls-command.html' title='Turn off color in output of ls command'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-1278897373470772783</id><published>2007-07-26T10:13:00.001+09:00</published><updated>2007-08-19T00:33:34.183+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Fixture path in ActiveRecord Testing</title><content type='html'>I am using fixture in ActiveRecord Testing. I have many test classes, each using fixtures located in different directories. Individual test work fine, but fails when running together in suite. The problem is &lt;code&gt;fixture_path&lt;/code&gt; is class attribute/variable of &lt;code&gt;Test::Unit::TestCase&lt;/code&gt; so all subclasses of it share the same value.
&lt;pre&gt;
require 'rubygems'
require 'active_record'
require 'active_record/fixtures'

class TestFoo &lt; Test::Unit::TestCase
   self.fixture_path='/u01/test/fixtures/foo'
end

TestFoo.fixture_path # "/u01/test/fixtures/foo"

class TestBar &lt; Test::Unit::TestCase
   self.fixture_path='/u01/test/fixtures/bar'
end

TestBar.new().fixture_path # "/u01/test/fixtures/bar"
TestFoo.new().fixture_path # "/u01/test/fixtures/bar"
&lt;/pre&gt;
Because the Test Unit framework, load all test classes, then run them, so &lt;code&gt;TestFoo.new().fixture_path&lt;/code&gt; get value of &lt;code&gt;TestBar.new().fixture_path&lt;/code&gt;. The solution is simple, just define a method &lt;code&gt;fixture_path&lt;/code&gt; in each test class (in upcoming version after ActiveRecord 1.15.3, the problem is fixed by change &lt;code&gt;fixture_path&lt;/code&gt; to class instance variable see &lt;a href="http://dev.rubyonrails.org/ticket/6672"&gt;ticket 6672&lt;/a&gt;). 
&lt;pre&gt;
class TestFoo &lt; Test::Unit::TestCase
   def fixture_path
      '/u01/test/fixtures/foo'
   end
end

class TestBar &lt; Test::Unit::TestCase
   def fixture_path
      '/u01/test/fixtures/bar'
   end
end

TestBar.new().fixture_path # "/u01/test/fixtures/bar"
TestFoo.new().fixture_path # "/u01/test/fixtures/foo"

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-1278897373470772783?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/1278897373470772783/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=1278897373470772783&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/1278897373470772783'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/1278897373470772783'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/07/fixture-path-in-activerecord-testing.html' title='Fixture path in ActiveRecord Testing'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-5796181095683313212</id><published>2007-07-18T18:19:00.001+09:00</published><updated>2009-02-12T23:24:16.276+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='exception'/><title type='text'>Exception handling</title><content type='html'>I have seen a lot of code, that handle exception in the following way
&lt;pre&gt;
begin
  do_some_things()
rescue
  #... print message, closing file/socket etc. 
end
&lt;/pre&gt;
There is a problem with this style. If there is error, we lost information where it happens because it is quite common that &lt;code&gt;do_some_things()&lt;/code&gt; again call methods of others classes located in different files and so all. &lt;br&gt;
I think that it should be a rule, that we alway print/save to logfile &lt;code&gt;backtrace&lt;/code&gt; of exception in every exception handling code
&lt;pre&gt;
begin
  do_some_things()
rescue =&gt; e
  require 'pp'
  pp e
  pp e.backtrace
  #... print message, closing file/socket etc. 
end
&lt;/pre&gt;
The &lt;code&gt;backtrace&lt;/code&gt; information will help us to identify bug during development and to analyze root cause of exception during operation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-5796181095683313212?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/5796181095683313212/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=5796181095683313212&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5796181095683313212'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5796181095683313212'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/07/exception-handling.html' title='Exception handling'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-4965859452975905373</id><published>2007-07-18T09:39:00.000+09:00</published><updated>2007-07-26T08:53:59.158+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>String concatenation</title><content type='html'>One of common thing that any programs do is concatenate two or more String value, e.g.
&lt;pre&gt;
first_name = 'huy'
sir_name = 'le'
name = first_name + ' ' + sir_name # huy le
&lt;/pre&gt; 
But the above code suffers a problem, if one of concatenated variables is &lt;code&gt;nil&lt;/code&gt;, then it will not work. Checking &lt;code&gt;nil&lt;/code&gt; is tedious and error prone, a simple solution of this problem is putting concatenated variables into an array, removing nil using &lt;code&gt;compact&lt;/code&gt; and using &lt;code&gt;join&lt;/code&gt; method to perform concatenation.
&lt;pre&gt;
first_name= 'huy'
middle_name=nil
sir_name = 'le'
name = [first_name, middle_name, sir_name].compact.join(' ') # huy le
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-4965859452975905373?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/4965859452975905373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=4965859452975905373&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4965859452975905373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4965859452975905373'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/07/string-concatenation.html' title='String concatenation'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-7993884277338691306</id><published>2007-07-07T10:01:00.000+09:00</published><updated>2007-07-07T10:06:56.545+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Standard_params to improve readability of tests</title><content type='html'>Link for &lt;a href="http://beechbonanza.blogspot.com/2007/02/standardparams-to-improve-readability.html"&gt;standard_params to improve readability of tests&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-7993884277338691306?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/7993884277338691306/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=7993884277338691306&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7993884277338691306'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7993884277338691306'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/07/link-to-standardparams-to-improve.html' title='Standard_params to improve readability of tests'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-1256905786501774643</id><published>2007-07-01T15:50:00.000+09:00</published><updated>2007-07-03T14:44:06.310+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Ruby block and command/query separation</title><content type='html'>The recent post &lt;a href="http://objo.com/2007/6/28/ruby-style-ruby-do-end-versus"&gt;Ruby block style do end versus {}&lt;/a&gt; on where to use &lt;code&gt;do ... end&lt;/code&gt; versus &lt;code&gt; {...}&lt;/code&gt; to enclose Ruby block reminds me &lt;a href="http://martinfowler.com/bliki/CommandQuerySeparation.html"&gt;command/query separation OOP principle&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-1256905786501774643?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/1256905786501774643/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=1256905786501774643&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/1256905786501774643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/1256905786501774643'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/07/ruby-block-and-commandquery-separation.html' title='Ruby block and command/query separation'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-413938030016091192</id><published>2007-06-29T09:07:00.001+09:00</published><updated>2007-07-01T13:44:08.364+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Easy verification of API behavior via irb</title><content type='html'>Learning programming language is not just learning language syntax, programmers including myself spend lot of time learning various API. Irb is wonderful tool for learning Ruby API, when I do program in Ruby, I always have Irb open, and I try to run a method of API including core lib, that I am not sure how it works. Comparing to Java, it is much faster and have better productivity.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-413938030016091192?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/413938030016091192/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=413938030016091192&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/413938030016091192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/413938030016091192'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/06/easy-verification-of-api-behavior-via.html' title='Easy verification of API behavior via irb'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-3756097217812994082</id><published>2007-06-29T09:06:00.001+09:00</published><updated>2007-09-22T19:30:17.090+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Open classes</title><content type='html'>When I want to change or add new behavior to existing class, static typed language give me only two options create new class that either extend existing class or delegate to existing class (in Java world some peoples do aspect oriented programming AOP, but it is little bit complicated and is external to the language).&lt;br&gt;
Ruby give me an ability to modify existing class directly. A cross concern or aspect then can be added easily by modifying existing class.&lt;br&gt;&lt;br&gt;
ADDING NEW FEATURE TO EXISTING CLASS&lt;br&gt;
&lt;pre&gt;
class Object
   def blank?
      return true if nil?
      return true if respond_to?(:empty?) &amp;&amp; empty?
      return false
   end
end
nil.blank? #=&gt; true
''.blank?  #=&gt;true
[].blank?  #=&gt;true
{}.blank?  #=&gt;true
'hello'.blank? #false
[:a].blank? #false
{:a=&gt;1}.blank? #false
&lt;/pre&gt;
The above code define method &lt;code&gt;blank?&lt;/code&gt; in class &lt;code&gt;Object&lt;/code&gt;, which is root of all Ruby classes. This will result in well behaving instances of NilClass, String, Array, Hash.&lt;br&gt;&lt;br&gt;
DECORATION A METHOD OF EXISTING CLASS &lt;br&gt;
To decorate a method of existing class is just easy as adding new one e.g.
&lt;pre&gt;
require 'active_support'
class Hash
    alias original_symbolize_keys! symbolize_keys!

    def symbolize_keys!
        each_value do |value|
             value.symbolize_keys! if value.is_a?(Hash)
        end
        original_symbolize_keys!
    end
end
&lt;/pre&gt;
Rails ActiveSupport add method &lt;code&gt;symbolize_keys!&lt;/code&gt;, above code decorate it to convert keys to symbol for a hash value if it is also hash.&lt;br&gt;
When modifying an existing class, we shall make sure that the class is already loaded, otherwise we may get a strange behavior. This is specially important in rails, when classes are loaded dynamically using &lt;code&gt;const_missing&lt;/code&gt; method. About how to handle this problem, there is good tip &lt;a href="http://practicalruby.blogspot.com/2007/02/reopen-with-moduleeval.html"&gt;reopen with class/module eval&lt;/a&gt; on practical ruby blog. Other way to decorate method without using alias is available on &lt;a href="http://split-s.blogspot.com/2006/01/replacing-methods.html"&gt;replacing methods&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-3756097217812994082?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/3756097217812994082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=3756097217812994082&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/3756097217812994082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/3756097217812994082'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/06/direct-change-of-existing-class-instead.html' title='Open classes'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-2033489792852128115</id><published>2007-06-27T15:32:00.000+09:00</published><updated>2007-08-19T11:23:30.832+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Using of keyword based parameter</title><content type='html'>I plan to have presentation of Ruby Language in enterprise application development for developers of the company I worked for and I am thinking about which message should I pass to them. Instead of trying to give many reasons that others already talked about huge benefit of using Ruby, I decide to  give my own very personal reasons why I love Ruby based on my one and half year working with this language. &lt;br&gt;
In early day, when I programed in PL/SQL, I know that PL/SQL support keyword based parameter in procedure/function but I never used this feature, simply I have not recognized the benefit of using it that time.&lt;br&gt;
Ruby does not support keyword based parameter but Ruby programmers fake it easily using  hash in combination with symbol. Using this style is very popular in Ruby core lib and Rails. The following example illustrates it, suppose we want to create method &lt;code&gt;create_user&lt;/code&gt; that create database user, in traditional position based parameter, we will do like that
&lt;pre&gt;
def create_user(username,password,ignore_error,force,verbose)
   #.. implementation detail is ignored
end
#calling it
create_user('scott','tiger',false,true,true)
&lt;/pre&gt;
on keyword based version, the method has simply one parameter &lt;code&gt;params&lt;/code&gt;
&lt;pre&gt;
def create_user(params)
   username = params[:username]
   password = params[:password]
   ignore_error = params[:ignore_error]
   verbose = params[:verbose]
   force= params[:force]
   #.. implementation detail is ignore
end
#calling it
create_user(:username=&gt;'scott',:password=&gt;'tiger',:ignore_error=&gt;false,
  :verbose=&gt;true, :force=&gt;true)
&lt;/pre&gt;
The keyword based version is obviously more verbose, requires more typing, but offers several benefits.&lt;br&gt;
&lt;br&gt;
MORE EXPRESSIVE AND LESS ERROR&lt;br&gt;
The keyword based version is more expressive, just by looking at how the method is called, we know what is the intention, there is no need to look at the implementation file to figure out what it does.
The position based version suffers what Joshua Bloch mentioned in his &lt;a href="http://www.scribd.com/doc/33655/How-to-Design-a-Good-API-and-Why-it-Matters"&gt;How to Design a Good API and Why it Matters&lt;/a&gt; "Long lists of identically typed params harmful"&lt;br&gt;
&lt;br&gt;
GOOD DEFAULT&lt;br&gt;
In the position based version, we can only assign default value for those parameters that are at the end of parameter list.
&lt;pre&gt;
def create_user(username,password=username,ignore_error=false,force=false,verbose=false)
   #.. implementation detail is ignored
end
#calling it
create_user('scott')
&lt;/pre&gt;
This will not give a flexibility of using default value just for few last one.
In the keyword based version, we can archive it easily as follow
&lt;pre&gt;
def create_user(params)
   username = params[:username]
   password = params[:password] || username
   ignore_error = params[:ignore_error] 
   verbose = params[:verbose]
   force= params[:force]
   
   #implementation detail is ignored
   
   #note that Ruby consider nil as false in condition expression, so we should design 
   #boolean value keyword in such way that its default value is false
end

#calling it
create_user(:username=&gt;'scott',:verbose=&gt;true)
create_user(:username=&gt;'scott',:force=&gt;true)
create_user(:username=&gt;'scott',:ignore_error=&gt;true)
&lt;/pre&gt;
I also see people using &lt;code&gt;Hash::merge&lt;/code&gt; to shorten assignment of default values and adding some assertion of accepted keywords e.g
&lt;pre&gt;
#borrow from ActiveSupport
class Hash
  def assert_valid_keys(*valid_keys)
    unknown_keys = keys - [valid_keys].flatten
    raise(ArgumentError,
    "Unknown key(s): #{unknown_keys.join(", ")}\nValid key(s): #{valid_keys.join(',')}")   
      unless unknown_keys.empty?
  end    
end

class DatabaseSchemaBuilder
  
  attr_accessor :ignore_error,:verbose,:force

  def default_options
    {:ignore_error=&gt;@ignore_error,:verbose=&gt;@verbose,:force=&gt;@force}
  end

  def create_user(params)
    params.assert_valid_keys(:ignore_error,:verbose,:force)
    params = default_options.merge(params)
   
    username = params[:username]
    password = params[:password] 
    ignore_error = params[:ignore_error]
    verbose = params[:verbose]
    force= params[:force]

   #implementation detail is ignored
  end
end
&lt;/pre&gt;
EASY TO CHANGE&lt;br&gt;
When we need lets say adding new parameter to the method. In position based version, we end up with changing contract of the method, which may result in looking at every line of code that use this method and make change unless you put at the end of parameter list with default value.&lt;br&gt;
In keyword based version, it is obvious less painful, just adding one more keyword, setting a default value, anyway change only the method itself, e.g. we want to add parameter &lt;code&gt;:noop&lt;/code&gt;, meaning no operation, just for testing.
&lt;pre&gt;
def default_options
   {:ignore_error=&gt;false,:verbose=&gt;false,:force=&gt;false,:noop=&gt;false}
end

def create_user(params)
   params.assert_valid_keys(:ignore_error,:verbose,:force,:noop)
   params = default_options.merge(params)
   
   username = params[:username]
   password = params[:password] || username
   ignore_error = params[:ignore_error]
   verbose = params[:verbose]
   force= params[:force]
   noop=params[:noop]

   #implementation detail is ignored
end
&lt;/pre&gt;
HIDING DESIGN DECISION&lt;br&gt;
Using position based parameter with little bit long parameter list, I have to decide if put one parameter before other or not. I do not have this problem when using keyword based parameter, so it help me do program faster.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-2033489792852128115?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/2033489792852128115/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=2033489792852128115&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2033489792852128115'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2033489792852128115'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/06/why-i-love-ruby.html' title='Using of keyword based parameter'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-5753718803194506685</id><published>2007-06-19T15:42:00.000+09:00</published><updated>2007-06-19T22:56:54.444+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Ant depend task</title><content type='html'>I am writing ruby helper class that will be used in Rakefile to build complex java application. Everything seem to be quite simple, I just copied what has been done by Matt Foemmel in his &lt;a href="http://blog.foemmel.com/jrake"&gt;JRake&lt;/a&gt;. The ruby helper class has a method that check if java class is upto date by comparing access time of the class file and the java source file. I believe that Ant javac task does the same. &lt;br&gt;
Using the ruby helper file, my java application most of time get build correctly but sometime, few class files are not upto date. It take me a while to figure out what is going wrong. &lt;br&gt;
The problem is when a java class depends on other, if other class changes then the java file shall be recompiled even though it is not modified. Looking at Ant documentation, I found that Ant solve this problem using &lt;a href="http://ant.apache.org/manual/OptionalTasks/depend.html"&gt;depend task&lt;/a&gt;. &lt;br&gt;
In order to solve this problem in ruby, I have to do the same as Ant depend task does, read our class file, extract all class references verify if these class references are changed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-5753718803194506685?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/5753718803194506685/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=5753718803194506685&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5753718803194506685'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5753718803194506685'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/06/ant-depend-task.html' title='Ant depend task'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-2478283907861966729</id><published>2007-06-19T07:36:00.001+09:00</published><updated>2009-03-09T18:57:07.821+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>Format of Date/Time when using ActiveRecord with Oracle Database</title><content type='html'>I found no place in ActiveRecord Documentation, that describes how to enter Date/Time into Oracle Database. By looking at source code of OracleAdapter in ActiveRecord, I recognized that ActiveRecord uses Oracle &lt;code&gt;alter session&lt;/code&gt; command to specify date format 
&lt;pre&gt;
ActiveRecord::Base.connection.execute "alter session set NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'"
&lt;/pre&gt;
As implication we shall use this format (e.g '2007-06-30' and '2007-06-30 23:01:45' String are accepted) when entering data (e.g in fixture file) to Date Field.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-2478283907861966729?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/2478283907861966729/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=2478283907861966729&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2478283907861966729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2478283907861966729'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/06/entering-datetime-into-oracle-database.html' title='Format of Date/Time when using ActiveRecord with Oracle Database'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-4278876796804362446</id><published>2007-06-18T10:38:00.007+09:00</published><updated>2009-07-12T18:00:42.103+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='resume-developer'/><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>My resume - SUMMARY OF SKILLS</title><content type='html'>&lt;hr
 /&gt;&lt;h4 id="business-analysis-&amp;amp;-leadership"
&gt;Business Analysis &amp;amp; Leadership&lt;/h4
&gt;&lt;ul
&gt;&lt;li
  &gt;Able to attract, retain and lead people. Led team up to 25 developers, responsible for task planning, technical direction, risk management, code inspections, quality control, performance reviews, staff development. Understood how to create working environment to keep people happy, motivated, creative and productive.&lt;/li
  &gt;&lt;li
  &gt;Solid presentation skill, proven in communication with customers, understanding problems, capturing domain knowledge and turning it into high level requirements in suitable form for development team and other stakeholders.&lt;/li
  &gt;&lt;/ul
&gt;&lt;h4 id="domain-knowledge"
&gt;Domain Knowledge&lt;/h4
&gt;&lt;ul
&gt;&lt;li
  &gt;Financial industry: retail and investment banking, automated trading systems, communication protocols including SWIFT, ISO8583 and FIX. Involved in proposal preparation, conceptual definition and prototyping automated trading system for brokerages based on Marketcetera platform.&lt;/li
  &gt;&lt;li
  &gt;Communication industry: Business processes, practices and standards in communication industry including eTom, SID, OSSJ, Mobile Network Architecture, IN, and TAP3. Hands-on experience in ERP implementation including Billing, Fulfillment, and Accounting.&lt;/li
  &gt;&lt;li
  &gt;Government sector: Hand-on experience in government sector including law enforcement, criminal justice, immigration. Good knowledge in biometrics technology (face and fingerprint) and it's application in government's projects including national ID Cards, and Immigration.&lt;/li
  &gt;&lt;/ul
&gt;&lt;h4 id="software-development"
&gt;Software Development&lt;/h4
&gt;&lt;ul
&gt;&lt;li
  &gt;More than 15 years experience in developing software products with deep knowledge of architecture / design of multi-tiered client-server systems based on middleware including Tuxedo, J2EE (WebSphere, WebLogic) and other emerging Web framework as Ruby on Rails.&lt;/li
  &gt;&lt;li
  &gt;Skillful in many programming languages including C/C++, JAVA, SQL, PL/SQL, RUBY. Passionate for the simple and easy to understand software with rich domain model. Well versed in OOP, design patterns (Design Patterns - GoF, Pattern for Enterprise Application Architecture - PEAA, Domain Driven Design).&lt;/li
  &gt;&lt;li
  &gt;Strong knowledge of algorithms and data structures and their applications in writing a high performance, time critical system for complex business domain.&lt;/li
  &gt;&lt;li
  &gt;Extensive experience with state of art software development practices such as pair programming, Test Driven Development (TDD), refactoring, continuous integration.&lt;/li
  &gt;&lt;/ul
&gt;&lt;h4 id="system-integration-using-messaging-system"
&gt;System Integration Using Messaging System&lt;/h4
&gt;&lt;ul
&gt;&lt;li
  &gt;More then 7 years in design and implementation of software systems that communicate with each other using asynchronous messages. Understand message creation and processing patterns (Enterprise Integration Patterns) and their applications in real world systems.&lt;/li
  &gt;&lt;li
  &gt;Engaged as system architect in many projects that use Event-driven Architecture (EDA) and Service Oriented Architecture (SOA) integration style.&lt;/li
  &gt;&lt;/ul
&gt;&lt;h4 id="infrastructures-design-implementation-&amp;amp;-administration"
&gt;Infrastructure's Design, Implementation &amp;amp; Administration&lt;/h4
&gt;&lt;ul
&gt;&lt;li
  &gt;More than 10 years experience in design, implementation and ongoing maintenance of complex IT infrastructure, that includes J2EE middleware (WebSphere AS, WebLogic), messaging system (MQ), database (Oracle), Unix servers, clustering system, IBM SAN DS series, IBM Tape libraries TS series, Tivoli Storage Manager, CISCO router, PIX firewall and VMWARE virtual technology.&lt;/li
  &gt;&lt;li
  &gt;Proven in writing script (SHELL, RUBY, PYTHON) to automate repetitive administrative activities including monitoring, deployment, configuration change, etc.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-4278876796804362446?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/4278876796804362446/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=4278876796804362446&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4278876796804362446'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4278876796804362446'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/06/my-resume-summary-of-skills.html' title='My resume - SUMMARY OF SKILLS'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-913652102439398208</id><published>2007-06-13T21:55:00.015+09:00</published><updated>2009-07-25T14:12:05.764+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='resume-admin'/><category scheme='http://www.blogger.com/atom/ns#' term='resume-developer'/><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>My resume - EMPLOYMENT HISTORY</title><content type='html'>&lt;hr/&gt;
&lt;h4 id="ing-direct-spain"&gt;ING Direct Spain, Jul. 2009 - Present&lt;/h4&gt;
&lt;p&gt;
&lt;strong&gt;Infrastructure's Software Engineer&lt;/strong&gt;
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;
Administer softwware infrastructure of WebSphere Application Server, JBOSS AS for direct banking system
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;h4 id="ing-direct-japan"&gt;ING Direct Japan, Sep. 2008 - Apr. 2009&lt;/h4&gt;
&lt;p&gt;
&lt;strong&gt;Technical Analyst WebSphere&lt;/strong&gt;
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;Maintain middleware infrastructure of WebSphere Application Server and WebSphere MQ for core banking system&lt;/li&gt;
&lt;li&gt;Plan, install, configure and troubleshoot large scale WebSphere Application Server ND and MQ in AIX environment&lt;/li&gt;
&lt;li&gt;Perform application software deployment, update, performance tuning and other house keeping activities&lt;/li&gt;
&lt;li&gt;Provide assistant for application development team in problem identification and solving
&lt;br/&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Middleware Monitoring System&lt;/em&gt;: directly involved in design, develop and implement monitoring system for middleware infrastructure including exception, performance, capacity monitoring&lt;br
     /&gt;&lt;/li
  &gt;&lt;li
  &gt;&lt;em
    &gt;Application Software Deployment Automation&lt;/em
    &gt;: directly involved in design and implementation system for automatic application software update that ensure fast, reliable, error free deployment with no downtime&lt;/li
  &gt;&lt;/ul
&gt;&lt;h4 id="centre-of-software-engineering---vietnam-dec-1998---jul-2008"
&gt;Centre of Software Engineering - Vietnam, Dec. 1998 - Jul. 2008&lt;/h4
&gt;&lt;p
&gt;&lt;strong
  &gt;Technical Director&lt;/strong
  &gt;&lt;/p
&gt;&lt;ul
&gt;&lt;li
  &gt;Managed software development process and quality&lt;/li
  &gt;&lt;li
  &gt;Prepared technical proposal and system architecture&lt;/li
  &gt;&lt;li
  &gt;Provided training/mentoring on software design, pattern, refactoring, testing&lt;/li
  &gt;&lt;li
  &gt;Participated in various development/implementation projects by rotating between different roles according to the need at each project phase (team leader, project manager, business analyst, software developer)&lt;/li
  &gt;&lt;li
  &gt;&lt;em
    &gt;Border Control System&lt;/em
    &gt;: managed the project to design, develop a J2EE application for immigration department and deploy under BEA WebLogic in major international airports across the country, integrate it with existing backend system using messaging middleware and perform data migration. Responsible for all technical aspects including overall architecture, software development, performance, quality control, server installation and production support.&lt;/li
  &gt;&lt;li
  &gt;&lt;em
    &gt;Data cleansing for law enforcement agency&lt;/em
    &gt;: led a team to perform cleansing of a massive database of hundreds of million of records. Directly involved in design and development algorithm, data structure and rule engine in C/C++.&lt;/li
  &gt;&lt;li
  &gt;&lt;em
    &gt;Utilities Billing - Hanoi Water Work Company&lt;/em
    &gt;: Led a team that implemented a distributed billing and customer management system based on ORACLE and JAVA. In charge of overall system design (including custom developed system, IT infrastructure component selection, data migration strategy) and development of data synchronization module using JMS.&lt;/li
  &gt;&lt;li
  &gt;&lt;em
    &gt;Telecom Billing and Order Fulfillment System&lt;/em
    &gt;: Responsible for implementation of high performance (up to 20,000 event per second), nearly real time event rating engine using C/C++, Tuxedo and database in memory technology.&lt;/li
  &gt;&lt;li
  &gt;&lt;em
    &gt;Personnel Management Information System - Ministry of Home Affair&lt;/em
    &gt;: Managed the development and implementation the Personnel Management Information System for public sector fund by Swedish Agency for Development Cooperation. The system was developed mainly using ORACLE PL/SQL and ORACLE Database.&lt;/li
  &gt;&lt;li
  &gt;&lt;em
    &gt;Electronic Library - Institute of Mathematics - Vietnam&lt;/em
    &gt;: Participated in concept definition, architecture and technology selection (ORACLE and PERL).&lt;/li
  &gt;&lt;/ul
&gt;&lt;h4 id="centre-of-software-engineering---vietnam-jul-1997---nov-1998"
&gt;Centre of Software Engineering - Vietnam, Jul. 1997 - Nov. 1998&lt;/h4
&gt;&lt;p
&gt;&lt;strong
  &gt;Software Developer, Database Administrator, Team Leader&lt;/strong
  &gt;&lt;/p
&gt;&lt;ul
&gt;&lt;li
  &gt;Performed installation, maintenance, support ORACLE Database System&lt;/li
  &gt;&lt;li
  &gt;Designed, developed and implemented framework/library for data synchronization&lt;/li
  &gt;&lt;li
  &gt;&lt;em
    &gt;Utilities Billing - Hochiminh Cities Water Supply Company&lt;/em
    &gt;: managed a final phase of the project to implement of billing and customer's care for Hochiminh Cities Water Supply Company using ORACLE PL/SQL and ORACLE Database. Directly involved in development of module for data synchronization between branches and head quarter&lt;/li
  &gt;&lt;li
  &gt;&lt;em
    &gt;Document management system&lt;/em
    &gt;: Installed, maintained, provided support ORACLE Database System ,Ministry of Science and Technology .&lt;/li
  &gt;&lt;/ul
&gt;&lt;h4 id="notia-information-system---czech-republic-apr-1994---may-1997"
&gt;Notia Information System - Czech Republic, Apr. 1994 - May 1997&lt;/h4
&gt;&lt;p
&gt;&lt;strong
  &gt;Software developer, Team leader&lt;/strong
  &gt;&lt;/p
&gt;&lt;ul
&gt;&lt;li
  &gt;Performed installation, maintenance, support ORACLE Database System&lt;/li
  &gt;&lt;li
  &gt;Participated in various software development projects under different roles team leader, software developer, database administrator, technical support personnel&lt;br
     /&gt;&lt;/li
  &gt;&lt;li
  &gt;&lt;em
    &gt;Custom developed ERP - Altron Czech Republic&lt;/em
    &gt;: Led development team in the project to develop and implement of ERP for a distribution and retail company in Czech Republic using ORACLE database design and GUI development in Borland Delphi.&lt;/li
  &gt;&lt;li
  &gt;&lt;em
    &gt;Fixed Asset Management - Eurotel Prague&lt;/em
    &gt;: Participated in design a fixed asset management software for a mobile phone company based in Prague.&lt;/li
  &gt;&lt;li
  &gt;&lt;em
    &gt;ERP Package Software&lt;/em
    &gt;: Responsible for development and support of C++ part A/R, A/P of ERP package software, that have been deployed to hundreds of customer in Czech Republic.&lt;/li
  &gt;&lt;/ul
&gt;&lt;h4 id="metasoft---czech-republic-jun-1993---jan-1994"
&gt;Metasoft - Czech Republic, Jun. 1993 - Jan. 1994&lt;/h4
&gt;&lt;p
&gt;&lt;strong
  &gt;Software Developer&lt;/strong
  &gt;&lt;/p
&gt;&lt;ul
&gt;&lt;li
  &gt;Developed, customized software, provided technical support&lt;/li
  &gt;&lt;li
  &gt;Implemented software supporting activities of an accommodation agency&lt;/li
  &gt;&lt;/ul
&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-913652102439398208?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/913652102439398208/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=913652102439398208&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/913652102439398208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/913652102439398208'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/06/my-resume-employment-and-education.html' title='My resume - EMPLOYMENT HISTORY'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-3291646660410895150</id><published>2007-06-13T11:07:00.000+09:00</published><updated>2007-06-13T11:19:15.770+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>irb and TAB autocompletion</title><content type='html'>To enable autocompletion on &lt;code&gt;irb&lt;/code&gt;, run
&lt;pre&gt;
irb
require 'irb/completion'
&lt;/pre&gt;
Note to hit double TAB on your keyboard not single one.
One of most comprehensive description can be found &lt;a href="http://drnicwilliams.com/2006/10/12/my-irbrc-for-consoleirb/"&gt;here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-3291646660410895150?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/3291646660410895150/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=3291646660410895150&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/3291646660410895150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/3291646660410895150'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/06/irb-and-tab-autocompletion.html' title='irb and TAB autocompletion'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-5231431290760963424</id><published>2007-06-12T10:15:00.004+09:00</published><updated>2009-07-12T17:55:19.520+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='resume-admin'/><category scheme='http://www.blogger.com/atom/ns#' term='resume-developer'/><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>My resume - TRAINING AND CERTIFICATION</title><content type='html'>&lt;hr
 /&gt;&lt;p
&gt;Oracle E*Business Suite Training (one week at IBM Singapore) - 2005&lt;/p
&gt;&lt;p
&gt;BEA Tuxedo 8 Administration Training (one week at BEA in Malaysia) - 2002&lt;/p
&gt;&lt;p
&gt;Project Management Training (3 weeks at Asia Institute of Technology (AIT) Thailand) - 2000&lt;/p
&gt;&lt;p
&gt;Software Engineering Conference (CASE University of Technology &amp;amp;Thomson CSF) - 1999&lt;/p
&gt;&lt;p
&gt;AIX 4.3 System Administration Certification (IBM Certified) - 1999&lt;/p
&gt;&lt;p
&gt;Oracle Certified Professional on Oracle8 DBA - 1999&lt;/p
&gt;&lt;p
&gt;RS/6000 Solution Sales Certification (IBM Certified) - 1999&lt;/p
&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-5231431290760963424?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/5231431290760963424/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=5231431290760963424&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5231431290760963424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5231431290760963424'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/06/training-and-certification.html' title='My resume - TRAINING AND CERTIFICATION'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-6191452965175190415</id><published>2007-06-12T08:05:00.000+09:00</published><updated>2007-06-12T08:15:06.093+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='writing'/><title type='text'>Switch Off Convert line breaks</title><content type='html'>I have problem when try to post some html stuff on my blog. The posted html contains simple table. However Blogger incorrectly displays it, alignment doesn't work, a lot of strange space. I finally recognized that, this is due to enabling "Convert line breaks" feature of Blogger, that encloses line break into html break tag, I switch it off, and everything work well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-6191452965175190415?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/6191452965175190415/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=6191452965175190415&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6191452965175190415'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6191452965175190415'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/06/switch-off-convert-line-breaks.html' title='Switch Off Convert line breaks'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-341214479765505542</id><published>2007-06-12T06:15:00.007+09:00</published><updated>2009-07-12T17:57:35.986+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='resume-admin'/><category scheme='http://www.blogger.com/atom/ns#' term='resume-developer'/><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>My resume - PROGRAMMING LANGUAGE AND TOOLS</title><content type='html'>&lt;hr
 /&gt;&lt;p
&gt;Operating Systems&lt;/p
&gt;&lt;ul
&gt;&lt;li
  &gt;AIX 4.3/5L, HACMP 4.3, Solaris 7/8, SCO Unix, Windows NT/2000/XP, Linux (Redhat Debian, Ubuntu)&lt;/li
  &gt;&lt;/ul
&gt;&lt;p
&gt;Middleware&lt;/p
&gt;&lt;ul
&gt;&lt;li
  &gt;Websphere ND 6, WebLogic Server 8.1, Websphere MQ 6, Tuxedo 8.0, Tomcat, Ruby on Rails&lt;/li
  &gt;&lt;/ul
&gt;&lt;p
&gt;Database&lt;/p
&gt;&lt;ul
&gt;&lt;li
  &gt;Oracle8i/9i/10g, Oracle Real Application Cluster, MySQL, Microsoft SQL Server 6.5, Microsoft Access&lt;/li
  &gt;&lt;/ul
&gt;&lt;p
&gt;Programming Languages&lt;/p
&gt;&lt;ul
&gt;&lt;li
  &gt;JAVA, C/C++, Ruby, Oracle PL/SQL, Visual Basic, PASCAL, PROLOG&lt;/li
  &gt;&lt;/ul
&gt;&lt;p
&gt;Tools&lt;/p
&gt;&lt;ul
&gt;&lt;li
  &gt;IDEA IntelliJ, Microsoft Visual C++, Rational Rose, Oracle Designer/Developer, Borland Delphi, Toplink, iBATIS, Subversion,Git, Svn, Ant, Maven, Cruisecontrol , JIRA, Mingle, Microsoft Project &amp;amp; Office Suite&lt;/li
  &gt;&lt;/ul
&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-341214479765505542?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/341214479765505542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=341214479765505542&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/341214479765505542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/341214479765505542'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/06/tools-and-languages.html' title='My resume - PROGRAMMING LANGUAGE AND TOOLS'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-4453647092614593185</id><published>2007-06-10T22:07:00.000+09:00</published><updated>2007-06-12T07:41:11.556+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>The secret behind Rails Integration Test</title><content type='html'>Find what is behind Rails Integration Test on good blog's post named &lt;a href="http://www.clarkware.com/cgi/blosxom/2006/04/04#HeadlessApp"&gt;HeadlessApp&lt;/a&gt;
&lt;pre&gt;
$ script/console
Loading development environment.

&gt;&gt; app.class
=&gt; ActionController::Integration::Session

&gt;&gt; app.get "/home"
=&gt; 302

&gt;&gt; app.controller.params
=&gt; {"action"=&gt;"home", "controller"=&gt;"accounts"}

&gt;&gt; app.response.redirect_url
=&gt; "http://www.example.com/login"
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-4453647092614593185?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/4453647092614593185/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=4453647092614593185&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4453647092614593185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4453647092614593185'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/06/behind-rails-integration-test.html' title='The secret behind Rails Integration Test'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-7215477383835806750</id><published>2007-06-09T16:00:00.000+09:00</published><updated>2007-06-12T07:41:41.081+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>gem's environment</title><content type='html'>When playing with gem on my Ubuntu machine, I found an useful command
&lt;pre&gt;
huy@huy-desktop:~/.gem$ gem environment 
Rubygems Environment:
  - VERSION: 0.9.0 (0.9.0)
  - INSTALLATION DIRECTORY: /var/lib/gems/1.8
  - GEM PATH:
     - /var/lib/gems/1.8
  - REMOTE SOURCES:
     - http://gems.rubyforge.org
&lt;/pre&gt;
that shows default gem's environment. By setting the GEM_PATH environment variable to one desire directory, we can share single gem repository across many ruby installations (e.g C ruby and JRuby). The full descriptive information of all gem environments variables can be found in &lt;a href="http://rubygems.org/read/chapter/12"&gt;Gem Command References&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-7215477383835806750?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/7215477383835806750/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=7215477383835806750&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7215477383835806750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7215477383835806750'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/06/gems-environment.html' title='gem&apos;s environment'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-935521328555140855</id><published>2007-06-07T15:51:00.000+09:00</published><updated>2008-12-11T16:35:56.365+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Naming Exception Corba Comm Failure</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hSKkcklzwTU/Rme2mYZ0TkI/AAAAAAAAAB4/EIDqpoCR8A0/s1600-h/naming-exception-corba-comm-failure.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_hSKkcklzwTU/Rme2mYZ0TkI/AAAAAAAAAB4/EIDqpoCR8A0/s400/naming-exception-corba-comm-failure.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5073224275758173762" /&gt;&lt;/a&gt;
Java RMI, Corba, J2EE are sometime still nightmare for developers including these with more than 2 years working experiences with these technologies like myself. I have encountered a "Naming ExceptionCorba Comm Failure" when remote client try to create InitialContext to my Weblogic server. I did check all small details, everything seem to be OK. My Weblogic server is configured to listen on single host interface named "app-svr" that represents a valid IP address 192.168.2.79. My remote client is configured connect to exact same address 192.168.2.79. However it does not work. 
At some moment, I changed address that Weblogic server is listening from "app-svr" directly to IP address 192.168.2.79, and suddenly it starts work. 
It also works when I change back listening IP address of Weblogic server to "app-svr" and at the same time put "app-svr 192.168.2.79" in to hosts file of my remote client. Such behavior of the JVM RMI implementation can cause big trouble most JAVA developers including myself.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-935521328555140855?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/935521328555140855/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=935521328555140855&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/935521328555140855'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/935521328555140855'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/06/naming-exception-corba-comm-failure.html' title='Naming Exception Corba Comm Failure'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_hSKkcklzwTU/Rme2mYZ0TkI/AAAAAAAAAB4/EIDqpoCR8A0/s72-c/naming-exception-corba-comm-failure.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-8149186705921270603</id><published>2007-06-01T20:20:00.000+09:00</published><updated>2007-06-09T16:14:26.447+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Cruisecontrol.rb is too slow</title><content type='html'>I encountered a problem with &lt;a href="http://cruisecontrolrb.thoughtworks.com/"&gt;Cruisecontrol.rb&lt;/a&gt;, the method link_to_code(log) is too slow to process a certain output log, sometime it takes 10 seconds making Cruisecontrol not workable. So for the time being, as workaround, I just comment out this code . 
&lt;pre&gt;
#file: app/helpers/builds_helper.rb
  def link_to_code(log)
    log
=begin    
    @work_path ||= File.expand_path(@project.path + '/work')

    log.gsub(/((\#\{RAILS_ROOT\}\/)?([\w\.-]*\/[ \w\/\.-]+)\:(\d+))/) do
      path, line = File.expand_path($3, @work_path), $4
      
      if path.index(@work_path) == 0
        path = path[@work_path.size..-1]
        link_to ".#{path}:#{line}", "/projects/code/#{@project.name}#{path}?line=#{line}##{line}"
      else
        $1
      end
    end
=end
  end
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-8149186705921270603?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/8149186705921270603/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=8149186705921270603&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8149186705921270603'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8149186705921270603'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/06/cruisecontrol-rb-take-too-long-time.html' title='Cruisecontrol.rb is too slow'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-5738696586016301243</id><published>2007-05-25T19:39:00.000+09:00</published><updated>2007-05-25T19:51:13.238+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>ActiveRecord testing ouside of Rails</title><content type='html'>There is many tips about how to use ActiveRecord outside of Rails but rarely about ActiveRecord testing ouside of Rails. I am working on project that use ActiveRecord ouside of Rails and need to create fixture for testing. It take me a little bit of time to figure out how to do. The source code below demonstrates the trick
&lt;pre&gt;
&lt;code&gt;
require 'test/unit'
require "active_record"
require "active_record/fixtures"

ActiveRecord::Base.establish_connection(
 :adapter =&gt; "mysql",
 :host =&gt; "localhost",
 :username =&gt; "nightlybatch",
 :password =&gt; "secret",
 :database =&gt; "web_orders"
)

#this is because fixture verify existence of rails database configuration
ActiveRecord::Base.configurations[:test] = ActiveRecord::Base.connection
  
class Product &lt; ActiveRecord::Base
end

class TestFoo &lt; Test::Unit::TestCase
 #set fixture path explicitly
 self.fixture_path="c:/temp"
 
 fixtures :products

 def test_ruby_on_rails_should_exist
  assert products(:ruby_on_rails)
 end

end
&lt;/code&gt;
&lt;/pre&gt;
In order to pass the test, the fixture file products.yml shall be created in directory c:/temp, and products table shall be created in MySQL database 
&lt;pre&gt;
#c:/temp/products.yml
ruby_on_rails:
   id:   1
   name: ruby on rails
rails_recipes:
   id:   2
   name: rails recipes

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-5738696586016301243?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/5738696586016301243/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=5738696586016301243&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5738696586016301243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5738696586016301243'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/05/activerecord-testing-ouside-of-rails.html' title='ActiveRecord testing ouside of Rails'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-1395386049504944182</id><published>2007-05-24T17:41:00.000+09:00</published><updated>2007-05-24T17:48:54.932+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Ruby adoption in Vietnam</title><content type='html'>From the time, I know ruby, it is my favorite language, but it seems that no so many developer in Vietnam is using it. Today I have found &lt;a href="http://vnruby.org/"&gt;Vietnam Ruby&lt;/a&gt; site. It is good news, that ruby got an attention in Vietnam and I am not alone, who see the huge benefit of wonderful and humane programming language.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-1395386049504944182?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/1395386049504944182/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=1395386049504944182&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/1395386049504944182'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/1395386049504944182'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/05/ruby-adoption-in-vietnam.html' title='Ruby adoption in Vietnam'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-4286654981530927342</id><published>2007-05-19T14:45:00.001+09:00</published><updated>2009-04-22T16:09:52.607+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>Notia</title><content type='html'>At my early time in Notia (in 1993 if my memory is correct), I has participated in a project, that develop a ERP package that includes General Ledges, Account Payable, Account Receivable, Warehouse Inventory modules. The technology used that time was Novell B*trieve as database engine, C++ and  for business logic, Borland Turbo Vision for C++ for GUI. At that time, Tran Duc Trung was leader, based on university compiler's knowledge, he developed a kind of Domain Specific Language, that allow end-users or implementors define posting rules using that DSL. The "posting rules" DSL is comprehensive featuring expression, AND, OR boolean condition, with Account, Money concept. Other team member, Martin Smid went so far and defined other DSL for reporting function. we called it FRT.  Until now, I have not seen better reporting tool with such flexibility, elegance, and easy to used.   Other other side, we also faced a lot problems. One of them is that MS*DOS can not run program with more than 1MB static data segment. C++ is also not good choice for GUI development, we encountered a lot of errors related to allocation/free memory, using pointer. And one of most ironical is in using of the DSL itself. The software developers didn't understand well accounting to be honest we was not willing to learn it on the other hand implementors and customers was not matured enough in using the DSL in effective manner. Despite these facts, Notia was able to sold the software and implement it in hundreds customers including few big names as ABB.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-4286654981530927342?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/4286654981530927342/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=4286654981530927342&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4286654981530927342'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/4286654981530927342'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/05/notia-and-notia-information-system.html' title='Notia'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-7230907014826083522</id><published>2007-05-10T16:56:00.000+09:00</published><updated>2007-05-10T21:35:08.785+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>ruby module_function</title><content type='html'>Ruby 'module' allows us to define methods then turn these methods into instance methods of a class by using key word 'include'. In ruby world, peoples call this feature 'mixin'. e.g.
&lt;pre&gt;
&lt;code&gt;
module Foo
   def hello
      puts 'hello'
   end
end
class Bar
include Foo
end
Bar.new.hello #=&gt; hello
&lt;/code&gt;
&lt;/pre&gt;
Sometime we need to call method defined in a module without including the module into a class. We can do it by
&lt;pre&gt;
&lt;code&gt;
module Foo
  def self.world
     puts 'world'
  end
end
Foo.world #=&gt; world
&lt;/code&gt;
&lt;/pre&gt;
There is a question how do we turn method 'hello' so it can be used in both mixin style and standalone . The answer is using kernel method 'module_function'
&lt;pre&gt;
&lt;code&gt;
module Foo
   module_function :hello
end
Foo.hello + ' ' + Foo.world # =&gt; hello world
&lt;/code&gt;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-7230907014826083522?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/7230907014826083522/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=7230907014826083522&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7230907014826083522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7230907014826083522'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/05/ruby-modulefunction.html' title='ruby module_function'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-2196617795354194987</id><published>2007-04-29T14:42:00.000+09:00</published><updated>2008-12-11T16:35:57.073+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Install Ubuntu 7.04</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_hSKkcklzwTU/RjQ9CsxYD6I/AAAAAAAAABo/3XoTgPYZ_ds/s1600-h/ubuntu-screen.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_hSKkcklzwTU/RjQ9CsxYD6I/AAAAAAAAABo/3XoTgPYZ_ds/s400/ubuntu-screen.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5058735398031200162" /&gt;&lt;/a&gt;
I took time during holiday to install Ubuntu 7.04 (code name Feisty) on my home computer. I thought for people with Unix background like myself, it should be simple exercise. It is not. My home computer is old Pentium IV 2.26 MHz, 768 MB RAM with installed Windows XP SP2 and I decided to install Ubuntu as guest OS on virtual machine using Vmware Workstation. First I used Vmware Workstation to create a machine with 6 GB Hard disk. Since Ubuntu is not on list of Vmware available guest OS, I just selected other Linux as guest OS for my virtual machine. I booted the virtual machine with fresh downloaded Ubuntu 7.04 and followed the instruction on the screen. The first installation got stuck at 69 %, I waited 10 minutes then reboot and try second attempt, that went well until completion. Now I can login using the account/password asked and created by installation program. My first impression is not bad, the screen looks nice on 1024x768 resolution, even sound card works. Pre-installed Firefox 2.0 work smoothly even on virtual machine, Ubuntu accepts an IP address assigned from my ADSL Internet modem automatically thus I got connection to Internet.&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;1. issue sudo:&lt;/span&gt; I want to install some additional software as root however what is password of my well known root?. After few minutes investigation, I recognized that Ubuntu using sudo as mechanism to allow normal account access to root and by default root is locked and no one can neither login as root nor su. To run program using root account, we have type e.g.
&lt;pre&gt; 
sudo shutdown -r +15 "quick reboot"
&lt;/pre&gt;
sudo will ask us to enter our password and then run shutdown using root account. I known that sudo mechanism is used also in Mac OSx 10.4 Tiger and it offers certain benefits against traditional root, however I can not change my habit so I unlock root account by enter
&lt;pre&gt;
sudo passwd 
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;2. issue apt-get:&lt;/span&gt; I want to try ruby so I type in command line terminal
&lt;pre&gt;
ruby
&lt;/pre&gt;
Ubuntu is intelligent enough to answer that ruby is not installed and offer me that I can install ruby by using
&lt;pre&gt;
sudo apt-get install ruby
&lt;/pre&gt;
I tried and it works. The apt-get is Ubuntu package manager (now I know that it is from Debian and Ubuntu is rooted from Debian). It does all things: downloads required software including dependencies, installs and configures. If we does not know name of software package, then Synaptic Package Manager is application that offers features such as listing, installing and uninstalling software package.
apt-get use configuration on /etc/apt/sources.list, which contains list of ftp servers storing debian distribution package.   
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_hSKkcklzwTU/RjsjPcxYD7I/AAAAAAAAABw/pmglrY93fc8/s1600-h/Screenshot-Synaptic+Package+Manager+.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_hSKkcklzwTU/RjsjPcxYD7I/AAAAAAAAABw/pmglrY93fc8/s400/Screenshot-Synaptic+Package+Manager+.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5060677354609184690" /&gt;&lt;/a&gt;
&lt;br&gt;
After adding new repository into /etc/apt/sources.list, hit 'reload' button to get package information from the new added repository. &lt;br&gt;
&lt;span style="font-weight:bold;"&gt;3. issue add path:&lt;/span&gt; I download and install SUN JDK 1.5.0_11 and want to add JDK 1.5 to PATH so I can type java, javac, etc. I created .bash_profile in home directory and add two following line
&lt;pre&gt;
export JDK_HOME=~/jdk1.5.0_11
export PATH=~/jdk1.5.0_11/bin:$PATH
&lt;/pre&gt;
and do logout/login, it doesn't work. I tried to put these line to .xssesion, after that I can't login to the system anymore and have to login using failsafe session to remove this .xsession file. Looking at documentation and even googling doesn't help. At the end I realized that I should add these line at the end of .bashrc. Then it works in both cases either I login using X-Desktop or terminal using Windows putty.&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;4. issue Vmware tools:&lt;/span&gt; we can not install Vmware tools using Vmware provided package, the Feisty kernel version simply does not match. However Ubuntu provides its own vmware tool package. Installation is pretty simple, just type
&lt;pre&gt;
uname -a
&lt;/pre&gt;
to get kernel version, my kernel version is 2.6.20-15 and then invoke apt-get
&lt;pre&gt; 
sudo apt-get install vmware-tools-kernel-modules-2.6.20-15
&lt;/pre&gt;
Finally reboot to take effect. To be honest, I have not observed better response from any application as Vmware claimed.&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;5. issue update time:&lt;/span&gt; To keep your clock synchronized, install ntpdate package as follows
&lt;pre&gt;
sudo apt-get install ntpdate
sudo /etc/network/if-up.d/ntpdate
sudo crontab -e 
@hourly /etc/network/if-up.d/ntpdate
&lt;/pre&gt;
&lt;span style="font-weight:bold;"&gt;6. issue missing c-header files:&lt;/span&gt; Ubuntu striped down in order to keep installation CD small and installation process fast. The result is default installation does not contain packages that developers normally expect. I got into trouble when I tried to compile a c program, gcc told me that file dlfcn.h is missing. I guested that some lib is missing but can not figure out which package contains the file. After spending time on Google, I found &lt;a href="http://packages.ubuntu.com/"&gt;Ubuntu Package Web Site&lt;/a&gt;, where I can enter file name and search for package containing that file.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-2196617795354194987?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/2196617795354194987/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=2196617795354194987&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2196617795354194987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2196617795354194987'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/04/install-ubuntu-704.html' title='Install Ubuntu 7.04'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_hSKkcklzwTU/RjQ9CsxYD6I/AAAAAAAAABo/3XoTgPYZ_ds/s72-c/ubuntu-screen.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-5363482030263041007</id><published>2007-04-16T10:19:00.001+09:00</published><updated>2008-08-20T17:28:12.752+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Create boot image in AIX</title><content type='html'>To create boot image e.g. on hdisk2 just type
&lt;pre&gt;
# bosboot -a -d hdisk2 --&gt; update the boot image information
# bootlist -m normal -o hdisk0 hdisk2  --&gt; create a new bootlist
# bosboot -a  --&gt;  update the boot image information
# bootlist -m normal -o  --&gt; verify the bootlist is correct
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-5363482030263041007?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/5363482030263041007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=5363482030263041007&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5363482030263041007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5363482030263041007'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/04/create-boot-image-in-aix.html' title='Create boot image in AIX'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-5403910163120798003</id><published>2007-04-14T16:58:00.002+09:00</published><updated>2009-03-09T18:56:21.238+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>Oracle import</title><content type='html'>I was asked by a colleague, how to import an oracle dump file, that was exported from customer production site without data. Someone may think that it is stupid to write about this trivial task. However it is not so simple. In order to provide support for production database, we sometime have to export customer database without data and then import the exported file containing only schema and store procedure into our developer sandbox for testing purpose. The problem is that when import, Oracle try to create table and allocate data segment on disk with the same size as in the production database. Our developer sandbox of couse does not have capacity as customer production machine, so the import process often fails. Solution to this problem is perform import process into 3 steps.
In Step 1, we create table and index creation file using e.g.
&lt;pre&gt;
$imp userid=system/manager@test file=exp-code.dmp full=yes indexfile=create-schema.sql
&lt;/pre&gt;
This will create create-schema.sql that contains tables and index creation commands. With little effort, using any text editor, we can modify this file to remove segment size parameter of each command and save it as create-schema-small.sql.
In Step 2, we run modified create-schema-small.sql against test database to create tables and indexes
&lt;pre&gt;
$sqlplus scott/tiger@test @create-schema-small.sql
&lt;/pre&gt;
In Step 3, we run normal import with ignore error option, so Oracle will create store procedures and others required metadata.
&lt;pre&gt;
$imp userid=system/manager@test full=yes file=exp-code.dmp ignore=yes
&lt;/pre&gt;
After reading, other colleague points out that in Oracle 10g, Oracle provide other tools expdp and impdp that can handle the above mentioned problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-5403910163120798003?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/5403910163120798003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=5403910163120798003&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5403910163120798003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5403910163120798003'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/04/oracle-import.html' title='Oracle import'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-6467263510674476849</id><published>2007-04-12T17:42:00.000+09:00</published><updated>2007-04-17T10:12:39.343+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pattern'/><category scheme='http://www.blogger.com/atom/ns#' term='dsl'/><title type='text'>Soft Coding</title><content type='html'>I have read &lt;a href="http://worsethanfailure.com/Articles/Soft_Coding.aspx"&gt;the soft coding article&lt;/a&gt; recently. Based on my own experience I have a sympathy to the hard coding approach. However I think the problem is not about whether soft coding or hard coding, but programmers including myself try rigidly to follow the soft coding approach believing that it will result in more flexible code, which is not true in most cases.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-6467263510674476849?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/6467263510674476849/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=6467263510674476849&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6467263510674476849'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/6467263510674476849'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/04/soft-coding.html' title='Soft Coding'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-7555559739767609514</id><published>2007-04-08T18:24:00.000+09:00</published><updated>2007-04-08T19:13:35.612+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Using Regexp</title><content type='html'>I got a task to parse file consisting of SQL commands and various noisy lines including empty, comment and echo. I decided to use ruby String::scan to extract SQL commands from files. The only problem is how to write an correct regexp. 
I started with some test
&lt;pre&gt;
entire=&lt;&lt;-EOF
create table A(id number)
/
create table B(id number)
/
EOF

entire.scan(/create table.*\//) #=&gt;[]
&lt;/pre&gt;
I passed to String::scan a regexp that represents a String starting with 'create table' following by any number of characters  and ending with '/'. But there is something wrong instead of 
&lt;pre&gt;
=&gt; ["create table A(id number)\n/", "create table B(id number)\n/"]
&lt;/pre&gt;
I got a empty array 
&lt;pre&gt;
=&gt;[]
&lt;/pre&gt;
I have looked at documentation, tried different alternatives without success. Then I picked the book &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0596528124"&gt;Mastering Regular Expressions&lt;/a&gt; and read the chapter. It is immediately clear to me, instead of using '.' as any character, I should use [^\/] mean any character different from '/'. The correct usage of regexp is
&lt;pre&gt;
entire.scan(/create table[^\/]*\//) 
#=&gt; ["create table A(id number)\n/", "create table B(id number)\n/"]
&lt;/pre&gt;
In order to support multi-line and avoid case sensitive, I just add two options 'm' and 'i' to the regexp
&lt;pre&gt;
entire.scan(/create table[^\/]*\//im) 
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-7555559739767609514?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/7555559739767609514/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=7555559739767609514&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7555559739767609514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/7555559739767609514'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/04/using-regexp.html' title='Using Regexp'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-3300368688536298759</id><published>2007-04-02T18:33:00.001+09:00</published><updated>2009-03-09T18:55:10.426+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>Using Ruby and Rails with Oracle database</title><content type='html'>1. Download ruby-oci8-VERSION-mswin32.rb
2. Install oci8 adapter e.g. on MS Windows
&lt;pre&gt;
c:\ruby ruby-oci8-VERSION-mswin32.rb
&lt;/pre&gt;
3. Using with with Rails
&lt;pre&gt;
ActiveRecord::Base.establish_connection(
 :adapter =&gt; "oci",
 :host =&gt; "sql_net_connect_string",
 :username =&gt; "foo",
 :password =&gt; "bar"
)
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-3300368688536298759?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/3300368688536298759/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=3300368688536298759&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/3300368688536298759'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/3300368688536298759'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/04/install-oci8-adapter.html' title='Using Ruby and Rails with Oracle database'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-2094387065859577153</id><published>2007-04-02T10:34:00.000+09:00</published><updated>2007-04-04T14:01:21.418+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>AIX varyon volume group in multi nodes environment</title><content type='html'>On environment with multi-nodes running AIX accessing single share fiber channel storage, I am facing a problem, if one node fails, I can not import volume group residing on that physical disk in an other surviving node, although physical volume owned by that node is accessible from surviving node. OS gives out a error can not access volume group descriptor. It make me crazy, because one reason, why I need expensive fiber channel storage is to have flexibility to access volume group of failure node from surviving node. It takes me a while to figure out how it works. When AIX activate volume group, it places a lock on corresponding physical volume, so other node can not activate this volume group. The varyon command always checks the physical volume and refuses to activate that volume group if it is locked by other. It does not matter if the locking node is still living or death. In order to release the lock, we should issue on locking node
&lt;pre&gt;
varyon -b volume_group_name 
&lt;/pre&gt;
This '-b' flag breaks disk reservations on disks locked as a result of a normal varyonvg command. Because this flag only works on volume group that is already varied on, we should do it on a node that originally owns this volume group to make sure that if that node fails, other can activate the volume group.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-2094387065859577153?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/2094387065859577153/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=2094387065859577153&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2094387065859577153'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2094387065859577153'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/04/aix-varyon-volume-group-in-multi-nodes.html' title='AIX varyon volume group in multi nodes environment'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-555921627543199391</id><published>2007-04-01T13:15:00.000+09:00</published><updated>2007-04-01T13:20:32.865+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>Writing an Use  Story</title><content type='html'>Having Use Story is first step of software development cycle. How to effectively write an good, concise Use Story is challenging task of business analyst. I have found quite good guideline on that topic on Dan North &lt;a href="http://dannorth.net/whats-in-a-story/"&gt;What is Story&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-555921627543199391?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/555921627543199391/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=555921627543199391&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/555921627543199391'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/555921627543199391'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/04/writing-use-story.html' title='Writing an Use  Story'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-2346023441375371724</id><published>2007-03-18T18:13:00.000+09:00</published><updated>2007-03-20T18:06:01.044+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='dsl'/><title type='text'>Who will develop software in 10 years?</title><content type='html'>This is topic of the panel moderated by Martin Fowler on recent JAOO Conference. But the discussion goes beyond it to other interesting questions "How is it going to be done ?" and "Where it is going to be done?". The video of this panel is available on InfoQ website &lt;a href="http://www.infoq.com/interviews/jaoo-future-of-software-development-panel#"&gt;here&lt;/a&gt;.
Opinions of panellists to the first question are software is still going to be developed by software developer in next 10 years. However tools, DSL will help non-software people i.e. domain experts more involving in the process such as configuring software or create domain model and using tool to generate software. This will make the distinction between application software developer and domain experts less obvious. As result of this, an idea to build a DSL rather than an application presented in &lt;a href="http://www.pragmaticprogrammer.com/ppllc/papers/1998_03.html"&gt;Never Build an Application&lt;/a&gt; becomes more acceptable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-2346023441375371724?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/2346023441375371724/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=2346023441375371724&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2346023441375371724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/2346023441375371724'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/03/who-will-develop-software-in-10-years.html' title='Who will develop software in 10 years?'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-5955559844637255501</id><published>2007-03-17T14:16:00.001+09:00</published><updated>2009-04-22T16:09:30.756+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='career'/><title type='text'>My second job</title><content type='html'>In 1992, one friend introduced me to Notia, an finance consulting, auditor and software development company in Prague. Then I joined Notia as programmer. This was one of most important milestone in my professional career and &lt;a href="http://www.notia.cz"&gt;Notia&lt;/a&gt; was my employer until 1996. I have worked for the company in many projects, playing different role, getting  a lot of wonderful friends, learned many new things. My first team leader was&lt;a href="http://weblogs.java.net/blog/ttran/"&gt; Tran Duc Trung&lt;/a&gt;, who is now Chief Architect for NetBean at Sun Microsystem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-5955559844637255501?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/5955559844637255501/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=5955559844637255501&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5955559844637255501'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/5955559844637255501'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/03/my-second-job.html' title='My second job'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-8118834754892168795</id><published>2007-03-10T20:17:00.000+09:00</published><updated>2007-03-10T22:41:31.947+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>An answer to PragDave Quick Ruby Quiz</title><content type='html'>Dave Thomas in &lt;a href="http://pragdave.pragprog.com/pragdave/2007/03/quick_ruby_quiz.html"&gt;Quick Ruby Quiz&lt;/a&gt; asked how to call method say_hello in 
&lt;pre&gt;
class Fred
  class &lt;&lt; self
    def self.say_hello
      puts "Hi!"
    end
  end
end
&lt;/pre&gt;
I have figured out one of possible way is
&lt;pre&gt;
klass = class &lt;&lt; Fred; self; end
klass.singleton_methods #=&gt; ["constants","nesting",
                        # "say_hello"]
klass.say_hello #Hi!
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-8118834754892168795?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/8118834754892168795/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=8118834754892168795&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8118834754892168795'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/8118834754892168795'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/03/pragdave-quick-ruby-quiz.html' title='An answer to PragDave Quick Ruby Quiz'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-3962410910948706527</id><published>2007-03-08T11:33:00.000+09:00</published><updated>2007-07-01T18:15:42.213+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='dsl'/><title type='text'>Using Ruby flatten and to_a</title><content type='html'>&lt;pre&gt;
class Processor
  def initialize arg
  @arg = arg
  end
 def process
  puts @arg
 end
end

def run_single(processor)
 processor.process
end

def run(processors)
 processors.each{|p| p.process}
end

run_single(Processor.new 'Hello')
run([Processor.new 'Hello',Processor.new 'World'])
&lt;/pre&gt;
In above example, we need to define two methods &lt;code&gt;run_single&lt;/code&gt; taking a processor and &lt;code&gt;run&lt;/code&gt; taking array of processors. To make it simple, we can remove run_single method just call 
&lt;pre&gt;
run([Processor.new 'Hello']) 
&lt;/pre&gt;
in case of single processor. However passing a single element array seems to be not natural, by using flatten or to_a we can create a method that accept both element and array of element as parameter 
&lt;pre&gt;
def run(processor)
 [processor].flatten.each{|p| p.process }
end
&lt;/pre&gt;
or other possible way is
&lt;pre&gt;
def run(processor)
 processor.to_a.each{|p| p.process }
end
&lt;/pre&gt;
then we can do
&lt;pre&gt;
run(Processor.new 'Hello')
run([Processor.new 'Hello',Processor.new 'World'])
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-3962410910948706527?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/3962410910948706527/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=3962410910948706527&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/3962410910948706527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/3962410910948706527'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/03/using-ruby-flatten-and-toa.html' title='Using Ruby flatten and to_a'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-3516790994059714902</id><published>2007-02-20T20:25:00.000+09:00</published><updated>2007-02-21T12:52:56.813+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='pattern'/><category scheme='http://www.blogger.com/atom/ns#' term='dsl'/><title type='text'>Ruby's DSL implementation pattern</title><content type='html'>DSLs are designed to solve a particular kind of problem. Implementation DSLs as internal DSLs in Ruby is getting popular. Jim Freeze in his article &lt;a href="http://www.artima.com/rubycs/articles/ruby_as_dsl.html"&gt;Creating DSLs with Ruby&lt;/a&gt; use "Interpret" pattern to implement DSL. According the article a problem will be solved by using instance of a Class Machine. The Machine has class method load that create an instance of the Class Machine and load a file containing machine's instructions writen in DSL. The Machine also has instance method process, that run loaded instructions with specified data. A Ruby implementation can be as follow
&lt;pre&gt;
class Machine
  def self.load(filename)
    machine = Machine.new
    machine.instance_eval(File.read(filename), 
      filename)
    machine
  end

  def process(*arg)
  #...
  end
end
&lt;/pre&gt;
Using this pattern, in &lt;a href="http://le-huy.blogspot.com/2007/02/ruby-implementation-of-example-in.html"&gt;The ruby implementation of an example in Martin Fowler's Language Workbenches article&lt;/a&gt;  the Reader class can be modified as follows
&lt;pre&gt;
class Reader
    #...

    def self.load dsl_file_name
        reader = Reader.new
        reader.instance_eval(File.read(dsl_file_name), 
          dsl_file_name)
        reader
    end

    def process data_file_name
        File.open(data_file_name,'r') do |file|
            while line = file.gets
                process_line line
            end
        end
    end

    #...

    def mapping type_code, type, &amp;block
        @strategies[type_code] =
            ReaderStrategy.new type_code, type, &amp;block
    end

end
&lt;/pre&gt;
&lt;pre&gt;
#dsl.txt
mapping('SVCL', ServiceCall) do
  extract 4..18, 'customer_name'
  extract 19..23, 'customer_ID'
  extract 24..27, 'call_type_code'
  extract 28..35, 'date_of_call_string'
end
mapping('USGE', Usage) do
  extract 9..22, 'customer_name'
  extract 4..8, 'customer_ID'
  extract 30..30, 'cycle'
  extract 31..36, 'read_date'
end
&lt;/pre&gt;
&lt;pre&gt;
#load_dsl.rb
require 'test/unit'
require File.join(File.dirname(__FILE__),
    '..', 'lib', 'data')
require File.join(File.dirname(__FILE__),
    '..', 'lib', 'data_reader')
require File.join(File.dirname(__FILE__),
    '..', 'lib', 'data_reader_strategy')
class TestLoadDsl &lt; Test::Unit::TestCase
    def test_read_file_load_dsl
        dsl_file_name =  File.join(File.dirname(__FILE__),
            'dsl.txt')
        reader = Reader.load dsl_file_name

        data_file_name = File.join(File.dirname(__FILE__),
            'sample.txt')
        reader.process data_file_name

        assert_equal 4, reader.result.size
    end
end
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-3516790994059714902?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/3516790994059714902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=3516790994059714902&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/3516790994059714902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/3516790994059714902'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/02/dsl-implementation-pattern.html' title='Ruby&apos;s DSL implementation pattern'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-853226759769790377</id><published>2007-02-19T20:00:00.000+09:00</published><updated>2007-11-24T13:35:47.264+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='dsl'/><title type='text'>Ruby and DSL</title><content type='html'>Googling on Internet, I found few interested sources of information of how to implements DSL on top of Ruby language.&lt;br&gt;
&lt;a href="http://www.artima.com/rubycs/articles/ruby_as_dsl.html"&gt;Creating DSLs with Ruby&lt;/a&gt;&lt;br&gt;
&lt;a href="http://liquiddevelopment.blogspot.com/2006/03/way-of-meta.html"&gt;The Way of Meta&lt;/a&gt;&lt;br&gt;
&lt;a href="http://weblog.jamisbuck.org/2006/4/20/writing-domain-specific-languages"&gt;Writing Domain Specific Languages&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-853226759769790377?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/853226759769790377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=853226759769790377&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/853226759769790377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/853226759769790377'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/02/ruby-and-dsl.html' title='Ruby and DSL'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-1925061301352821542</id><published>2007-02-18T12:46:00.000+09:00</published><updated>2007-02-19T19:29:11.818+09:00</updated><title type='text'>ERP Application Service Providers</title><content type='html'>During Tet Holiday, I have time to read the Friedman's Book "The World Is Flat: A Brief History of the Twenty-first Century " that is given to me by a friend. One chaper of the book mention about Salesforce, a company that provides CRM software as service via Internet at very low cost. (Software as a Service) SaaS is not new, the idea rooted from 60, 70 year of last century under different name such as service bureau, utilities computing, etc. I think, using ERP as service is very attractive for small, mid-size companies. Searching on Google, I found the following companies (ASP) offering ERP sofware as service
&lt;a href="http://www.24sevenoffice.com/"&gt;24SevenOffice&lt;/a&gt;
&lt;a href="http://www.netsuite.com/portal/home.shtml"&gt;NetSuite&lt;/a&gt;
&lt;a href="http://www.salesforce.com/"&gt;SalesForce&lt;/a&gt;
&lt;a href="http://www.twinfield.com/"&gt;TwinField&lt;/a&gt;
&lt;a href="http://www.oracle.com"&gt;Oracle CRM On Demand&lt;/a&gt;
&lt;a href="http://www.rightnow.com/"&gt;RightNow Technologies&lt;/a&gt;
Fee of service is different from company to company ranging from 40 to 100 USD per user per month.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-1925061301352821542?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/1925061301352821542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=1925061301352821542&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/1925061301352821542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/1925061301352821542'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/02/erp-application-service-providers.html' title='ERP Application Service Providers'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-346873778629161165</id><published>2007-02-17T17:13:00.000+09:00</published><updated>2007-06-12T07:58:08.251+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='tiếng Việt'/><title type='text'>White Paper về ngành CNTT Việt Nam của GS TS  John Vũ</title><content type='html'>Một người bạn gửi cho Tôi tài liệu nhan đề "Ngành CNTT Việt Nam phải làm gì để thành công trên thị trường thế giới?" của John Vũ. Do đây là chủ đề được nhiều người từ các nhà hoạch định chính sách, các nhà đầu tư, các nhà quản lý, cho đến các kỹ sư phần mềm quan tâm, Tôi đưa nguyên văn dưới đây để mọi người tham khảo. &lt;br&gt;
&lt;hr&gt;
Hội Tin Học TP.HCM (HCA) nhận được nội dung Bạch Thư (White Paper) về ngành công nghiệp CNTT Việt Nam của GS. TS John Vũ - Viện sĩ Viện Hàn Lâm Software Engineering Institute (SEI) thuộc Carnegie Mellon University (CMU); Kỹ sư Trưởng Trung Tâm CNTT của Tập Đoàn Boeing. Qua nội dung của Bạch Thư, người đọc không chỉ tiếp thu thông điệp từ Boeing về những khuyến nghị mà ngành công nghiệp CNTT Việt Nam cần thực hiện mà còn cảm nhận được tình cảm của một trong những chuyên gia Việt Kiều CNTT hàng đầu thề giới gởi đến cộng đồng CNTT Việt Nam, để cùng suy nghĩ cho một ước mơ sử dụng CNTT đưa đất nước vượt thoát đói nghèo, nắm bắt được thời cơ lịch sử của CNTT Việt nam trong bối cảnh cạnh tranh toàn cầu. Hội Tin Học TP.HCM (HCA) tạm dịch nội dung của Bạch Thư và mong nhận được những ý kiến trao đổi của các Anh Chị chuyên gia và doanh nghiệp trong cộng đồng CNTT Việt Nam:&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Ngành CNTT Việt Nam phải làm gì để thành công trên thị trường thế giới?&lt;/span&gt;&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Bạch Thư&lt;/span&gt;&lt;br&gt;
Người thực hiện: John Vu – Viện sĩ Viện Hàn Lâm - Carnegie Mellon Univeristy-CMU;  Kỹ sư trưởng TT CNTT tập đoàn Boeing 09/2006
Dựa trên những thông tin được cung cấp bởi Hội Tin học TP.HCM (HCA), trang web của rất nhiều công ty cũng như những trao đổi với các lãnh đạo doanh nghiệp CNTT  trong suốt chuyến đi Việt Nam, tôi đã thực hiện báo cáo này, đưa ra một cái nhìn tổng quát về ngành CNTT Việt Nam. Dựa trên những kinh nghiệm mà tôi đã trải nghiệm tại Ấn Độ, Trung Quốc, Nam Triều Tiên và Châu Âu, tôi đã đúc kết được một vài vấn đề then chốt nhằm giúp Việt Nam thành công trên lĩnh vực CNTT toàn cầu. Tuy nhiên, báo cáo này cũng chỉ là những quan sát và nhận xét chủ quan của riêng cá nhân tôi, còn nhiều thiếu sót do không đủ thời gian và nỗ lực để thu thập đầy đủ dữ liệu và các thông tin quan trọng. Xét về khía cạnh nào đó, tôi tin chắc rằng báo cáo này có thể giúp Việt Nam tạo ra những lối đi riêng trong việc tập trung vào một vài hoạt động trong năm đầu tiên; tuy nhiên, những hành động có tính chất toàn diện của các khuyến nghị là cần thiết để làm thay đổi ngành công nghiệp CNTT Việt Nam và cho phép tham gia kinh doanh toàn cầu. &lt;br&gt;
&lt;span style="font-weight:bold;"&gt;1) Quy mô là một vấn đề:&lt;/span&gt;&lt;br&gt;
Hầu hết các công ty CNTT tại Việt Nam đều là công ty nhỏ (số nhân sự dưới 50 người). Đây chính là nguyên nhân gây ra những khó khăn, cản trở trong việc hội nhập với thế giới. Nếu nhân sự của công ty bạn đủ mạnh, các đối tác nước ngoài sẽ tin rằng họ đang hợp tác với một công ty đủ sức đương đầu với những rủi ro, luôn có đội ngũ nhân viên chuyên nghiệp, có thể thực hiện được những mong muốn của họ và dĩ nhiên, họ sẽ giữ mối quan hệ hợp tác lâu dài với công ty bạn. Ngoài việc liên doanh và sát nhập, một giải pháp khác là thành lập một liên kết chặt chẽ giữa một số công ty CNTT nhưng vẫn giữ tính cách độc lập của các thành viên (consortium), bao gồm những công ty nhỏ để tập trung nguồn nhân lực cùng thực hiện các dự án chung. Lãnh đạo của consortium (có thể là Khu Công nghệ (CN) Cao sẽ đóng vai trò là nhà đại diện để giao dịch với khách hàng. Consortium có một thực thể pháp l‎ý riêng và tiếp cận thị trường qua một thương hiệu riêng. Dĩ nhiên, các công ty CNTT  trong consortium phải có khả năng làm việc độc lập và hiệu quả để tối thiểu hoá những rủi ro cho khách hàng. Để không ngừng phát triển và mở rộng thị trường quốc tế, doanh nghiệp CNTT tại Việt Nam phải chuyển đổi hình thức “kinh doanh gia đình” sang hình thức hoạt động chuyên nghiệp và cần tập trung vào những thị phần chuyên biệt. Mặt khác, các doanh nghiệp cần cải tiến quy trình quản l‎ý, đặc biệt là việc lập các báo cáo tài chính và tín dụng. Không có một hệ thống quản l‎ý và tài chính tốt, doanh nghiệp Việt Nam rất khó mà có được chỗ đứng trong thị trường quốc tế. Hơn nữa, doanh nghiệp Việt Nam cũng cần nắm rõ những thị trường tiềm năng, nắm bắt thị hiếu đối tác và đầu tư vào lĩnh vực nghiên cứu và phát triển (R&amp;D) để đủ sức cạnh tranh với các đối thủ. &lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Khuyến nghị:&lt;/span&gt;&lt;br&gt;
• Nghiên cứu kỹ lưỡng về khả năng tạo ra một consortium CNTT thông qua Khu CN  cao. Khu CN cao  đóng vai trò như một thực thể pháp lý độc lập trong việc thương thảo với đối tác.&lt;br&gt;
• Để làm việc quốc tế, ta nên tạo ra thương hiệu chung giữa 20-30 công ty nhỏ hơn là các công ty cá thể.&lt;br&gt;
• Đầu tư vào lĩnh vực R&amp;D để nhận biết những sở trường chủ yếu của ngành công nghiệp CNTT và phát triển các cơ hội tương lai.&lt;br&gt;
• Tập trung vào việc cải tiến cơ cấu quản lý, tài chính, kế toán và cơ sở hạ tầng để nâng tầm kinh doanh toàn cầu.&lt;br&gt;
• Nghiên cứu xu hướng thị trường để xác định và triển khai những thị phần chuyên biệt trước khi phát triển theo diện rộng.&lt;br&gt;
• Tăng cường hoạt động tiếp thị để xây dựng hình ảnh một Việt Nam thực sự  là một địa điểm kinh doanh.&lt;br&gt;
• Đề nghị sự hỗ trợ chuyên môn từ Boeing để nhận diện môi trường kinh doanh CNTT hiện nay và nắm bắt những cơ hội trong tương lai.&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;2) Dịch vụ là một vấn đề:&lt;/span&gt;&lt;br&gt;
Dựa trên “Báo cáo Toàn cảnh CNTT-TT Việt Nam” của Hội Tin học TP.HCM (HCA), ngành công nghiêp CNTT Việt nam dường như tập trung nhiều vào các hoạt động như lắp ráp máy tính, kinh doanh phần cứng và cung cấp các dịch vụ internet.  Đây là những lĩnh vực có tính không ổn định rất cao do sự cạnh tranh từ các doanh nghiệp được tổ chức tốt như Lenovo, IBM, Dell, HP and AOL, đặc biệt là khi Việt Nam gia nhập Tổ chức Thương mại Thế giới (WTO). Sẽ tốt hơn và có nhiều lợi ích hơn nếu ngành công nghiệp CNTT  Việt Nam tập trung vào ngành công nghiệp dịch vụ; như gia công phần mềm, gia công dịch vụ trong qui trình quản lý (Business Process Outsourcing - BPO) và gia công lưu trữ dữ liệu thông tin (Media Storage Outsourcing - MSO) là những lĩnh vực có thể sinh lợi rất nhiều cũng như tạo ra nhiều cơ hội việc làm hơn là ngành công nghiệp sản phẩm hiện nay. &lt;br&gt;
Ngành công nghiệp gia công phần mềm Việt Nam vẫn còn rất non trẻ với nhiều công ty chỉ tập trung vào một phần nhỏ trong chu trình phát triển phần mềm như nhập liệu, testing và mã hóa, trong khi có rất ít doanh nghiệp thể hiện năng lực phát triển ứng dụng, quản trị dự án, kiến trúc hệ thống, tích hợp hệ thống, quản trị cơ sở dữ liệu hoặc phân tích quy trình kinh doanh. Nguyên nhân cũng có thể là do hệ thống giáo dục hiện nay vẫn còn ảnh hưởng từ truyền thống Đông Âu – chuyên về đào tạo lập trình hơn là phân tích, thiết kế và phát triển các ứng dụng, các kỹ năng quản l‎ý vốn là thế mạnh của truyền thống đào tạo giảng dạy tại Mỹ. &lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Khuyến nghị:&lt;/span&gt;&lt;br&gt;
• Tiếp thu cách tiếp cận mới về phát triển phần mềm và tập trung vào toàn bộ chu trình phát triển sản phẩm thay vì chỉ triển khai một phần nhỏ trong chu trình.&lt;br&gt;
• Chuyển ngành CNTT Việt Nam từ khuynh hướng nghiêng về sản phẩm sang khuynh hướng nghiêng về dịch vụ.&lt;br&gt;
• Xây dựng kế hoạch quôc gia, hoặt ít nhất là kế hoạch vùng để tập trung vào công nghiệp gia công.&lt;br&gt;
• Hợp tác với các trường đại học nhằm đào tạo nhiều hơn nữa nguồn nhân lực tập trung vào quy trình phần mềm tổng thể và một số kỹ năng chuyên biệt hiện đang thiếu hụt trên thế giới hiện nay.&lt;br&gt;
• Đề nghị sự hỗ trợ về chuyên môn của Boeing nhằm nhận thức đầy đủ về công nghiệp gia công CNTT và nắm bắt được các cơ hội thị trường.&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;3)Năng lực là một vấn đề:&lt;/span&gt;&lt;br&gt;
Có một sự cường điệu khi giới thiệu ưu thế của ngành CNTT Việt Nam là chi phí nhân công thấp trong việc thay thế Ấn Độ và Trung Quốc trong thị trường CNTT thế giới. Ngay cả khi có một giá nhân công thấp hơn, thì nếu chỉ có giá thấp cũng không tạo ra một yếu tố chính cho sự lựa chọn của đối tác. Nhận được đơn hàng mới chỉ là giai đoạn ban đầu trong khi tạo được sự hài lòng cho khách hàng mới là tất cả công việc. Nếu khách hàng nhận ra việc thiếu năng lực của mình thì rất khó giữ được sự hợp tác lâu dài. Hầu hết các doanh nghiệp trên thế giới đều rất cẩn trọng trong việc chọn lựa nhà cung ứng thông qua hệ thống tiêu chuẩn chọn lựa khắt khe có được từ những kinh nghiệm tại những thị trường đã được định hình như Ấn Độ.&lt;br&gt;
Tôi thiết tha khuyến cáo các doanh nghiệp CNTT tại Việt nam nên xác định vị thế của mình dựa trên năng lực chuyên môn hơn là chỉ dựa vào giá thấp. Năng lực chỉ được công nhận dựa trên một hệ thống giáo dục và đào tạo tiên tiến; điều này cần rất nhiều thời gian và công sức. Sự phóng đại năng lực chỉ làm tăng tỉ lệ thất bại hoặc đưa đến những dự án không đạt yêu cầu trong mắt của đối tác. Điều này làm cho chúng ta đánh mất sự tín nhiệm và mất cả những cơ hội hợp tác tiếp theo.  Tốt hơn cả là nên bắt đầu bằng năng lực thực sự và xây dựng sự tín nhiệm nơi khách hàng, khi đã tạo nên mối quan hệ tốt và năng lực đã vững vàng thì việc kinh doanh sẽ phát triển nhanh chóng.&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Khuyến nghị:&lt;/span&gt;&lt;br&gt;
• Đặt kế hoạch phát triển kỹ năng nghiệp vụ hơn là cách đưa ra giá thấp.&lt;br&gt;
• Hợp tác với các trường đại học để đào tạo các kỹ năng như bảo mật, khai thác dữ liệu, quản l‎ý dự án, kiến trúc phần mềm, tích hợp hệ thống v.v…&lt;br&gt;
• Tập trung vào việc cải tiến kỹ năng và năng lực cũng như xác định những kẽ hở thị trường mà Việt Nam có thể chiếm lĩnh trong hiện tại và tương lai.&lt;br&gt;
• Xây dựng mối quan hệ tốt với khách hàng qua việc thực hiện công việc hơn là giá thấp.&lt;br&gt;
• Phân tích thị trường nhằm nhận diện các khả năng phát triển.&lt;br&gt;
• Đề nghị sự hỗ trợ của Boeing trong việc cải tiến giáo dục và đào tạo. &lt;br&gt;
&lt;span style="font-weight:bold;"&gt;4) Vấn đề về trình độ quản lý vững vàng và việc đạt được chính thức chứng chỉ chất lượng quản lý :&lt;/span&gt;&lt;br&gt;
Các khách hàng quốc tế trông đợi nhiều vào trình độ quản lý và chất lượng công việc từ các nhà gia công CNTT. Ấn Độ là quốc gia gia công chiếm lĩnh được vị trí hàng đầu, Việt nam cũng nên đạt đến vị trí của các công ty Ấn độ hoặc sẽ trở thành nhà cung cấp hạng hai hay hạng ba, chỉ nhận được các công việc có lợi nhuận thấp như nhập liệu hoặc thử nghiệm phần mềm.&lt;br&gt;
Chứng chỉ quản lý chất lượng CMMI (Capability Maturity Model Integrated) được phát triển bởi Viện Công Nghệ Phần Mềm (Software Engineering Institute - SEI) của Carnegie Mellon University (CMU), được chấp nhận bởi khách hàng trên toàn thế giới như một tiêu chuẩn bảo đảm cho chất lượng phát triển phần mềm. Các công ty Việt Nam cần đạt được các trình độ cao của CMMI (cấp 4 và 5).&lt;br&gt;
Đối với các khách hàng quốc tế, việc tìm kiếm các nhà cung cấp mới đem đến nhiều rủi ro, nhiều người trong số họ không thích có thêm những nhà cung cấp mới. Một chứng chỉ quản lý chất lượng được công nhận bởi một cơ quan chứng thực độc lập giúp họ giảm bớt những rủi ro. Có được chứng chỉ chính thức CMMI là điểm tạo sự khác biệt chính trong hoạt động gia công phần mềm. Để cạnh tranh toàn cầu, tất cả các doanh nghiệp CNTT Việt Nam cần phải đạt được chứng chỉ CMMI từ các nguồn được công nhận.&lt;br&gt;
Hiện nay, có nhiều chứng chỉ chất lượng “giống CMMI” được cấp bởi những nhà tư vấn ở một số quốc gia nhưng không được tổ chức quốc tế chính thức công nhận. Việc nhận các chứng chỉ như vậy có thể gây ra sự nhầm lẫn đem đến sự tổn hại về uy tín của doanh nghiệp Việt Nam. Chứng chỉ CMMI của Mỹ đòi hỏi sự chứng thực của cơ quan đánh giá được SEI uỷ nhiệm hợp pháp. Danh sách các đơn vị được cấp chứng chỉ CMMI được SEI công bố để bảo đảm tính hợp pháp của qui trình chứng thực. Hầu hết khách hàng quốc tế đều tham khảo danh sách cấp chứng chỉ CMMI của SEI để thẩm định tính xác thực về chứng chỉ CMMI của những ứng viên cung cấp dịch vụ gia công cho họ.&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Khuyến nghị:&lt;/span&gt;&lt;br&gt;
• Các công ty CNTT Việt Nam nên nhanh chóng đạt được chứng chỉ CMMI từ nguồn chính thức.&lt;br&gt;
• Dự trù ngân sách cho việc đạt chứng chỉ CMMI.&lt;br&gt;
• Tạo sự đồng thuận trong tất cả nhân viên xem việc cam kết chất lượng là phương cách kinh doanh.&lt;br&gt;
• Tập trung vào chất lượng và hiệu quả để tạo nên điểm khác biệt của doanh nghiệp.&lt;br&gt;
• Quảng bá kết quả của việc nhận chứng chỉ CMMI như là một phần việc marketing.&lt;br&gt;
• Đề nghị sự hỗ trợ của Boeing trong việc đào tạo và cấp chứng chỉ CMMI.&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;5. Vấn đề thử thách mới, kỹ năng mới:&lt;/span&gt;
Là một thử thách rất lớn cho Việt Nam khi đối mặt với những đối thủ hàng đầu như Trung Quốc, Ấn Độ. Tuy vậy, với việc đào tạo đúng và tiếp cận tốt, CNTT Việt Nam có thể cạnh tranh trực tiếp với những đối thủ lớn này trong thị trường toàn cầu. Việt Nam có những ưu và nhược điểm riêng; nên tập trung vào những gì mình làm được hơn là theo những việc mà Trung Quốc và Ấn Độ đang làm. Để có thể chiến thắng nên thay đổi quan điểm như chi phí thấp và khả năng cao.&lt;br&gt;
Hiện nay cả Trung Quốc và Ấn Đô đều bị ảnh hưởng của việc thiếu hụt trầm trọng nguồn nhân lực kỹ năng cao và họ cố gắng giải quyết vấn đề bằng cách đào tạo ồ ạt số lượng lớn người làm CNTT. Điều này dẫn đến việc giảm chất lượng của nguồn nhân lực. Đây là cơ hội tốt  cho Việt Nam để cạnh tranh bằng cách cung cấp nguồn nhân lực kỹ năng cao qua những chương trình giáo dục và dạy nghề nghiêm chỉnh.&lt;br&gt;
Ngành công nghiệp CNTT thay đổi nhanh chóng, việc hiểu rõ tiến trình và xu hướng phát triển sẽ giúp Việt Nam điều chỉnh hướng đi và tái họach định để bảo đảm kẽ hở thị trường hơn là đi theo những việc người khác đã làm. Xu hướng hiện nay xem trọng giá trị công việc và mối quan hệ hơn là nguồn nhân lực giá rẻ. Hầu hết các phần mềm đang trở thành hệ thống hội tụ mạng lưới, ngày càng phức tạp; đòi hỏi những kỹ năng thành thạo về cấu trúc hệ thống, thiết kế, tích hợp hơn là lập trình hay testing. Khuynh hướng này không có nghĩa là sẽ không còn việc cung ứng nhân lực giá rẻ nhưng ngành công nghiệp ngày càng mở ra nhiều cơ hội cho những quốc gia nào có thể cung cấp được những kỹ năng mới cho khách hàng. &lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Khuyến nghị:&lt;/span&gt;&lt;br&gt;
• Tiến hành nghiên cứu thị trường để nhận diện những kỹ năng, những khả năng mới - đặc biệt tránh những kỹ năng thông thường như lập trình, testing mà nước nào cũng có …&lt;br&gt;
• Thu thập và phát triển những chương trình đào tạo các kỹ năng chuyên sâu - đặc biệt trong quản lý dự án, phân tích yêu cầu kinh doanh, kiến trúc hệ thống, tích hợp hệ thống, quản trị toàn bộ, thiết kế, xây dựng hệ thống…&lt;br&gt;
• Đào tạo những kỹ năng mới cho nhân viên.&lt;br&gt;
• Đề nghị Boeing hỗ trợ các chương trình đào tạo kỹ năng mới từ các trường đại học Mỹ.&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;6. Vấn đề truyền thông:&lt;/span&gt;&lt;br&gt;
Kinh doanh toàn cầu cần kỹ năng giao tiếp trong nhiều ngôn ngữ nhưng tiếng Anh vẫn quan trọng nhất. Doanh nghiệp CNTT Việt Nam cần đào tạo nhân viên về giao tiếp tiếng Anh và hiểu về văn hóa của khách hàng đối với từng nước.&lt;br&gt;
Để giải quyết vấn đề này, cần đến sự trợ giúp của ngoại kiều hoặc của Việt kiều làm người đại diện. Trong môi trường kinh doanh toàn cầu, nên có bộ phận quản lý tại chỗ gồm những người am hiểu văn hóa và tập quán kinh doanh bản địa. Ước tính có khoảng một triệu người Việt Nam tại nước ngoài có khả năng như vậy. Cộng đồng này hầu hết có thể nói hai ngôn ngữ và thường hiểu văn hóa thị trường nơi mà họ lớn lên. &lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Khuyến nghị:&lt;/span&gt;&lt;br&gt;
• Thu thập những chương trình dạy Anh văn cho nhân viên CNTT.&lt;br&gt;
• Thuê nhân viên địa phương hoặc Việt kiều làm đại diện ở mỗi thị trường.&lt;br&gt;
• Tập trung vào việc hiểu rõ văn hóa kinh doanh của khách hàng.&lt;br&gt;
• Thu thập các chương trình đào tạo Anh ngữ cho các khu công nghiệp kỹ thuật cao và các trường đại học.&lt;br&gt;
• Đề nghị Boeing hỗ trợ việc hợp tác với các Học viện và trường đại học Mỹ. &lt;br&gt;
&lt;span style="font-weight:bold;"&gt;7) Vấn đề về đối tác và liên minh:&lt;/span&gt;&lt;br&gt;
Tất cả những công ty CNTT thành công đều có đối tác tại những lĩnh vực nằm ngoài khả năng của họ. Các công ty CNTT Việt Nam cần liên kết với những đối tác khác và tạo ra những liên minh hoạt động trong những lĩnh vực nhất đinh nhằm xác định thị trường theo ngành dọc. Những doanh nghiệp Việt Nam nên giao cho các đơn vị khác cung ứng cho mình những dịch vụ bên ngoài dịch vụ chính và hình thành các mối quan hệ tin cậy với khách hàng. Khu công nghiệp cao có thể là nơi được cân nhắc trước tiên để tạo lập mối quan hệ đối tác hoặc liên minh lẫn nhau. Một cách cơ bản là một thực thể liên kết nhiều công ty sẽ tạo nên một sức mạnh lớn trong thị truờng cạnh tranh gay gắt hiện nay. &lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Khuyến nghị:&lt;/span&gt;&lt;br&gt;
• Thăm dò khả năng thành lập mối quan hệ đối tác và liên minh.&lt;br&gt;
• Hình thành thực thể liên kết consortium lớn để quản lý toàn bộ chu trình hoạt động.&lt;br&gt;
• Nghiên cứu các chủ trương chính sách nhà nước các cấp để xúc tiến thành lập consortium.&lt;br&gt;
• Xác định, kết nối và đo lường những giá trị gia tăng của từng liên minh.&lt;br&gt;
• Hợp thức hoá việc uỷ quyền cho Khu công nghiệp cao như một thực thể đại diện và thương hiệu duy nhất.&lt;br&gt;
• Đề nghị Boeing hỗ trợ xây dựng thương hiệu cho Khu Công nghệ cao.&lt;br&gt;
• Đề nghị Boeing hỗ trợ việc đào tạo cho các nhà quản lý Khu Công nghệ cao từ các trường Đại học và các trung tâm đào tạo ở Mỹ.&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;8) Vấn đề tiếp thị và quảng cáo:&lt;/span&gt;
Cho dù là ngành công nghiệp CNTT Việt nam phát triển rất nhanh trong vài năm qua, nhưng hầu như tình hình này chưa được biết đến trên bình diện kinh doanh toàn cầu. Nếu khách hàng không biết gì về Việt Nam thì tại sao họ phải làm kinh doanh tại đây?
Điều quan trọng bây giờ là Việt Nam cần nỗ lực sử dụng các chiến dịch kinh doanh để chào hàng cho được “CNTT Việt Nam”. Rất khó cạnh tranh với các đối thủ được tổ chức tốt như Ấn Độ, Trung Quốc . Nếu chỉ có giá thấp thì sẽ nhận được rất ít đề nghị có giá trị. Hiện nay hầu hết các doanh nghiệp phương tây giao gia công không coi vấn đề chi phí là chuyện chính yếu mà họ đang tìm kiếm những nguồn cung ứng các dịch vụ có giá trị như hệ chuyên gia và tiếp cận thị trường địa phương. &lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Khuyến nghị:&lt;/span&gt;
Việt Nam cần xác định vị trí của ngành công nghiệp CNTT vào:&lt;br&gt;
* chất lượng và hiệu quả (được chứng nhận bởi tiêu chuẩn CMMI).&lt;br&gt;
* cơ sở hạ tầng ổn định để có thể chuyển giao các dịch vụ cho khách hàng nhanh hơn, tốt hơn và đáng tin cậy hơn.&lt;br&gt;
* xây dựng các kỹ năng chuyên biệt.&lt;br&gt;
* đầu tư phù hợp cho hạ tầng để có thể kinh doanh tốt.&lt;br&gt;
* thân cận với các thị trường Châu Á Thái Bình Dương.&lt;br&gt;
* bảo đảm sự ổn định chính trị và an ninh xã hội.&lt;br&gt;
* thu hút doanh nhân và khách du lịch đến Việt nam.&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Kết luận:&lt;/span&gt;&lt;br&gt;
Những thông tin trong bạch thư này được tôi thu nhận trong chuyến công tác vừa qua ở Việt Nam, có tính chất chủ quan hơn là dựa trên số liệu nghiên cứu khách quan. Tôi tin chắc rằng ngành công nghiệp CNTT Việt Nam cần nghiên cứu rộng hơn và hành động. Những khuyến nghị của tôi giới hạn trong phạm vi quan sát cá nhân với nhận thức đây chỉ là những hỗ trợ ban đầu của Boeing giúp Việt Nam cải thiện hệ thống giáo dục để xây dựng ngành khoa học không gian và ngành CNTT - TT mạnh mẽ; được nhận biết trên thị trường quốc tế và có khả năng cạnh tranh toàn cầu.&lt;br&gt;
(Nguồn: HCA)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-346873778629161165?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/346873778629161165/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=346873778629161165&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/346873778629161165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/346873778629161165'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/02/white-paper-v-ngnh-cntt-vit-nam-ca-gs.html' title='White Paper về ngành CNTT Việt Nam của GS TS  John Vũ'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6288624699880009928.post-9167434298300617888</id><published>2007-02-15T20:26:00.000+09:00</published><updated>2008-12-11T16:35:57.597+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='leisure'/><category scheme='http://www.blogger.com/atom/ns#' term='tiếng Việt'/><title type='text'>Chúc mừng năm mới Đinh Hợi</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_hSKkcklzwTU/RdRDrr9ZGZI/AAAAAAAAABY/BTFjQOw0yFI/s1600-h/dy003.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_hSKkcklzwTU/RdRDrr9ZGZI/AAAAAAAAABY/BTFjQOw0yFI/s400/dy003.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5031721101493344658" /&gt;&lt;/a&gt;
Bức tranh Hoa Đào (Peach Blossom) này là của họa sĩ đương đại Trung Quốc DU YINGQIANG.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6288624699880009928-9167434298300617888?l=le-huy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://le-huy.blogspot.com/feeds/9167434298300617888/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6288624699880009928&amp;postID=9167434298300617888&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/9167434298300617888'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6288624699880009928/posts/default/9167434298300617888'/><link rel='alternate' type='text/html' href='http://le-huy.blogspot.com/2007/02/chc-mng-nm-mi-qu-hi.html' title='Chúc mừng năm mới Đinh Hợi'/><author><name>Le Huy</name><uri>https://profiles.google.com/110372917353678359917</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-l-7KwGOvzuw/AAAAAAAAAAI/AAAAAAAAAp4/dJvqVuchE6c/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_hSKkcklzwTU/RdRDrr9ZGZI/AAAAAAAAABY/BTFjQOw0yFI/s72-c/dy003.jpg' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
