How to Develop Virtual Appliances Using Ubuntu JeOS

Ubuntu JeOS (pronounced" juice") is an efficient variant of the Ubuntu Server operating system, configured specifically for virtual appliances. Soren Hansen and Nick Barcet discuss how to use JeOS to create your own virtual appliance to help distribute your applications.

Virtual appliances are an effective and convenient way to distribute applications, whether it’s an open source application stack or a commercial product. Users and customers can simply fire up the virtual machine and start using the application, without having to deal with the installation and configuration that goes along with it.

Ubuntu JeOS (pronounced” juice”) is an efficient variant of the Ubuntu Server operating system, configured specifically for virtual appliances. JeOS is a specialized installation of Ubuntu Server Edition with a tuned kernel that only contains the base elements needed to run within a virtualized environment.

Ubuntu JeOS has been tuned to take advantage of key performance technologies in the latest virtualization products from VMware. The combination of reduced size and optimized performance ensures that Ubuntu JeOS Edition delivers a highly efficient use of server resources in large virtual deployments.

Without unnecessary drivers, and only the minimal required packages, ISVs can configure their supporting OS exactly as they require. They have the peace of mind that updates, whether for security or enhancement reasons, will be limited to the bare minimum of what is required in their specific environment.

In turn, users deploying virtual appliances built on top of JeOS will have to go through fewer updates and therefore less maintenance than they would have had to with a standard full installation of a server.

Initial setup (VMware Only)

The current version of Ubuntu JeOS was built to run under VMware Server or VMware ESX, and doesn’t work under other virtualization technologies yet. We’ll assume that you’ve already installed a VMware environment for the purpose of this tutorial.

Download JeOS

The latest JeOS iso image can be found at http://cdimage.ubuntu.com/jeos/releases/. As of this writing, the most recent is the 7.10 release:

wget http://cdimage.ubuntu.com/jeos/releases/7.10/release/ubuntu-7.10-jeos-i386.iso

It’s a good idea to verify the MD5 sum of the ISO with the sum provided on the Ubuntu site. For 7.10, you’ll find the MD5 sum here: http://cdimage.ubuntu.com/jeos/releases/7.10/release/MD5SUMS. To get the ISO’s MD5 sum, run md5sum ubuntu-7.10-jeos-i386.iso. If the values are not the same, you should try to download the file again.

Installation of JeOS

Installation of JeOS is done the same way you would install any other OS in VMware, but you’ll need to consider a few things:

  • To reduce the size of JeOS, SCSI drivers have not been included in the kernel shipped with JeOS. Make sure that you instruct VMware to use an IDE drive instead.

  • If you plan on shipping a virtual appliance, do not assume that the end-user will know how to extend disk size to fit their needs. So, either plan for a large virtual disk to allow for your appliance to grow, or provide the user with adequate documentation on allocating more space.

  • Given that it’s much easier to change the amount of RAM allocated to your VM, set the RAM to whatever you think is a safe minimum for your appliace. The user can change this if/when necessary.

  • Even though LVM setup is proposed by the installer, it doesn’t work at this time– so if you need LVM, it will need to be set up post-install.

Defining the VMware machine

The following example is based on using VMware server:

  1. Create a new virtual machine.

  2. Select Custom configuration.

  3. Select Linux, pick Ubuntu in the version drop down menu.

  4. Pick a name for your virtual appliance (use something that makes sense for your product).

  5. Pick one processor (always default to the lowest configuration you think your users may have).

  6. Letting the machine be private is a good secure basis.

  7. Pick the minimum RAM you think your appliance will need (this can be changed easily by the user later on).

  8. Bridged networking might seem a sensible default to simplify user set-up later on.

  9. Do not use default SCSI at this point, use IDE, as SCSI drivers are not included in the kernel.

  10. Pick a disk size that makes sense for your virtual appliance. A minimum of 8GB seems reasonable, particularly if you do not pick allocate disk space now. Split the disk into 2GB files makes sense if you want to allow storage on FAT volumes.

  11. Pick where you want to store the disk image, click Finish.

JeOS installation parameters

Once your machine has been defined, you need to start it, but before you do that you need to tell it to boot from the ISO image you downloaded earlier. The installer for JeOS is very similar to the Ubuntu Server Installer, but as we are preparing a virtual appliance, there are a few steps that we want to change from a regular install.

