LendKey

Monday, December 3, 2007

Start multiple versions of Firefox at the same time in Windows

I have been long time Firefox user. I started using Firefox since it was 0.7 or so.

Now Firefox 2.0 has been used for my most day-to-day work, its profile contains lots of my cookies, passwords, plugins, etc. which I rely on everyday.

But 2.0 is famous as a memory eater. It can easily use up to 500M of RAM, and make my Vista 64bit with 4G of RAM running slow. So I started trying Best 3. It works great, and eats up way less RAM than 2.0 does. However, since all plugins in my 2.0 are not supported in 3.0 beta yet, I do need to switch back and force between the two versions. By Googling for a while, I found a site and learned the trick there. Basically I need to create a short cut for my 2.0 Firefox as:

C:\Windows\System32\cmd.exe /C set MOZ_NO_REMOTE=1 & start "Firefox" "C:\Program Files (x86)\Mozilla Firefox\firefox.exe" -p default

and another shortcut for my 3.0 Beta as:

C:\Windows\System32\cmd.exe /C set MOZ_NO_REMOTE=1 & start "Firefox" "C:\Program Files (x86)\Mozilla Firefox 3 Beta 1\firefox.exe" -p "Li Ma Test"


Now the two works greatly together.

The trick is to create a new profile named as Li Ma Test. You need to run Firefox with the following command line option:

-ProfileManager

Then you can create a new profile to be used by the shortcut.

The two useful sites I found were:

http://www.hiveminds.co.uk/node/3114

and

http://www.google.com/search?source=ig&hl=en&rlz=1G1_____ENUS242&q=firefox+command+line&btnG=Google+Search

Enjoy!

And hope 3.0 Beta can go to final soon.

Saturday, December 1, 2007

Implement resumable file download by PHP

I had a requirement to implement a file downloading service with Apache + PHP.
The files are all uploaded by another tool. All uploaded files are renamed to UUID, and a UUID.info file is attached to store corresponding information of the original file.

Now at downloaded side, I need to:
1. verify UUID info before download
2. still able to download the file into the original file name instead of a user-in-friendly UUID.
3. Support browser and download manager, such as FlashGet

Without PHP code the 1 and 2 could not be accomplished.
But to support 3, PHP does not have any built-in support. Especially when considering downloading large files from server, PHP normally does not work well.

Luckily, I found a PHP class from:
http://www.phpclasses.org/browse/package/2221.html

Big thanks to the author, I was able to implement all I needed in less than 30 lines of my code :)

Hopefully, my finding can be helpful to you.

Li

Wednesday, November 28, 2007

Get default folders in Windows

In order to get any system folder under Windows (I guess from 95 to Vista) by any programming language, you can call function:

HRESULT SHGetFolderPath( HWND hwndOwner,
int nFolder,
HANDLE hToken,
DWORD dwFlags,
LPTSTR pszPath
);
( http://msdn2.microsoft.com/en-us/library/ms647764.aspx )

and pass in the folder you are looking for, such as:
CSIDL_MYDOCUMENTS: My Document
CSIDL_COMMON_APPDATA: C:\Documents and Settings\All Users\Application Data
CSIDL_PROGRAM_FILES: C:\Program Files.

Check the following link for all IDs:
http://msdn2.microsoft.com/en-us/library/bb762494.aspx

Hope these two links can be handy to you.

Friday, November 23, 2007

Some tricks on ImageMagick

I had about 1000 images with all different resolutions. I needed to resize them to fit into 100x100 square. So I looked around and found a great command line tool that can do lots of different image manipulation in a batch.

The tools is called Image Magick, you can find it at:
http://www.imagemagick.org/script/index.php

After downloaded a Windows version and installed, I had a brief look at the manual find out the way to resize everything into a specific size and keep the image ratio at the same time:

c:convert -resize 100x100 -quality 100 ..\*.* %d.jpg

Basically I create a new folder under the folder where all my original images are located. Went to he new folder and ran the command above.

The command resized all image files under the parent folder ( original files ) to 100x100 area and kept original image ratio. The result files are named as numbers from 0.jpg to 999.jpg. All original files were converted to JPG format,not matter what they were.

Please be advised, the result image might not be exact 100x100. For example, if the original image is 400x200, the new image will end up as 100x50. You got the idea?

I set quality to 100, so shrunk image still looks pretty nice.

You can also add one more option -strip which is very helpful for me to strip out all image information stored in each file, such as tags, comments, etc. and saved me lots of space.

So far so good, untilthe second day. I suddenly realized an issue, when I show the images on my website in a 100x100 area, my tag on site requires 100x100 exact size, otherwise, the image will be stretched and got disordered. So I need to do another conversion:

convert -gravity Center -extent 100x100 ..\*.jpg %d.jpg

By this command, I was able to convert everything int a new image with exact 100x100 resolution. By using -gravity Center, the original image got placed at center of the new image. So everything is working perfectly now!

There're hundreds of commands provided by Image Magick. You have to either spend hours reading through all of them and become a guru, or like I did, simply search a word I want to work on my images, and jump to that command directly and try.

Image Magick is surely a great tool. I hope I can find more real-life tricks playing with it in the future. And hope you enjoy playing with it yourself too.

-Li

Thursday, October 18, 2007

A Thread Safe Date Formatter/Parser

I have seen many different ways to use DateFormat classes(most ly SimpleDateFormat) from different people including myself, and unfortunately, most of them are either buggy or not efficient.
The following are the most common scenarios I saw:
1. Use a static final formatter in different thread:
static final private DateFormat df = new SimpleDateFormat("yyyy/MM/ddd");
...
void myMethod()
{
df.parse(..)
df.format(..)
}
People, including me, were thinking to reduce number of instances of df and reuse it everywhere. But this is dead wrong! The JavaDoc has clearly mentioned that SimpleDateFormat is NOT thread-safe. So once you put multiple threads using the same instance, strange result will happen. Most of the time, people tent to ignore the warning from JavaDoc or don't even know it. And most of time, the code works ok, because after all, there is not that many threads running in parallel if you are only doing a small website.
2. Create DateFormat instance eveyrtime it is used
void myMethod()
{
DateFormat df= new SimpleDateFormat("yyyy/MM/dd");
df.parse(..);
df.format(..);
}
This works without bug, but you can tell lots of df objects will be created, they I always feel it is not good to create extra objects when you are coding for large and heavily loaded website.
3. Apache Jakarta Common Lang's FastDateFormat
http://www.jdocs.com/lang/2.1/org/apache/commons/lang/time/FastDateFormat.html
This is a thread-safe solution. But the problem is still you have to create each instance for different pattern. Many times in your code, you have to create multiple instance of the same pattern at many different places, which mean multiple different objects to do the same thing. The biggest problem with FastDateFormat is it only format and does not do parsing.
So after spending about an hour or so doing research, I came up with my own solution:
ThreadSafeDateParser.
Here's the class:

And the test Class:



Idea of the class is:
  1. Very easy to use. Just call those static methods and provide a string and pattern. The class will handle everything else, including formatter object creation, thread mangement, etc.
  2. For same patter and same thread, the class create only one instance of DateFormat, so you got thread-safe and use the minimum system resource
I tested the class with 1000 threads running at the same time, and it works solid with out any problem.

Hopefully this is something lots of people can reuse in your code.
I know I do not have locale and timezone handling yet. I you have any comment or suggestion, feel free to share.

Enjoy!

Li