Re: Enhancing object-oriented programming with OWL

Hey Timothy,

RDF is metadata that can be easily managed: it has standard transport,
serializations, query language etc. The object model has none of that.
By coupling the application domain model with the data model (e.g. by
naming classes/methods after ontology terms) you prevent the
application from being generic. You need to keep the objects mirroring
the RDF -- this is similar to what ORM was supposed to deliver but
haven't really succeeded.
I think generic applications are inevitable given how fast the data
volumes grow. If we want achieve that we should be doing the opposite
-- pushing the application domain logic into a generic model such as
RDF, so that it can be managed.

I agree your approach is useful when semantifying the OO world. But if
I can achieve the same end result in plain Java (using Jena and our
own platform), why should I use an extra layer of software (given the
above points)?

Martynas
graphity.org

On Tue, Sep 11, 2012 at 10:07 PM, Timothy Armstrong
<tim.armstrong@gmx.com> wrote:
> Hi,
>
> Martynas, I'm not sure what you mean by “huge abstraction level.” If you
> look at my example program, http://www.semanticoop.org/example.html, you'll
> see that all the code is the OWL semantics for the attributes/properties, a
> single line at the beginning of the program, and then regular Java code. If
> we add OWL to Java, all OWL data are just object-oriented data, so we just
> use object-oriented code to manipulate the OWL data instead of some special
> sort of code as in Jena, Sesame, RDFLib, etc. (This software is very
> valuable; I'll probably want to combine my software with both Jena and
> Sesame.)
>
> My motivation is mainly to allow people to use the Semantic Web in any of
> their object-oriented code, which I'm sure no one else has ever done before.
> Really, I think people will love it. However, I think my software also has
> some advantages over Semantic Web software that stores its data as whole
> triples, and I believe it is very much worth investigating them. I ran some
> benchmarks comparing my software with Jena for creating resources / Java
> objects and making triple statements. If you look at them,
> http://www.semanticoop.org/benchmarks.html, you'll see that my software
> compares very favorably. Please feel free to try them yourself! (And email
> me if you have problems running the code.) I'll gladly run any more
> benchmarks anyone suggests, given that I don't have SPARQL working yet
> (though it should be close to working). At least, they should be good
> benchmarks to run.
>
> Well I'm glad people are talking to me, but I'm just surprised I'm really
> not getting people to say much positive. Shouldn't we just go ahead and try
> to convince people to post their object-oriented data on the Semantic Web so
> that people have access to the data, as in my last post? Once the code is
> written, that is.
>
> Tim
>
>
>
> On 09/07/2012 09:15 AM, Martynas Jusevičius wrote:
>>
>> Tim,
>>
>> let me be so bold as to argue that you do not need the object model
>> *at all* to build Semantic Web apps. Above RDF/SPARQL API level, that
>> is.
>>
>> So your idea might be interesting as a computer science experiment,
>> but to those building practical applications, it might be just another
>> huge abstraction level without real added value.
>> It might be helpful in order to integrate legacy Java apps or lower
>> the SW learning curve for developers coming from that world, but
>> that's pretty much it. Are you sure it's worth the effort?
>>
>> Martynas
>>
>> On Fri, Sep 7, 2012 at 2:48 AM, Timothy Armstrong <tim.armstrong@gmx.com>
>> wrote:
>>>
>>> Hi,
>>>
>>> Well, we need a new reasoner.  I explain my approach a bit below for the
>>> reasoner I wrote.  I believe it is new, but I could be entirely mistaken
>>> that it's new.  At no time does all of memory have to be in a reasoned
>>> state, only a small part of it.  We need a new reasoner because all the
>>> existing ones run on a set of whole triples, and we need one that just
>>> runs
>>> on Java.
>>>
>>> I believe it is eminently worthwhile to write a new reasoner.  I'm sure
>>> there is a lot we can take from existing reasoners.  We would have to
>>> work
>>> on it.  I'm always surprised that more people don't know about the
>>> Semantic
>>> Web.  It is a very powerful set of technologies, and I think making the
>>> Internet into a giant database is just a great practical development in
>>> computers.  I have in mind for all programmers to use the Semantic Web
>>> every
>>> day in all their object-oriented code: OWL, SPARQL, rules, and Semantic
>>> Web
>>> Services.  I have in mind for everyone to know about the Semantic Web.
>>> Likely people will want a lot more Semantic Web software if that happens.
>>>
>>> People didn't seem impressed when I said we could post all
>>> object-oriented
>>> data on the Semantic Web.  We can.  The Semantic Web will just be giant
>>> with
>>> all that data on it.  I'd like to explain in more detail.  People have
>>> commented on the difference between attributes and properties, and I've
>>> read
>>> some of the links.  My view is still that an attribute is just a binary
>>> predicate, nothing more, nothing less.  It just relates two entities.
>>> Translating Java data into RDF is on my to do list to code, but it's
>>> straightforward to explain.  Each Java package is an ontology.  The
>>> classes
>>> in the package are members of the ontology.  We make each attribute into
>>> a
>>> property.  In my software, properties are defined in their own files
>>> alongside the classes.  We could put all the properties in the main
>>> ontology
>>> if the properties from different classes don't conflict, or we could
>>> create
>>> a separate ontology for each class that just contains the class's
>>> attributes.  Then for the data, we just take each Java Collection or
>>> array
>>> that is an attribute and make each element of it into a triple.  When it
>>> is
>>> a list or an array, we will have to differentiate whether the programmer
>>> really means a set of triples or a list like rdf:List.  Sometimes when
>>> programmers use lists, they really mean sets.  The value of each
>>> attribute
>>> that is not a Java Collection or an array is just a single triple.  There
>>> are rdf:type triples for class membership.  So all object-oriented data
>>> are
>>> triples.  Then we can post all object-oriented data on the Semantic Web.
>>> We
>>> should just go ahead and do that so that people have access to the data.
>>>
>>> My approach to reasoning is a little difficult to explain, but I did my
>>> best
>>> to explain it in my article, which I quote here.  It might make better
>>> sense
>>> in the context of the article, but you should be able to follow it.  As I
>>> mentioned, for each read operation, it is as if Protege reasoned only the
>>> part of the data set relevant to the screen the user is currently viewing
>>> and did not do any more reasoning.  When we call a read method on a Java
>>> Collection that is an attribute, we do only the reasoning that could
>>> potentially cause objects to be added to the set of objects.
>>>
>>> Property reasoning consists of trying to add objects to a certain
>>> subject-predicate pair.  When we call a read method on a Java Collection
>>> that is an attribute for a certain subject and predicate, we want all the
>>> objects to be in it.  The goal is to reason this object set, i.e. add as
>>> many members to it as we can according to the reasoning.  For each type
>>> of
>>> property reasoning, there is a certain manner in which objects may be
>>> added
>>> to the object set.  We need to try to add objects by each type of
>>> reasoning.
>>> Depending on the semantics of the property, we need to try to add objects
>>> by
>>> zero or more of rdfs:subPropertyOf (including owl:equivalentProperty),
>>> owl:inverseOf, owl:ReflexiveProperty, owl:SymmetricProperty, and
>>> owl:TransitiveProperty.  So let us look at each type of reasoning.  For a
>>> subject s and a predicate p, let us call the set of objects O_s,p.
>>>
>>> First, let us look at rdfs:subPropertyOf reasoning.  Let us have a
>>> property
>>> hasChild with two subproperties, hasDaughter and hasSon, representing the
>>> sets of a person's children, daughters, and sons, respectively.  The
>>> domains
>>> are all Person, a class representing a person.  The ranges are Person,
>>> Female, and Male, respectively, where Female is a female person and Male
>>> is
>>> a male person.  We are trying to find all of a person x's children.
>>> I.e.,
>>> we are trying to reason the object set O_x,hasChild, with person x as
>>> subject and hasChild as predicate.  To find all of x's children, we need
>>> to
>>> find all of x's daughters and sons.  I.e., we need to reason the object
>>> sets
>>> O_x,hasDaughter and O_x,hasSon.  However, if the only form of reasoning
>>> we
>>> are using for hasChild is rdfs:subPropertyOf, i.e. if no other form of
>>> reasoning can add objects to O_x,hasChild, then we reason O_x,hasDaughter
>>> and O_x,hasSon, and then we are done reasoning.  We reason those two
>>> object
>>> sets and add them to O_x,hasChild along with any objects that were in it
>>> before the reasoning.  We have found all of x's children and have likely
>>> reasoned only a small part of the whole data set.  None of the rest of
>>> the
>>> data matters, so we do not have to reason it.  In general, when we are
>>> trying to reason an object set O_s,p, we need to reason O_s,q for each
>>> subproperty q of p.
>>>
>>> Let us say that hasChild has further semantics beyond having
>>> subproperties.
>>> In particular, let us say it has an inverse property by owl:inverseOf,
>>> hasParent, the set of a person's parents.  The domain and range of each
>>> is
>>> Person.  We have found the object sets we need to reason for adding
>>> objects
>>> to O_x,hasChild by rdfs:subPropertyOf reasoning.  Now let us find the
>>> object
>>> sets we need to reason for adding objects to it by owl:inverseOf
>>> reasoning.
>>> For each member y of the Person class, we reason the object set
>>> O_y,hasParent.  If x is in O_y,hasParent, i.e. if y hasParent x, then x
>>> hasChild y.  However, those object sets are the only ones we need to
>>> reason
>>> for the owl:inverseOf reasoning.  We do not need to do any more
>>> reasoning.
>>> We are not having our particular hasChild example be reflexive,
>>> symmetric,
>>> or transitive.  So for our particular hasChild example, we reason the
>>> object
>>> sets in this paragraph and the previous one.  Then if those forms of
>>> reasoning are the only ones our system does, nothing else can possibly
>>> add
>>> objects to O_x,hasChild.
>>>
>>>
>>> (I use AspectJ to get all instantiated members of a class, which normally
>>> we
>>> cannot do in Java.)  The other property reasoning is exactly the same
>>> (it's
>>> on page 8 in the article on my web page, but I'll gladly explain here if
>>> anyone asks): when we are trying to reason an object set, for each type
>>> of
>>> reasoning there is only a certain number of other object sets we need to
>>> reason to complete the reasoning.  So when we call a read method on a
>>> Java
>>> Collection that is an attribute, we reason only a small part of memory.
>>> Well, someone can tell me if that approach isn't new, but it seems very
>>> efficient computationally.
>>>
>>> Oh, I really think I've done something new.  I have the basis for a whole
>>> Semantic Web system that just runs on Java instead of on a set of whole
>>> triples.
>>>
>>> Tim
>>> http://www.semanticoop.org
>>>
>>>
>>>
>>>
>>> On 09/01/2012 08:02 PM, adasal wrote:
>>>
>>> Hi,
>>> I don't think you answered the question of how what you propose would be
>>> optimised. How would it deal with reasoning, for instance, bearing in
>>> mind
>>> that Pellet and many others have been subject to many years of
>>> development
>>> and probably the subject of many Phds too!
>>>
>>> You might want to look at this project which Henry Story tipped me off
>>> to:-
>>> https://github.com/w3c/banana-rdf
>>>
>>> This is from the test suit:-
>>> ObjectExamples.scala
>>>
>>> package org.w3.banana
>>>
>>> import scalaz.{ Validation, Failure, Success }
>>> import java.util.UUID
>>>
>>> class ObjectExamples[Rdf <: RDF]()(implicit diesel: Diesel[Rdf]) {
>>>
>>>    import diesel._
>>>    import ops._
>>>
>>>    case class Person(name: String, nickname: Option[String] = None)
>>>
>>>    object Person {
>>>
>>>      val clazz = uri("http://example.com/Person#class")
>>>      implicit val classUris = classUrisFor[Person](clazz)
>>>
>>>      val name = property[String](foaf.name)
>>>      val nickname = optional[String](foaf("nickname"))
>>>      val address = property[Address](foaf("address"))
>>>
>>>      implicit val container = uri("http://example.com/persons/")
>>>      implicit val binder = pgb[Person](name, nickname)(Person.apply,
>>> Person.unapply)
>>>
>>>    }
>>>
>>>    sealed trait Address
>>>
>>>    object Address {
>>>
>>>      val clazz = uri("http://example.com/Address#class")
>>>      implicit val classUris = classUrisFor[Address](clazz)
>>>
>>>      // not sure if this could be made more general, nor if we actually
>>> want
>>> to do that
>>>      implicit val binder: PointedGraphBinder[Rdf, Address] = new
>>> PointedGraphBinder[Rdf, Address] {
>>>        def fromPointedGraph(pointed: PointedGraph[Rdf]):
>>> Validation[BananaException, Address] =
>>>          Unknown.binder.fromPointedGraph(pointed) orElse
>>> VerifiedAddress.binder.fromPointedGraph(pointed)
>>>
>>>        def toPointedGraph(address: Address): PointedGraph[Rdf] = address
>>> match {
>>>          case va: VerifiedAddress =>
>>> VerifiedAddress.binder.toPointedGraph(va)
>>>          case Unknown => Unknown.binder.toPointedGraph(Unknown)
>>>        }
>>>      }
>>>
>>>    }
>>>
>>>    case object Unknown extends Address {
>>>
>>>      val clazz = uri("http://example.com/Unknown#class")
>>>      implicit val classUris = classUrisFor[Unknown.type](clazz,
>>> Address.clazz)
>>>
>>>      // there is a question about constants and the classes they live in
>>>      implicit val binder: PointedGraphBinder[Rdf, Unknown.type] =
>>> constant(this, uri("http://example.com/Unknown#thing")) withClasses
>>> classUris
>>>
>>>    }
>>>
>>>    case class VerifiedAddress(label: String, city: City) extends Address
>>>
>>>    object VerifiedAddress {
>>>
>>>      val clazz = uri("http://example.com/VerifiedAddress#class")
>>>      implicit val classUris = classUrisFor[VerifiedAddress](clazz,
>>> Address.clazz)
>>>
>>>      val label = property[String](foaf("label"))
>>>      val city = property[City](foaf("city"))
>>>
>>>      implicit val ci = classUrisFor[VerifiedAddress](clazz)
>>>
>>>      implicit val binder = pgb[VerifiedAddress](label,
>>> city)(VerifiedAddress.apply, VerifiedAddress.unapply) withClasses
>>> classUris
>>>
>>>    }
>>>
>>>    case class City(cityName: String, otherNames: Set[String] = Set.empty)
>>>
>>>    object City {
>>>
>>>      val clazz = uri("http://example.com/City#class")
>>>      implicit val classUris = classUrisFor[City](clazz)
>>>
>>>      val cityName = property[String](foaf("cityName"))
>>>      val otherNames = set[String](foaf("otherNames"))
>>>
>>>      implicit val binder: PointedGraphBinder[Rdf, City] =
>>>        pgb[City](cityName, otherNames)(City.apply, City.unapply)
>>> withClasses
>>> classUris
>>>
>>>    }
>>>
>>> }
>>>
>>> The stated aim of the developers is to follow the RDF spec 'carefully'
>>> and
>>> to work with Jena and Sesame, so perhaps not the same as yours?
>>>
>>>
>>> Adam
>>>
>>>
>>> On 30 August 2012 17:03, Timothy Armstrong <tim.armstrong@gmx.com> wrote:
>>>>
>>>> Hi,
>>>>
>>>> Sorry for taking so long to respond, and thank you for talking to me.
>>>>
>>>> As far as I can tell, it is entirely possible to build Semantic Web
>>>> software on top of object-oriented programming languages, and presumably
>>>> database technologies, instead of starting Semantic Web software from
>>>> scratch.  Object-oriented languages already have a lot of the OWL data
>>>> model
>>>> implemented.  Well, all they have are classes, properties, and
>>>> rdfs:subClassOf, but they do those very well.  So we want to add the
>>>> rest of
>>>> OWL to them.
>>>>
>>>> All the property reasoning just works directly for attributes.
>>>> Attributes
>>>> can have subattributes, inverse attributes, be transitive, etc., and it
>>>> all
>>>> makes perfect sense.  We just let people use property reasoning for any
>>>> of
>>>> their object-oriented attributes.  I tried to show how useful it would
>>>> be in
>>>> the example program on my web page:
>>>> http://www.semanticoop.org/example.html.
>>>> There is a Person Java class with attributes for the person's mother,
>>>> father, parents, children, ancestors, descendants, an attribute for all
>>>> the
>>>> person's relatives, etc.  You can imagine how messy the Java program
>>>> would
>>>> be without the property reasoning.  The reasoning really helps.  Well,
>>>> maybe
>>>> there are better ways of doing it than with my software, but I think
>>>> that if
>>>> we can add OWL to OOP, people will really like it.
>>>>
>>>> Well, I really don't know what to do with the software.  Thank you for
>>>> talking to me about it.
>>>>
>>>> Tim Armstrong
>>>>
>>>>
>>>>
>>>> On 08/20/2012 05:21 PM, adasal wrote:
>>>>
>>>> OK, there is something like multiple inheritance in Scala with Scala
>>>> traits and there are a few implementations of mixin frameworks in Java
>>>> which
>>>> is really IoC using DI. Tapestry was my example, but Spring allows
>>>> similar
>>>> to enable separation of concerns.
>>>> However I believe that Sesame/AliBaba also allows such hooks.
>>>> When it comes to reasoning there are existing Java reasoners. It seems
>>>> more than a tall order to build your own!
>>>> For instance http://clarkparsia.com/pellet/
>>>> The problem that you will have if you build your own is that you will
>>>> both
>>>> have to optimise and verify it.
>>>>
>>>> The mixin pattern is also available in Python, there are some advantages
>>>> against inheritance as run time behaviour can be determined.
>>>>
>>>> Are you able to explain better the difference and implication of your
>>>> approach to existing approaches?
>>>> It has been said in this thread that code up to the RDF level is the
>>>> better approach, that is the RDF is not fully modelled in the code but
>>>> translated through e.g. SPARQL I suppose.
>>>> How do you understand this?
>>>>
>>>> Best,
>>>>
>>>> Adam
>>>>
>>>> On 20 August 2012 16:39, Timothy Armstrong <tim.armstrong@gmx.com>
>>>> wrote:
>>>>>
>>>>> Hi,
>>>>>
>>>>> Well, if there would be some way to do multiple inheritance in Java,
>>>>> that
>>>>> could be very useful.  I was thinking it would probably be possible to
>>>>> do
>>>>> some of the class reasoning in Java with its limited support for
>>>>> multiple
>>>>> inheritance with interfaces, just we would be partially limited in what
>>>>> we
>>>>> can do with classes in Java.  There shouldn't be a problem with the
>>>>> property
>>>>> reasoning, SPARQL, or rules in Java though (well I have methods to
>>>>> compute
>>>>> all the triplestore indexes).  Semantic Web Services written as Java
>>>>> annotations on methods should work if annotations are extended to
>>>>> support
>>>>> arbitrary datatypes.
>>>>>
>>>>> I could have written the code in a language that has multiple
>>>>> inheritance, but we can do a lot in Java, and Java is just my best
>>>>> language.
>>>>> It might be straightforward to copy the code to any other
>>>>> object-oriented
>>>>> language.  I just looked at Python decorators this morning, since
>>>>> Python has
>>>>> multiple-inheritance.  It doesn't look straightforward to use them just
>>>>> for
>>>>> metadata on code elements like Java annotations, but maybe it can be
>>>>> done.
>>>>> If it can, it looks like they would support arbitrary datatypes.  And
>>>>> then
>>>>> maybe we could add all of OWL, SPARQL, rules, and Semantic Web Services
>>>>> to
>>>>> Python without modifying Python...  Well, there would need to be
>>>>> something
>>>>> like AspectJ for Python as I'm doing it.
>>>>>
>>>>> Truthfully, I haven't spent much thought about how best to do the class
>>>>> reasoning.  I focused on the property reasoning and indexes and was
>>>>> waiting
>>>>> to talk to people about the class reasoning.  I'll have to look into
>>>>> the
>>>>> technologies you mention.
>>>>>
>>>>> Tim
>>>>>
>>>>>
>>>>>
>>>>> On 08/18/2012 04:55 PM, adasal wrote:
>>>>>>
>>>>>> We would need to modify a compiler to determine to which classes an
>>>>>> object belongs so we would know what methods can be used with it.
>>>>>> There
>>>>>> could be methods in defined classes.
>>>>>
>>>>>
>>>>> You must be thinking about a multiple class inheritance hierarchy.
>>>>>
>>>>> There is this project
>>>>> http://insightfullogic.com/blog/2011/sep/16/multiple-inheritance/
>>>>> but I think there must be other implementations.
>>>>> Further containers for IoC such as Tapestry have a mature mixin
>>>>> implementation for class transformation, or Scala (and Java 8 to be)
>>>>> supports traits.
>>>>> Wouldn't this cover it instead of messing around with the compiler?
>>>>>
>>>>> I would have thought the real problem is how to define precedence in
>>>>> the
>>>>> multiple hierarchy. How does OWL deal with contradictory definitions in
>>>>> the
>>>>> hierarchy?
>>>>>
>>>>> Adam
>>>>>
>>>>> On 18 August 2012 16:10, Timothy Armstrong <tim.armstrong@gmx.com>
>>>>> wrote:
>>>>>>
>>>>>> Hi Adam,
>>>>>>
>>>>>> What I have in mind is fitting my software together with Sesame or
>>>>>> Jena
>>>>>> and just having the back-end store sets of objects instead of whole
>>>>>> triples
>>>>>> and see how that works.  For benchmarks, I think it won't be very
>>>>>> difficult
>>>>>> to get SPARQL running on my software, since I have methods to compute
>>>>>> all
>>>>>> the triplestore indexes (permutations of subject-predicate-object)
>>>>>> from all
>>>>>> of main memory, but SPARQL isn't running yet.
>>>>>>
>>>>>> I just meant that my understanding was that OWL can express anything
>>>>>> about data OOP can express, and more, but I'm sure Alan is right that
>>>>>> there
>>>>>> is more than abstract classes. By "disparity" I meant that even if
>>>>>> there are
>>>>>> differences between OOP and OWL of which I'm not aware, I still don't
>>>>>> see a
>>>>>> problem with adding OWL to OOP.
>>>>>>
>>>>>> We would need to modify a compiler to determine to which classes an
>>>>>> object belongs so we would know what methods can be used with it.
>>>>>> There
>>>>>> could be methods in defined classes.
>>>>>>
>>>>>> Tim
>>>>>>
>>>>>>
>>>>>>
>>>>>> On 08/18/2012 07:35 AM, adasal wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>> On 17 August 2012 23:08, Timothy Armstrong <tim.armstrong@gmx.com>
>>>>>> wrote:
>>>>>>>
>>>>>>> Certainly, object-oriented classes and OWL classes are different, but
>>>>>>> my understanding is that the main difference is just that OWL is
>>>>>>> strictly
>>>>>>> better.
>>>>>>
>>>>>>
>>>>>> What do you mean by 'strictly', 'better' and 'strictly better'?
>>>>>>
>>>>>>>   I'm not aware of anything OOP can do that OWL cannot do, but OWL
>>>>>>> can
>>>>>>> do a lot more.
>>>>>>
>>>>>>
>>>>>> What do you mean by 'do'? Do you mean it is more expressive such that
>>>>>> it
>>>>>> is possible to define in OWL what cannot be defined in OOP? Isn't that
>>>>>> axiomatic in that they are different languages with different
>>>>>> semantics?
>>>>>> What you are really saying is that you want to extend the syntax of
>>>>>> OOP
>>>>>> in a form you think is convenient to use such that it will be able to
>>>>>> express OWL semantics.
>>>>>>
>>>>>>> Well, abstract classes, but that's all I can think of.
>>>>>>
>>>>>> So is this relevant?
>>>>>>
>>>>>>> Or if there is still going to be a disparity,
>>>>>>
>>>>>> What does this mean?
>>>>>>
>>>>>>> we should still just be able to add all the OWL class constructs and
>>>>>>> everything else about OWL and let people use them in OOP.
>>>>>>
>>>>>> You mean with your annotations - but the issue really is whether this
>>>>>> is
>>>>>> more convenient than existing approaches.
>>>>>>
>>>>>>> We'd need to get into a compiler to do some of it, but I think it
>>>>>>> would
>>>>>>> be worth it.
>>>>>>
>>>>>> Why would it be necessary to get into the compiler, what are you
>>>>>> talking
>>>>>> about?
>>>>>> Do you mean to pick up annotations - that is not necessary as new
>>>>>> annotations can be defined as things stand - or to optimise such as in
>>>>>> the
>>>>>> way you mention where reasoning is selective. I can't see that this
>>>>>> needs
>>>>>> access to the compiler so much as an understanding of the logic of
>>>>>> whether
>>>>>> and when selective reasoning is a proper optimisation.
>>>>>>
>>>>>> You would have to show that your approach is better than the existing
>>>>>> approaches to optimisation that sit on top of triple and quad stores.
>>>>>> Can you do this?
>>>>>>
>>>>>> Adam
>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>
>

Received on Tuesday, 11 September 2012 20:15:28 UTC