Friday, January 25, 2008

Regular Expressions in Oracle Database 10g

by Fábio Souza

Hello everybody!

This is my debut post to Java 2 Go! (ironically it's not about Java) and I'm really happy for having been invited to write by Eduardo. I hope you will enjoy as much as I am!

As the title says, this is a short how-to about the use of regular expressions in Oracle Database. This feature was introduced in Oracle 10g and is really helpful, useful and, better off, not too complicated. Let's take a look.

There are three built-in SQL functions and one operator for working with regular expressions in Oracle 10g:
  • OPERATOR:

    • REGEXP_LIKE
      It's used in the WHERE clause with column filtering purpose. The filter is the informed pattern.

  • FUNCTIONS:

    • REGEXP_INSTR
      Returns the initial position where the informed pattern was found.

    • REGEXP_SUBSTR
      Returns the result of the informed pattern application.

    • REGEXP_REPLACE
      Replaces the informed pattern with another given string.

NOTE: pattern is the regular expression which is used to match specific regions of a string.

This example will show only the REGEXP_REPLACE function and the intention is to return only the value of field "Login".

-- Description:
-- First argument: string which the pattern will be applied to (it's possible to use a column instead).
-- Second argument: the pattern.
-- Third argument: new string that will replace the portion of the original string matching the given pattern.

select REGEXP_REPLACE(
   'ID = 13737009 - Login = T123456 - Status nonAdmin - WorkingPlace = HeadQuarter - Sector = B',
   '(.+)(Login = )([^ ]+)(.+)',
   '\3')
from dual;


The pattern used above defines four groups between parenthesis:
  1. "(.+)" matches 1 or more characters

  2. "(Login = )" matches the exact substring "Login = "

  3. "([^ ]+)" matches 1 or more character different from " " (space)

  4. "(.+)" again, matches 1 or more characters

In our example, the result for each group above is:
  1. "ID = 13737009 - "

  2. "Login = "

  3. "T123456"

  4. " - Status nonAdmin - WorkingPlace = HeadQuarter - Sector = B"

For the simple query above, the result of function "REGEXP_REPLACE" will be the replacement of the substring matching the given pattern with "\3". The presence of character "\" tells the function to replace "\3" with the substring matching the third group defined in the given pattern, which is "([^ ]+)". As you may notice, in this case, the given pattern matches the entire string so, at the end, the entire string will be replaced with "T123456".

Despite the beauty of this, there's one thing we should always keep in mind: performance. As we already know, applying functions to table columns in WHERE clauses typically makes Oracle's choice optimizer to ignore any index on that particular column which may result in a table full scan. If we're dealing with big volumes, this might be a huge concern. Thank God Oracle gives us some options like Partitioning and Parallel Queries.

That's all for now. If you'd like to get further information on the subject I recommend reading this article from OTN:

http://www.oracle.com/technology/oramag/webcolumns/2003/techarticles/rischert_regexp_pt1.html

Cheers! (and keep reading...)

New "acquisition"

Hi folks!

It's with the greatest satisfaction that I welcome the blog's most recent "acquisition": the Oracle consultant Fábio Saraiva de Souza. You may check his profile here.

Fábio is a good friend with whom I've had the opportunity to work for almost a whole year in my last project. As you will certainly notice, Fábio is one of that curious guys that are never satisfied until they really understand things to their deepest details.

Welcome Fábio! We'll be willing to read from you soon.

Tuesday, January 22, 2008

My favorite JDeveloper extensions

by Eduardo Rodrigues

Hi everybody!

You must have noticed that JDeveloper may be boosted by a great number of extensions provided either by Oracle itself or by an open source and partners community. If you did not noticed that yet, then you certainly should do so. Even if it's just for curiosity, you may check a complete list of all extensions available selecting the menu item "Help -> Check for Updates...".

It's important to say that for this feature to work properly, your JDev's web proxy configuration must be correct. So it's worth to take a look at this first by selecting menu item "Tools -> Preferences...":

Web proxy configuration

Now that we're all set, let's go back to the "Help -> Check for Updates..." thing.

On the wizard's first step you should make the following selection:

JDeveloper Update Centers selection

After pressing "Next" you'll be presented to a list of available extensions from the update centers selected before. Browse the list and see how many interesting and useful stuff you can add to your JDeveloper environment. All you have to do is to select the extensions you like and proceed with the wizard. After restarting JDeveloper will automatically install all downloaded extensions. I recommend that you always restart JDeveloper immediately when prompted to.

An alternative way to browse and download these extensions outside JDeveloper is to visit the following URLs:

In this case, to install them, use the feature "Install From Local File" in "Help -> Check for Updates..." wizard:

Installing an update from local file

As a suggestion, here is a list of my favorite extensions:
  • MUST HAVE

    • Oracle ADF SRDemo Applications
      Great way to learn ADF by example. Comes in 2 flavors: EJB 3.0 + Toplink Essentials JPA or ADF BC

    • Oracle ADF Developer's Guides Update

    • JDeveloper Spring 2.5 Support
      Adds support for creating and editing Spring 2.5 bean defintions. This addin will create the Spring 2.5 library and register the relevant XSDs and DTDs with the IDE to provide a productive editing experience for Spring definitions

    • Struts Documentation 10.1.3
      Complete Javadoc for Struts

    • Variable Highlighter Extension
      Dynamically highlights variables as you click on them

    • Subversion VCS Extension
      Much better version controller than plain CVS

  • USEFUL

    • JUnit Integration Extensions
      Various extensions providing integrated support for JUnit

    • Oracle JHeadstart Evaluation Version
      Oracle JHeadstart is a productivity toolkit that works on top of Oracle ADF. Using ADF Faces as View, JSF as Controller and ADF Business Components as Business Service, JHeadstart generates sophisticated ADF web applications using simple metadata. Generated features include wizards, shuttles, trees, list of values, multi-row insert/update/delete, advanced and quick search capabilities, file upload/download, deeplinking, conditionally dependent items, dynamic breadcrumbs and more.

    • Copy As HTML
      Great extension that makes the task of copying bits of source code to blogs much easier

    • XPath Search Extension
      Best way to search inside XML documents

    • Make Read-only Files Writable

    • GWT Developer
      Provides visual editing environment to help with developing with the Google Web Toolkit (GWT)

    • PMD JDeveloper Extension
      Provides integrated support for PMD 4.1

    • Remove Workspaces and Projects
      Adds a context menu option that allows the deletion of projects and workspaces and of their sub-contents, quick and easy.

    • Additional Skins for ADF Faces

    • Zipper
      This extension provides a simple ZIP feature for applications and projects

On the other hand, the extension "JDeveloper Keep Resident (for Windows only)" is definitely one that you should NOT use. That's an experimental extension, works only on Windows and the very same effect may be achieved in a much better way which has already been explained in a previous post.

Finally, if you want to contribute with your own great JDeveloper extension, you may install "JDeveloper Extensions SDK" which is an extension itself and includes documentation and sample extensions.

That's all for now.

Cheers and... keep reading!

Thursday, January 10, 2008

I've got tagged too!

I got tagged in the Oracle Blogsphere tag game by Juan Camilo Ruiz so now it's my turn. 8 things you didn't know about me:

  1. I got married for the 2nd time on Sep. 7th, 2007 with the most beautiful and amazing woman I've ever met in my entire life and her name is Heloisa. I hope this one is forever.

  2. My first computer ever was a TK-85 based on Sinclair architecture with a Z80 CPU and 16KB of RAM. I was 12 years-old and my first Basic program was:

    10 PRINT "Eduardo ";
    20 GOTO 10;


    Cooooool!!! =)

  3. I totally hate traffic jams! That's why I could never live in São Paulo, Brazil. I would certainly die from a heart attack really soon.

  4. If I could choose a place to live here in Brazil, I'd choose Florianópolis (The Island of Magic). And not only because my wife was born there.

  5. When I was a child, I suffered a lot from bronchitis. Doctors recommended swimming as a long term treatment so my parents forced me to attend swimming classes, which I used to hate. Now I'm 100% cured and love to swim. Kids...

  6. My father is a presbyterian minister just like my grandfather was too. My grandfather, Rev. Zaqueu Ribeiro, founded a presbyterian church in Rio de Janeiro, in a neighborhood called "Tijuca".

  7. For almost a half of my life, I spent practically every holiday at my family's country house in a very small city called Eng. Paulo de Frontin near Rio de Janeiro. Unfortunately, after my grandfather's death, my family ended up selling the house. Too bad.

  8. I've always wanted to ride a jet ski but never got the chance to do it :(

Well, let me see who I'm going to tag next...

Steve Button, Carlos Rubinstein, Debu Panda, Mike Lehmann, Frank Nimphius, Olaf Heimburger, Steve Muench and Marcos Campos.

Come on guys! Let's play!

Tuesday, January 8, 2008

JAXB 1.0 vs. 2.0 in JDeveloper 10g

by Eduardo Rodrigues

Ok, I know JDeveloper 10g already comes with an embedded JAXB compiler which can be found in menu "Tools -> JAXB Compilation...". The only problem with this compiler is that it's a JAXB 1.0 implementation and, believe me, the differences are simply HUGE when compared to it's successor, JAXB 2.0. And all for the very best. To prove my point, let's go through a simple example comparing both JAXB versions.

First of all, let's create a new application in JDeveloper with one empty project called "JAXB 1.0" adding only "XML" to its technology scope:

Click to enlarge

We must have a valid DTD or XML Schema so the JAXB compiler can work. Let's consider this small and simple XML Schema borrowed from a W3C tutorial:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

<!-- definition of simple elements -->
<xs:element name="orderperson" type="xs:string"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
<xs:element name="title" type="xs:string"/>
<xs:element name="note" type="xs:string"/>
<xs:element name="quantity" type="xs:positiveInteger"/>
<xs:element name="price" type="xs:decimal"/>

<!-- definition of attributes -->
<xs:attribute name="orderid" type="xs:string"/>

<!-- definition of complex elements -->
<xs:element name="shipto">
 <xs:complexType>
  <xs:sequence>
   <xs:element ref="name"/>
   <xs:element ref="address"/>
   <xs:element ref="city"/>
   <xs:element ref="country"/>
  </xs:sequence>
 </xs:complexType>
</xs:element>
<xs:element name="item">
 <xs:complexType>
  <xs:sequence>
   <xs:element ref="title"/>
   <xs:element ref="note" minOccurs="0"/>
   <xs:element ref="quantity"/>
   <xs:element ref="price"/>
  </xs:sequence>
 </xs:complexType>
</xs:element>

<xs:element name="shiporder">
 <xs:complexType>
  <xs:sequence>
   <xs:element ref="orderperson"/>
   <xs:element ref="shipto"/>
   <xs:element ref="item" maxOccurs="unbounded"/>
  </xs:sequence>
  <xs:attribute ref="orderid" use="required"/>
 </xs:complexType>
</xs:element>
</xs:schema>


Just copy the code above to a file named "shiporder.xsd" in the project's root directory so it will automatically show in project's "Resources" folder:

Click to enlarge

Now select file "shiporder.xsd" in the application navigator, click the menu item "Tools -> JAXB Compilation..." and fill up the pop-up shown as the screenshot bellow:

Click to enlarge

After pressing the "OK" button, you should see the following scenario:

Click to enlarge

As you can see, the JAXB compiler generates a bunch of classes and interfaces reflecting the structure defined by the compiled XML Schema. If you look closer, you'll notice that some of the classes extend "oracle.xml.jaxb.JaxbNode" (like class ShiporderTypeImpl, for instance). That's because the built-in JAXB compilation feature we just showed relies on a JAXB 1.0 proprietary implementation provided by Oracle in its XML Developer Kit which comes with JDeveloper. You may get more details on this at Oracle XDK Home site.

Continuing with our test case, let's create a sample "testorder.xml" based on our shiporder.xsd schema:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<shiporder orderid="0001" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:noNamespaceSchemaLocation="shiporder.xsd">
  <orderperson>Eduardo Rodrigues</orderperson>
  <shipto>
    <name>John Doe</name>
    <address>#100, Oracle Parkway</address>
    <city>Redwood City</city>
    <country>USA</country>
  </shipto>
  <item>
    <title>DVD+RW</title>
    <quantity>50</quantity>
    <price>.50</price>
  </item>
  <item>
    <title>17&quot; LCD Monitor</title>
    <quantity>5</quantity>
    <price>150.00</price>
  </item>
  <item>
    <title>Bluetooth Mouse</title>
    <quantity>10</quantity>
    <price>40.00</price>
  </item>
</shiporder>


To read in and process this sample XML using the package generated by Oracle's JAXB compiler, we must use the JAXB feature called "Unmarshal". To do that, I'll modify class test.jaxb1.TestJAXB1 like this:

package test.jaxb1;

import java.io.File;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import test.jaxb1.shiporder.*;

public class TestJAXB1 {

   static JAXBContext context = null;

   public static void main(String[] args) {
      try {
         context = JAXBContext.newInstance("test.jaxb1.shiporder");
         Unmarshaller unmarshaller = context.createUnmarshaller();
         Shiporder order = (Shiporder)unmarshaller.unmarshal(new File("testorder.xml"));
         System.out.println("Items included in order #"+order.getOrderid()+" are:");
         
         for (ItemTypeImpl item : (List<ItemTypeImpl>)order.getItem()) {
            System.out.println("\t:. "+item.getTitle()+" - "+
               item.getQuantity()+" item(s) at $"+item.getPrice()+" each");
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}


Making a long story short, the "magic" performed by the Unmarshaller is basically to parse the XML using the classes generated by the JAXB compiler to map its entire content into memory. It's just like using a DOM parser to load the XML's DOM tree into memory. The advantage here is that the names, attributes and methods in JAXB generated objects strictly reflect the XML's structure defined by its schema making it much easier and more intuitive to work with them instead of a pure DOM tree. Running the test above, the outcome should be:

Click to enlarge

Quite easy. You'd probably think: Well... I'm ok with that. It's easy enough already. The question is: is that so??? NOT!!!

Now I will repeat the same test case described above only upgrading from JAXB 1.0 to JAXB 2.0. First, we'll need to get a working implementation of JAXB 2.0. I recommend Sun's reference implementation which can be downloaded here (at the time I was writing this post, version 2.1.6 was the latest one). Just follow the instructions in that page to install it correctly and notice the bin subdirectory containing some scripts, including "xjc.bat" (for Windows; "xjc.sh" for Unix). This is the script supplied to execute JAXB 2.0 compilation. The trick here is to embed it in JDeveloper as an "External Tool". I'll show you how to do that step-by-step:

  1. Click the menu item "Tools -> External Tools..."

  2. Press the "New..." button to start the "Create External Tool" wizard

  3. Select "External Program" as the "Tool Type" and press "Next"

  4. Fill the 3 displayed fields as follows:

    • Program Executable:
      full path to the script "xjc.bat" which sould be <Sun_JAXB_2.1.6_install_dir>/bin/xjc.bat (or "xjc.sh" on Unix)

    • Arguments:
      -d "${project.first.sourcepath}" -p ${promptl:label=Target Package Name} "${file.path}".

      Press button "Insert..." to see all macros available (i.e.: ${file.path}).

      The arguments above will be passed to the script "xjc.bat". Execute it with no arguments in a command prompt to see a help on all possible arguments. The default is to compile a XML Schema but you can use -dtd to compile a DTD instead, although it's an experimental feature.

    • Run Directory:
      <Sun_JAXB_2.1.6_install_dir>/bin


  5. Press "Next" to advance to "Display" step and fill the 3 fields as you like. I suggest the following:

    • Caption for Menu Items:
      Compile XML Schema with JAXB 2.0

    • ToolTip Text:
      Compile a XML Schema with JAXB 2.0 Reference Implementation by Sun Microsystems

    • ToolTip Text:
      ide.fileicon:<SUN_JAXB_2.1.6_install_dir>/bin/xjc.bat


  6. Press "Next" to advance to "Integration" step where I recommend selecting "Tools Menu" and "Navigator Context Menu"

  7. Press "Next" to advance to the final step "Availability". Here, I recommend choosing the option "When Specific File Types are Selected" and then move only the item "XML Schema Type" from list "Available Types" to list "Selected Types"

  8. Press "Finish" and done!
Now we have the same built-in "JAXB Compilation" functionality described before but now using Sun's JAXB 2.1.6. So, let's repeat the same test case using our new tool.

First, create a new empty project called "JAXB 2.0" also adding only "XML" to its technology scope.

We'll need to create a JAXB 2.0 library and add it to the project:

Click to enlarge

The important here is to add the following archives, located in directory <Sun_JAXB_2.0_install_dir>/lib, to the library's class path: jaxb-api.jar, jaxb-impl.jar and jsr173_1.0_api.jar.

Now just copy files "shiporder.xsd" and "testorder.xml" from project "JAXB 1.0" to this new project's root directory. Also be sure that the sources directory configured for the project exists and, if it doesn't, create it manually. That's needed because Sun's JAXB 2.1.6 compiler won't create its output directory automatically and the process will fail if that directory doesn't exist. Finally, select file "shiporder.xsd" in the Applications Navigator and execute our newly created menu item "Tools -> Compile XML Schema with JAXB 2.0"

Click to enlarge

Define "test.jaxb2.shiporder" as the "Target Package Name" when prompted. After execution, you should see the following output:

Click to enlarge

Just click the "Refresh" button on the Applications Navigator and the new package "test.jaxb2.shiporder" will appear. At this point we can already make a simple comparison:

Click to enlarge

As you can see, instead of generating 16 interfaces, 15 classes and 1 property file, JAXB 2.0 generated only 4 classes! And like it was not enough, if you look inside those 4 classes you'll notice that they are all very simple POJOs!!!

Take class "Shiporder.java" for example:

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.1.5-b01-fcs 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2008.01.09 at 12:41:26 PM BRST 
//

package test.jaxb2.shiporder;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for anonymous complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType>
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element ref="{}orderperson"/>
 *         &lt;element ref="{}shipto"/>
 *         &lt;element ref="{}item" maxOccurs="unbounded"/>
 *       &lt;/sequence>
 *       &lt;attribute ref="{}orderid use="required""/>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "orderperson",
    "shipto",
    "item"
})
@XmlRootElement(name = "shiporder")
public class Shiporder {

    @XmlElement(required = true)
    protected String orderperson;
    @XmlElement(required = true)
    protected Shipto shipto;
    @XmlElement(required = true)
    protected List<Item> item;
    @XmlAttribute(required = true)
    protected String orderid;

    /**
     * Gets the value of the orderperson property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getOrderperson() {
        return orderperson;
    }

    /**
     * Sets the value of the orderperson property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setOrderperson(String value) {
        this.orderperson = value;
    }

    /**
     * Gets the value of the shipto property.
     * 
     * @return
     *     possible object is
     *     {@link Shipto }
     *     
     */
    public Shipto getShipto() {
        return shipto;
    }

    /**
     * Sets the value of the shipto property.
     * 
     * @param value
     *     allowed object is
     *     {@link Shipto }
     *     
     */
    public void setShipto(Shipto value) {
        this.shipto = value;
    }

    /**
     * Gets the value of the item property.
     * 
     * <p>
     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a <CODE>set</CODE> method for the item property.
     * 
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getItem().add(newItem);
     * </pre>
     * 
     * 
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link Item }
     * 
     * 
     */
    public List<Item> getItem() {
        if (item == null) {
            item = new ArrayList<Item>();
        }
        return this.item;
    }

    /**
     * Gets the value of the orderid property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getOrderid() {
        return orderid;
    }

    /**
     * Sets the value of the orderid property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setOrderid(String value) {
        this.orderid = value;
    }
}


"public class Shiporder {". No interfaces being implemented, no classes being extended at all. Only a simple JavaBean with its attributes and their respective accessors. The "magic" here is done thanks to the annotations. They perform the actual mapping between the XML's structure defined by the compiled XML Schema and the classes derived from that compilation process.

I think it's pretty obvious to see the huge advantages of JAXB 2.0 when compared to version 1.0. The compilation of a XML Schema produces much fewer classes and those classes are simply annotated POJOs. This certainly implies a much faster, lighter and easier to understand XML binding.

Besides, there are some other details that makes JAXB 2.0 even more beneficial. Javadocs are automatically generated, it relies on cutting-edge XML parsing technology called "Streaming API for XML" which basically gives much more precise control over XML document processing. For further info on this, read "Oracle StAX Pull Parser Preview" and "JSR#173 homepage". Finally, as opposed to the known limitations of JDeveloper's built-in JAXB 1.0 compiler, Sun's JAXB 2.1.6 supports:

  • Javadoc generation

  • The key and keyref features of XML Schema

  • The List and Union features of XML Schema

  • SimpleType mapping to TypeSafe Enum class and IsSet property modifier

  • XML Schema component "any" and substitution groups

  • Customization of XML Schema to override the default binding of XML Schema components

  • On-demand validation of content based on a given Schema

To run the same unmarshalling test, just create class "test.jaxb2.TestJAXB2" as follows:

package test.jaxb2;

import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import test.jaxb2.shiporder.Item;
import test.jaxb2.shiporder.Shiporder;

public class TestJAXB2 {

   public static void main(String[] args) {
      try {
         JAXBContext context = JAXBContext.newInstance("test.jaxb2.shiporder");
         Unmarshaller unmarshaller = context.createUnmarshaller();
         Shiporder order = (Shiporder)unmarshaller.unmarshal(new File("testorder.xml"));
         System.out.println("Items included in order #"+order.getOrderid()+" are:");
         
         for (Item item : order.getItem()) {
            System.out.println("\t:. "+item.getTitle()+" - "+
               item.getQuantity()+" item(s) at $"+item.getPrice()+" each");
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}


This is slightly different from class "test.jaxb1.TestJAXB1" but, after running it, you should see exactly the same outcome:

Click to enlarge

Well, that's it. I think I've made my point. So good luck in your JAXB 2.0 adventures!

Saturday, January 5, 2008

A new year with a new face

Hello everybody!

I can not think of anything better than a complete makeover to start the new year. And just because I can't do that to myself, it doesn't mean I can't do that to my blog. So I did it!

That's right. As you may notice (at least if you're already a reader) the look and feel is quite different, hopefully for the best. The blog now fills almost the whole screen which gives much more space for posts. I also adopted a more clean style, with a white-predominant background.

Some useful tools have been added at the upper right corner:


Now it is much easier to subscribe to all the amazing content posted here. It's even possible to receive all new posts directly into your e-mail. Ain't that just great?!

At last, and certainly not least, another huge improvement or, should I say... the final touch: now all blog's feeds are being redirected to FeedBurner. This means widely compatible, comprehensive and automatically disseminated feeds. Click here and see for yourself.

Well, I'm pretty happy with the blog's new look and improvements. I hope you all like it as much as I do.

May we all have a fantastic 2008 and... keep reading!!!