Assigning a fixed IP address

As a virtual appliance that may be deployed on various very different networks, it is very difficult to know what the actual network will look like.

In order to simplify configuration, it’s a good idea to take an approach similar to what network hardware vendors often do, namely assigning an initial fixed IP address to the appliance in a private class network that you will provide in your documentation. An address in the range is usually a good choice.

When you arrive at the screen Configure your network, you’ll be prompted to provide a hostname for this machine. Press Escape to access the network configuration menu. Select Configure network manually in the next screen. Enter a fixed IP address and other network information in the next screen. Once this is done, the installer will continue to its next steps automatically.


When partitioning the virtual appliance, you will have to take into consideration what you are planning to do with it. As mentioned before, do not pick one of the LVM options as it will fail, LVM not being provided by default on JeOS at this time. Because most appliances will run as server, using separate /home, /usr, /var and /tmp partitions would make sense.

User and password

Again setting up a virtual appliance, you will need to provide a default user and password that is generic so that you can include it in your documentation. We will see later on in this tutorial how we will provide some security by defining a script that will be run the first time a user actually logs in the appliance, that will, among other things, ask him to change his password. In this example I will use’ user’ as my user name, and’ default’ as the password.

Preparing the OS

Once we’re done with the initial installation of JeOS, and our virtual machine is waiting with a login prompt, we now have to prepare our operating to accommodate our application. It’s generally a good time to make a snapshot of your clean VMware image, so that if a mistake is made later on, it will be possible to revert to a blank page without having to reinstall everything.

The very first thing to do after install of the system is to check that it is up to date. This is done by running:

sudo apt-get update && sudo apt-get upgrade

Installing VMware Tools

VMware Tools will allow to have a better control of our appliance by the VMware environment, so it’s a pretty good idea to set it up. First, lets set up our environement by installing the build tools:

sudo aptitude install build-essential linux-headers-$(uname -r)

Next, you should ask VMware to mount the VMwareTools CD by clicking on VM-> Install VMware Tools… in the VMware Server menu.

Mount the cdrom using mount /media/cdrom0 or similar, and then copy the tools to the /tmp directory and uncompress them with sudo cp-a /media/cdrom0/VMwareTools*.gz /tmp/. Next, cd to the /tmp directory and run sudo tar-xzvf VMwareTools*.gz.

Now you can run the vmware-install.pl script. You’ll want to accept all of the default options when prompted during its setup.

cd vmware-tools-distrib/sudo ./vmware-install.pl

Installing Required Packages

In this example we will be installing a very simple application consisting of a Web page that accesses a MySQL database. So, we’ll need our OS to provide us with Apache, PHP, and MySQL– the basic LAMP stack, which we can install in one single step using the apt-get command:

sudo apt-get install lamp-server

Note that at this point we could easily install any additional packages that we might need using, for example, the aptitude command line utility.

Once we are done installing our base packages, it’s a good time to do a snapshot of our virtual machine. We also can save the intermediary steps by doing a full copy of the virtual machine by issuing the following command on our host after powering it down (you will have to adapt it to your particular environment):

cp -rf /var/lib/vmware/Virtual\ Machines/JeOS /var/lib/vmware/Virtual\ Machines/JeOS-basePackages/

Security Considerations

Another convenient tool that we want to have on our appliance is OpenSSH, as it will allow our admins to access the appliance remotely. However, pushing externally an appliance with a pre-installed OpenSSH server is a big security risk as all these servers will share the same secret key, making it very easy for hackers to target our appliances with all the tools they need to crack it open. As with the user password, we will instead rely on a script that will install OpenSSH the first time a user logs in so that the key generated will be different for each appliance.

However, it might be simpler during the set-up to access our appliance using ssh, so we still install it at this time. Note that it will need to be fully removed by the time we ship our appliance, which is described in the last part of this tutorial. To install it, simply run:

sudo apt-get install openssh-server

When we ran apt-get to install the lamp-server, the only question we were asked was to provide a default password for MySQL. It would not be wise to have all our deployed appliances to use the same password, so we will change it the first time a user logs into our appliance.

Installing and Maintaining Our Application

