Categories
RDF Writing

Practical RDF-Generating giggles around the world

Practical RDF has now been immortalized in a comic strip.

Achewood

Hey! I love black licorice!

Categories
RDF

Jena Week: Migrating the first example

Recovered from the Wayback Machine.

(Note: all examples are compiled and run on a Windows 2000 box, MySql 4.x, Java 1.4.1_01)

I downloaded and unzipped the Jena2 from the SourceForge project and first thing I noticed is that there is a lot of material with this download. With the classes for the ontology support as well as RDF, this is a large Java framework, providing support for all aspects of RDF and OWL, including an inferential engine, the ‘reasoner’.

The second thing I noticed is that the documentation for Jena2 is sketchy at best, with the tutorial still set for Jena 1.4, some migration guides, and the ubiquitous Javadocs. But hey! We all know that Java is self-documenting with Javadocs, so we don’t need to stinkin’ tutorials and user manuals. Besides, tutorials are for babies.

Seriously, the generated Java documentation, installation and migration guides, and the essential Jena Mini I/O are enough if you’ve worked with Jena previously. If not, hopefully the essays this week, migrating the Jena applications in the book to Jena2 will provide a good start in your efforts.

(If all goes well, next week we’ll work with the ontology classes and all of the other new Jena2 goodes. )

Once installed, I added all of the Jena jar files to my classpath, per the README document in the root directory. I then tested the installation using the test.bat file, but I could have used Ant, or used test.sh within a Unix environment. Once tested, second step was to start porting the first example Java application, reproduced here as a guide:

import com.hp.hpl.mesa.rdf.jena.mem.ModelMem; import com.hp.hpl.mesa.rdf.jena.model.*; import com.hp.hpl.mesa.rdf.jena.common.PropertyImpl; import java.io.PrintWriter;

public class pracRDFFirst extends Object {

public static void main (String args[]) { String sURI = “http://burningbird.net/articles/monsters1.htm”; String sPostcon = “http://www.burningbird.net/bbd/elements/1.0/”; String sRelated = “related”; try { // create an empty graph Model model = new ModelMem();

// create the resource Resource postcon = model.createResource(sURI);

// create the predicate (property) Property related = model.createProperty(sPostcon, sRelated);

// add the properties with associated values (objects) postcon.addProperty(related, “http://burningbird.net/articles/monster3.htm”); postcon.addProperty(related, “http://burningbird.net/articles/monster2.htm”);

// Print RDF/XML of model to system output model.write(new PrintWriter(System.out));

} catch (Exception e) { System.out.println(“Failed: ” + e); } } }

This example is pretty simple: create an in-memory model, a new resource, and add two properties to that resource, both with the predicate “related”. Absolute URIs are used, and once the model is built, it’s printed out to the system. General exceptions are captured and the error message is printed. No other error checking and management is done.

The first step in migrating this example is to change the existing class structure to the new refactored one:

    * com.hp.hpl.mesa.rdf.jena.model -> com.hp.hpl.jena.rdf.model
    * com.hp.hpl.mesa.rdf.jena.vocabulary -> com.hp.hpl.jena.vocabulary

This is a bit tricky at first because not only is ‘mesa’ removed, the jena.rdf reference is reversed. Another change is the fact that there no longer is a specific ModelMem class or a specific PropertyImpl implementation class. This simplifies the number of Java classes that are included:

import com.hp.hpl.jena.rdf.model.*;
import java.io.FileOutputStream;
import java.io.PrintWriter;

The actual code of the application doesn’t change drastically. We’re using a class factor rather than new, but creating the resource and adding the properties doesn’t change:


import com.hp.hpl.jena.rdf.model.*;
import java.io.FileOutputStream;
import java.io.PrintWriter;

