Saturday, December 15, 2007

Hard time installing Ubuntu 7.10

While I can easily install Ubuntu 7.10 on my Thinkpad R52 laptop and got it to work out of the box. I had hard time installing it on my Desktop PC. There are many difficulties I came across which I short-note them here for future references and for those who might have the same problem.

The Black Screen after GRUB Issue

I am not sure how could this happened. But when I chose to boot into Ubuntu (generic) from GRUB boot menu, for the first time. My screen goes blank and nothing happened.

I tried to diagnose the problem by pressing Ctrl-Alt-F1 right after you GRUB disappeared. This will let you see the boot sequences in text mode.

It amazed me since It finally brought me to login screen at that moment. I tried to login but got some message like GTK+ failed and a permission denied message indicating that it cannot create the ~/username/.gnome2/accels directory.

could not create gnome accelerators directory `/home/m3rlinez/.gnome2/accels': Permission denied

So I quit and change the session type of Fail-Safe Command line mode and login again.

There was a big white rectangle appeared on the right of my screen and I could use it as a terminal. I type the following command to remove some directories of gnome.

WARNING:
This command will permanently delete the directories passed as parameter and their contents. Use this at your own risk.

rm -rf .gnome .gnome2 .gconf .gconfd

After that I typed exit and logged in again. I could then get to the desktop.

The Cannot Start Firefox Issue


When I tried to start Firefox, there was a tab indicating "Starting Firefox Web Browser" appeared at my task bar for some seconds before it finally disappeared and nothing happened.

I tried to run Firefox from terminal to see if there might be some sorts of error message output to the terminal. But there was not.

Some guys at Ubuntu forums suggested the readers to run Firefox using strace utility. I then use the following command to start Firefox.

strace firefox


The strace program really gives me some clues on why Firefox failed to started. There is something like a permission problem at the end of strace output. So, I tried to run Firefox using sudo firefox command. And it worked!

Finally, I changed the Firefox folder and theif contents permissions to 777. I could then start Firefox as a normal user. Firefox folder is located at /usr/lib/firefox. A little weird place for Windows user like me :(

cd /usr/lib
chmod -R 777 firefox


The Thai Keyboard Issue

This is easy. Go to System -> Preferences -> Keyboard and add a new Thai Keyboard layout. After that you need to configure the layout switching method, click the Layout Options tab and expand the Group Shift/Lock behavior mode node then tick the Alf-Shift changes group.



The ATi Graphics Display Driver Issue


WARNING: The following instructions are OUTDATED. You can find clear and concise instructions on this page: http://wiki.cchtml.com/index.php/Ubuntu_Edgy_Installation_Guide

I heard from many sources that ATi graphics hardware is hard to use with Linux OS. I have ATi Radeon HD 2600 XT which works fine with Windows Vista. Unfortunately, It did not work well with my Ubuntu.

After logged into X-session for the first time. The screen resolution was set to certain size which was not native resolution of my LG 19'' 1440 x 900 model. I cannot enable the Desktop Effects too. There was a little dialog that suggested me to enable the Restricted Driver from ATi. So I enabled it and reboot.

When I booted into Ubuntu again, my screen got messed up to a resolution like 800 x 600. And there is a message box indicating that I am using a Low Graphics Mode. I tried to change the resolution to my native resolution (1440 x 900) but it does not work. So I clicked the cancel button and logged into X-session using the Low Graphics Mode.

To undo the changes made by Restricted Driver, I loaded up the terminal and type this command to revert the video drivers back to auto-detected one again.

sudo dpkg-reconfigure xserver-xorg


I followed the instructions on the screen, leave every choices as default, and reboot. Everything goes back to normal with Restricted Driver disabled. But, still, I cannot enable the Desktop Effects.

So I went googling and found many suggestions. I finally goes to official ATi website to download a drivers for my graphics card. After made some selections about my system, the website brought me to a page the let my download the ATi Catalyst Drivers for Linux. So I downloaded it. Its name is ati-driver-installer-7-11-x86.x86_64.run.

I started the installer using sh ./ati-driver-installer-7-11-x86.x86_64.run command. I then restarted the X-server by pressing Ctrl-Alt-Backspace key combination. You can simply reboot the machine at this point too but it would takes more time. I finally now got the screen resolution to my native LCD resolution at 1440 x 900. But, again, I still cannot enable the Desktop Effects.

The last step is to install the xserver-xgl package.

sudo aptitude install xserver-xgl command


Here is a short description of what the package does, taken from http://packages.ubuntu.com/hardy/x11/xserver-xgl.

Xgl provides a GL-based X server, performing its drawing through a GL stack. In combination with a GL-based compositing manager, this allows for high-speed transformations of windows.


After the installation, I rebooted the machine again. And I can now finally enable the Desktop Effects :) You can also install the Custom Desktop Effects config tool using this command

sudo aptitude install compizconfig-settings-manager


So, that is anothor story of ATi with Ubuntu Linux of mine. Hope this helps.



My desktop


Another great window management tool

Great MSN Messenger Clone on Linux

My friend, Tap, recommended me a good MSN Messenger client for Linux, emesence (I am not sure if the author tend to let me pronounce that as em-es-ence).

After some experiments with this new program, I have to tell you that this is by far the best MSN Messenger clone I have ever used. The experience is very similar to Microsoft Windows Live Messenger. The GUI is also polish. Here is a sample screen shot I took.



It seems like installing this program from the package manager is not possible at the moment (without adding unstable repository they provided). However, manually installing this program is easy. Because you only need to unpack the archive file and double click the script to get it run. You can eventually create a nice launcher for this program and assign an icon located at /misc/ directory for it too.

I think this program will soon be a great option from those of Pidgin and aMSN. Finally, I really recommend this program for new Linux users :)

You can get it here, http://emesene.org/trac/wiki/WikiStart.

Friday, December 14, 2007

Uninstalled Netbeans 5.5.1 from my Ubuntu

It is not because I do not like Netbeans or something like that. But it is because I got the brand new Netbeans 6.0 IDE installed on my computer. So I think it is OK to uninstall the old version now :)

You can get Netbeans 6.0 IDE here!


Different versions of Netbeans IDE actually can coexist without any conflict. Unfortunately, my HDD space of Ubuntu partition is very limited (at 6 GB). So I need to keep only the programs I actually use.

Uninstalling program from Ubuntu Linux is done differently from Windows. I installed the Netbeans IDE using the Package Manager. But I cannot find a way to uninstall the program using it. So I checked Application->Add/Remove... but still got no luck. So I finally browsed to Netbeans 5.5.1 folder located at /home/m3rlinez/netbeans-5.5.1/_uninst/ and found an uninstall script (uninstaller.sh). I double clicked on it and selected Run in Terminal. Then, the nice GUI popped up and I uninstalled Netbeans.



After my experience from using the latest release of Ubuntu (7.10). I think Ubuntu is now ready for many computer geeks and Java developers. But it may not be ready my mom :( The team has to get more works done.

Friday, December 7, 2007

My Java Remote Method Invocation Tutorial in Thai

My assignment in course Distributed System forced me to study Java Remote Method Invocation or, in short, Java RMI. The requirements are to invoke some methods on the server, host my own server and let my client invoke method in it.

Java RMI is in the same position as .NET Remoting object I mentioned before. It facilitates the interprocess communication. However, I think both method are too hard to use. The .NET Remoting requires ugly configuations while Java RMI requires the policy file. They should be easier.

So, to help the less experience Java programmers getting started, I decided to publish an article on how to make use of Java RMI with Eclipse IDE. The article is in Thai language. You can find it here, http://m3rlinez.googlepages.com/RMITutorial.pdf

Edit: I got some feedbacks from my friends and found that there are still some mistakes in the tutorial. I will correct these when I have time.

Saturday, November 17, 2007

Load bitmap images onto Xilinx Spartan-3 FPGA board

As I mentioned before in this blog about my Hardware Synthesis term project, I designed the copy of Pong game using Verilog and tested it on Xilinx Spartan-3 FPGA Starter Kit. The highlight feature of my project is the ability to display bitmap images as game's components. The following instructions are how to do that.

Note: I will assume that the readers know how to design ASIC using Verilog language with Xilinx Webpack and have some background in computer programming.

First, since I was going to use 640x480 8-color mode, so I prepared 8-color bitmap images of in-game components. These are few examples.



To display these images, we need to store their pixel data somewhere in our circuit. There are few options.

  1. Hard-code the static wire or reg variables, which store pixel data, in the Verilog code. This is going to be easy. But you will suffer from long synthesis, post-place and route time. The size of .v files are going to be unacceptable big too.
  2. Utilize the Block RAMs available as external component on Xilinx Spartan-3 FPGA board. Just set the initial values of these Block RAMs to the pixel data of our images.
In this entry, I am going to use the latter method. For more information about how to use Block RAMs in your design, you can consult this documentation from Xilinx.

No matter which way you chose, we need to convert .jpg, .gif , .png, .bmp, etc. images data into easy-to-understand pixel data. This can be done via a little programming. The following Java program prompts user for an image and convert it to Coefficients File (.coe) for use as initial value of Block RAMs. The format of Coefficient File can be found in the Xilinx documentation I mentioned recently.
The program generates two files, name.coe for color images and name.bw.coe for black and white images. BW images consume less space.

You can now add new ROM module to your design using Xilinx Core Generator from with Xilinx Project Navigator. The detailed instructions on how to do this can also be found on the document I mentioned before. But I am kind enough to provide you this less-detailed screen shots :)



Create new source and select IP (Coregen & Architecture Wizard)



For this kind of use, a read-only Single Port Block Memeory would be enough.



You can specify some memory attributes here.



This is the most important part. You have to tick the "Load Init File" checkbox and click "Load File ..." button then choose the generated .coe file or .bw.coe file.



You can click on the "Show Coefficients" button to make sure that your file properly loaded.

Finally, click on the "Generate" button to generate your ROM module. Your ROM is now ready to use :)

I hope this helps.

Sunday, October 7, 2007

Implementing polymorphism in C

It is about my project at Chulalongkorn University again. My instructor assigned a term project in course Operating System and System Programmingto my team. We have to create a program that simulates some concepts in operating system such as
  • Process creation
  • Process termination
  • Process Scheduling
  • Interrupts
  • Interprocess Communication
  • etc.
Other requirements are the program must be able to run on at least one kind of Unix or Linux systems and the program must be coded in pure C. We used Code::Blocks + Cygwin as our development environment (how to setup Code::Blocks and Cygwin to work together?). However, we compiled and presented our program on a Mac (which is a kind of Unix).

Let's get back to our topic. In our project, a process is represented by a worm moving around the screen. I want each type of worm to move differently.

If I were coding in Java, I would create a base class, named it Worm, and derived it to create other specific classes such as LeftWorm, RightWorm, RandomWorm. This is where polymorphism comes in handy.

How can I implement such high-level object-oriented mechanism in a pure low-level C program ?

The solution is to use pointers to functions. The following code is my code sample which shows how can each animal has different behaviors.

#include <stdio.h>
#include <stdlib.h>

#define DOG 1
#define CAT 2
#define FISH 3


struct
animal{
// animal's name
char *name;
// parameters: count, target's name; return type: void
void (*bark)(int, char*);
};


// typedef a pointer to animal struct
typedef struct animal* ANIMALPTR;

// animals' behaviors
void dogbark(int count, char *target){
int
i;
for
(i = 0 ; i < count ; i++){
printf("Box! %s ", target);
}

printf("\n");
}


void
catbark(int count, char *target){
int
i;
for
(i = 0 ; i < count ; i++){
printf("Meow~ %s ", target);
}

printf("\n");
}


void
fishbark(int count, char *target){
int
i;
for
(i = 0 ; i < count ; i++){
printf("(Cannot bark) %s ", target);
}

printf("\n");
}



ANIMALPTR get_animal(int type){
ANIMALPTR ret =
(
ANIMALPTR)malloc(sizeof(struct animal));
switch
(type){
case
DOG:
ret->name = "Dog";
ret->bark = dogbark;
break
;
case
CAT:
ret->name = "Cat";
ret->bark = catbark;
break
;
case
FISH:
ret->name = "Fish";
ret->bark = fishbark;
break
;
}
}


int
main()
{

int
i;
ANIMALPTR arr[3];
arr[0] = get_animal(DOG);
arr[1] = get_animal(FISH);
arr[2] = get_animal(CAT);
for
(i = 0 ; i < 3 ; i++){
printf("Animal: %s\n", arr[i]->name);
arr[i]->bark(2,"M3rlinez");
printf("\n");
}

return
0;
}
The following is this program's output.

Animal: Dog
Box! M3rlinez Box! M3rlinez

Animal: Fish
(Cannot bark) M3rlinez (Cannot bark) M3rlinez

Animal: Cat
Meow~ M3rlinez Meow~ M3rlinez


Press ENTER to continue.

Friday, September 21, 2007

FPGA Project Completed!




This semester I has enrolled in course Hardware Synthesis Lab. It was about designing an ASIC (Application Specific Integrated Circuit) using HDL (Hardware Description Language). With HDL, the circuit designers do not have to interfere with primitive elements such as AND, OR gates. Instead, they write a module specification in a human-readable language (VHDL, Verilog) and let the synthesizer do the rests. In my class, everyone has to use Verilog with Xilinx ISE Webpack with Xilinx Spartan-3 Starter kit board.

The final project assignment is to design the classic Pong game. The video is displayed through VGA interface in 640 x 480 8 colors mode. And the users can also control their paddles using PS/2 keyboard.

It took me a week to finish this project, Here is its screen shot. (I had took this photo with my phone. The famous PrntScrn is useless in this situation :P )



Only this FPGA board and a monitor needed to run the game!
No need for CPU!




While playing



Set of in-game objects


The really hard part in this project is to make the user interface looks good while you can use only 8 colors! My lab partner, Oei, helped me a big part in choosing the color for this design. To make the screen more beautiful, I decided to put my effort into finding a way to load an image data onto my board. It took me hours reading through Xilinx documentations to find a method to load initial values for Blocked RAM on Spartan-3. I will write an entry on this later when I am free.

In conclusion, this course show me what I can get from little Spartan-3 FPGA board. And how hard it is to make a little Pong game.

I would rather code this in Java or C# and get the result in a blink if I ever need to make my own version of Pong next time o__O

Friday, August 10, 2007

AVG detects Win32/PolyCrypt viruses

Woke up at 10.30 AM today, I am surprised to see that AVG reported 20 infected files in my machine. The virus name is Win32/PolyCrypt. All the infected files are in my Cygwin folder (Cygwin is a program suite that simulate Unix environment in Windows system).



After googling, I found a thread at Ubuntu forums discussing the same problem but they instead found the viruses in their Ubuntu partitions. This lead me to the thread at AVG posted by Adam Hunt.

Ahunt

While it certainly is possible that what you are seeing is a false positive... first let me correct something you said... Just because a malware may not spread on a Linux ( or other OS ) system, doesn't automatically make the item a false positive. A compromised system could still be used to store and distribute other malware even if that malware may not directly affect the system it is on. This is why AVG and other antivirus programs still look for Windows based malware on a Linux box ( and visa versa ) .


If you suspect a file to be a false positive. Test the file at [virusscan.jotti.org] and if it is a false positive, archive (zip, arc, tar etc) the file using a password and email a copy to virus@grisoft.com with a brief description as well as the password you used to archive it with.

If it is a false positive , turn off hueristic scanning for the time being. When Grisoft adjusts the virus defintions you can turn it back on. If you are unable to still test/email the file after disabling the hueristics, you will need to temporarily disable the Resident Shield.

Dear AVG:

Sorry for the delay in taking care of this issue - meetings intervened.

As you recommended I scanned several of the files at [virusscan.jotti.org] that AVG picked up as infected with WIN32/PolyCrypt and only AVG detected them as infected. The rest of scanners indicted "nothing found".

I think it is likely that we have a "false positive" here.

As you have asked I will try to package up one of the files, password protect it and send it to you at virus@grisoft.com. The infected files all seem to be binaries, so it may take me a bit to package them to send to you.

I have the same AVG virus definition file installed on my Windows XP PC and have scanned that PC with no infections found. I believe that this is not a "virus issue", but is an issue of the last definition file's compatibility with Linux instead, judging by the number of Ubuntu users with the same problem at [ubuntuforums.org] . Perhaps this thread would be better moved back to the Linux section of the forum?

Thank you for your time on this. I hope that this will help you solve the issue in a future definitions update.

Adam


In conclusion, it seems like this is an issue with AVG virus definition file and the result is false positive. The detected files won't do any harm to the computer. I will wait for the next AVG update to correct this problem.

Note: What is a false positive result?

Occurs when the system classifies an action as anomalous (a possible intrusion) when it is a legitimate action.
www.tsl.state.tx.us/ld/pubs/compsecurity/glossary.html

When a test wrongly shows an effect or condition to be present (eg that is woman is pregnant when, in fact, she is not).
www.i-bio.gov.uk/UkBioportal/Beginners/html/glossary.html

Some women are told that tests have shown that their baby may have a problem. If further tests then show that this is not the case, that result is called a false positive.
www.arc-uk.org/glossaryofterms/glossaryofterms.htm

Sunday, August 5, 2007

Unwritable session save path in Joomla setup

I found a good fix at http://forum.mamboserver.com/showthread.php?t=12800 by Yohan. Thanks :)

My environment is PHP 4.40 with IIS 5.1 on Windows XP. First, I created new directory and named it sessionsave at C:\php\sessionsave. After that, I changed this directory permission to enable the IUSR_machinename to have full control over it.




Note: If you cannot find Security tab in your Windows XP system. You can enable it by go to the Tools -> Folder Options ... -> View -> remove the tick in front of "Use simple file sharing". Windows Server family enable this by default.

Finally, I edited my php.ini file. Back to the setup, Joomla can now write to the session save path.

[Session]
; Handler used to store/retrieve data.
session.save_handler = files

; Argument passed to save_handler. In the case of files, this is the path
; where data files are stored. Note: Windows users have to change this
; variable in order to use PHP's session functions.
; As of PHP 4.0.1, you can define the path as:
session.save_path = "C:\php\sessionsave\"

PHP with IIS error: The page cannot be found

Recently, I mangled up my IIS's wwwrooot directory. So I had to create a new one.

Today, I need to install Joomla, one of popular PHP CMS applications. But when I copied the package to my new wwwroot and browse to http://localhost/GearGame ("GearGame" is my project's name) the web server return me the 404 error. I am running PHP 4.40 with IIS 5.1 on Windows XP.



After some experiments, I found that I cannot run any PHP file. So I consult the PHP's readme file and found these lines:

The following steps are optional:

* Edit your new php.ini file. If you plan to use OmniHTTPd, do not
follow the next step. Set the doc_root to point to your web
servers document_root. For example:

doc_root = c:\inetpub\wwwroot // for IIS/PWS

doc_root = c:\apache\htdocs // for Apache

Then, I browse to my php.ini file located at C:\Windows\php.ini and edit the doc_root to my new wwwroot.

; The root of the PHP pages, used only if nonempty.
; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root
; if you are running php as a CGI under any web server (other than IIS)
; see documentation for security issues. The alternate is to use the
; cgi.force_redirect configuration below
doc_root = C:\wroot

I finally refresh the page, I can setup my Joomla now.

Tuesday, July 31, 2007

Simple Tic-Tac-Toe AI in JavaScript

Click here to see the Tic-Tac-Toe game in action! (open in new window)

Last year, I was challenged by the thread at Thaiadmin to implement a two-player OX (or Tic-Tac-Toe, XO, what you may call) game. I had done this kind of program in VB6 before, so I decided to implement the one-player JavaScript version.

The hardest part of of this project is debugging the JavaScript. I had to write the value of each variable and things done in each step to the screen (as you see in the bottom of the figure above) to diagnose the problems. I was so embarrassed that I did not know any of the great web developer's tools such as FireBug.

The ideas behind the decisions making part (or the AI) are to search every possible moves and take the best one. In each move, We assumed that the opponent chose his best move and we chose our best move. This method is "Minimax" method. As described in Wikipedia:

Minimax (sometimes minmax) is a method in decision theory for minimizing the maximum possible loss. Alternatively, it can be thought of as maximizing the minimum gain (maximin). It started from two player zero-sum game theory, covering both the cases where players take alternate moves and those where they make simultaneous moves. It has also been extended to more complex games and to general decision making in the presence of uncertainty.

The Minimax method can be applied to many other board games too. But in some complex games such as Chess, there was so many game states that you cannot search into them entirely (it would take many many years on an ordinary computer). So some heuristic must be used to approximately determine value of each state and the search must be limited at a fixed level (deeper level of search makes the AI cleverer).

In my case, there was not too many game states so I can search on them entirely. You can test my game here - http://m3rlinez.googlepages.com/oxai.htm. Choose View->Source to view the JavaScript source code.

Saturday, July 14, 2007

Fast nth Fibonacci number calculation

I am now preparing myself for Dynamic Programming quiz this Wednesday. One classic example of DP is the calculation of nth Fibonacci.

The straight-forward way is to convert the recurrence relation, Fn = Fn-1 + Fn-2, F0=0, F1=1, to a recursive function. However, the problem overlapping makes this solution poor in performance. A betterway is to calculate value of Fk from 2 to n in a bottom-up style. The asymptotic running time of this DP method is O(n).






private static int FibN(int n)
{
if (n <= 1)
return n;

int a = 0, b = 1, c = 1;
for(int i = 2 ; i <= n ; i++)
{
c = a + b;
a = b;
b = c;
}

return c;
}



My instructor, Aj.Somchai, wrote in one of his book, "การออกแบบและวิเคราะห์อัลกอริทึม (Design & Analysis of Algorithms)", the challenge of finding a method that calculate Fn in less than O(n) time. After thinking for a while, I fired up my browser and search :)

This page described a method of calculating Fn in O(log n) time using a property of special case of matrix multiplication. The following is my implementation of this O(log n) method and O(n) method in C#.





using System;
using System.Collections.Generic;
using System.Text;

namespace FastFibo
{
class Program
{
private static int[] G = new int[] { 1, 1, 1, 0 };

/// <summary>
/// Get [[1,1][1,0]]^n matrix.
/// </summary>
/// <param name="n">n</param>
/// <returns>[[1,1][1,0]]^n</returns>
private static int[] GetFiboMatrix(int n)
{
if (n == 1)
return G;
int[] c = GetFiboMatrix(n / 2);
c = MatrixMul(c,c);
if (n % 2 == 1)
c = MatrixMul(c, G);
return c;
}

private static int[] MatrixMul(int[] a, int[] b)
{
if (a.Length != 4 || b.Length != 4)
throw new Exception("Invalid matrix size");

int[] res = new int[4];
res[0] = a[0] * b[0] + a[1] * b[2];
res[1] = a[0] * b[1] + a[1] * b[3];
res[2] = a[2] * b[0] + a[3] * b[2];
res[3] = a[2] * b[1] + a[3] * b[3];
return res;
}

private static int FibLogN(int n)
{
if (n <= 1)
return n;

return GetFiboMatrix(n)[1];
}

private static int FibN(int n)
{
if (n <= 1)
return n;

int a = 0, b = 1, c = 1;
for(int i = 2 ; i <= n ; i++)
{
c = a + b;
a = b;
b = c;
}

return c;
}


static void Main(string[] args)
{
for (int i = 1; i <= 46; i++)
Console.WriteLine("{0,4} FibN = {1,10} FibLogN = {2,10}",
i, FibN(i), FibLogN(i));
}
}
}



The normal 4-byte integer can only contain values in range [-2^31,2^31-1] and we can only get actual nth Fibonacci number up to n = 46. The difference of running time between O(n) and O(log n) for n under 47 can hardly be noticed.

This, however, can be apply to some Computer Olympiad problems such as "Find the last digit of nth Fibonacci number" :) You can also make this faster by convert it to non-recursion version.

RocketDock: Cool desktop dock menu!



Have been using RocketDock since last week. I found that it is so convenient to launch applications from dock menu. The icons are bigger than those on quick launch bar. You can actually configure the size of icons too!

Get RocketDock here (freeware)

Wednesday, July 4, 2007

Programmer Personality Type

Found an interesting test to do at Nut's blog.

My programmer personality type is ...

PHTB

You're a Planner.
You may be slow, but you'll usually find the best solution. If something's worth doing, it's worth doing right.


You like coding at a High level.
The world is made up of objects and components, you should create your programs in the same way.


You work best in a Team.
A good group is better than the sum of it's parts. The only thing better than a genius programmer is a cohesive group of genius programmers.


You are a liBeral programmer.
Programming is a complex task and you should use white space and comments as freely as possible to help simplify the task. We're not writing on paper anymore so we can take up as much room as we need.


You can take this test at http://www.doolwind.com/index.php?page=11 :)

My experiences from working on my last project influence most of my answers.

Friday, June 22, 2007

Running a J2ME application on Windows Mobile 5.0 devices

It is a real pain for Windows Mobile users to get a simple J2ME program to run on their mobile devices. I owned a Dopod 818 pro which is running WM5, and now I have to get my J2ME application to run on it.

Dopod actually bundled an application named MIDLet manager to run J2ME program. But after using it for a while, I experienced some weird behaviors such as automatic closing of the running program. So I think I should find other JVM for my phone.

After some googlings, I found that IBM J9 is one of the good choices. I download the installation package and follow instructions in install.pdf. There is also a good guide, which covers the installation for other platforms, at Markus blog too.



I first faced with the weird Exception from emulator.exe which says it cannot download the jad files.

An exception occurred
[//J9/IBM/examples/golfscoretrackersuite.jad] while downloading from file://J9/IBM/examples/golfscoretrackersuite.jad


Then, I found out that I mistyped the URL. It has to be “file:///{path}” instead of “file://{path}” (Note that there are THREE SLASHES) :P

I can now get the example ran.

Thursday, June 7, 2007

ChemL1ve! quite a hard time …

My team and I had just finished our Imagine Cup 2007 local round project, ChemL1ve!, and had given presentation on yesterday at TK Park, Central World Plaza. We won the third prize. I am really happy since I thought our team would not be in the top three of six teams from various Universities.

We had to give the presentation in very limited time of 15 minutes and we could not finish it in time. It was a really bad feeling. Try to think of yourself spent days coding a program and had only five minutes to show it off. It is hard to admit but this is normal situation. Good developers should learn some presentation skills too.

The winner was a team from CPE, Kasetsart University. Their project is an application that helps people who cannot read to be able to understand a book. By let the web camera point to the contents of the book. The application quickly recognizes the word on the page and displays the image and details of that word on the screen in a stylish way using WPF. User can also browse to the word he/she interested in by pronouncing that word to the microphone. The demo was really great and I can tell that this is the obvious winner of this year, right after I attend their presentation.

Our project is multi-user virtual chemistry lab software. At the stage of proposal submission, without any research, I thought it would not be so hard to develop such kind of system. But after that, when I tried to model it, I realize this was too big for a team with two inexperienced developers! More importantly, to correctly and effectively model this kind of system, you need a solid understanding of Chemistry which I actually got a “C” in my first Intania year T-T

Since this is a tech blog, I may go into the details of implementation. Here is my “ugly” class diagram at one stage of the development. Please note that it is “ugly” in term of OO design (Visual Studio 2005 generates this polish diagram quite well). It is “ugly” because it cannot support many of the system behaviors.

With this diagram, number of kind of lab equipment is fixed because I use a class to represent equipment. I am wondering if I could dynamically create new equipment at runtime. Those reflection stuffs might be able to do this sort of thing.

That is all my part. Another part is a client that my friend develops using the WPF as presentation layer. The client sends the interaction between lab equipment and get result from Web Service which wraps my part. This diagram below may help visualize architecture of our project (I designed this diagram using Expression Design, it is suitable for creating this kind of image than Adobe Photoshop).

Here are some screenshots of the client, ChemL1ve! Action.

For those who want to join next year’s Imagine Cup s/w design competition, I suggest that you should focus more on your ideas than the implementation details and make sure that your application can really solve the problem addressed. And keep in mind that this is “ideas” and “software design” competition. Do not mess with the coding too much. Just make sure that the app will not throw any uncatched exceptions during the demonstration : )

Friday, May 11, 2007

Programming MSMQ (Microsoft Message Queue) - Sample code

Yesterday, I went to "MSDN Connection Training Sneak Peak Preview" seminar at Microsoft Thailand. The topic is "Distributed Application Development with Visual Studio 2005". It is actually a shortened version of Iverson training course : if you want to take a full course, you will have to pay at least ten thousand baht for 3 days training o__O!

I really learned many things from this session. One of them is MSMQ or Microsoft Message Queue.

Message queuing is a communication tool that allows applications to reliably interconnect in a distributed environment where one of the applications may or may not be available at any given time. The queue acts as a holding container for messages as they are sent between applications. The applications send messages to and read messages from queues to communicate back and forth. An application writes a message to a queue, which will then be received and processed by another application at some point determined by the receiving application. This type of communication is designed for asynchronous use where the applications involved are not waiting for an immediate response from the other end. - http://www.codeguru.com/Csharp/.NET/net_general/netframeworkclasses/article.php/c4241/


This really fits into my project's need for a queue which can serve clients over the internet.

To program the MSMQ you need to install Messaging Queuing first. Insert your Windows Setup CD and choose "Install optional Windows components". Then, tick the checkbox in front of "Message Queuing" and go on.



Now, create a new Visual C# Console project. Add reference to System.Messaging and add the following code.




using System;
using System.Collections.Generic;
using System.Text;
using System.Messaging;
using System.Threading;

namespace MSMQSample
{
class Program
{
static void Main(string[] args)
{
// Check if queue alreasy exists.
string queuePath = @".\private$\SampleQueue";
MessageQueue queue;
if (!MessageQueue.Exists(queuePath))
// If not, create one.
queue = MessageQueue.Create(queuePath);
else
queue = new MessageQueue(queuePath);

// Send something to queue.
DateTime dt = DateTime.Now;
Console.WriteLine("Message to send: " + dt.ToString());
Message sendMsg = new Message(dt, new XmlMessageFormatter());
queue.Send(sendMsg, "My DateTime");

// Wait for five seconds.
Thread.Sleep(5000);

// Get sent message from queue.
Message receiveMsg = queue.Receive();
receiveMsg.Formatter = new XmlMessageFormatter(
new Type[] { typeof(DateTime) });
DateTime ret = (DateTime)receiveMsg.Body;

Console.WriteLine("Message Received: " + ret);
Console.Read();


}
}
}


And this is what our message looks like. You can open this window in Computer Managment/Services and Applications/Message Queuing/samplequeue



Here are some great resources on the basics of MSMQ:
And for those who want to attend next MSDN Connection Training Sneak Peak Preview you have to register for an account at http://www.msdnconnection.com/thailand and monitor this page [MSDN Connection Training Sneak Peak Preview]



Wednesday, May 2, 2007

Really simple blob detector

Few days ago while i was reading news at Blognone, I spotted an interesting topic on how to detect
(and calculate the area of ..) circles in an image. This is a well-known problem in the field of Computer Vision known as Blob Detection. I had some experiences in implementing the blob detector in C and C# but had never done it in Java. So I decided to write one. The code was more compact and straight to the point than my C and C# version.

This is the input image.



And here is my code.




package blobdetector;

import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
import javax.imageio.ImageIO;
import javax.management.Query;

/**
*
* @author m3rlinezatgmaildotcom
*/
public class Main {

public Main() {
}

public static boolean isBlack(BufferedImage image,int posX,int posY){
// หาสีที่สุดที่สนใจ
int color = image.getRGB(posX,posY);

// หาค่าความสว่างจากการเฉลี่ย RGB
int brightness =
(color & 0xFF) +
((color >> 2) & 0xFF) +
((color >> 4) & 0xFF);
brightness /= 3;
return brightness < 128;
}

public static void main(String[] args) {
if(args.length != 1){
System.err.println("ERROR: Pass filename as argument.");
return;
}

String filename = args[0];
// String filename = "C:\\Users\\Natthawut\\Desktop\\Polymorphism\\blob.jpg";
try {
BufferedImage bimg = ImageIO.read(new File(filename));

// map สำหรับเก็บว่าจุดใดบ้างที่ได้รับการสำรวจไปแล้ว
boolean[][] painted =
new boolean[bimg.getHeight()][bimg.getWidth()];

// วนรอบทุกจุดในรูป
for(int i = 0 ; i < bimg.getHeight() ; i++){
for(int j = 0 ; j < bimg.getWidth() ; j++) {
// System.out.println(i + " " + j + " b " + isBlack(bimg,j,i));
// ถ้าจุดนั้นเป็นสีดำ และยังไม่เคยถูกสำรวจ
if(isBlack(bimg,j,i) && !painted[i][j]){

// ทำการ floodfill
Queue<Point> queue = new LinkedList<Point>();
queue.add(new Point(j,i));

int pixelCount = 0;
while(!queue.isEmpty()){
Point p = queue.remove();

// เช็คว่าจุดที่ดึงมาอยู่ในขอบเขต
if((p.x >= 0) && (p.x < bimg.getWidth() && (p.y >= 0) && (p.y < bimg.getHeight()))){
if(!painted[p.y][p.x] && isBlack(bimg,p.x,p.y)){
painted[p.y][p.x] = true;
pixelCount++;

// ใส่จุดรอบๆจุดที่ดึงออกมาลงไปในคิว
queue.add(new Point(p.x + 1,p.y)); queue.add(new Point(p.x - 1,p.y));
queue.add(new Point(p.x,p.y + 1)); queue.add(new Point(p.x,p.y - 1));
}
}
}
System.out.println("Blob detected : " + pixelCount + " pixels");
}

}
}

} catch (IOException ex) {
ex.printStackTrace();
}

}

}




And here is the output.

Blob detected : 1 pixels
Blob detected : 1339 pixels
Blob detected : 1 pixels
Blob detected : 5582 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 4018 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels


Edit: P'Deans4J suggested me to write the same program using recursion too. Here is my code in recursive version. I added another static method "floodfill" which returns number of pixels in current blob.




package blobdetector;

import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
import javax.imageio.ImageIO;
import javax.management.Query;

/**
*
* @author m3rlinezatgmaildotcom
*/
public class Main {

public Main() {
}

public static boolean isBlack(BufferedImage image,int posX,int posY){
// หาสีที่สุดที่สนใจ
int color = image.getRGB(posX,posY);

// หาค่าความสว่างจากการเฉลี่ย RGB
int brightness =
(color & 0xFF) +
((color >> 2) & 0xFF) +
((color >> 4) & 0xFF);
brightness /= 3;
return brightness < 128;
}

public static int floodfill(
BufferedImage image,
boolean[][] painted,
int posX, int posY){

// ตรวจสอบขอบเขต
if((posX < 0) || (posX >= image.getWidth()) || (posY < 0) || (posY >= image.getHeight()))
return 0;

if(!painted[posY][posX] && isBlack(image,posX,posY)){
painted[posY][posX] = true;
return 1 + floodfill(image,painted,posX+1,posY) +
floodfill(image,painted,posX-1,posY) +
floodfill(image,painted,posX,posY+1) +
floodfill(image,painted,posX,posY-1);
}

return 0;
}

public static void main(String[] args) {
if(args.length != 1){
System.err.println("ERROR: Pass filename as argument.");
return;
}

String filename = args[0];

try {
BufferedImage bimg = ImageIO.read(new File(filename));

// map สำหรับเก็บว่าจุดใดบ้างที่ได้รับการสำรวจไปแล้ว
boolean[][] painted =
new boolean[bimg.getHeight()][bimg.getWidth()];


// วนรอบทุกจุดในรูป
for(int i = 0 ; i < bimg.getHeight() ; i++){
for(int j = 0 ; j < bimg.getWidth() ; j++) {

// ถ้าจุดนั้นเป็นสีดำ และยังไม่เคยถูกสำรวจ
if(isBlack(bimg,j,i) && !painted[i][j]){

int pixelCount = floodfill(bimg,painted,j,i);

System.out.println("Blob detected : " + pixelCount + " pixels");
}

}
}

} catch (IOException ex) {
ex.printStackTrace();
}

}

}


While the recursive version uses less LOC, easier to understand and easier to code than the first solution, its performance is not as good as the first one and it actually gives me java.lang.StackOverflowError when used with the sample image. But if the problem's size is small, I prefer implementing the recursive version too.