Thursday, January 26, 2012

Small things around Oracle Weblogic 11g (10.3.4)

I am doing a lot of setting up and configuration for Weblogic this week (devops I guess). I have been working with Weblogic for the past 4 years and I have to admit - like Eclipse - I have started getting used of it. I was a Netbeans / JBoss developer and I've turned to Eclipse/ Weblogic guy. I am writing this post as a reference of things I found during research and some small technical problems encountered setting up the server on different environments (this is ongoing work since I will try RHEL in the fews days). 

General Comment regarding Weblogic
My first try and experience with Weblogic was with version 9. Still a BEA trademark - I could not really see any point on why it was considered better comparing to JBoss. It had a quite good admin console but that is all about it. This feeling did not change through the early version 10.x releases. In the past 2 years I was working with 10.3.1. In general it was stable enough, it had WLST (which is really handy if you manage to master your Jython skills) but was still a J2EE 5 container and IMHO had lots of medium to small sized bugs that could drive you crazy. Some of them would be resolved through this slow paced release cycle. Now I am trying 10.3.4, I can see many improvements on start-up times, less warnings and errors plus boarder support for 'other' operating systems (for example I can now run almost error free on MacOSX the server). Still a pure J2EE5 container with many extra technologies provided by Oracle like Coherence (which i am not going to use or enable anyway). Overall, things have improved, it is not that bad anymore (there are still worse containers on production out there) and I am really curious (eager) to work on the very latest version 12c.

Installing Weblogic on a Mac:
This is an old trick - so I am just re-posting. From 10.3. and on (if I remember well) we had generic distributable as a jar provided,  so it could be used on MacOSX or other OSes. When you are running the installer at some point you are asked to provide a suitable JDK. Up until JDK 6 which is the latest supported version on MacOSX - when you were indicating the path from your Mac's system library the installer was arguing that this was not a valid path. It was searching for a /jre folder within the jdk folder.In order to make it work you just had to follow this trick (create the jre folder on your own and touch the required libs). Note the following:that this  is expected tochange with JDK7, for example on the openJDK builds currently installed on my MacBookPro the jdk folder has a /jre  subfolder in place. Maybe Oracle fixes the generic java installer to support MacOSX jdk folder format who knows.

Installing Weblogic 11g on 64bit OS
Ok that was fun but scary. I installed Weblogic 10.3.4 (11g) using the small zip distribution on a pure 64 bit Intel PC with Windows7 Enterprise. Just unzip the thing and run the configure script. When I started the server I got among others a scary message like the following.

I did a quick search and ended up that was some sort of a bug. On windows I followed the instructions as found here, and modified the JAVA_OPTIONS value to point on the specific x64 path for the native I/O lib paths.

Interestingly enough, when I installed Weblogic on the same environment using the generic java (jar) installer I did not get this warning! The same applied when I installed Weblogic on MacOSX. It seems that the generic java installer does - put things properly in place. 

That is all for now....more to come I guess (thank god there still people willing to share tips and tricks on every dev problems. Kudos to the developer community).

Sunday, January 15, 2012

Taskrabbit..και σχετικές ιδέες στην Ελλάδα

Είμαι στην φάση που προσπαθώ να διαβάσω όσα τεύχη του Wired είχα αφήσει για μήνες στο συρτάρι. Στο τεύχος Αυγούστου διαβάζω ένα πολύ ενδιαφέρον άρθρο απο την Alexia Tsotsis, την οποία και είδα στο LeWeb 11, για το TaskRabbit. Λογικά, αρκετοί απ εσάς θα ξέρετε πια για την υπηρεσία ή μπορείτε να διαβάσετε το πολύ καλό άρθρο. Πρόκειται για μια πολύ έξυπνη ιδέα. Λίστα αγγελιών, για να κάνεις ουσιαστικά Outsourcing μικρές καθημερινές δουλειές που δεν μπορείς ή δεν προλαβαίνεις. Πχ Θέλω κάποιον να με βοηθήσει να πλύνω τα χαλιά, κάποιο να πάει στο supermarket το πρωί, κάποιον να πάει το αμάξι στο συνεργείο και να το παραλάβει και άλλα! 

