Friday, December 24, 2010
Christmas Redwoods
Unfortunately the only horizontal branches strong enough to really hold ornaments are near the base of the trees, about an inch or two from the soil in their pots. We managed to hang a few ornaments around the trunk. It didn't help that the ornament kit we got had no hooks for hanging.
As you can see the seedlings are doing just fine so far this winter. Generally they have been near the window for the short amount of direct sunlight we have in the apartment, the cold temperatures from outside haven't seemed to affect them too much.
India Trip Inventory
- 2 bottles of 30 doses Malarone - Anti-malarial
- 2 bottles of 3 doses IC Azithromycin - anti-biotic for severe stomach illness
- 1 bottle of 6 doses IC Zolpidem Tartrate ( Ambien ) - for jet lag
- 2 tubes of Ultrathon™ Insect Repellent - 34% DEET (2 oz.)
- 1 tube AfterBite® Outdoor - insect bite and itch relief. (0.7 oz.)
- 1 bottle Pepto Bismol - 40 caplets
- 10 fl. oz. total of Purell® Instant Hand Sanitizer - 65% alcohol, 2 bottles
- 1 Adventure Medical Kits Hand Sanitizer + Lotion, alcohol free spray bottle.
- 1 tube 100 SPF Sunblock (3.0 oz)
- 1 tube Cortizone-10® itch relief gel (1 oz.)
- 6 boxes of Ben's® Tick & Insect Repellent Wipes - 12 individually wrapped packs, 30% DEET
- 6 packs of Wet Ones Antibacterial wipes, Travel Pack
- 2 US to India electrical adapters
- 2 Dr. Fresh Dailies Travel Kit - incl. Toothbrush, toothpaste and brush case
- 1 schedule book/expenses record/travel diary
- 2 boxes Pedialyte® Oral Electrolyte Maintenence Powder - help prevent dehydration
- 1 shaving kit with razor, blades, shaving gel
- Gauze bandages, band-aids, neosporin, ibuprofen tablets
Thursday, December 2, 2010
Helpful Gmail Labs Reviews
- Mark as Read Button
- Default 'Reply to all'
- Authentication icon for verified senders
If you're tired of digging into the "More actions" menu every time you want to mark unread messages as read, just turn on this Labs feature to add a "Mark as read" button to the top of your inbox.
Very useful, I was missing this for some time. The button blends in well with the other default buttons at the top of your inbox. I found it saves a lot of time as I compulsively read every other email otherwise, I don't really like the "More actions" menu, so this was a time saver, and more direct way to get this function. I did notice it is not 100% production ready.
If you check a already read email, the Mark as Read button remains enabled and you may click it, which gives the erroneos message "The conversation has been marked as read. Undo". Clicking the misleading provided "Undo" link in the message also does nothing. I submitted this feedback to Gmail Labs support.
Default 'Reply to all' by Mark K
When we're working on features for Gmail, the email etiquette on the team is to reply all so everyone involved is kept in the loop. Mark was an intern here this past summer who got frustrated when he'd reply to an email only to realize that he forgot to reply all and had to resend the message. Thus, this Labs feature, which makes reply all your default selection.
Thank you Mark, I had the exact same experience multiple times with Gmail. Often when multiple recipients are copied on an email, among my social group the convention is to include all in your reply to include everyone in the conversation, almost like an ad-hoc forum. This works very well with Gmail's threading of email chains. This is a useful Lab feature, didn't find any issues since I enabled it.
Authentication icon for verified senders by "E R"
Turn on "Authentication icon for verified senders" from the Labs tab under Settings, and you'll see a key icon next to verified emails that are super-trustworthy.
...
It's a bit of work for senders to make their email super-trustworthy, which is why this feature is limited to just eBay and PayPal right now. We hope to add more senders in the future, and when we do, you'll know because you'll see the super-trustworthy key icon magically appear by those senders too. Give it a whirl and let us know what you think.
Seems like a good feature to just have that extra bit of security that you aren't being phished. I verified that it w for a advertisement-type newsletter email from PayPal. It would require more participation from other 3rd parties to be useful as now most companies I receive email from aren't on that list. Top on my priority would be Amazon.com and other "Large Financials"
If you aren't aware you may enable these Gmail Lab features in Gmail.
Click on Gmail menu bar > Settings > Labs (or the little green chemistry beaker icon next to Settings).
In the list of "Available Labs" click Enable radio button for the labs you want.
Click Save Changes button at the top when done.
The Send Feedback link under each individual lab lets you send specific feedback to the Gmail team either to report problems, give praise or make suggestions. This is a great feature in of itself. Wish there was something equivalent for all Google products.
Thursday, November 25, 2010
Blame WorldWind
As I've written about before, I have basically given up on being a contributor to the World Wind .NET OpenSource project. I haven't really touched any WorldWind related code in months. But on my laptop where I kept all of my development files I left everything there for now, in case I do want to resume and make some contributions.
For the longest time I have had very odd behavior from this machine. Essentially on start up my system would grind to a halt, with my hard disk at near 100% utilization, for 10 minutes or more. This also happened when resuming Windows from sleep. All in all, very annoying. For a while I thought the problem might be antivirus related, maybe too much scanning on start up. So I switched from one anti-virus program to another, but the problem more or less continued. My computer is relatively new, it is Vista (64-bit) version, with sufficient memory and processor, the hard disk like most laptops isn't particularly fast, but my work laptop and my wife's laptop don't even experience behavior like mine.
Anyway, I was trying to solve this problem, a bit worried my system was compromised by malware. So I was performing some scans. I noticed that the scanners seemed to get hung up on a particular set of WorldWind debug log files created under my user folder. I knew WorldWind did generate a lot of debug logs when built and run in debug mode, and it didn't do a very good job of cleaning it up. I went and and took a look.
In C:\Users\[user]\AppData\Roaming\NASA\WorldWind\1.4.0.1\ there were 72,000 + log files seemingly created by DEBUG log messages. It also seemed that whatever was logging those, was rolling over that log after 1 or 2KB, meaning it would generate tons of very small individual files. I didn't realize the massive amount of these files, also the main WorldWind.log file was around 90MB, a known issue, we planned to do something about eventually.
After deleting these log files (I am never going to go back now to look at any of them), my computer feels reborn. It now starts up normally and doesn't crazily start disk I/O for the first 20 minutes after starting up. I mainly use the laptop now for watching Netflix movies as I've shifted development more to my Linux machine.
I can't seem to reproduce creating all those log files when I try restarting WorldWind executable in Debug mode now. If I have time this weekend maybe I'll try to make a fix for this and the other logging issue as a last World Wind hurrah.
Bath, England
Wandering around the center of Bath, it was hard to miss the Roman bath tourist attraction, right near Bath Abbey.
I went to the William Herschel museum. I had recently read the Age of Wonder by Richard Holmes, which featured an extensive biography of Herschel and his discoveries. He was famous in the 19th century for his telescopes, discovering Uranus and numerous comets as well as for outlandish theories of cosmology. I was lucky to happen to be in the city where he did his early work. They turned his former home into a very modest museum.
Monday, November 8, 2010
GNU/Linux Application Programming book review
I focused on Part I - Introduction, Part II - GNU Tools and Part III - Application Development Topics. I just skimmed through Part IV - GNU/Linux Shells and Scripting and Part V - Debugging, which I have a feeling I'll come back to.
I posted my review to Amazon which I'll reprint here:
I am an experienced software engineer but have not had much experience programming for Unix/Linux environment. I was also interested in a basic book to go into low-level C system APIs. This book provided a good introduction for me at a reasonable pace over a wide range of subjects. I focused on the C programming chapters, but there are additional chapters for things like source control, shell commands, awk, sed, Ruby, Python and debugging.
Book expects some familiarity or background with C programming language. While basic functions of the Standard C library are described, the language constructs and syntax of C are not referred to at all but are assumed familiar to the reader.
Other reviewers have mentioned that source code was available for free online so CD was not valuable. I have not found this to be the case, so in that respect the CD is useful.
Some negatives, in general code samples were often incomplete, with errors. Several of the chapters of the book contain content with mistakes or do not list all necessary prerequisites. For example, I tried to perform almost every code/script sample provided and ran into numerous issues or additional packages and tools to install that were never mentioned. Some code would execute on a 32-bit Linux system but not on a 64-bit system. Also I found the code samples provided on the CD to be lacking in completeness, for example a sample code for a Makefile example from chapter 6 did not include the source files the Make script was supposed to build. In the end it did encourage me to create my own "Hello World" type source files just to go through the same steps being described in the book. Other chapters included source but not Makefiles to compile the code, source files with no relation to the examples in the book and source files that did not compile. Generally such errors could be resolved with a few minutes of Internet research on the errors/warnings.
For my next act I'll start on Real-Time Systems and Programming Languages by Alan Burns and Andy Wellings.
Sunday, November 7, 2010
New blog template and design
For now I have settled on the "Awesome Inc." blogger template, I liked how it . For the background I am using one of the Nature backgrounds. Under Layout > Adjust Width in the designer, I expanded the width of the entire blog from 880px to 1000px (max). I reduced the total width of the right sidebar as well. This gives more space for the longer code samples in the main body of my posts.
Not totally sold on the new looks. I notice that the Awesome Inc. template incorrectly floats some of the widgets in the side bar, so I've adjusted those to the bottom of the page layout, and the code samples extend beyond the main body now and into the space of the sidebar.
It is all still a work in progress. The backgrounds can be a distraction. It is cool I can make all these changes and the content is unaffected.
Thursday, November 4, 2010
Deep Impact makes closest approach to comet Hartley 2
http://www.space.com/scienceastronomy/comet-hartley2-poison-gas-jets-101103.html
The comet Hartley 2 is now visible from Earth as well.
http://www.skyandtelescope.com/observing/home/102632669.html
11/7/2010 - Edit Pictures came out:
http://www.jpl.nasa.gov/news/news.cfm?release=2010-371
Sunday, October 31, 2010
Interpreting C function pointer syntax
This is the general syntax for a function pointer is always
return_type (* pointer_name) ( variable1_type variable1_name , variable2_type variable2_name,....)
See more explanation and example at:
http://www.cprogrammingreference.com/Tutorials/Basic_Tutorials/Pointers.php#10
In my first example with a typedef, that is defining a function pointer as a type. Ignore the typedef and it is a function "sighandler_t", returns void and accepts one argument of type int. The (* ... ) groups the pointer asterisk with the typedef's name and indicates that the typdef is for a function pointer. e.g. "void sighandler_t(int);".
See more discussion at Stack Overflow: Reading function pointer syntax
C Socket Server example, with semaphores, signal handling
The program is a BSD Socket based server (ch. 13), that accepts connections on a specific port and sends over TCP a "temperature" value, which at the moment I am simply randomly generating for example. I have added the use of counting semaphores (ch 17) to demonstrate a critical section of code as well as used POSIX signal handling (ch. 14) as a mechanism to cleanly exit. I developed this in Eclipse CDT IDE. I am not a C expert, this is my first C program since approx 2002 but it runs and compiles without warning!
Therm- ServerProject set up and dependencies
I created two static libraries for generating the random number/temperature reading. This are linked in my Eclipse project. For the purposes of this example you only need to know about these function prototypes (from thermapi.h)
/*
* Initialization for Therm API. Call before using any other function
*/
extern void initTherm( void );
/*
* Returns the current temperature reading from sensor
*/
extern float getTemp( void );
Other than this, I depend on various standard libraries in Linux for sockets, signal handling, etc..
thermserv.c - Includes and Defines.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
/* sockets and addresses */
#include <sys.h>
#include <arpa.h>
#include <netinet.h>
#include <netinet.h>
#include <netinet.h>
#include <netinet.h>
#include <netdb.h>
/* semaphores */
#include <sys.h>
/* signal handling */
#include <sys.h>
#include <sys.h>
#include <signal.h>
/* my own includes for custom functions */
#include <thermapi.h>
#include "thermserv.h"
/* magic number constants */
#define MAX_BUFFER 128
#define THERM_SERVER_PORT 6777
#define THERM_SEM_ID 6778
static int loopCounter = 1;
/* Exit handler function called by sigaction */
void exitHandler(int sig, siginfo_t *siginfo, void *ignore) {
printf("*** Got %d signal from %d\n", siginfo->si_signo, siginfo->si_pid);
loopCounter = 0;
return;
}
Print Server Info utility method just to clean up the main function a little. It still is too long.
/*
* Prints out basic server information for startup
*/
void printTServerInfo(struct sockaddr_in servaddr, int cliLen,
time_t startupTime) {
printf("*** Thermo Server initialized.\n");
printf("*** cliLen size: %d\n", cliLen);
printf("*** Server Listening as %s:%d\n", inet_ntoa(servaddr.sin_addr),
ntohs(servaddr.sin_port));
printf("*** Server PID: %d\n", getpid());
printf("*** Start up time: %s", ctime(&startupTime));
}
Note: I was getting warnings from gcc for this function.
../thermserv.c: In function ‘main’:
../thermserv.c:122: warning: implicit declaration of function ‘printTServerInfo’
../thermserv.c: At top level:
../thermserv.c:180: warning: conflicting types for ‘printTServerInfo’
../thermserv.c:122: note: previous implicit declaration of ‘printTServerInfo’ was here
To resolve these, I added thermserv.h:
#ifndef THERMSERV_H_
#define THERMSERV_H_
/*
* Prints out basic server information for startup
*/
void printTServerInfo(struct sockaddr_in servaddr,
int cliLen,
time_t startupTime);
#endif /* THERMSERV_H_ */
Warnings resolved!
back to the rest of thermserv.c:
main() - set up code
/* start main */
int main(void) {
/*
* TODO implement server as daemon, per best
* practices, Advanced Programming in Unix Environment (ch 13, p417)
*/
int serverFd, connectionFd;
struct sockaddr_in servaddr;
char tempBuffer[MAX_BUFFER + 1];
time_t currentTime;
time_t startupTime;
float fread;
socklen_t cliLen;
struct sockaddr_in cliaAddr;
int therm_sem_id;
struct sembuf semAcquireBuffer;
struct sembuf semReleaseBuffer;
struct sigaction act;
/*init socket*/
serverFd = socket(AF_INET, SOCK_STREAM, 0);
/* set up semaphore */
therm_sem_id = semget(THERM_SEM_ID, 1, 0666 | IPC_CREAT);
if (therm_sem_id >= 0) {
printf("*** Semaphore %d\n", therm_sem_id);
/* init semaphore count to 1 */
semctl(therm_sem_id, 0, SETVAL, 1);
} else {
printf("Could not create/get semaphore with errno: %d %s", errno,
strerror(errno));
exit(-1);
}
semAcquireBuffer.sem_flg = 0;
semAcquireBuffer.sem_op = -1;
semAcquireBuffer.sem_num = 0;
semReleaseBuffer.sem_flg = 0;
semReleaseBuffer.sem_op = 1;
semReleaseBuffer.sem_num = 0;
/* Set exit handler function for SIGUSR1 , SIGINT (ctrl+c) */
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = exitHandler;
sigaction(SIGUSR1, &act, 0);
sigaction(SIGINT, &act, 0);
/* Set socket server */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(THERM_SERVER_PORT);
bind(serverFd, (struct sockaddr *) &servaddr, sizeof(servaddr));
listen(serverFd, 5);
/* initialize thermometer api (required by rand api) */
initTherm();
/* get set up to capture client socket address */
cliLen = sizeof(struct sockaddr_in);
startupTime = time(NULL);
printTServerInfo(servaddr, cliLen, startupTime);
Now the block with all the hot action, an infinite while loop for the socket server to accept connections, get the current temperature value and then write to the socket. If a SIGUSR1 or SIGINT (ctrl+c) is received by the handlers the loop value loopCounter will be set to false and the while loop will end allowing for some clean up at the end to close the sockets, semaphores, etc...
/* infinite loop until SIGUSR1 or SIGINT is handled */
while (loopCounter) {
printf("Waiting for Client connection\n");
connectionFd = accept(serverFd, (struct sockaddr*) &cliaAddr, &cliLen);
/* valid connection to client accepted */
if (connectionFd >= 0) {
currentTime = time(NULL);
/*print client address info and time of connection*/
/* http://www.cs.odu.edu/~cs476/fall03/lectures/sockets.htm
*
* Note ctime() seems to build in trailing \n
* */
printf("Client Connected %s:%d at %s",
inet_ntoa(cliaAddr.sin_addr), ntohs(cliaAddr.sin_port),
ctime(¤tTime));
/*Begin Critical Section acquire Semaphore*/
if (semop(therm_sem_id, &semAcquireBuffer, 1) == -1) {
printf("Critical Section Begin failed semid: %d\n",
therm_sem_id);
} else {
printf("Critical Section Begin\n");
/*write current temp in F to connected socket*/
fread = getTemp();
snprintf(tempBuffer, MAX_BUFFER, "%f\n", fread);
/*End Critical Section Release Semaphore*/
if (semop(therm_sem_id, &semReleaseBuffer, 1) == -1) {
printf("Critical Section End failed semid: %d\n",
therm_sem_id);
}
printf("Critical Section End\n");
}
/*write string tempBuffer to connected socket, close connection*/
write(connectionFd, tempBuffer, strlen(tempBuffer));
close(connectionFd);
}
}
The clean up code is reached by the signal handler function changing the loopCounter to allow the while loop to end. Other signals could cause the process to exit, I am not sure what that really means for the still open socket, and more importantly the semaphore. Might there be a better facility in C to handle this case?
/* clean up socket, semaphore before process exits*/
/* TODO better way to do this? ie Java finally{}?*/
printf("Shutting down server\n");
close(serverFd);
semctl(therm_sem_id, 0, IPC_RMID);
return 0;
}
Building therm-server
Invoking: GCC C Compiler - note libtherm and libexp are my custom static libraries
gcc -I"/home/ammianus/workspace/libtherm" -I"/home/ammianus/workspace/libexp" -O0 -g3 -pedantic -Wall -c -fmessage-length=0 -MMD -MP -MF"thermserv.d" -MT"thermserv.d" -o"thermserv.o" "../thermserv.c
Invoking: GCC C Linker
gcc -static -L"/home/ammianus/workspace/libtherm/Debug" -L"/home/ammianus/workspace/libexp/Debug" -o"therm-server" ./thermserv.o -ltherm -lexp
Running therm-server
For the fun part. Open a terminal and navigate to /home/ammianus/workspace/libtherm/Debug
./therm-serv
This launches the server, it acquires the semaphore and inits the socket listening on port 6777
*** Semaphore 131075
*** Thermo Server initialized.
*** cliLen size: 16
*** Server Listening as 0.0.0.0:6777
*** Server PID: 4790
*** Start up time: Sun Oct 31 12:27:11 2010
Waiting for Client connection
To connect to the socket with a client, use telnet or a web browser and connect to 0.0.0.0:6777
ammianus@Hadrian:~$ telnet 0.0.0.0 6777
Trying 0.0.0.0...
Connected to 0.0.0.0.
Escape character is '^]'.
72.720497
Connection closed by foreign host.
Getting 72.720497 is the "temperature" that was our goal from the start!
On the server side it logged this connection attempt:
Waiting for Client connection
Client Connected 127.0.0.1:57090 at Sun Oct 31 12:30:17 2010
Critical Section Begin
Critical Section End
Waiting for Client connection
Etc..
The server will continue to run and accept connections, (try connecting with a browser and holding down 'F5').
To shutdown the server, you can send a signal to its PID
ammianus@Hadrian:~$ kill -s SIGUSR1 4790
And server handles this signal gracefully
*** Got 10 signal from 4794
Shutting down server
References
http://www.suite101.com/content/c-header-files-a2936
http://stackoverflow.com/questions/2406986/c-warning-implicit-declaration-of-function-exit
http://stackoverflow.com/questions/4009090/what-is-correct-way-to-have-single-signal-handler-function-for-multiple-signals
http://www.cs.odu.edu/~cs476/fall03/lectures/sockets.htm
Jones, M. Tim. GNULinux application programming. 2nd ed. Cengage Learning, 2005. Print.
Richard, W., and Stephen A. Advanced Programming in the UNIX Environment. Addison-Wesley Professional, 2008. Print.
Saturday, October 30, 2010
Blogger stats behind the scenes
This has got me thinking about how to increase traffic to this blog, and provide more useful information to the public.
Top Post
Installing Korean support on Windows Mobile 6.5 (Feb 27, 2010)
Distant 2nd place
Java HashMap vs. C# Hashtable (Apr 18, 2009)
Posts on other programming topics, including recent Ubuntu/Linux related posts round out the rest of my "top posts". On the other end posts on Redwoods don't seem very popular :(, and neither do the WorldWind topics (surprise, surprise).
It was very cool to see an audience from across the globe.
Top Ten Countries
- United States
- France
- Germany
- South Korea
- Canada
- Singapore
- Japan
- Netherlands
- India
- Indonesia
Thank you all for reading!
Conclusions
My goal with the blog has always been to document information I consider useful. If it couldn't help others in someway, why bother posting it on a public channel like a blog? To that end I think I should do more to attract visitors and give them more of what they want. Some interpretations of my statistics so far:
- More content = more page views. I have a backlog of topics I would like to write about. I will make an effort to start putting out these posts on a variety of topics
- More "how-tos", lets be honest, nobody cares that I am growing redwoods in my house. More useful step by step guides to do things applicable to a wider audience (smart phone users, programmers, etc...) may drive traffic from search engines.
- Post design, as a corollary to the previous point. I could change the style of my post. Typically I explain why I worked on a particular problem, then how to solve it, with examples, etc. If I was searching the Internet for some tips on solving a coding problem, I would want the solution to be right up front. I may lead off my posts with the "solution" and let the viewers read on if they like to my back story.
- I will post a sequel to my blockbuster "Korean font on WinMo" post series. I have to give the people what they want.
Saturday, October 23, 2010
Java Sockets
At work there was a customer issue related to a workflow engine that appeared to hang on sending emails through the client's SMTP servers. We had some basic questions on whether or not the workflow engine would hang or eventually timeout if it stayed connected to the server? Or cause exceptions?
It dawned on me I could easily set up a socket server that listened on the STMP port and simulated a server not releasing a connection just for a test.
The socket model is basically: Create Socket > Bind to an address > Listen > Accept client connection > [Data Transfer] > Close > loop back to Accept.
Given my recent experience it would be pretty trivial to replace [Data Transfer] with [Delay indefinitely] in order to see what effect that had. Since we use Windows 7 at work, and I didn't have the C code handy, I figured I would just write the same sort of socket server in Java.
I created a new class, SMTPServerSocket
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import javax.net.ServerSocketFactory;
Just a few necessary imports from java.net and javax.net packages.
public class SMTPSocketServer
{
public SMTPSocketServer(){
super();
}
Definition and default constructor
public static void main(String[] args)
{
try
{
//get the default server socket factory
ServerSocketFactory socketFactory = ServerSocketFactory.getDefault();
//port 25 - SMTP, allow a backlog of 1000 before connections are refused.
ServerSocket smtpServer = socketFactory.createServerSocket(25, 1000);
System.out.println("Started: "+smtpServer.getLocalSocketAddress().toString());
//TODO need a way to break out of this infinite loop
boolean listen = true;
while(listen){
System.out.println("Waiting for connection "+(new Date()));
Socket sock = smtpServer.accept();
//print some info on the connection
System.out.println("Accepted: "+sock.getInetAddress().toString());
System.out.println("SO_TIMEOUT: "+sock.getSoTimeout());
System.out.println("Data: "+sock.getReceiveBufferSize());
System.out.println("Sleeping "+(new Date()));
//sleep for n * 1000 milliseconds
Thread.sleep(2000 * 1000 );
System.out.println("Done "+(new Date()));
sock.close();
}
//close
smtpServer.close();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
This was the main body. The socket is created using the ServerSocketFactory. I set it up to listen on port 25 (default SMTP port). I entered an infinite while loop. For the purposes of this demo I didn't build anything in that would allow it to break out of the loop. Ctrl+C seems to do the trick. The socket calls accept() which blocks until a client connects. Then when the client connects I printed some debug info, then put the process to sleep for a long amount of time to test the effects on our workflow engine. After the sleep period the connection is closed.
This actually ended up working ok. We proved that the workflow doesn't appear to have any timeout when it tries to connect to the SMTP server. I could reproduce the behavior of the hanging process while it waited on my SMTPServerSocket during the long sleep.
Sunday, October 10, 2010
Redwoods - Closeups
Instead of looking at the macro view for these trees, today I thought it would be more interesting to focus on closeups of the seedlings, now a couple months old. The colors are really striking as the stem is now turning a reddish-brown color that contrasts with the various shades of green needles and branches.
Subclipse SVN plug-in for Eclipse
I've experiences utter frustration with the SVN command-line client to maintain the various projects I've been working on and the lack of a Linux equivalent to TortoiseSVN. Typical example, I added a directory to the repository by mistake before running a clean operation. It took 20 minutes trying to delete files, cleanup commands to get back to a starting place with the files I really wanted to add.
The only apparent GUI for SVN on Linux appears to be through an Eclipse plug-in. Since I am moving my projects to Eclipse anyway this is a no-brainer.
Subclipse
Subclipse is the Eclipse client that integrates directly with the Eclipse IDE, even my Eclipse CDT IDE works. The download instructions are out of date with the Helios package of Eclipse (or Linux version). But you can more or less follow the instructions they give.
The installation is performed from within Eclipse
1. Start Eclipse
2. Help > Install New Software
3. In the Install wizard, Work with: field, enter the URL for the Subclipse version from the download and install page of the Subclipse site. In my case: http://subclipse.tigris.org/update_1.6.x.
4. I selected all the packages there, Core SVNKit Library, Optional JNA Library, Subclipse.
5. Finish your way through the wizard to install everything.
6. After the install you have to restart Eclipse.
7. I got a JavaHL error on start up of Eclipse, having to do with the JNA library. This is another topic discussed on the Subclipse wiki.
8. I ignored the error and Subclipse worked so I don't know how serious it is. I since went and installed then performed the JavaHL test cases successfully.
9. Note: I already had the SVN subversion command-line client installed, that may be a prerequisite, I am not sure to be honest.
The usage of Subclipse is not that clear-cut and documentation is lacking.
1. You need to set up a repository. Under Window > Open Perspective > Other choose SVN Repository Exploring. You can add a new repository if you have the URL (I had already created a local repository with the command line client, "file:///home/ammianus/svn-repo").
2. From the SVN Repository Explorer perspective, you can right-click a folder in your repository then click Import..., select a project in your workspace and you are good to go.
3. Once a project is associated with a location in your repository, if you right-click on a project or file > Context Menu > Team > * there will be all the normal SVN commands you would need. You will also notice that next to the project name will be the SVN repository location in brackets [].
4. You can see the behavior of Subclipse in a Console view in which you can switch to the SVN console output.
Sunday, September 26, 2010
Building Static Libraries and Test Program with Eclipse CDT
I have managed to get projects set up in Eclipse for a simple application that prints numbers to a file. For the sake of practice, I have split the code into 1) a static library, libexp, based on the random number API library example from Chapter 7 2) a static library, libtherm, that wraps the random function with a function that returns the "temperature" 3) a simple executable that calls the temperature library function multiple times and prints the results.
Eclipse CDT
I downloaded and installed the Eclipse CDT Helios version for Linux (x86_64)
This requires a Java Runtime be installed on the machine. I had to install OpenJDK (1.6.0_18, 64-bit)
Project Structure
I started from an existing project I had created using the Automake/Autoconfig to set up a build environment. In this set up, I there was a single "project" directory with an app and lib subfolders containing respective source and build files.
As far as I can tell, the Eclipse CDT approach is that there is a single build target per Project. Perhaps if you develop the Makefile rather than have Eclipse create one you could do a different set up. Going with a completely Eclipse controlled build process I created separate projects for each static library and the executable file. All the source files went directly into each project directory under the workspace.
Build Artifacts
See Right-click Project > Properties > C/C++ Build > Settings > Build Artifact
For each of my projects libexp and libtherm, I set the Build Artifact properties as Artifact Type: Static Library, Artifact Name: ${ProjName}, Artifact Extension: a.
This results when you compile in Eclipse building and archiving the object files into libexp.a and
For temp-app the difference was the Build Artifact was set to Type Executable and there was no extension.
Referencing Libraries
In my case, the libtherm library references libexp library. The temp-app needed to reference both libtherm and libexp.
For libtherm Properties > C/C++ General > Paths and Symbols > References. I checked off libexp / Active.
This adds under the Includes > GNU C tab the Include directory /libexp.
I also updated the Properties > Project References to check off libexp project.
These steps also add GCC Compiler flags. Under Properties > C/C++ Build > Settings > GCC C Compiler > Includes it adds under -l included paths: "${workspace_loc:/libexp}"
If you click on the main GCC C Compiler heading All the options are listed:
-I"/home/me/workspace/libexp" -O0 -g3 -pedantic -Wall -c -fmessage-length=0
For the temp-app the procedure was more or less the same. Under the Project References, Path and Symbol References I added the two library projects libexp, libtherm.
Difference seems to be in the Executable type Project, the C/C++ Build > Settings has new options for GCC C Linker. Under Libraries -l I added "therm" and "exp" (GCC C Linker will prepend "lib" and append ".a"). Under the Library Search Path (-L) I added paths to the Debug directories in my other projects where the library artifacts were being built. For GCC C Linker All Options this results in:
-static -L"/home/me/workspace/libtherm/Debug" -L"/home/me/workspace/libexp/Debug" -o"appexp" ./test.o -ltherm -lexp
(note: one crucial step when linking libraries that may refer to each other: you must order them in a top down way. i.e. the libraries that have their own references to lower level libraries should be ordered first, so in my case it was -ltherm then -lexp. See this discussion on StackOverflow for more details: GCC C++ Linker errors: Undefined reference to ...')
Running the Project
Once the projects have been set up and you have a working build. You can try to run it.
See Run > Run Configurations
Add a new C/C++ Application to run e.g. "AppExp". Clicking run will execute the program with output going to your Eclipse Console panel
Monday, September 20, 2010
Java method to copy file to UNC network location
To copy a file with Java (JRE 1.4 or higher) the method found here was really helpful:
...
//File in = new File("local-file.txt")
//File out = new File("\\\\network\folder\file.txt")
FileChannel inChannel = new
FileInputStream(in).getChannel();
FileChannel outChannel = new
FileOutputStream(out).getChannel();
try {
inChannel.transferTo(0, inChannel.size(),
outChannel);
}
catch (IOException e) {
throw e;
}
finally {
if (inChannel != null) inChannel.close();
if (outChannel != null) outChannel.close();
}
...
Credit: http://www.rgagnon.com/javadetails/java-0064.html
Used the "new" technique using the java.nio package for transferring the file. See FileChannel.transferTo()
The example in the how-to page describes copying an input File in to an output File out
All I had to do was make sure that Java would understand a UNC style network file path for the out File that I wanted to copy to. It was really as simple as that, and worked perfectly. Just remember to double-escape the "\" including the starting "\\" prefix in your UNC file path.
File out = new File("\\\\host-name\\path\\to\\target-file.zip");
That page also discusses an issue on Windows where files of sizes greater than 64 MB fail with an "java.io.IOException: Insufficient system resources exist to complete the requested service" error. I initially tried with the suggested workaround to transfer the file in 64 MB chunks, which worked. For the record the file transfer for a larger file (167 MB) took around 18sec with this method. Given that this issue is several years and java versions old I thought I would try this out without splitting up the file.
My development system is Windows 7, JRE 1.5.0_22, the target host with the network share was on Windows XP. Using the original transferTo method without splitting the file successfully copied my large test file with no errors. There was also a slight performance gain as the copy took about 16 seconds that time.
Doing a little research in the Oracle Sun Developer Network Bug Database, it seems this may have been an issue fixed in: 6431344. Or it may have been that this was an OS problem and doesn't manifest on the Win 7 platform. In either case seems to be working.
Related bugs:
6822107
6486606
Sunday, August 22, 2010
WorldWind - WMS Authentication Support
Unfortunately I don't have a WMS server with authentication to test his fix against. I did some basic regression testing and existing WMS functionality seems to work fine. From reviewing the code nothing appeared to be harmful and it made sense, though he added no commenting for any of the changes. I asked the user to provide more code comments as well as to finish an enhancement he was apparently making to the WMS browser for username and password fields in the browser GUI.
Forum discussion
You can get the source and see it in action from my SVN branch:
https://nasa-exp.svn.sourceforge.net/svnroot/nasa-exp/branches/ammianus
I will hold off on commiting his changes to the World Wind trunk until he responds to my questions and maybe finishes his work on the WMS Browser.
I have to say, this is probably my last contribution to the WW.NET project for now. I think it has run its course and led to a dead end, technically and in terms of a learning experience. I have begun new projects to learn more about coding in GNU/Linux and as a result want to focus my efforts towards Real-Time and Embedded system development. I have to thank the World Wind project both as a learning exercise and for the fact it did get me a job interview for a GIS programming position, and it was the first true Open Source project I made contributions to. Here's to many more.
Tuesday, August 17, 2010
Redwoods - Day 32
In general we water about twice a week, and spray the leaves and branches around every other day. The only windows in the room face east, so they get a lot of direct sun in the morning, and indirect the rest of the day. We've used some Miracle-Gro Liquid Houseplant Food, which we use for all our other house plants. In both cases starting from the bottom of the stem and growing up, the stem is turning a reddish-brown color with what seems to be the start of the redwood bark in what will be the trunk. It is only about the first 4-5 inches and after that the rest of the stem is still green like a plant's.
Specimen J2 is growing a bit fuller and maybe slightly taller. It grew a second set of branches radiating from the crown.
Specimen B2 is a little slower growing. Early on it had some "burning" of needles on some lower branches, possibly due to too much direct sunlight or under-watering. It seems to have recovered slowly but now is growing taller with more branches off the main stem.
Saturday, August 7, 2010
Ubuntu Remote Desktop
After speaking to a co-worker I found out that Ubuntu has a remote desktop capability built in to Gnome. That was great to know, so this weekend I spent some time to set that up finally. Enabling Remote Desktop connections is as easy as going to a Preferences Control Panel, a few check boxes are you it took to set it up. See this guide for more info: Remote Access to the Ubuntu Linux Desktop.
On the Windows side, my laptop already had TightVNC client (http://www.tightvnc.com). Using the above guide it was easy to connect to the Remote Desktop on the server using the default port of 5900 and desktop of :0.
This did log me in to the Gnome desktop, and thought I could move the mouse and control the desktop through TightVNC, it would not refresh the screen in the client window. After trying out a few solutions from the Ubuntu forums that didn't work, I remembered something the same co-worker mentioned. Basically there are some issues with VNC if you have any of the desktop effects enabled.
To disable them go to:
System > Preferences > Appearence >Visual Effects
Set to "None"
Immediately this disables the "effects". The only noticeable difference is that there were some transparency effects in some of the windows, and these were turned off. This probably helps with performance in any case.This did the trick and my VNC client came back to life and started to function. Although it is a little choppy if you try to drag a window around the desktop it worked pretty well with the "High-speed Network" connection profile in TightVNC.
Update
Adobe Flash Plugin installed today randomly. All I did was go to http://www.pandora.com/ and install the plugin, worked fine, and the box has been serving its first function as a dedicated internet radio player in my living room.
Sunday, August 1, 2010
Ubuntu Experiment
To move towards that goal, I needed a Linux development system. I didn't want to dual boot one of my existing Windows machines and possibly deal with driver hell.
Got a machine the other day. Nothing cutting edge. AMD Athlon II X2 215 (Dual cores, ~2.70 GHz). 4GB Memory, 500GB hard disk, NVIDIA® GeForce® 6150 SE. Good thing is that the case has a slim profile, 10.4" H x 3.9" W x 14.6" D. I wanted something small and quiet so I could leave running as a server and work on remotely. It came with Windows 7 and the obligatory set of crappy trial software and spyware. Also bought a book for some programming practice: GNU/Linux Application Programming
I went with the Ubuntu Linux distribution. Created an installer CD with the 10.04 LTS 64 bit Server Edition.
Installing was a simple(!) process, the installation documentation on the Ubuntu site is pretty good, if verbose. No snags were hit, though because I chose the Server edition it didn't come with the Graphical Installer option, though its not like there were any shell commands you had to run during the install. Since I didn't care about the pre-installed Win 7 OS, I didn't have to bother with creating any partitions, I just overwrote the whole drive as one big Linux partition.
Once it booted up after install it came to the default shell prompt. There is no desktop in the Server edition. A quick google search gave me the command to install the Gnome desktop. This was plugged in
$ sudo apt-get install ubuntu-desktop
That probably took longer than the install itself. In any case it loaded up fine with a snappy new purple themed Ubuntu desktop. From start to end it was probably around 4 hours of time.
One odd thing is that during the server install you are prompted for what kind of "server package" you want to set up. I chose Java/Tomcat, though I may not even use it. I can find no evidence that Java was installed so I am not sure what that was supposed to do.
Startup now takes under 10 seconds I would say, it is incredibly smooth.
I tried to connect remotely from my windows PC using PuTTy, but no luck, there was no SSH listener running on the server. You have to enable it by installing the SSH packages.
$ sudo apt-get install ssh
That worked and I could connect via PuTTy SSH over port 22. Trouble is you needed to connect by the IP address of the box, you apparently can't resolve the Linux server's machine name from Windows. Fine, so I had to add an entry into my Hosts file, C:\Windows\System32\Drivers\etc\hosts. Its funny that Windows to Windows doesn't require this to resolve the machine name, but Windows to Linux doesn't work. I noticed that the Linksys router administration site did recognize the Linux server's name in the DHCP Clients Table.
In any case minor issue.
The other thing I've found is that Adobe Flash plugins doesn't seem to install, I tried the .apt and the .deb versions offered by Adobe, neither worked, getting "Architecture Not Supported 'I386'" errors. Great job Linux! I would guess it may have to do with 64-bit vs 32 as I believe Flash doesn't have any native 64 bit versions, at least not on Windows.
Next step is to try to set up VNC in order to make a remote desktop connection from my laptop to the new server. We do this at work with our Linux Oracle database host, so I know it works well.
Wednesday, July 14, 2010
Redwoods - Day 1
The two seedlings arrived in the mail today from a grower in Michigan. Found them on eBay for about $4 each. They were packed in a cardboard box with shredded newspapers to keep them protected and wet?. They apparently are in good health after that trip. My uneducated guess, from reading about growing these online, these two are probably several months old at least.
Specimen B2
Approximately 9" tall
Specimen J2
Approximately 10" tall
I have been using a number of resources online for tips on growing redwoods. We'll see how they do and I'll continue to post updates here to track their progress.
http://www.virtualsecrets.com/redwood_and_pines.html
http://www.redwoodworld.co.uk/faqs.htm
http://www.ehow.com/how_4421951_plant-grow-redwood-seedling.html
Sunday, June 27, 2010
GeoDjango review - part 2
Following this installation guide I went about creating my own GeoDjango stack locally.
My stack included the following components:
- Windows Vista Home Premium x64
- Python 2.6.2
- PostgreSQL 8.3.11-1 (PostGIS not available for 8.4 yet[1])
- PostGIS 1.3.6
- psycopg2-2.0.10.win32
- GeoDjango installer[2] (for windows , bundles together Django 1.1, GDAL 1.6.0, PROJ 4.6.1 and the GeoDjango components)
Following installing the software I went through the basic GeoDjango tutorial to load the a sample "World Borders" shape file data set to PostGIS and create necessary models in the Django db.
Following these steps worked perfectly for me, there is nothing I can really add. I would say that one feature that is missing from the tutorials, sample projects online and I would daresay, geodjango itself is a default viewer for viewing your entire layer set on one map. I couldn't find any such advice on taking this to the next step and it was not included in their default admin site, you can only view the world border records one at a time on individual screens.
To get a better sense of the Django framework's features I went through some of those "Hello World" style examples to build some basic templates and views with their framework, which I have to say being new to Python and modern webframeworks in general was quite easy.
Essentially I went through chapters 1 - 4 of the online The Django Book in an afternoon.
GeoDjango review
Recently I was asked to present my evaluation of a geospatial web framework called GeoDjango. This was in the context of a job interview with a center for geographical analysis at a local university.
I had to come up with a presentation based on benefits or features relative to a proposed system that the center wanted to develop for allowing users(researchers presumeably) to upload and manage map related data for geospatial analysis. Not knowing anything about GeoDjango or much about the whole geospatial research domain outside of my limited WorldWind exposure this was quite a test. As part of this presentation and my own attempt to show my skills for the interview, I set up a demo installing GeoDjango locally following some basic tutorials. The following is a summary of my analysis taken from my presentation.
GeoDjango - Summary
• Built as extension to the Django web framework written in Python.
• Open Source
• Includes related Geospatial Python libraries: GDAL/OGR(subset of full GDAL features, vector only), GEOS (geometry operations), PROJ.4(map coordinate projections)
• Support for spatial databases, PostGIS, Oracle, MySQL, etc…
• Extends Django Admin Site for directly editing models
• Built in cmd-line utilities for importing data into your database
GeoDjango – Some Useful Features
Based on the requirements I was given I took a look at the various features you get out of the box by using this framework over any of the other general frameworks of which there countless numbers these days or other “similar” products written in Java, Ruby, etc.
You do get some useful features, mostly the big draw that Django provides is it’s default CRUD administration interface where you can directly modify database records or just view them. In addition to CRUD representation for your “Models” (essentially a Model is the Django representation of a db table), you get a user admin interface for adding/updating user accounts as well as groups of users. The Django framework includes a basic permission model, where you can assign users or groups to the pre-defined permissions. The permissions allow you to grant users the ability to add records, update records or delete records. These permissions are enforced by the admin UI, though you would have the methods to check user’s permissions when creating your own UI pages. One missing privilege in my opinion is a “view” permission.
Beyond the front end the Django model provides various libraries set up for some common features of any web framework such as user authentication, a comment framework with automated moderation. On the geospatial side there seems to be the useful inclusion of the various geospatial libraries. What seems to be useful, not being an expert, were the inclusion of libraries for simplifying queries to the spatial database, supposedly no SQL required. There is also good support for conversion of your spatial data into various output formats such as the GML or KML formats.
Analysis of GeoDjango supporting requirements
These were some of the requirements the center had, and my evaluation of them.
User to upload spatial data (Shape, GeoTiff at a minimum)
• Shape Files
▫ Possible, Python utilities exist for importing Shape files
▫ Different Shape file attributes require coding Python models
• Geotiff
▫ Raster formats are not supported in GeoDjango
▫ Possible other 3rd party libraries could be leveraged (WKTRaster for PostGIS)
User to control visibility of data (who can see my data, public, private, shared)
• Django administration UI allows configuring permissions for user access to a Model type, but not by “owner” or “creator” of instances of Models.
• Only administrators have ability to add or remove permissions from other users. No way to specify which permissions they could grant or take away.
• Would require some extension of Django security model to provide this feature as well as change to UI screens.
User to control access to who can interact with their data
• Can restrict who could see or edit through the admin UI by Models but not by a user’s own content.
• Permissions not granular enough for mark-up / edit distinction in admin screen.
• Would require extension of security model and rework of current admin UI.
Conclusion
• Some of the central requirements are not available in GeoDjango off the shelf.
• Implementing the required features could still be done in GeoDjango framework.
• Most useful features of GeoDjango seem to be on server-side relating to interacting with the geospatial data.
• Django itself provides useful framework for dynamic website creation.
References
Couldn’t possibly list every site I visited to find all this data, and some of it came from my own observations. Here are few useful sites for more information
· http://geodjango.org/presentations/
· http://groups.google.com/group/geodjango
· http://docs.djangoproject.com/en/1.2/ref/contrib/gis/install/#windows-xp
· http://www.ohloh.net/p/geodjango
· A day with GeoDjango - Thinking in GIS
· http://www.geowebguru.com/articles/99-overview-geodjango
Tuesday, June 15, 2010
Dojo filteringselect popup out of position on window resize
This is documented fairly well at Ticket #5777 popups: close when window resized.
In the case of filtering select I feel it is a valid workaround to close the popup on window resize.
My workaround is here, although I am sure there may be more elegant ways. This assumes some familiarity with dojo and the FilteringSelect widget.
Start with the widget itself, assume you have necessary infrastructure for this FilteringSelect i.e. data store, dojo.requires, etc...
<input dojoType="dijit.form.FilteringSelect"
searchAttr="name" store="principalRisk1DataStore" class="medium" id="principalrisk1" name="principalrisk1" />
In order to close the popup containing the drop down selections for this FilteringSelect I need an onResize method
function onWindowResize()
{
//get the popup created when you click the widget, by default this seems to be the id of your input + _popup
var principalRisk1 = dijit.byId('principalrisk1_popup');
//useful for firebug to see what you get
console.debug(principalRisk1);
//this method closes the popup node you retrieved
dijit.popup.close(principalRisk1);
}
Now, lastly add this to the body tag's handler for onresize
<body class="tundra" onresize="onWindowResize()">
Saturday, May 15, 2010
Exploring the Milky Way
I've been reading a lot lately about the two Mars rovers, and the Galileo space probe thats orbiting Saturn's moon Titan. And I'm really curious to read about the software design of those machines. That must be some of the most complicated code ever written. These machines have to be "smart" enough to manage navigation through space, communication with earth, management of sensors and storage of sensor information, create and possibly interpret diagnostic data, and be smart enough to recover if a problem occurs. What should it do if it cant communicate with earth any more? What should it do if one of it's systems fails? I'd venture to say that code is about as close as we come right now to artificially intelligent machines.
Does anybody know where I could read more about this topic? I've looked around, but I cant find anything on the internet. That information might be classified, but I just thought I'd ask.
Well sir, I had the exact same questions, so I started to google it. My own particular interest had more to do with the deep space missions to the outer solar system, Jupiter, Saturn, etc. That limits it down to the Voyagers (software probably written in the 70s), Galileo (Jupiter mission, 1989 - 2003), Cassini (Saturn, 1997 - present). Certainly there a couple missions underway or to be launched (e.g. Juno).
I decided to look into Cassini. In the end I found a number of resources that help explain how the software was designed and what it does. (Cassini software was written in Ada)
So if you want to know more about Cassini or other spacecraft implementation details these are some useful resources I've found:
- Basics of Space Flight, JPL
http://www2.jpl.nasa.gov/basics/index.php
Top to bottom introduction to physics, mission operations and spacecraft components. Useful reference or for putting it all together. Much higher level than many of the technical papers describing the actual software or components that assumes this knowledge. - The Cassini Spacecraft: Object Oriented Flight Control Software, Hackney, J., Bernard, D.Rasmussen, R.
http://hdl.handle.net/2014/34861
Article about how they used OO methodology for design of components to steer/orient the spacecraft. - An Attitude Control Design for the Cassini Spacecraft, Wong, Edward
http://hdl.handle.net/2014/30851
How the spacecraft determines attittude and estimates attitude for pointing (Star-sensor, sun-sensor, gyros, etc..) - System Fault Protection Design for the Cassini Spacecraft, Slonski, John P.
http://hdl.handle.net/2014/31814
Attempts at generic or reusable fault protection models, designs and algorithms for fault protection. - Cassini Star Tracking and Identification Algorithms, Scene Simulation, and Testing, Alexander, James W.
Chang, Daniel H.
http://hdl.handle.net/2014/26388
How the spacecraft's star tracker, literally takes an "image" of the sky, on the fly looks up the configuration of stars in an on-board "database", calculates relative distance between stars, and then based on that can give an estimate of where it is pointing. Amazing stuff.
More public domain, articles in PDF format are also available for many subjects on BEACON eSpace at Jet Propulsion Labratory.
Enter the Dojo
One downside, the Dojo documentation is all over the place, a lot of it is incomplete and when you google search you often see out of date pages or broken links come up first.
My project was cool in a way and I can go into what it involved. But first to give credit where credit is due, I found this really helpful tutorial to add checkbox inputs to a Dojo/Dijit tree (yes it is much harder than one would think)
http://www.thejekels.com/dojo/Dijit_Tree_Chkbox.html
Examples were easy to follow and worked (note that the first steps in the tutorial don't actually work in Dojo 1.4, but he helpfully points that out the workarounds near the end).
Wednesday, March 3, 2010
Best Coffee Blend
Prerequisite: Home filter-brewing coffee maker.
2 spoons of Trader Joe's Dark Sumatra
2 spoons of New England Coffee Blueberry cobbler
2 spoons of Trader Joe's Colombia Supremo medium roast
4 cups of water
Brew with coffee maker
Mix the brewed coffee with 6-7 packets of Splenda
Chill for until needed.
Serve with plenty of ice and a decent amount of half & half
Local java tile server in SVN
This is now under the ammianus branch in world wind SVN.
Saturday, February 27, 2010
Installing Korean support on Windows Mobile 6.5
I followed some links in the user comments at the blog I wrote about earlier that had some registry key manipulation suggestions for adding Korean font to a phone.
First I downloaded this font pack 'Korean_font.cab',
http://www.careace.net/2008/11/11/korean-font-for-samsung-epix-download/
I can't really verify the source or speak to security of this file. It seems to have worked without noticeable downsides, I would say download at your own risk.
I copied this to my memory card in my phone via USB then executed it. One downside: I found I did seemingly have to reset my phone every time I disconnected my USB for it to recognize my memory card, which is odd.
Executing the cab from the Folder View on the phone worked, no problems. I think I did a Soft Reset afterward.
Second, I downloaded another .cab from a user's comment post
#42 Written By punkwhan on August 3rd, 2009 @ 11:50 pm
If you want write hangul.
You can you moakey keyboard from samsung.
Download link below.
http://www.megaupload.com/?d=WV1PF7WC
This download link brought me to 'Moakey2.0.0528.rar'. This provides a Hanguel keyboard input method that you can switch to when typing in any application. Again it worked for me, I haven't noticed any spyware, but I have no idea where this comes from.
The .rar contained four versions of the .cab, I suppose for different screen resolution phones. I picked Moakey2.0.0528_WVGA.cab, copied to my memory card, rebooted the phone and then installed. It did have a Korean "installation" wizard, presumeably if you want to use this to write Korean you can navigate your way through that. I don't understand the options but it seemed to be a way to configure the "style" of your korean keyboard, the way I set it up seems to be more like a cell phone input method than a computer keyboard layout.
Installation went ok, after reboot by default I get the Hanguel keyboard, and you can easily switch back to the default provided QWERTY keyboard from an arrow next to the keyboard icon at the bottom when ever you can input text in an app.
So far so good an no compatibility problems.