In general this is a four-step process:

  1. Packaging our application so that it is easily deployable.

  2. Setting up a MySQL user. Finish preparing the system so that our application can run. Here we will simply create a MySQL user for our application to use.

  3. Configure Apache to access the database.

  4. Set up the system for updates so that it will be updated automatically every day.

Packaging the application

We have two options. The recommended method is to make a Debian package. Since this is outside of the scope of this tutorial, we will not perform this step here. We do invite the reader to read the documentation on how to do this at https://wiki.ubuntu.com/PackagingGuide.

In this case it is also a good idea to set up a repository for your package so that updates can be pulled from it conveniently. See http://www.debian-administration.org/articles/286 for a tutorial on this.

Manually install the application under /opt as recommended by the Filesystem Hierarchy Standard (FHS) guidelines at http://www.pathname.com/fhs/. This is the approach we will be using here for more simplicity, even though this is not the one we would recommend for any serious application as it does mean more complexity in maintaining it. We cover this in the” How to get your application updated” section below.

Setting up a MySQL user

Our application needs to access the MySQL database. For security reasons, we do not want this user to be the root MySQL user, so we define a user named www-data that has read access to the local databases and can only connect locally with some password.

First we need to connect to the MySQL monitor using the default password we specified earlier:

user@JeOS:$ mysql -p --user=root
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 5.0.45-Debian_1ubuntu3-log Debian etch distribution
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

Then we can create our user and exit the MySQL monitor:

mysql> GRANT SELECT ON *.* TO 'www-data'@'localhost' IDENTIFIED BY 'password';
Query OK, 0 rows affected (0.00 sec)
mysql> exit

Installing the Application

Now it’s time to install the application itself. In this example our application is a very simple PHP script that lists the databases available in MySQL:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
   <meta name="description" content="Database List">
   <title>Database List</title>