Πόσες φορές δεν έχεις βρεθεί σε αυτή την θέση. Πρέπει να πας κάπου, να πάρεις ή να δώσεις κάτι αλλά δεν μπορείς να μην πας στην δουλειά. Αν είσαι τυχερός και ο εργοδότης σου έχει μια κάποια κατανόηση κάτι πάει κι έρχεται, αν όχι;  Όπως και να έχει πραγματικά πολύ καλή ιδέα. Βάζεις την αγγελία σου, θέτεις και μια τιμή και αφήνεις τους άλλους χρήστες να κάνουν την προσφορά τους. Το site κρατάει ένα ποσοστό της αμοιβής 10-15%. Ανακάλυψα επίσης και μερικά άλλα site τα οποία θέλουν ή προσπαθούν να κλέψουν την δόξα του TaskRabbit, όπως το Zaarly.

Στα δικά μας τώρα, πιστεύω ότι μια τέτοια υπηρεσία θα είχε απήχηση και στην Ελλάδα. Εγώ θα την χρησιμοποιούσα σίγουρα και πιστεύω αρκετοί άλλοι. Αλλά αυτό που σκέφτηκα γρήγορα είναι ότι δεν είναι τι δύσκολο να την υλοποιήσεις ή να την ξεκινήσεις αλλά το νομικό πλαίσιο στην χώρα μας για την εργασία, την ασφάλιση και ή την μερική απασχόληση. Δουλειές σαν τις αγγελίες του TaskRabbit δεν ξέρω αν μπορούν να θεωρηθούν μερική απασχόληση, σίγουρα αρκετοί χρήστες μπορούν να βγάζουν ένα πραγματικά καλό χαρτζιλίκι ή μικρο- εισόδημα. Από εκεί και πέρα στην Ελλάδα θα είχαμε να σκεφτούμε πράγματα όπως την ασφάλιση, την εφορία και άλλα! Σε μια ερώτηση μου πριν από λίγο στο twitter οι πρώτες απαντήσεις και εντυπώσεις για την ιδέα ήταν ' καλή ιδέα αλλά δεν θέλω να σκεφτώ ότι πρέπει να αντιμετωπίσω το ελληνικό κράτος  και την νομοθεσία του'. Δεκτό. 

Παρόλα αυτά για να είμαστε ειλικρινής, στην Ελλάδα έχουμε ένα παλιό - πλαίσιο εργασίας - εισφορών και γενικά καθόλου ευέλικτο ΚΑΙ παράλληλα έχουμε και την ολική προσπέραση του. Η ανασφάλιστη εργασία χωρίς ενδιάμεσους, χωρίς φόρους και ασφάλιση μπορεί να είναι κάτι το οποίο στα δελτία ειδήσεων αλλά και σε πολιτικές προγραμματικές δηλώσεις δεν υπάρχει ή θα καταπολεμηθεί αλλά όλοι μας γνωρίζουμε ότι είναι ΠΑΝΤΟΥ. Στο παιδί που σου φέρνει τον καφέ στην καφετέρια ή στο μπαρ, στον ελεύθερο επαγγελματία και σε πολλές μικρές ή μικρο μεσαίες επιχειρήσεις. 

Δεν θέλω να επεκταθώ πιο πολύ για την γενικότερη αναθεώρηση που πρέπει να υπάρξει στις εργασιακές σχέσεις. Το παιδί στο μπαρ που παίρνει 40 euro μεροκάματο - αντί να τα παίζει όλα μαύρα ας βρουν μια λύση να μπορεί να δώσει μέρος για κάποιες εισφορές. Από το να έιναι ΟΛΑ μαύρα (ίσως τελικά συμφέρει τους πάντες εκτός από το κράτος) και μια πολύ δύστροπη νομοθεσία, ας περάσουμε σε κάτι λιγότερο δύστροπο και με κάποιες ωφέλειες για τα ταμεία του κράτους. Θα τολμούσα να πω ότι και σαν ασφαλισμένος χρόνια στο ΙΚΑ θεωρώ απαράδεκτα τα ποσά που παρακρατούν από εμένα ΑΛΛΑ αλλά και τον εργοδότη μου.  Πλάτιασα..

Ωραία ιδέα το Taskrabbit μακάρι να μπορούσε να παίξει και στην Ελλάδα, σίγουρα θα συμμετείχα σε μια τέτοια προσπάθεια. 

Saturday, January 14, 2012

Εντυπώσεις: Boomerang, the meltdown tour by Michael Lewis