public class pracRDFFirst extends Object {
public static void main (String args[]) { String sURI = “http://burningbird.net/articles/monsters1.htm”; String sPostcon = “http://burningbird.net/postcon/elements/1.0/”; String sRelated = “related”; try { // create an empty graph Model model = ModelFactory.createDefaultModel();
// create the resource Resource postcon = model.createResource(sURI);
// create the predicate (property) Property related = model.createProperty(sPostcon, sRelated);
// add the properties with associated values (objects) postcon.addProperty(related, “http://burningbird.net/articles/monster3.htm”); postcon.addProperty(related, “http://burningbird.net/articles/monster2.htm”);

Once the model is built, to print it out with Jena, I used to use Jena’s Writer. In Jena2, this is replaced with InputStream and OutputStreams, a change significant enough for the Jena team to put out wht they call a “Rush Guide – Jena 1 Migration (Must Read)”.

According to the guide:

The Jena1 developer will note that all but one of these methods are new in Jena2. Jena1 mistakenly required the use of java.io.Reader and java.io.Writer. While these classes work well on a single machine, the way they address character encoding problems differs significantly from the solution offered by XML. A typical use of the Jena1 input interface such as mdl.read(new FileReader(fName)); is incorrect, and will give the wrong results if the file contains non-ASCII data. Also, in Jena1, mdl.write(new FileWriter(fName)); wrote incorrect XML for non-ASCII data (now fixed). However, these two bugs in Jena1 canceled each other out, as long as the system doing the reading had the same default character encoding as the one doing the writing, which is why it did not bite in a typical development environment. There is the substantial migration task when porting Jena1 code to Jena2 code of reviewing all the I/O calls and changing them to use InputStream’s and OutputStream’s.

Now, this is my kind of technical description, …which is why it did not bite in a typical development environment…. According to the guide, the old methods are still supported, and can still be useful and I found this so when I compiled the application without making the I/O change. However, Jena now traps for the bugs mentioned in the description and issues errors – errors that are almost guaranteed to occur.

You can still use Reader and Writer, but do so when you’re working with StringBuffer in memory, or when you specifically control the string encoding. Otherwise – go with the new OutputStream/InputStream objects. Only problem is, according to the Rush I/O guide example, to access the new OutputStream class, RDFWriter, use getRDFWriter. This was a typographical error, and to get RDFWriter, use getWriter on the model object, passing in an optional string with the serialization language. The default serialization language, RDF/XML, works so we don’t need to pass in the string.

The change to the code to use RDFWriter in the updated application is (outputting to System.out):

          
// Print RDF/XML of model to system output
          RDFWriter writer = model.getWriter();
          writer.write(model, System.out, null);

Easy enough to change. The complete new tiny application that creates an RDF model with one resource and a repeating property, printed out to system is:

import com.hp.hpl.jena.rdf.model.*;
import java.io.FileOutputStream;
import java.io.PrintWriter;

 

public class pracRDFFirst extends Object {

public static void main (String args[]) { String sURI = “http://burningbird.net/articles/monsters1.htm”; String sPostcon = “http://burningbird.net/postcon/elements/1.0/”; String sRelated = “related”; try { // create an empty graph Model model = ModelFactory.createDefaultModel();

// create the resource Resource postcon = model.createResource(sURI);

// create the predicate (property) Property related = model.createProperty(sPostcon, sRelated);

// add the properties with associated values (objects) postcon.addProperty(related, “http://burningbird.net/articles/monster3.htm”); postcon.addProperty(related, “http://burningbird.net/articles/monster2.htm”);

// Print RDF/XML of model to system output RDFWriter writer = model.getWriter(); writer.write(model, System.out, null);

} catch (Exception e) { System.out.println(“Failed: ” + e); } } }

Compiling the application and running it gives us the following serialized RDF/XML:

<rdf:RDF
    xmlns:j.0="http://burningbird.net/postcon/elements/1.0/"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
  <rdf:Description rdf:about="http://burningbird.net/articles/monsters1.htm">
    <j.0:related>http://burningbird.net/articles/monster3.htm</j.0:related>
    <j.0:related>http://burningbird.net/articles/monster2.htm</j.0:related>
  </rdf:Description>
</rdf:RDF>

That’s it, an application that compiles and runs within Jena2, and a remarkably pain free migration. Of course, this was a small application. Next essay in this series, we’ll start looking at slightly more complicated applications. I’m sure the headache factor of the migration will increase as the complications in the applications increase. Isn’t there a law saying this is so?

Categories
RDF

Jena Week: Lovely, lovely factories

Recovered from the Wayback Machine.

While factories in the real world tend to be messy, ugly things polluting the environment, within Java, they’re wonderful creations that hide much of the implementation detail of Java interfaces. This is particularly obvious when we take a look at porting the third example from Chapter 8 in Practical RDF to the new Jena2.

(No worries about skipping – at the end of the series I’ll post a file that contains all of the converted applications.)

The third example introduces the implementation of two concepts: one having to do with RDF and RDF/XML – bnodes, or blank nodes; the other having to do with hiding some of the implementation details when working with a pre-defined RDF vocabulary in Jena – RDF vocabulary classes.

The Java code from the book for the third example is:

 

import com.hp.hpl.mesa.rdf.jena.mem.ModelMem; import com.hp.hpl.mesa.rdf.jena.model.*; import com.hp.hpl.mesa.rdf.jena.vocabulary.*; import com.burningbird.postcon.vocabulary.POSTCON; import java.io.FileOutputStream; import java.io.PrintWriter;

public class pracRDFThird extends Object {

public static void main (String args[]) {

// resource names String sResource = “http://burningbird.net/articles/monsters1.htm”; String sRelResource1 = “http://burningbird.net/articles/monsters2.htm”; String sRelResource2 = “http://burningbird.net/articles/monsters3.htm”;

try { // create an empty graph Model model = new ModelMem();

// create the resource // and add the properties cascading style Resource article = model.createResource(sResource) .addProperty(POSTCON.related, model.createResource(sRelResource1)) .addProperty(POSTCON.related, model.createResource(sRelResource2));

// create the bio bnode resource // and add properties Resource bio = model.createResource() .addProperty(DC.creator, model.createLiteral(“Shelley Powers”)) .addProperty(DC.publisher, model.createLiteral(“Burningbird”)) .addProperty(DC.title, model.createLiteral(“Tale of Two Monsters: Legends”, “en”));

// attach to main resource article.addProperty(POSTCON.bio, bio);

// Print RDF/XML of model to system output model.write(new PrintWriter(System.out));

} catch (Exception e) { System.out.println(“Failed: ” + e); } } }

 

This application code uses the cascade style of piggy backing instantiation of objects that are then passed to the function calls that instantiate other objects and so on. This is an effective technique to use if you’re not re-using interim objects.

Note also that the code creates a new resource that does not have a specific URI because it’s a blank node:

  Resource bio
     = model.createResource()

 

As you’ll remember from the book – you do have the book, now, don’t you? – a blank node is a resource where a URI is not meaningful, or doesn’t yet exist. In this example, the bio section doesn’t have a meaningful URI, yet. Once created, the bnode resource is then attached directly to the model’s top-level resource using the predicate, ‘bio’. Later we’ll see what the bnode looks like as generated RDF/XML.

One major change with this code from the previous example covered in the last post is that it uses another class, POSTCON, for the PostCon vocabulary elements. Though not a requirement, using a vocabulary has several advantages, including code reuse and modularization, as well as hiding some of the implementation characteristics. The Jena development team used this approach with several existing and widespread vocabularies, including DC, DCTERMS, and VCARD – all of which are included with the Jena installation.

The original code for the PostCon vocabulary class is:

package com.burningbird.postcon.vocabulary;

 

import com.hp.hpl.mesa.rdf.jena.common.ErrorHelper; import com.hp.hpl.mesa.rdf.jena.common.PropertyImpl; import com.hp.hpl.mesa.rdf.jena.common.ResourceImpl; import com.hp.hpl.mesa.rdf.jena.model.Model; import com.hp.hpl.mesa.rdf.jena.model.Property; import com.hp.hpl.mesa.rdf.jena.model.Resource; import com.hp.hpl.mesa.rdf.jena.model.RDFException;

public class POSTCON extends Object {

// URI for vocabulary elements protected static final String uri = “http://burningbird.net/postcon/elements/1.0/”;

// return URI for vocabulary elements public static String getURI() { return uri; }

// define the property labels and objects static final String nbio = “Bio”; public static Property bio = null; static final String nrelevancy = “Relevancy”; public static Property relevancy = null; static final String npresentation = “Presentation”; public static Resource presentation = null; static final String nhistory = “history”; public static Property history = null; static final String nmovementtype = “movementType”; public static Property movementtype = null; static final String nreason = “reason”; public static Property reason = null; static final String nstatus = “currentStatus”; public static Property status = null; static final String nrelated = “related”; public static Property related = null; static final String ntype = “type”; public static Property type = null; static final String nrequires = “requires”; public static Property requires = null;

// define the resources static final String nresource = “Resource”; public static Resource resource = null; static final String nmovement = “Movement”; public static Resource movement = null;

// instantiate the properties and the resource static { try {

// instantiate the properties bio = new PropertyImpl(uri, nbio); relevancy = new PropertyImpl(uri, nrelevancy); presentation = new PropertyImpl(uri, npresentation); history = new PropertyImpl(uri, nhistory); related = new PropertyImpl(uri, nrelated); type = new PropertyImpl(uri, ntype); requires = new PropertyImpl(uri, nrequires); movementtype = new PropertyImpl(uri, nmovementtype); reason = new PropertyImpl(uri, nreason); status = new PropertyImpl(uri, nstatus);

// instantiate the resources resource = new ResourceImpl(uri+nresource); movement = new ResourceImpl(uri+nmovement);

} catch (RDFException e) { ErrorHelper.logInternalError(“POSTCON”, 1, e); } } }

 