<h1>Database list</h1>
$link = mysql_connect('localhost', 'www-data', 'password');
$db_list = mysql_list_dbs($link);
$i = 0;
$cnt = mysql_num_rows($db_list);
while ($i < $cnt) {
    echo "<li>" . mysql_db_name($db_list, $i) . "</li>\n";

To install the script we’ll make a directory and create the file:

sudo mkdir /opt/sample-app/ 

Now, open the file /opt/sample-app/index.php using sudo with the text editor of your choice and paste the script in the text editor, then save the file and make it readable by Apache using sudo chown-R www-data:www-data /opt/sample-app.

Then we just need to modify the default Apache configuration to point to our application directory. Open /etc/apache2/sites-enabled/000-default using sudo with your text editor of choice and change all instances of /var/www/ to /opt/sample-app. Then, save and exit the file, and reload Apache using sudo /etc/init.d/apache2 reload.

You can now test your application by pointing your browser to the IP address of the virtual appliance.

Setting Up Automated Updates

To have your system be configured to update itself on a regular basis, we will just install unattended-upgrades sudo aptitude install unattended-upgrades.

If you decided to package your application as a Debian package and set up your own repository, all you need to do is to add your repository to /etc/apt/source.list.d/.

The auto-update cron job will then pull the update each time you provide it in your repository. Another advantage of using a packaged approach is that, if your dependencies evolve during the life of your application, all updated dependencies will be automatically installed in the same process.

If you decided to install your application manually, it’s up to you how to automate the updates. One solution would be to place a tar file with your app on some HTTP server, along with a version file, and create a script that is placed in /etc/cron.daily that compares the version file on the server with the version file that you would have stored in /opt/sample-app/. If the version online is newer, download and apply the new tar file, then reload Apache.

Preparing First User Boot

To deal with the security risks we outlined earlier, we need to have a few tasks performed the first time a user logs in. Reinstall OpenSSH if the appliance can be accessed this way, ask for a new user password, ask for a new MySQL root password, and regenerate the SSL certificate if our application can be accessed through SSL.

Sound complicated? It’s not, and here’s how we can do it. Add a line to the very end of /etc/bash.bashrc:

if [ ! -e /etc/opt/sample-app/initial_config_done ]; then  /opt/sample-app/bin/initial_config  sudo touch /etc/opt/sample-app/initial_config_donefi

Through this line, the script /opt/sample-app/bin/initial_config will be executed upon first login if the file /etc/opt/sample-app/initial_config_done does not exist. So we now need to create the directory /etc/opt/sample-app/:

sudo mkdir /etc/opt/sample-app/

Then create the script /opt/sample-app/bin/initial_config using sudo and copy the script shown here:

# Let's change the user's password
echo "Thank you for choosing our sample-app appliance"
echo "For the security of the appliance, we need you to change this user password now."
# Now change the MySQL password
echo "We now need you to specify a new MySQL root password"
let done=0
while [ $done -eq 0 ]; do
  read -e -s -r -p "New mysql root password:" PASS1
  echo ""
  read -e -s -r -p "Retype mysql root password:" PASS2
  if [[ "$PASS1" == "$PASS2" ]]; then
    let done=1
    #perform the actual change assuming that our initial password is default
    mysqladmin -u root --password='default' password $PASS1
    echo "The 2 passwords did not match, please try again."
#Perform the reinstall of openssh so that the key is regenerated
echo "We are now going to generate your ssh keys."
sudo apt-get --purge -y remove openssh-server
sudo apt-get install -y openssh-server
#You can add any additional first user login 
#actions that you require after this line

Make it executable with sudo chmod a+x /opt/sample-app/bin/initial_config and that’s it.

Cleaning Before Shipping

After testing our appliance, it’s time to make it” clean” before shipping it. You want to provide your users with a production-ready appliance, so get rid of all the unnecessary scripts and such before sending it on its way.

First, remove /etc/opt/sample-app/initial_config_done with sudo rm /etc/opt/sample-app/initial_config_done. Reset the passwords to their default values if you have changed them, and remove services that are no longer needed.

Also, remember to remove configuration files, too. You can use sudo aptitude purge, sudo apt-get--purge remove, or sudo dpkg-P, whichever tool you prefer. From our example this would include openssh-server, build-essentials, and linux-headers-$ (uname- r).

Now, clear out the apt cache with sudo apt-get clean and remove $HOME/.ssh for users and root with sudo rm-rf /home/user/.ssh && sudo rm-rf /root/.ssh.

You’ll also want to remove any build directories that have been used in the process. In our example that would be the content of the /tmp directory. Also, you probably want to remove the history of your commands, which you can do with history-c.

Now it’s time to shut down the system and do the final cleanup. Once it’s shut down, go to your virtual machine settings in the VMware management console and select the virtual disk. Defragment it, which should reclaim all of the space you’ve freed, which will make the appliance smaller. Your virtual appliance is ready to ship!


We hope that this tutorial will make building your own appliance much simpler. For further documentation on the Ubuntu Server Edition, please refer to the Ubuntu Server Guide: https://help.ubuntu.com/7.10/server/C/. If you are interested in learning more, have questions or suggestions, you are welcome to come talk with us at on IRC(# ubuntu-server on Freenode) and on the Ubuntu mailing list (https://lists.ubuntu.com/mailman/listinfo/ubuntu-server).

Comments on "How to Develop Virtual Appliances Using Ubuntu JeOS"


Thanks. Here’s my little contribution,
a recipe for using VMWare Player to create
a Jeos virtual machine that can run in VMWare


You wouldn’t think one would need such a recipe,
but the experience was painful; there are
four or five gotchas, all of which I document.

Compressing the resulting vmware image with p7zip
produces a 94MB download, which isn’t too shabby.


It is clearly stated that a jeos-guest needs ide-disks and cannot coop with scsi disks. That indicates for me it does not work on VMWare ESX, since guests on ESX only get scsi-disks and no ide-disks…

Can we expect that the next ubuntu release has an option on the server-installation to get a jeos system?


followed your guide, up until the point where VMware-tools are to be installed, and I get the following error:
The following VMware kernel modules have been found on your system that were
not installed by the VMware Installer. Please remove them then run this
installer again.


Execution aborted.

The Host is VMware Workstation 6.0 running in Windows


I’ve got the very same error trying to install vmware-tools in Ubuntu JeOS.

The host is VMware workstation 6.0 runing in Linux.


Somebody recently egged me to lookup “jeos”, as I am looking to build a VM appliance. Like most others, I eventually landed on this page. My advice for anybody who’s making a maiden experiment with building VM appliance, THIS is the place guys. Nick & Soren have written a great “step-by-step howto” here.

Jeos, by itself is very well built, and lives upto it’s claimed strengths, so if you can accept its admitted lacunae, it definitely is the best platform to build your VM appliance. Jeos is also a great place to begin with, if you are looking to experiment with truly debian lineage of linux.

I have personally checked out the stuff built by others. Most of the Linux OS distributed as a VM appliance, are vulgarly “obese” compared to Jeos. Most irritatingly, you have to install atleast one email server and client (sic) to properly install the base OS! But, Jeos has been built rather intelligently, and the usually required packages have been carefully built to use as few dependencies as possible. This is because, most of the other distros have merely rehashed their existing distros into a VM image, to simply show-case the included goodies. Jeos on the other hand has been carefully built, keeping the VM appliance developers in mind.
So all my votes go to Jeos, alongwith a lot of thanks to the Jeos team.

A few things that Nick & Soren missed out on -

1. Novice developers, who may be migrating from other distros may have been more comfortable with a few links that helped them understand apt-get / aptitude.

2. VM appliance first timers could be a little shocked to note that their eforts of appliance building could result in really huge vmdk files. A few tricks like the one documented here http://h0bbel.p0ggel.org/shrinking-vmdk-files
should help. And the users should take heart, from the fact that, even if post-optimisation, if the vmdk files look rather too huge to upload / download, tar / gzip-ing them will make them comfortably small tar.gz packages. I do wish Nick & Soren do a follow up on this article to include tips and tricks for such things too.

So all of you fellow developers, if you wanted to build your VM appliance, read the above article a couple of times, and calmly go step-by-step.


Yeah, it took me a while to figure out how to
shrink my .vmdk’s. I describe the steps at
but in short, it’s
1. delete unneeded files (and I show which ones)
2. copy to a fresh filesystem (a bit more effective
than the zero copy trick you link to)
3. compress with 7zip (yeah, I know, it’s a wierd tool, but it compresses .vmdk’s much better than
anything else I’ve tried).
My vanilla jeos gutsy image is down to 80MB now!


Thanks for your very usefull comments. As we are working on v8.04 of JeOS, we are currently rewriting this article and will publish it soon after release in the Ubuntu Wiki. We’ll make sure to address your remarks and you’ll have the opportunity to do some fixing yourself if you feel like it.

Regarding the issues you may have with Ubuntu JeOS, it would be very usefull if you could report them in our bugtracking tool at https://bugs.launchpad.net/ubuntu-jeos/ as Karsten did lately with bug #192771, reporting the WMWare tool installation problems (which brought me here, by the way, as I am not reading my own article every day ;).

Again, thanks for you remarks,



sudo apt-get install lamp-server doesn’t work for me. Does it needs special repository to work?


Looks like the editor thought that ‘^’ was a typo. The command line should have read :
$ sudo apt-get install lamp-server^

Sorry about this.


‘sudo tasksel install lamp-server’ workerd for me, when I tried ‘sudo apt-get install lamp-server’ I just got package not found errors


I attempted to automate the trick described at

I wrote this script “packit.sh”, into one of my jeos based appliances.
It could automatically remove the fragmented pockets, from all the partitions.

When I need to ship and share my appliance, with anybody, I run this script, then I run the VMware utility to defragment, and then tar/gzip the directory that needs to be shipped.

Works pretty well for me so I thought I might share.
Could somebody share a trick, that allows me to call this script automatically, whenever I shutdown my appliance.

### Bash script – packit.sh starts below this line ###

echo “creating $1, and filling up that partition until there\’s no more space”
cat /dev/zero > $1
echo “deleting $1, so that we have no pockets left in that partition”
rm -f $1

## Description:
# This will “fillup” each partition with a file called zero.fill.
# And then delete that file, to remove fragmented pockets.

DISKS=`df -h`
D=`echo “${DISKS}” | wc -l`
C=`expr $D – 1`

ITEMS=`echo “${DISKS}” | tail -n $C | awk ‘{print $6}’`
for S in ${ITEMS}
SHRINK_IT `readlink -f ${S}/zero.fill`

# The list of Functions that must be called


### Bash script ends above this line ###

I guess we could similarly automate the other tasks, by adding more functions in the packit.sh script and then including them in the MAIN ()

Shipping and sharing jeos based appliance should also be always accompanied with a note for users to modify vmx file for new eth0 and also change in /etc/udev/rules.d/70-persistent-net.rules

When I get some more time, I think I will add-in functions for security too like removing SSH keys, etc., besides something to fix the changed mac-address.


Another JeOS which might be worth looking at is the RPM/Yum-based Orange JeOS (derived from the excellent CentOS distribution). It is hosted on SourceForge at http://orangejeos.sourceforge.net or http://www.orangejeos.org


Thank you for another fantastic post. The place else may just anyone get that type of info in such a perfect method of writing? I’ve a presentation subsequent week, and I’m at the look for such information.


Helpful information. Lucky me I found your website unintentionally, and I’m surprised why this twist of fate did not came about in advance! I bookmarked it.


I am not certain the place you’re getting your information, however good topic. I must spend a while finding out more or working out more. Thanks for wonderful info I used to be looking for this information for my mission.


When in truth, no matter which Home Based Business
opportunity you find, most often it has one major obstacle to overcome – finding people interested in the product or
opportunity. If you are at a computer and want to find some interesting things on the Internet to entertain you, the list of
most entertaining websites may probably be helpful to you.
In addition, there are plenty of social networks out there that
are made specifically for doing just that.


I cling on to listening to the news broadcast speak about getting free online grant applications so I have been looking around for the best site to get one. Could you tell me please, where could i find some?


Thank you for another great post. Where else could anybody get that type of information in such a perfect way of writing? I have a presentation next week, and I am on the look for such information.


I loved as much as you’ll receive carried out right here. The sketch is attractive, your authored subject matter stylish. nonetheless, you command get got an shakiness over that you wish be delivering the following. unwell unquestionably come further formerly again as exactly the same nearly a lot often inside case you shield this hike.


Hiya, I am really glad I have found this information. Today bloggers publish only about gossips and web and this is actually frustrating. A good website with interesting content, that is what I need. Thank you for keeping this web-site, I’ll be visiting it. Do you do newsletters? Can’t find it.


This really answered my problem, thank you!


That is a really good tip particularly to those fresh to the blogosphere. Brief but very precise information Thanks for sharing this one. A must read post!


It is the best time to make a few plans for the longer term and it is time to be happy. I’ve read this put up and if I may just I wish to suggest you some interesting issues or tips. Perhaps you could write subsequent articles relating to this article. I desire to read more issues approximately it!


jvM2OV Im grateful for the blog post. Fantastic.


Youre so cool! I dont suppose Ive read anything like this before. So nice to search out any individual with some unique thoughts on this subject. realy thank you for beginning this up. this website is something that’s wanted on the web, someone with a bit of originality. helpful job for bringing one thing new to the web!


The data talked about inside the post are a number of the best accessible.


That will be the finish of this article. Right here you?ll discover some websites that we feel you?ll value, just click the links.


Although internet sites we backlink to below are considerably not connected to ours, we feel they may be really worth a go as a result of, so possess a look.


I’m very happy to read this. This is the kind of manual that needs to be given and not the random misinformation that’s at the other blogs. Appreciate your sharing this best doc.


Every once inside a even though we pick blogs that we read. Listed beneath are the most up-to-date web sites that we select.


That will be the end of this write-up. Here you?ll obtain some web sites that we feel you will enjoy, just click the hyperlinks.


Please stop by the web sites we comply with, like this one, because it represents our picks from the web.


We like to honor many other net web-sites on the web, even though they aren?t linked to us, by linking to them. Under are some webpages really worth checking out.


The time to study or visit the content material or sites we’ve linked to below.


Although internet sites we backlink to beneath are considerably not associated to ours, we really feel they may be essentially worth a go via, so possess a look.


Just beneath, are many totally not connected web sites to ours, even so, they may be certainly worth going over.


Every as soon as in a although we choose blogs that we read. Listed below would be the newest websites that we pick.


Wonderful story, reckoned we could combine some unrelated data, nevertheless truly really worth taking a search, whoa did one particular learn about Mid East has got extra problerms too.


Leave a Reply

Your email address will not be published. Required fields are marked *


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>