Πριν απο μερικές μέρες ολοκλήρωσα την ανάγνωση του τελευταίου βιβλίου από τον γνωστό  μας (πια), Michael Lewis. Το Βoomerang (ταξίδια στον Nέο Τρίτο Κόσμο) είναι σε μεγάλο μέρος η συλλογή άρθων και κειμένων του Lewis τα τελευταία χρόνια μετά την συγγραφή του the Big Short

Εδώ στην Ελλάδα, όπως και σιγά σιγά στην υπόλοιπη Ευρώπη έχουμε ξεκινήσει να συνηθίζουμε τις έννοιες και τις ιδέες των μοντέρνων χρηματο-οικονομικών και της σχετικής επιστήμης. Η κρίση, η πλήρης άγνοια για το γενικότερο σύστημα το οποίο ζούμε και τέλος η πολιτικο- κοινωνική μας αποχαύνωση ίσως στον μεγαλύτερο βαθμό σε σχέση με τους άλλους Ευρωπαίους πολίτες - μας οδήγησαν τώρα να έχουμε λίγο η πολύ άποψη για την οικονομία, τα spread, τα δάνεια και τα δομημένα ομόλογα. Δεν είναι κακό, δεν είναι καθόλου κακό - ήταν η μεγάλη ευκαιρία μας να μάθουμε κάτι ή να συνειδητοποιήσουμε μέρος της αλήθειας.

Υπάρχει ένα γενικότερο ρεύμα εκλαΐκευσης και απλοποίησης της γνώσης αυτής και γενικότερα κατανόησης χρηματο - οικονομικών μοντέλων αλλά και στρατηγικών.  Πολλές φορές - μπορούν να το πιστοποιήσουν και άνθρωποι που ακαδημαικά έχουν αφιερώσει χρόνια στην μελέτη τους - πολλά απο αυτά τα πράγματα είναι - απίστευτα πολύπλοκα λες και κάποιος επείτηδες έχει τυλίξει μια σχετικά απλή εννοια ή μια απάτη με επιστημονικούς όρους. Γνώση για τους λίγους θα πουν μερικοί - θα συμφωνήσω.

Ο Lewis είναι ένας συγγραφέας που έχει ασχοληθεί εκτεταμένα με όλα αυτά τα οικονομικά φαινόμενα, γράφει ανάλαφρα, απλά έτσι ώστε να μην θες πτυχίο οικονομικών για να πιάσεις τις βασικές έννοιες και τέλος - γράφει χιουμοριστικά - μερικές φορές ιδιαίτερα καυστικός (κάτι που δεν θα μας αρέσει σαν έθνος στο τελευταίο του βιβλίο).

Αρκετοί Έλληνες των γνώρισαν από εδώ. Κοιτάξτε την φωτό, ο γνωστό μας Αρσένιος χεχε. Το βιβλίο είναι χωρισμένο σε 5 μεγάλες ενότητες για κάθε μια χώρα που ασχολήθηκε. Ιρλανδία, Ελλάδα, Ισλανδία, Γερμανία και Αμερική. Θα διαβάσετε σε στυλ διήγησης αλλά και συνεντεύξεων λεπτομέρειες για τις καταστροφές και πολιτικές σε κάθε μια από αυτές τις χώρες. Μου άρεσε αρκετά η ενότητα της Ισλανδίας. Το ίδιο και της Γερμανίας. Σαν 'Ελληνας δεν ένιωσα και αρκετά περήφανος με το καυστικό του χιούμορ αλλά τι σύμπτωση και πόσο δίκιο είχε να γράφει έτσι. Ακόμα και μήνες μετά το βιβλίο, τις ημέρες που τον διάβαζα οι πρωταγωνιστές στο κεφάλαιο του για την Ελλάδα Εφραίμ, Αρσένιος έβλεπαν της φυλακής τα σίδερα.

Διαφωνώ λίγο με την τάση του να παίζει με εθνικά στερεότυπα από την άλλη σε πολλά πράγματα δεν έχει άδικο. Μπορεί να μην είμαστε η ρίζα του κακού σε αυτό το πολιτικό και οικονομικό βατερλό (ας υποδεχτούμε στο άγχος τους Γάλλους και Αυστριακούς - δεν θα αργήσουν και άλλοι) αλλά ακόμα μετά από 2-3 χρόνια ακόμα σαν λαός δεν έχουμε δείξει ότι θέλουμε να αλλάξουμε.