What a mess – all the implementation details for the interfaces are exposed, making for extra work and minimizing readability of the code. But all of that’s changed now in Jena2.

With Jena2, rather than using a series of …Impl classes, and having to implement the RDF class interfaces directly, the actual implementation of the interfaces occurs deep down inside the guts of Jena, through factory objects. This is where this type of implementation should occur so that we can focus on developing RDF applications, rather than on Java implementation language details.

Compare the POSTCON vocabulary class in Jena1 with the new one, defined using Jena2 functionality:

package com.burningbird.postcon.vocabulary;

 

import com.hp.hpl.jena.rdf.model.*;

public class POSTCON {

// URI for vocabulary elements protected static final String uri = “http://burningbird.net/postcon/elements/1.0/”;

// return URI for vocabulary elements public static String getURI() { return uri; }

private static Model model = ModelFactory.createDefaultModel();

// define the property labels and objects public static final Property bio = model.createProperty(uri + “bio”); public static final Property relevancy = model.createProperty(uri + “relevancy”); public static final Property presentation = model.createProperty(uri + “presentation”); public static final Property history = model.createProperty(uri + “history”); public static final Property movementtype = model.createProperty(uri + “movementType”); public static final Property reason = model.createProperty(uri + “reason”); public static final Property status = model.createProperty(uri + “status”); public static final Property related = model.createProperty(uri + “related”); public static final Property type = model.createProperty(uri + “type”); public static final Property requires = model.createProperty(uri + “requires”);

// define the resources public static final Resource Resource = model.createResource(uri + “Resource”); public static final Resource Movement = model.createResource(uri + “Movement”); }

 

The difference is significant, and greatly improved. Another approach to use could be to use the ResourceFactory object directly to create the individual items:

