Google Forms to Google Docs with Apps Script

Google Apps Script

This past week I have had the opportunity to learn a new JavaScript-based language, Google Apps Script thanks to a tutorial provided by one of my clients.

It’s basically a scripting language used to integrate Google Apps with each other, such as Google Docs and Google Forms, Google Spreadsheets and Gmail, and so on.

One of my client’s requests was to create a PDF out of the form data once a Google Form is submitted. However, in order to do that, I need to create a separate template file with Docs, which is going to take very long considering it’s 7-page long when the form is printed out. And unfortunately, Google doesn’t support converting from Forms into Docs.

I won’t be copying the fields from a Google Form to a Google Doc one by one manually. Instead, I will be using Google Apps Script to loop through the field elements and copy them into a new Doc with a simple and readable format.

Here is the code I wrote:

 * Adds a custom menu to the active form, containing a single menu item for
 * invoking checkResponses() specified below.
function onOpen() {
      .createMenu('Custom Actions')
      .addItem('Convert to PDF', 'formtopdf')

function formtopdf() {
  var form = FormApp.getActiveForm();
  // Create the required folder if it doesn't exist
  var rootFolder = '';
  var folderName = "Folder where the document will be generated in";
  if (DriveApp.getFoldersByName(folderName).hasNext() == false) {
    rootFolder = DriveApp.createFolder(folderName);
  } else {
    var matchedFolder = DriveApp.getFoldersByName(folderName);
    while (matchedFolder.hasNext()) {
      rootFolder =;
      break; // Only assign the first matched folder to rootFolder
  var contents = '\n';  // Initiate the contents variable with a new line
    // Get the title and description of the form and output to the document
  var formTitle = form.getTitle() + "\n";
  var subtitle = form.getDescription() + "\n";  
  contents += formTitle + subtitle + "\n";
    // Get all the responses that are submitted through the form
  var responses = form.getResponses();

  for (var j = 0; j < responses.length; j++) {
    var response = responses[j].getItemResponses();  // Get field names and corresponding values for the submitted data
    var doc = DocumentApp.create(formTitle + " for " + response[0].getResponse()); // Generate a document at the root of your account named title of the form plus the first value
    var docID = doc.getId();
    var docBody = doc.getBody();
    docBody.appendParagraph(contents);  // Add title and subtitle of the form to the document

    for (var item = 0; item < response.length; item++) {

      var title = response[item].getItem().getTitle(); // Get the field name
      var getResponse = response[item].getResponse();  // Get the submitted value
      docBody.appendParagraph(title + "\n").editAsText().setBold(false);  // Unbold the field text because of the loop
      docBody.appendParagraph(getResponse + "\n").editAsText().setBold(true);  // Bold the response text
      if (item == response.length - 1) continue;  // Prevent the output of horizontal line when it is the last item

      doc.appendHorizontalRule();  // Add a horizontal separator between items

    doc.saveAndClose();  // Save the changes to the document and close it

  // Notice to user that the generated PDF(s) are in the root of his Drive folder
  FormApp.getUi().alert(responses.length + " document(s) have been generated. They are available in your main Drive Folder.");

The above code should be self-explanatory since it’s well commented. If you still have some questions regarding the code, please leave a discussion in the comments below.

It basically loops through all of the form fields & values and outputs to the generated Doc. In the process, it makes values bold and places a horizontal line after each value to make the generated document more readable.

If you want to learn more about Google Apps Script, there are several ways. One is look through the sample code in the new project for each Google App. Another is to read and learn through the tutorials provided by Google. And another way is to just use the editor. The project editor has a nice auto-complete feature, and not to mention that the language itself has easy to understand syntax.

And of course, I will write more about the Apps Script while I’m learning it.

Prevent Tab Closing with an Userscript


While it’s impossible to prevent close of tab directly using JavaScript, we can at least remind ourselves do not close the current open tab when pressing the CMD + W close tab keyboard shortcut.

Add the following script to either Greasemonkey for Firefox or Tampermonkey for Chrome on the site you want the reminder to appear:

// ==UserScript==
// @name       Always Google Calendar
// @namespace
// @version    0.1
// @description  Prevent close the Google Calendar window through keyboard shortcut
// @match
// @copyright  2014, Robby Chen
// @require
// ==/UserScript==

$(document).ready(function() {
    $(document).on("keydown", function(e) {
        if (e.keyCode == "87" || e.keyCode == "93") {
            alert("Do not close this window. If you want to refresh this window, press Left command key and R.");

For the above code, change the meta information between “// ==UserScript==” as appropriate. Here is the documentation of the @ headers for Tampermonkey. It should be the same as Greasemonkey.

You can add the following code to the “keydown” event to display the keycode in the JavaScript Console for the specific key you would like to use instead of the W (87) and right CMD (93) keys in the code:


You can also change the reminder message to be displayed when the specified key is pressed by modifying the alert message. If you don’t like alert box, you can display the alert message to any exist element on the page. However, I find that the alert box is most useful reminder method.

Do you find the above code snippet useful for preventing the unintentional close of tab? Do you have any other tips on how to prevent tab from accidental closing? Please share your thoughts in the comments.

Using Chromebook as a Second Monitor

Three laptopsUpdate: According to the Wikipedia, using meta tag to refresh the page is discouraged. However, I think it is okay for development. I also changed the refresh time. It seems that where I originally copied the code from has incorrect information. The refresh time is in seconds, not in milliseconds.

Since my second monitor was broken long time ago, I always missed the two-screen experience.

I have an idea today that since the Chromebook is always connected to the cloud, I can make it as a second monitor by connecting to my main machine’s localhost/IP address. This way I can write the code on my primary PC and instantaneously see the result from the secondary monitor by inserting the following meta tag to the testing web page:

<meta http-equiv="refresh" content="1" />

It allows web page to automatically refresh every one second so that it will show the latest rendering result whenever I save the edited web page.

Note that using this method, you can connect more than two PCs as multiple screens as long as they are connected to your home network.

Here are some photos demonstrating this method using a laptop, a Chromebook, and a netbook running different browsers:

Three laptops

From left to right: Firefox, Chrome OS, Opera

Address Bars

From top to bottom: Firefox (primary PC), Chrome OS, Opera

In case you don’t know, the command for checking the IP address for the primary PC is ifconfig or you can right-click the network connection icon at the top right corner and choose Connection Information:

Connection Information

Connection Information dialog

Leave a comment below to discuss about this method or have any question regarding this post.

Bash Script to Install Ubuntu to CR-48 through USB easier (Updated)

Update (01/18/2011): Thanks to flyboy415’s comment below, it inspires me to add an optional parameter to the script that allows you to customize the path of your USB drive. You probably read my another post shows you how to mount the USB drive manually in Chrome OS. Now you can run this script with that directory that you created:

bash /tmp/usb

I spent last several days writing and testing the script which could help some of you installing Ubuntu onto CR-48 using USB drive a little easier.

This script is inspired by Jay’s script over at It’s also based on the steps over at the Chromium projects website. However, it uses your custom generated rootfs.bin in the USB drive instead of downloading the pre-made image.

Below is the entire script. You can either copy it directly to gEdit and save as .sh file or download the same script at github.

The Code

# This script is used to install Ubuntu to CR-48 (or any other Chrome OS devices) from USB drive

# Display the purpose of this script
echo -e "n==============================================================="
echo -e "This script helps you to install Ubuntu on CR-48 (or any other nChrome OS devices) from USB drive a little easier.n"
echo -e "NOTE: You can pass the location of your USB drive as the only nparameter of this script"
echo -e "For example, bash /tmp/usb"
echo -e "================================================================="

# Disabled powerd service
echo -e "nDisabling power management service..."
sudoV="`initctl start powerd`"
sudoV2="`initctl stop powerd`"
if [ "$sudoV" = "" -a "$sudoV2" = "" ]
 echo "Make sure you run this script in the root account. Enter the following to enter root:"
 echo "sudo su"
 echo "After you are in the root account, run this script again."
initctl stop powerd
echo -e "Power management disabled."

echo -e "nChecking the partitions size..."

# Do the following tasks if they were not already done
resizeV="`sudo cgpt show /dev/sda | grep 12103680`"
if [ "$resizeV" = "" ]; then

 # Resize the partitions
 echo -e "Resizing the partitions..."
 sudo umount /mnt/stateful_partition
 sudo cgpt add -i 1 -b 266240 -s 12103680 -l STATE /dev/sda
 sudo cgpt add -i 6 -b 12369920 -s 32768 -l KERN-C /dev/sda
 sudo cgpt add -i 7 -b 12402688 -s 10485760 -l ROOT-C /dev/sda

 # Destory the stateful_partition
 echo -e "Clearing the stateful_partition, it will take some time..."
 sudo dd if=/dev/zero of=/dev/sda bs=131072 seek=1040 count=47280

 # Restart the notebook
 echo -e "nYou need to reboot your notebook in order to continue.nMake sure to press CTRL + ALT + => (Left arrow), login as chronos, and run this script one more time after Chrome OS was rebooted.nPress ENTER to continue or wait 1 minute to reboot automatically."
 read -t 60 iputs
 sudo reboot


echo -e "The partitions are resized."

# USB drive verification
usbV="`mount | grep sd | grep -v sda`"
listing="`ls /media | tail -n 1`"
if [ "$1" == "" ]; then
 usbDr="`ls /media/$listing`"
while [ "$usbV" = "" -o "$usbDr" = "" ]; do
 echo -e "nPlease insert the USB drive with rootfs.bin,, and in it.nPress ENTER when the drive is inserted.nIf you are not signed on to Chrome OS. Please press CTRL (left) + ALT (left) + <= (left arrow) to return to the graphical interface and sign on in order to detect yout USB drive by Chrome OS. Press CTRL + ALT + => (right arrow) to return to this script and press ENTER to continue.n";
 echo -e "Note that if you already mounted your USB driver manually, you can kill this script by pressing CTRL + Z and rerun this script with a parameter that points to the path of your USB drive.nFor example, bash /tmp/usb"
 read ready
 echo -e "Detecting USB device..."
 sleep 10
 usbV="`mount | grep sd | grep -v sda`"
 listing="`ls /media | tail -n 1`"
 usbDr="`ls /media/$listing`"

# Mount the USB drive
echo -e "nMounting USB drive..."
if [ "$1" == "" ]; then
echo -e "USB drive is mounted."

# Determine the existence of three required files
rootfs="`test -e $usbDir/rootfs.bin;echo -e $?`"
makeDev="`test -e $usbDir/;echo -e $?`"
commons="`test -e $usbDir/;echo -e $?`"
if [ "$rootfs" = 1 -o "$makeDev" = 1 -o "$commons" = 1 ]; then
 echo -e "nSome of the required files cannot be found on the drive.nMake sure rootfs.bin,, and are copied to the drive and reinsert it to the notebook.nRestart this script when you are ready."
 sudo umount $usbDir

# Copy rootfs.bin in USB drive to /dev/sda7
echo -e "nCopying rootfs.bin to /dev/sda7, this will take some time..."
sudo dd if=$usbDir/rootfs.bin of=/dev/sda7
echo -e "rootfs.bin successfully copied."

# Mount /dev/sda7
echo -e "nMounting Ubuntu partition..."
sudo mkdir /tmp/urfs
sudo mount /dev/sda7 /tmp/urfs
echo -e "Ubuntu partition is mounted."

# Copy cgpt and /lib/modules/ to Ubuntu partition
echo -e "nCopying necessary files to Ubuntu..."
sudo cp /usr/bin/cgpt /tmp/urfs/usr/bin/
sudo chmod a+rx /tmp/urfs/usr/bin/cgpt
sudo cp -ar /lib/modules/* /tmp/urfs/lib/modules/
echo -e "The files are copied successfully."

# Unmount /dev/sda7
echo -e "nUnmounting Ubuntu partition..."
sudo umount /tmp/urfs
sudo rmdir /tmp/urfs
echo -e "Ubuntu partition successfully unmounted."

# Decide the rootdev
echo -e "nDetermining the Chrome OS kernel partition..."
rootfs="`rootdev -s`"
if [ "$rootfs" = "/dev/sda3" ]; then
echo -e "Your kernel partition is in $ker."

# Copy the kernel to /dev/sda6
echo -e "nCopying $ker to /dev/sda6..."
sudo dd if=$ker of=/dev/sda6
echo -e "Copied successfully."
echo -e "nNow is the critical time to check the above output for any errors. If there are some errors, press Ctrl+z to stop this script and correct them. By not correcting them, you might need recover image from Google to restore Chrome OS. Otherwise, press ENTER to continue."
read checkEr

# Change kernel command line
echo -e "nChanging the kernel command line..."
cd $usbDir
sudo sh ./ --partitions '6' --save_config foo
echo -e "console=tty1 init=/sbin/init add_efi_memmap boot=local rootwait ro noresume noswap i915.modeset=1 loglevel=7 kern_guid=%U tpm_tis.force=1 tpm_tis.interrupts=0 root=/dev/sda7 noinitrd" > foo.6
sudo sh ./ --partitions '6' --set_config foo
echo -e "Changed successfully."

# Generate ubuntu alias in .profile
echo -e "nGenerating ubuntu alias..."
echo -e "alias ubuntu="sudo cgpt add -i 6 -P 5 -S 1 /dev/sda;sudo cgpt add -i 2 -P 0 -S 0 /dev/sda;echo 'Swiched to Ubuntu, restart to take effect'"n" >> /home/chronos/.profile
echo -e "ubuntu alias generated."
echo -e "nYou can type 'ubuntu' (without quotes) in Chrome OS command line to switch to Ubuntu from now on.nIn Ubuntu, add the following line to .bashrc to use 'chromeos' (without quotes) to switch back to Chrome OS:"
echo -e "alias chromeos="sudo cgpt add -i 2 -P 5 -S 1 /dev/sda;sudo cgpt add -i 6 -P 0 -S 0 /dev/sda;echo 'Switched to Chrome OS, restart to take effect'""
echo -e "nPress ENTER after you copied the above alias down."
read chromeos

# Complete Ubuntu installation
sudo cgpt add -i 6 -P 5 -S 1 /dev/sda
sudo cgpt add -i 2 -P 0 -S 0 /dev/sda
echo -e "nUbuntu installation is complete.nPress ENTER or wait 30 seconds to enter the newly installed Ubuntu."
read -t 30 ubuntu
sudo reboot

Few warnings before running this script

You need to running the script under bash instead of sh, for example


where ubuntu is the name of your script.

If you use sh instead, you won’t see the error messages produced on the screen and might need the recovery image to restore Chrome OS as stated in the script above.

The and files can be downloaded here which are provided by You might not have these two files during the chroot installation if you chose to get minilayout instead of the full layout of Chromium OS source code.

Other requirements, such as login as root, will be provided as you execute through the script.

Issues while running the script

If you have any issues while running this script, feel free to leave a comment or create an issue over at github.

My Touchpad and Keyboard Solutions for Ubuntu on CR-48 / ChromeOS

Update (09/09/2011): I no longer use CR-48 because of its hardware limitation. The solutions in this post may not be working as Chrome OS kernel is updated frequently. Sorry for the disappointment.

Update (01/05/2010): As Pheonix7117 pointed out in the comment, here is the fix to the Touchpad issue in Ubuntu. Note that you don’t need to do the first step (Downgrade Xorg) and the last step (Broken Packages) if you are running Lucid (Ubuntu 10.04) on the CR-48.

Update (12/26/2010): For those of you never read comments (like me), Pheonix7117 has posted another tip for vertical scrolling using the touchpad. Here is the direct copy of Pheonix7117’s comment:

Here’s a temporary workaround to get *some* amount of scrolling working in the meantime:If you install the package ‘gpointing-device-settings’ it will add a menu entry to System > Preferences called Pointing Devices.
It *should* list a device called “PS/2 Synaptics TouchPad”.
What I did was enable wheel emulation and changed it to button 3 (which I believe is right click) and enabled vertical scroll. I left timeout and inertia default (inertia seems to be 0, timeout is fairly short) and left middle button emulation unchecked. This enables a regular right click when doing a ‘hard’ click in the bottom right corner without lingering, and if you hold the right click you can swipe a finger up or down to scroll. Granted, this isn’t using the touchpad driver at all as this is supposed to be used for regular mice, but it’s a start for getting by for now.

Update (12/21/2010): Pheonix7117 posted a Python script for controlling the xbacklight in the comments section. I only have a little understanding of Python language, but I think it’s a well-written script to control the backlight with the keyboard.


Ever since I installed Ubuntu on CR-48, I wondered about how to improve the touchpad speed and keyboard functions. I experimented with the touchpad driver today and noticed that while I can enable the touchpad tab inside the Mouse property with xinput, the options under the touchpad tab doesn’t seem to take any effect. Therefore I have to find other ways to configure the touchpad. The keyboard configuration was easy since all the functions are available in Ubuntu except for the right click, caps-lock and delete keys.


General setup – Under the general tab in the Mouse Preferences, move the Acceleration and Sensitivity sliders to the max fast and high respectively so that the cursor could move a little fast and reduce the chance to accidentally tap the touchpad while typing.

Left click and right click – The bottom left and bottom right corners of the touchpad recognize by Ubuntu as the left and right buttons, while toward middle of the touchpad doesn’t have any click event.

Middle click (Scrolling wheel) – I usually use the middle click on web pages when I want to open a link in a new tab. It doesn’t have a middle button on the touchpad. However, I can use Ctrl + tap to open a link to a new tab in most of the browsers. As for the most of the applications I use, none of them has middle click event except for games, which cannot run on this notebook because of the hard drive space limit.


The brightness keys – Install the xbacklight package, and assign the following commands to the corresponding keys on the first row of the keyboard through Keyboard Shortcuts window:

xbacklight -dec 10 # Decrease the backlight by 10
xbacklight -inc 10 # Increase the backlight by 10

The volume mute, decrease volume, and increase volume keys – Change the default shortcuts for Volume mute, Volume down, and Volume up in the Keyboard Shortcuts window to the appropriate keys on the top row of the keyboard.

Right click, caps-lock and delete keys – As I stated earlier, I cannot find the functions for these keys since they are not available on the keyboard. However, you can use some remapping programs to remap these keys to the available keys.


Do you have any other touchpad and keyboard related tips for CR-48 (ChromeOS)? Please share them below. Also leave a comment below if you have any questions for this topic.

My First Tip on using Ubuntu with Chrome OS on CR-48 notebook

Update (03/15/2010): Based on Dan’s comment below, I’ve updated chromeos and ubuntu aliases in the post to remove the Chrome OS partition part. According to Dan, my previous aliases raised Chrome OS partition whenever the OS was switched, which means that when Chrome OS is updated, these aliases would restore the Chrome OS to the oldest version. For more information about this update, please read Dan’s comment.

Update (12/19/2010): I wrote a post on how to use your flash/USB drive to (re)install Ubuntu on the CR-48. Check it out.

Update (12/18/2010): I just discovered that .bashrc file is never executed in Chrome OS unless running another bash after chronos is logged in, and .profile is the file which being executed after each login. Therefore I changed the following instruction to .profile for Chrome OS. If you already created .bashrc file in the chronos home folder, you just have to rename it to .profile using the command below:

mv .bashrc .profile


I have used the newly received CR-48 from Google for two days. I enjoyed so far for web browsing, but not so for web development / programming. Since I couldn’t find any good IDE on the cloud which has support for WebDAV, I decided to following the instruction on the Chromium Project website to install Ubuntu onto this device. After several hours of installation, Ubuntu loaded to the device. However, because it comes from a VirtualBox disk image, it’s nearly impossible to reinstall Ubuntu without re-transferring the disk image from my laptop to this notebook which is a 5GB file, it would spend another 5 hours just for transferring this file over ssh. I’m trying to shorten this long waiting hours. I will post another tip if I find a way. But for now, here are the two scripts I wrote to switch between Ubuntu and Chrome OS using the alias command.


First of all, I assume you also received a CR-48 notebook and installed Ubuntu on it by following on this page.

This first script is for Ubuntu:

  1. Open the file named .bashrc in the home folder  using your favorite text editor (make sure to show the hidden files by pressing Ctrl+H).
  2. Add the following line to the end of the file:
    alias chromeos='sudo cgpt add -i 6 -P 0 -S 0 /dev/sda;echo "Switched to Chrome OS, restart the machine to take effect"'
  3. Open a new terminal window to load the new alias.
  4. Type chromeos and a message will be displayed stating that you need to restart to switch to Chrome OS
  5. Restart your device and you are in the Chrome OS.

Now inside the Chrome OS:

  1. Press Ctrl + Alt + -> (the Forward button in the first row) and login as chronos
  2. Since Chrome OS also uses bash, we can write to the .profile file, but this time in the chronos home folder.
    qemacs .profile

    The command above creates and opens a new file called .profile inside the home folder using the only text editor available in Chrome OS qemacs.

  3. Insert the following line into .profile
    alias ubuntu='sudo cgpt add -i 6 -P 5 -S 1 /dev/sda;echo "Switched to Ubuntu, restart the machine to take effect"'
  4. Execute bash to launch another instance of bash, or if you are confused, you could just logoff current session by typing exit command and login again.
  5. Typing ubuntu command to switch to Ubuntu on the next startup.
  6. Restart your device to begin using Ubuntu.

In the future, you could just use chromeos and ubuntu commands to switch back and forth between Chrome OS and Ubuntu without changing back to normal mode using the small switch on the back of the battery.

Enjoy the free dual-boot notebook from Google.

Enable Backspace in Chromium

Since I discovered that Google doesn’t add the backspace support to its Chrome browser to navigate between web pages history, I always tried to find a way to add this shortcut key support to Chromium. I don’t like to press two or more keys combo (in this case, alt + left) just to go back one page, especially in the low-light condition when I cannot clearly see the keyboard.

Finally, with the help of an Ubuntu forum I found a Chrome extension called Backspace As Back/Forward for Linux. Once you installed this extension, the backspace key icon () would appear at the end of the URL address bar along with other extensions when the web pages history is available. Note that you need to refresh the existing opened web pages in order to activate the extension.

The only disadvantage I’ve found with this extension is that the page needs to be fully loaded in order to activate the backspace key. I think this is the nature of Chrome extension since the Chrome extensions are JavaScript / AJAX based.

Play Around with Google Nexus One

I received my Nexus One today which I ordered from Google on Saturday. The FedEx delivery of the device was earlier than I expected. They delivered my order 10 AM in the morning, nearly 5 hours earlier than the estimated time of 3 PM.

After I set up the phone, I decided to move the SIM card from my old T-Mobile based cell phone to Nexus One. It only adds basic call functionality to the device since I own the pre-paid SIM card.

GPS on the Nexus One doesn’t require Internet connection. However, the maps must be cached on the device in order to use the full GPS function. Turn-by-turn direction also needs to be cached from the Internet. I have not found any GPS app that supports offline viewing of entire US map that supports different zoom levels from Android Market. Maybe I will create one for myself using OpenStreetMap once I learn the Android SDK :) But first I must finish learning C.

The 5MP camera works very well. Below is a test photo that I took in the bathroom.

imageThis photo was taken in front of mirror
Click the image to enlarge

As you can see, the picture is very smooth without flashlight. I have not tested the flashlight and video recorder yet, but I think it won’t be very bad. One thing I noticed when playing around with camera is that the zoom level is not great. For the most time, I got pixelated pictures with the max zoom level. However, the problem isn’t visible on the device until I see the pictures on the PC.

Since I have no idea which audio/video formats does Android support, I copied one mp4 and one avi videos to the root of the memory. The gallery only showed the mp4 video. After browsing through Android Market, I downloaded and tried the ad version of RockPlayer. This player supports DivX, AVI, MKV, and Real formats. I watched some avi videos using this app and they all worked fine.

I transferred all the stuffs from iPod Touch and cell phone to Nexus One. From now on, I only need to carry one device in my pocket instead of two devices. I will see how long will Google Nexus One last in my pocket because my pockets usually get water when it’s raining whether I wear different cloths :)

Finally Ordered Nexus One (Updated)

Update: I received the phone. Please read this post for more information on my first hands-on of Nexus One.

After I heard this morning that Google will stop selling its Nexus One once the final set of devices is sold out, I decided to order unlocked one from the Nexus One web store.

When Google first released Nexus One, I was hoping that the original version of Android could sometimes come to some media players similar to the iPod Touch. Back then, I didn’t know the meaning of unlocked phone. I thought it is some kind of hacks that allows phone to be used illegally.

As time went by, I discovered Zii Egg. As some of you who read the posts during the early stage of this blog may know, I was waiting for Zii Egg to be released as a consumer product for over five months. Within these months, I learned a lot of how the Android operates and different variations of Android. I also discovered the definition of unlocked phone.

Since the unlocked version of Nexus One requires a SIM card and it has wifi functionality, and I don’t use cell phone very much, I could use Nexus One without the SIM card as a PMP (Portable Media Player) device. This idea came to my mind last week.

Since then, I have abandoned waiting for the Zii Egg. Mainly because I want the Android market on the device, and as far as I know, only the original version of Android has this feature.  Because of the financial issue and the surprise of the unlocked Nexus One being too expensive,  I couldn’t order the device immediately. However, after today’s news, I finally decided to purchase the device using my remaining funds.

According to the tracking info on FedEx, I will receive the device by next Monday at 3:00 PM EDT. I will post an update once I received the device and test it whether it supports operation under none-SIM card condition, as well as some experience with the device as appropriate.