Διαβάστε το boomerang, θα σας κάνει καλό, είναι και εύκολο. Περήφανος πολίτης του Νέου Τρίτου Κόσμου ;). Τι διαφωνείτε; Υπάρχουν αρκετοί Εφραιμ, Αρσένιοι , Κίμωνες και Άκηδες εκεί έξω..μην τους ξεχνάτε! 

Thursday, January 12, 2012

Using Mockito Spy objects to test java objects/classes with inheritance (very simple example)

I came across today a case where I needed to complete a unit-integration test of some quite complex enterprise Java code. Actually it was JSF backing bean with a specific inheritance chain, wired all together with some EJB's.

Mockito is my library of preference for  all these kinds of tests (really lovely library and highly recommended). There is again an excellent post here with various comments. I just felt like providing a simplistic example + have a post to remind myself in the future.

The power of Mockito on such a scenario which actually can be something like - "I want to unit-integrate test something that inherits legacy code from super classes" is the use of Spy objects (see here as well). The power of Spy objects is that you can have a proper Mock object but you are able to invoke some real methods as well. A mixture that is.

A very simple example with a super and a sub class.
  
class GenericConstruct{
 
 public String doSomethingGeneric(){
  return "I do something";
 }
 
 public String doSomethingElseGeneric(){
  return "I do something else generic";
 }
}

class SubTypeOfGeneric extends GenericConstruct{
 
 public String doSomethingExtra(){
  System.out.println(doSomethingGeneric());
  System.out.println(doSomethingEleseGeneric());
  return "this is a very extra thing I am doing";
 }
 
}

The test, creates an actual spy, mocks the 2 methods inherited from the the super() class and then goes on with the rest of the implementation.

import static org.junit.Assert.*;

import org.junit.Test;
import org.mockito.Mockito;

public class TheTest {

 @Test
 public void test() {
  SubTypeOfGeneric aSpy = Mockito.spy(new SubTypeOfGeneric());
  Mockito.doReturn("a random value").when((GenericConstruct)aSpy).doSomethingGeneric();
  Mockito.doReturn("another random value").when((GenericConstruct)aSpy).doSomethingElseGeneric();
  
  String result =aSpy.doSomethingExtra();
  assertTrue(!result.isEmpty());
  
 }
}


Happy mocking!

Wednesday, January 11, 2012

Comparing Java enum items...tiny bugs with a busines side effect

I continue to browse through numerous classes and packages, using the report from Sonar and the issues indicated by PMD and Findbugs. Most of the issues fixed are of trivial to medium severity (IMHO). It can be a bit boring task, there are moments though, where something small and trivial may lead to  well hidden business bug.

A method, a check somewhere that once fixed, might alter the business behavior of a component or a business rule.At the end of the day you get a small satisfaction of contributing a lot of small fixes towards a greater cause - feels nice - especially when the code base is really huge. Lots of KLOCs.

Many thanks to Findbugs for this - what a lovely library that is!

The problem: Sometimes comparing enum items using  equals() method may lead to a bug. 