    public static final Property requires = ResourceFactory.createProperty(uri + “requires");
    public static final Resource Resource = ResourceFactory.createResource(uri + “Resource");

 

Looking through the source code for the vocabulary classes included with Jena, I see both approaches being used. Once the new POSTCON vocabulary class has been compiled, we can look at porting the rest of the third example from the book.

Returning to the code for the third example, the only changes that need to occur now to make this work with Jena2 is to use the ModelFactory to create the model, and update the code to use the new outputstream class, as discussed in the previous posting. The updated code now becomes:

import com.burningbird.postcon.vocabulary.POSTCON;

 

public class pracRDFThird extends Object{

public static void main (String args[]) {

// resource names String sResource = “http://burningbird.net/articles/monsters1.htm”; String sRelResource1 = “http://burningbird.net/articles/monsters2.htm”; String sRelResource2 = “http://burningbird.net/articles/monsters3.htm”;

try { // create an empty graph Model model = ModelFactory.createDefaultModel();

// create the resource // and add the properties cascading style Resource article = model.createResource(sResource) .addProperty(POSTCON.related, model.createResource(sRelResource1)) .addProperty(POSTCON.related, model.createResource(sRelResource2));

// create the bio bnode resource // and add properties Resource bio = model.createResource() .addProperty(DC.creator, “Shelley Powers”) .addProperty(DC.publisher, “Burningbird”) .addProperty(DC.title, model.createLiteral(“Tale of Two Monsters: Legends”, “en”));

// attach to main resource article.addProperty(POSTCON.bio, bio);

// Print RDF/XML of model to system output RDFWriter writer = model.getWriter(); writer.write(model,System.out, null);

} catch (Exception e) { System.out.println(“Failed: ” + e); } } }

 

The resulting RDF/XML is:

<rdf:RDF
    xmlns:j.0="http://burningbird.net/postcon/elements/1.0/”
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#”
    xmlns:dc="http://purl.org/dc/elements/1.1/” >
  <rdf:Description rdf:about="http://burningbird.net/articles/monsters1.htm">
    <j.0:related rdf:resource="http://burningbird.net/articles/monsters2.htm"/>
    <j.0:related rdf:resource="http://burningbird.net/articles/monsters3.htm"/>
    <j.0:bio rdf:nodeID="A0″/>
  </rdf:Description>
  <rdf:Description rdf:nodeID="A0″>
    <dc:creator>Shelley Powers</dc:creator>
    <dc:publisher>Burningbird</dc:publisher>
    <dc:title xml:lang="en">Tale of Two Monsters: Legends</dc:title>
  </rdf:Description>
</rdf:RDF>

 

The blank node is given a node identifier of “AO” to differentiate it in the model. Use caution with bnode identifiers – they lose all meaning outside of the particular instance of the model; they are not true URIs, but merely a placeholder and a convenience.

 

Well, that was fun. Still no hassle porting the code, and since we used a vocabulary class in the original application, we’ve helped minimize the code changes in all of the applications that use the class. Golly, isn’t it nice how this stuff works, sometimes?

Categories
RDF

Jena Week: Containers and namespaces

Recovered from the Wayback Machine.

The RDF/XML syntax differs a great deal from vanilla XML, not the least of which is there is no assumptions associated with the order of elements, and XML lacks many of the precision refinements built directly into RDF/XML.

For instance, in XML you can have several children of an element, but then you’d have to use DTDs or XML Schema to treat the children other than a group whereby order matters. In RDF/XML you can use containers and collections to provide additional information about the members.

Example five in the book created a specific type of Container, a Seq. The code for the example for Jena1 is as follows:

import com.hp.hpl.mesa.rdf.jena.mem.ModelMem;
import com.hp.hpl.mesa.rdf.jena.model.*;
import com.hp.hpl.mesa.rdf.jena.vocabulary.*;
import com.burningbird.postcon.vocabulary.POSTCON;
import java.io.FileOutputStream;
import java.io.PrintWriter;

 

public class pracRDFFifth extends Object {

public static void main (String args[]) {

// resource names String sResource = “http://burningbird.net/articles/monsters1.htm”; String sHistory1 = “http://www.yasd.com/dynaearth/monsters1.htm”; String sHistory2 = “http://www.dynamicearth.com/articles/monsters1.htm”; String sHistory3 = “http://www.burningbird.net/articles/monsters1.htm”;

try { // create an empty graph Model model = new ModelMem();

// create Seq Seq hist = model.createSeq() .add (1, model.createResource(sHistory1) .addProperty(POSTCON.movementtype, model.createLiteral(“Add”)) .addProperty(POSTCON.reason, model.createLiteral(“New Article”)) .addProperty(DC.date, model.createLiteral(“1998-01-01T00:00:00-05:00″))) .add (2, model.createResource(sHistory2) .addProperty(POSTCON.movementtype, model.createLiteral(“Move”)) .addProperty(POSTCON.reason, model.createLiteral(“Moved to separate dynamicearth.com domain”)) .addProperty(DC.date, model.createLiteral(“1999-10-31:T00:00:00-05:00″))) .add (3, model.createResource(sHistory3) .addProperty(POSTCON.movementtype, model.createLiteral(“Move”)) .addProperty(POSTCON.reason, model.createLiteral(“Collapsed into Burningbird”)) .addProperty(DC.date, model.createLiteral(“2002-11-01:T00:00:00-5:00″)));

// create the resource // and add the properties cascading style Resource article = model.createResource(sResource) .addProperty(POSTCON.history, hist);

// Print RDF/XML of model to system output RDFWriter writer = model.getWriter(); writer.setNsPrefix(“pstcn”, “http://burningbird.net/postcon/elements/1.0/”); writer.write(model, new PrintWriter(System.out), “http://burningbird.net/articles” );

} catch (Exception e) { System.out.println(“Failed: ” + e); } } }

 

Note also that this code example introduces a method of changing the namespace abbreviation used, so that we don’t get the generic J0 we’ve been seeing in previous examples:

            // Print RDF/XML of model to system output
            RDFWriter writer = model.getWriter();
            writer.setNsPrefix("pstcn", “http://burningbird.net/postcon/elements/1.0/");
            writer.write(model, new PrintWriter(System.out), “http://burningbird.net/articles” );

 

As with previous examples the primary changes are to the class library structure and to use the factory object to create the memory model. When compiling the application, though, errors appeared.

The setNSPrefix method on the Jena1 RDFWriter class has been removed. To set the namespace, we’ll need to use the code that Ian provided in my comments in the last example:

		// set namespace qualifier
		model.getGraph()
		.getPrefixMapping()
		.setNsPrefix( “pstcn",
		“http://burningbird.net/postcon/elements/1.0/” );

 

At this point no errors are occurring, and I get the generated RDF/XML shown in this file.

This RDF/XML is close, and valid, but not what I was expecting – the Jena code stripped the absolute URI for the primary resource down to a relative URI when attaching the Seq to the resource using a bnode:

  <rdf:Description rdf:about="http://burningbird.net/articles/monsters1.htm">
    <pstcn:history rdf:nodeID="A0″/>
  </rdf:Description>

 

Relative URIs are valid, they resolve to their parent document, or to whatever is specified with xml:base. Why Jena2 alters the URI to a relative one is a big mystery.

You can also set xml:base, but I haven’t been able to locate the class method to use to do this with Jena2. I’ll continue hunting this and hopefully post the information in the next essay

The complete code for this example is:

import com.hp.hpl.jena.rdf.model.*;
import com.hp.hpl.jena.vocabulary.*;
import com.burningbird.postcon.vocabulary.POSTCON;
import java.io.PrintWriter;

 

public class pracRDFFifth extends Object {

public static void main (String args[]) {

// resource names String sResource = “http://burningbird.net/articles/monsters1.htm”; String sHistory1 = “http://www.yasd.com/dynaearth/monsters1.htm”; String sHistory2 = “http://www.dynamicearth.com/articles/monsters1.htm”; String sHistory3 = “http://www.burningbird.net/articles/monsters1.htm”;

try { // create an empty graph Model model = ModelFactory.createDefaultModel();

// create Seq Seq hist = model.createSeq() .add (1, model.createResource(sHistory1) .addProperty(POSTCON.movementtype, model.createLiteral(“Add”)) .addProperty(POSTCON.reason, model.createLiteral(“New Article”)) .addProperty(DC.date, model.createLiteral(“1998-01-01T00:00:00-05:00″))) .add (2, model.createResource(sHistory2) .addProperty(POSTCON.movementtype, model.createLiteral(“Move”)) .addProperty(POSTCON.reason, model.createLiteral(“Moved to separate dynamicearth.com domain”)) .addProperty(DC.date, model.createLiteral(“1999-10-31:T00:00:00-05:00″))) .add (3, model.createResource(sHistory3) .addProperty(POSTCON.movementtype, model.createLiteral(“Move”)) .addProperty(POSTCON.reason, model.createLiteral(“Collapsed into Burningbird”)) .addProperty(DC.date, model.createLiteral(“2002-11-01:T00:00:00-5:00″)));

// create the resource // and add the properties cascading style Resource article = model.createResource(sResource) .addProperty(POSTCON.history, hist);

// set namespace qualifier model.getGraph() .getPrefixMapping() .setNsPrefix( “pstcn”, “http://burningbird.net/postcon/elements/1.0/” );

// Print RDF/XML of model to system output RDFWriter writer = model.getWriter(); writer.write(model, new PrintWriter(System.out), “http://burningbird.net/articles” );

} catch (Exception e) { System.out.println(“Failed: ” + e); } } }

 

Well, this example’s conversion wasn’t without confusion. We’ve spent enough time on creating models – next example, we’ll look at reading a model in from an RDF/XML file, and accessing the individual statements.

Categories
Photography Weblogging Writing

Big Water

Recovered from the Wayback Machine.

Pretty tired today, and no, it has nothing to do with the peace party that happened in the comments to the last post. The participants worked things out for themselves, which is as it should be. I’m not sure what Happy Tutor is doing and where he’s taking it, but he’s a big boy and can handle burning material. Since he’s taken said burning material elsewhere, I am content.

I’m currently working on three articles for O’Reilly and some other promotional activity for the Practical RDF book. Additionally, I’ve been out virtually knocking on the doors of several local and national publications trying to re-awaken my moribund writing career. The end result of this activity is that I need to write. A lot. Knock a bit more, write a bit more, and repeat.

I also need to drop some of the bad writing habits I’ve picked up with weblog writing, such as the assumptions, the higher level of familiarity, the creative spelling and sentence construction, the use of ’so’, and the other quaint little short-cuts that fit this format, but not necessarily others.

So … I’m organizing my photos into online albums and am surprised at how many there are. Once finished, I need to select the best 50 for one portfolio, and then the best 20 of that number for another portfolio. However, when I think of my photos in something like a portfolio, my view of them changes and I become more critical of the work. It’s hard to explain but when you look at a photo one way, it can look good; but look at the photo from a different perspective – and I’m not talking the photo’s perspective – and it doesn’t quite work. At the rate I’m going, I’ll be lucky if I find five that work.

This phenomena happens with writing, too.

I’m planning a little trip South and along the Gulf in the nature of a combined vocational challenge/public interest jaunt. In September when the kiddies are in school, the weather cools, and the gas and motels are cheaper.

I don’t think I’ve posted the following photo previously. It’s the Chain of Rocks Bridge again, part of the old Route 66. I’m not saying the photo’s a portfolio member, but it’s cheerful, don’t you think? Imagine Nat King Cole singing in the background, and being in a convertible wearing a soft summer dress and iron maid bra, breeze blowing your hair in the warm, humid night. Get your kicks on Route 66.

rt66bridge.jpg