There are lots of debates around comparing enum items and a really great post in StackOverflow. There are people who tend to compare enums using the '==' operator and others using the equals(). Both of them work (enum is a special thing anyway. I think I will go with the '==' use, since it might prevent you from accidentally ending with today's bug. I will provide very similar example derived from this answer (credits).
  
 enum AComplexNameForAnEnum { ITEM_ONE, ITEM_TWO };
 enum AComplexNameForSimilarEnum { ITEM_ONE, ITEM_TWO };

 //compiles fine - but the accident has happened
 if(AComplexNameForAnEnum.ITEM_ONE
        .equals(AComplexNameForSimilarEnum.ITEM_ONE)); 

 //wont compile at all
 if(AComplexNameForAnEnum.ITEM_ONE==AComplexNameForSimilarEnum.ITEM_ONE) 


The example is the same with the one provided in the threads answer, my point here about the accident about to happen is that 'we' (the developers) sometimes have to fight with huge codebases and projects where dozens of Enumerations and subtypes are declared.
Sometimes all these constructs come with similar names or of very similar business meaning. Using the equals() method, the compiler wont notice anything at all - technically it would have compiled a useless if statement but business wise we would have a business check resulting to a false result. Switching to the '==' operator the compiler would save us, to have a better loook on what we are trying to compare and change the subtype or use the appropriate construct. 

Sometimes complex naming can lead to such small errors. I am sort of a supporter of complex naming but I have to agree noticed that it can be error prone at the same level as a hack-named (short named) construct. By the way the findbugs warning was this (EC: Call to equals() comparing different types (EC_UNRELATED_TYPES).

Small and nice things, while browsing hude codebases. I am really enjoying this review thing since I can do a small research on each topic and maybe find all the related causes of a bug, rather than just a technical coding error.  

Tuesday, January 10, 2012

Code formatting in Eclipse, a couple of tips.

I have been assigned lately some code review/ quality code fix tasks, on a large enterprise Java project and I am trying to assist the existing software development team, while waiting to resume my old duties on another project. 

Kind of fun, but at the same time dangerous enough, since you don't want to break anything important or ruin the work of your colleagues while  they rush towards an early release. With no knowledge of the underlying business, you have to review multiple times even the smallest change you are about to do.

Sometimes coding style and they way we structure our code proves to be very important for people coming in the project later on, aiming to resume our work or do maintenance work (like I am doing at the moment to a code base that I don't really master).

Tip 1: Write code, thinking the next guy/girl taking over your work.

I am a great supporter of the above idea. Sometimes we rush into hacking pieces of code that look smart or great at that time being, but in a couple of weeks even we can not understand how and why we did it that way. Try to keep it simple, add inline comments if you feel so, I really enjoy reading comments in the code explaining why a piece of code was developed that way and not the other way. These small hints act as time savers next time (in the long long future) you will have to review, fix or change this part. 

Tip 2: Eclipse: Prevent auto formatting in certain pieces of code.

There are cases where you have to write pieces of code that look a bit complicated, or you want to save some lines instead of breaking down the logic, especially in some trivial parts. I came up with a couple of long hashCode() and equals() methods that were not amazingly complex but at the same time not obvious. In order to fully understand why some parts of the checks performed on these methods were there, I had to manually format the code  in a form where the logic in ifs and the various logic operators were obvious.  There are other cases where tools like FindBugs or CheckStyle will alarm you about certain development decisions inside such methods - that most of the times will not be valid. 

Eclipse gives you the freedom to, disable Partially its formatter by adding a special tag in your code. All you have to do is browse through the sections below, under your Eclipse Preferences.

Preferences - Java - Code Style - Formatter - Active Profile (you need to have your custom - can not change the eclipse built in) - Edit- Tab (On/Off tabs) enable.



It is a good thing to configure your own formatter Profile (Per project is even better, or company wise). You may inherit the basic Eclipse (Built-In) profile and make your own.  When you have the above option enabled then you can exclude the code you don't want you or a colleague of yours - automatically formatted again, so that it becomes difficult to read (aka ugly).
  //@formatter:off
    if(aFlag){
    //do this
    }else if(anotherFlag){
     //do that etc
     }
   //@formatter:on

Watch out: Make sure all the members of the team share either the same options, otherwise upon commit another member with default configuration will turn your custom formatting to the previous state.

Tip 3: Eclipse, Put Braces in if statements,loops, equals() etc.
This is a long lasting battle, there are developers who dislike braces, some others (like me) who think they improve readability and some others that don't mind in general. I really hate missing braces (my personal preference) and I usually add them even in simple one line if statements.  You may have a look on the official Java Code Conventions here.
  //@formatter:off
    //I don't like this style
    if(aFlag)
       System.out.println("Do something");
    //I like this style
    if(anotherFlag){
      System.out.println("Do something better");
    }
Eclipse can help you fix this bad coding style in auto generated style or in formatting as well. There is a 'Clean up' section under the Eclipse Java Preferences that enforces 'blocks' on related code structures.

Preferences - Java - Code Style - Clean up - Active Profile (you need to have your custom - can not change the eclipse built in) - Edit- Tab (Code Style - use blocks in if/while/for/do statements. I have the 'Always' setting checked.



Watch out (again): Make sure all the members of the team share either the same options.

There is a special case as one of my colleagues indicates, related to the generated by the Eclipse IDE equals() method. In older versions of eclipse there was actually some sort of styling bug but it has been fixed from version 3.5 and onwards. 

When you select from Source -> Generate has hashCode() and equals() 


Make sure to select 'Use blocks in if Statements'. That way you will save some code quality warnings by related tools.




That is all for now, many thanks for the concerns, tips and questions to GeorgeK and Andreas.

Monday, January 09, 2012

Book review: Jenkins, The definite guide,(J.F Smart), O'Reilly.



Continuous Integration became a point of interest in the enterprise software development world, in the recent 5 to 6 years. In the Java EE case, we are happy enough to see tools and practises evolving rapidly, becoming tools of reference for other technologies and contributing the most to modern software development teams and methodologies. 

The induction of build servers / C.I (nowdays) tools has boosted software development efficiency (when used), increased long awaited automation on several tasks that required lots of estimated man hours in the past and helped reduce the amount of errors, bugs and inefficiencies on a software project.

I was lucky enough to participate in development teams that have embraced early enough several build server software and integrated into their software development methodology. Tools such as Continuum, early releases of Hudson and nowdays Jenkins. Some of them nowdays are evolving through the cloud either as a S.A.S offering or a mixture of related resources. Since the devops saga is still evoling in the software development community, the knowledge and skills related to such tools are becoming important not only for modern administrators but to software developers as well. 

Jenkins, the Definite Guide is a must read book for every devops admin or software  developer who wants to either make a first dive into the C.I integration world or extend his already (maybe limited if he/she was not totally exposed up until know) knowledge on the subject. I personally consider using such a tool as a must for every new Java Enterprise Project being currently developed or about to start. The better you are familiar with the extensive power and flexibility given by your C.I server the more you are going to gain in terms of productivity, automation, saving work force hours and providing a more robust deliverable.

The  first four chapters of the book are expanding from a good and solid introduction to the principles of Continous integration to a concrete guide on installing the latest flavor of Jenkins. Since I have installed and partially configured hudson in the past (sometimes experimenting in different enviroments) I found all the details covered in the book concrete enough. The author did a a very good job on covering installation issues and flavors on many cases and underlying operating systems. You will find adequate information on setting and configuring your Jenkins server both as a standalone process or as a web application (something very relevant for larger development teams).

The fifth chapter, (IMHO could have been 2 smaller) is going through in large detail around setting up a simple build project, using a freestyle configuration. The author, using a small software project which can be found online is configuring Jenkins to pull the project from various Source Code repositories, build it using maven, deploy it, run tests or experimenting with other build related software tools such as Ant, Groovy scripts etc. It is a quite good introduction of the main features of Jenkins and the potential tools that can be used along with it.

Chapters 6,7 and 8 cover some quite important features that are going to be levereaged by any user /team when they have completed mastering the basic stuff, and  have a first flavor or automation in their project. An important phase of the C.I cycle is testing, so the author goes through covering topics of testing inside the Jenkins enviroment. Quite complete chapter and quite rich list of mainstream tools integrated like Cobertura or Clover. Security and notification services are the next two chapters and I was very surprised by the technical debth of informatiuon provided on the how-to sections related to integrating Jenkins with several security domains (LDAP, MS based domains, Unix) + complete overview of the built in Jenkins security and role management configuration. 

Chapter 9 covers the important topic of code quality (one of my favourite features on such tools) and how a potential user can integrate modern code quality tools such as Checkstyle,PMD, Findbugs or others into their C.integration enviroment. Some of these tools are already famous among java developers for years now, so  the book is eventually quite up to date with all their related features. 

I really enjoyed chapter 10 which illustrates the power of Jenkins on providing the feature of disitributed builds. Having seen several build servers trying to cope with large code bases, thousands of integration of functional test suites and numerous hardware configurations failing due to high use, this is a killer feature that I hope to see it becoming mainstream (when it is needed). The book does a very good job on providing details about why and how you could leverage the distributed job functionality of Jenkins.

Overall, I think this book should be a must have for any corporate library and any team currently using Hudson or Jenkins as their mein C.I enviroment. It can be called 'a reference book' and most of the times the current information related to the recent builds is already covered. There are minor cases at the time being where the reader will have to resolve on googling for setting upa project or fix a configuration issues.  Definitelly worth buying. I hope to see and read more concrete books on structure and content as this one on 2012.

You can find it on Amazon, Oreilly