diff options
| author | Federico Igne <federico.igne@cs.ox.ac.uk> | 2020-08-19 11:11:53 +0100 |
|---|---|---|
| committer | Federico Igne <federico.igne@cs.ox.ac.uk> | 2020-08-19 11:11:53 +0100 |
| commit | 3a166085e656be5f957423e6e371b6647b313997 (patch) | |
| tree | cc3486d5bde7dc692ee71948fd03e907b7badc7f | |
| parent | 56a3cc7f1a2d1dc85a262f2648cf246197684caf (diff) | |
| download | RSAComb-3a166085e656be5f957423e6e371b6647b313997.tar.gz RSAComb-3a166085e656be5f957423e6e371b6647b313997.zip | |
Use `rdf(..)` instead of `create(..)` to create `Atom`s
| -rw-r--r-- | src/main/scala/rsacomb/RDFoxClassExprConverter.scala | 28 | ||||
| -rw-r--r-- | src/main/scala/rsacomb/RDFoxPropertyExprConverter.scala | 29 | ||||
| -rw-r--r-- | src/main/scala/rsacomb/RDFoxUtil.scala | 9 | ||||
| -rw-r--r-- | src/main/scala/rsacomb/RSA.scala | 8 | ||||
| -rw-r--r-- | src/main/scala/rsacomb/RSAOntology.scala | 28 | ||||
| -rw-r--r-- | src/main/scala/rsacomb/SkolemStrategy.scala | 32 |
6 files changed, 76 insertions, 58 deletions
diff --git a/src/main/scala/rsacomb/RDFoxClassExprConverter.scala b/src/main/scala/rsacomb/RDFoxClassExprConverter.scala index 9116be0..c1fd85a 100644 --- a/src/main/scala/rsacomb/RDFoxClassExprConverter.scala +++ b/src/main/scala/rsacomb/RDFoxClassExprConverter.scala | |||
| @@ -22,7 +22,8 @@ import tech.oxfordsemantic.jrdfox.logic.{ | |||
| 22 | Term, | 22 | Term, |
| 23 | Variable, | 23 | Variable, |
| 24 | Literal, | 24 | Literal, |
| 25 | Datatype | 25 | Datatype, |
| 26 | IRI | ||
| 26 | } | 27 | } |
| 27 | 28 | ||
| 28 | import rsacomb.SkolemStrategy | 29 | import rsacomb.SkolemStrategy |
| @@ -56,10 +57,11 @@ class RDFoxClassExprConverter( | |||
| 56 | unsafe: List[OWLObjectPropertyExpression] | 57 | unsafe: List[OWLObjectPropertyExpression] |
| 57 | ) extends OWLClassExpressionVisitorEx[RDFoxRuleShards] { | 58 | ) extends OWLClassExpressionVisitorEx[RDFoxRuleShards] { |
| 58 | 59 | ||
| 60 | import RDFoxUtil.owlapi2rdfox; | ||
| 61 | |||
| 59 | // OWLClass | 62 | // OWLClass |
| 60 | override def visit(expr: OWLClass): RDFoxRuleShards = { | 63 | override def visit(expr: OWLClass): RDFoxRuleShards = { |
| 61 | val name = expr.getIRI.getIRIString | 64 | val atom = List(Atom.rdf(term, IRI.RDF_TYPE, expr.getIRI())) |
| 62 | val atom = List(Atom.create(TupleTableName.create(name), term)) | ||
| 63 | RDFoxRuleShards(atom, List()) | 65 | RDFoxRuleShards(atom, List()) |
| 64 | } | 66 | } |
| 65 | 67 | ||
| @@ -84,9 +86,8 @@ class RDFoxClassExprConverter( | |||
| 84 | .head // restricts to proper "nominals" | 86 | .head // restricts to proper "nominals" |
| 85 | .asOWLNamedIndividual | 87 | .asOWLNamedIndividual |
| 86 | .getIRI | 88 | .getIRI |
| 87 | .getIRIString | ||
| 88 | val atom = List( | 89 | val atom = List( |
| 89 | Atom.sameAs(term, Literal.create(ind, Datatype.IRI_REFERENCE)) | 90 | Atom.sameAs(term, ind) |
| 90 | ) | 91 | ) |
| 91 | RDFoxRuleShards(atom, List()) | 92 | RDFoxRuleShards(atom, List()) |
| 92 | } | 93 | } |
| @@ -101,25 +102,22 @@ class RDFoxClassExprConverter( | |||
| 101 | // technique it might involve the introduction of additional atoms, | 102 | // technique it might involve the introduction of additional atoms, |
| 102 | // and/or fresh constants and variables. | 103 | // and/or fresh constants and variables. |
| 103 | val (head, body, term1) = skolem match { | 104 | val (head, body, term1) = skolem match { |
| 104 | case SkolemStrategy.None => (List(), List(), y) | 105 | case SkolemStrategy.None => (List(), List(), y) |
| 105 | case SkolemStrategy.Constant(c) => | 106 | case SkolemStrategy.Constant(c) => (List(), List(), c) |
| 106 | (List(), List(), Literal.create(c, Datatype.IRI_REFERENCE)) | ||
| 107 | case SkolemStrategy.ConstantRSA(c) => { | 107 | case SkolemStrategy.ConstantRSA(c) => { |
| 108 | val lit = Literal.create(c, Datatype.IRI_REFERENCE) | ||
| 109 | if (unsafe.contains(prop)) | 108 | if (unsafe.contains(prop)) |
| 110 | ( | 109 | ( |
| 111 | List( | 110 | List( |
| 112 | Atom.create(TupleTableName.create("internal:PE"), term, lit), | 111 | Atom.rdf(term, IRI.create(RSA.PredicatePE), c), |
| 113 | Atom.create(TupleTableName.create("internal:U"), lit) | 112 | Atom.rdf(c, IRI.RDF_TYPE, IRI.create(RSA.PredicateU)) |
| 114 | ), | 113 | ), |
| 115 | List(), | 114 | List(), |
| 116 | lit | 115 | c |
| 117 | ) | 116 | ) |
| 118 | else | 117 | else |
| 119 | (List(), List(), lit) | 118 | (List(), List(), c) |
| 120 | } | 119 | } |
| 121 | case SkolemStrategy.Standard(f) => | 120 | case SkolemStrategy.Standard(f) => |
| 122 | // At the time of writing the RDFox library does not have a | ||
| 123 | // particular class for the "SKOLEM" operator and it is instead | 121 | // particular class for the "SKOLEM" operator and it is instead |
| 124 | // a simple builtin function with a "special" name. | 122 | // a simple builtin function with a "special" name. |
| 125 | ( | 123 | ( |
| @@ -153,7 +151,7 @@ class RDFoxClassExprConverter( | |||
| 153 | .map(expr.getProperty.accept(_)) | 151 | .map(expr.getProperty.accept(_)) |
| 154 | .flatten | 152 | .flatten |
| 155 | RDFoxRuleShards( | 153 | RDFoxRuleShards( |
| 156 | List(Atom.create(TupleTableName.create("owl:sameAs"), vars(0), vars(1))), | 154 | List(Atom.sameAs(vars(0), vars(1))), |
| 157 | classResult.res ++ propertyResult | 155 | classResult.res ++ propertyResult |
| 158 | ) | 156 | ) |
| 159 | } | 157 | } |
diff --git a/src/main/scala/rsacomb/RDFoxPropertyExprConverter.scala b/src/main/scala/rsacomb/RDFoxPropertyExprConverter.scala index 78ac98c..340fa90 100644 --- a/src/main/scala/rsacomb/RDFoxPropertyExprConverter.scala +++ b/src/main/scala/rsacomb/RDFoxPropertyExprConverter.scala | |||
| @@ -3,29 +3,28 @@ package rsacomb | |||
| 3 | import org.semanticweb.owlapi.model.{OWLPropertyExpression, OWLObjectProperty} | 3 | import org.semanticweb.owlapi.model.{OWLPropertyExpression, OWLObjectProperty} |
| 4 | import org.semanticweb.owlapi.model.OWLPropertyExpressionVisitorEx | 4 | import org.semanticweb.owlapi.model.OWLPropertyExpressionVisitorEx |
| 5 | 5 | ||
| 6 | import tech.oxfordsemantic.jrdfox.logic.{TupleTableName} | 6 | import tech.oxfordsemantic.jrdfox.logic.{Atom, Term, IRI, Variable, Literal} |
| 7 | import tech.oxfordsemantic.jrdfox.logic.{Atom, Term, Variable, Literal} | ||
| 8 | 7 | ||
| 9 | import rsacomb.SkolemStrategy | 8 | import rsacomb.SkolemStrategy |
| 10 | import org.semanticweb.owlapi.model.OWLObjectInverseOf | 9 | import org.semanticweb.owlapi.model.OWLObjectInverseOf |
| 11 | 10 | ||
| 12 | class RDFoxPropertyExprConverter(term1 : Term, term2 : Term, skolem : SkolemStrategy) | 11 | class RDFoxPropertyExprConverter( |
| 13 | extends OWLPropertyExpressionVisitorEx[List[Atom]] | 12 | term1: Term, |
| 14 | { | 13 | term2: Term, |
| 14 | skolem: SkolemStrategy | ||
| 15 | ) extends OWLPropertyExpressionVisitorEx[List[Atom]] { | ||
| 15 | 16 | ||
| 16 | override | 17 | // Automatically converts OWLAPI types into RDFox equivalent types. |
| 17 | def visit(expr : OWLObjectProperty) : List[Atom] = { | 18 | import RDFoxUtil.owlapi2rdfox; |
| 18 | val name = expr.getIRI.getIRIString | 19 | |
| 19 | List(Atom.create(TupleTableName.create(name), term1, term2)) | 20 | override def visit(expr: OWLObjectProperty): List[Atom] = |
| 20 | } | 21 | List(Atom.rdf(term1, expr.getIRI, term2)) |
| 21 | 22 | ||
| 22 | override | 23 | override def visit(expr: OWLObjectInverseOf): List[Atom] = { |
| 23 | def visit(expr : OWLObjectInverseOf) : List[Atom] = { | ||
| 24 | val name = expr.getInverse.getNamedProperty.getIRI.getIRIString; | 24 | val name = expr.getInverse.getNamedProperty.getIRI.getIRIString; |
| 25 | List(Atom.create(TupleTableName.create(name ++ "_inv"), term1, term2)) | 25 | List(Atom.rdf(term1, IRI.create(name ++ "_inv"), term2)) |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | def doDefault(expr : OWLPropertyExpression) : List[Atom] = List() | 28 | def doDefault(expr: OWLPropertyExpression): List[Atom] = List() |
| 29 | 29 | ||
| 30 | } // class RDFoxPropertyExprConverter | 30 | } // class RDFoxPropertyExprConverter |
| 31 | |||
diff --git a/src/main/scala/rsacomb/RDFoxUtil.scala b/src/main/scala/rsacomb/RDFoxUtil.scala index 9be7a2d..4cefd83 100644 --- a/src/main/scala/rsacomb/RDFoxUtil.scala +++ b/src/main/scala/rsacomb/RDFoxUtil.scala | |||
| @@ -3,14 +3,18 @@ package rsacomb | |||
| 3 | /* Java imports */ | 3 | /* Java imports */ |
| 4 | import java.util.HashMap | 4 | import java.util.HashMap |
| 5 | import tech.oxfordsemantic.jrdfox.Prefixes | 5 | import tech.oxfordsemantic.jrdfox.Prefixes |
| 6 | import tech.oxfordsemantic.jrdfox.logic.IRI | ||
| 6 | import tech.oxfordsemantic.jrdfox.client.{ | 7 | import tech.oxfordsemantic.jrdfox.client.{ |
| 7 | ConnectionFactory, | 8 | ConnectionFactory, |
| 8 | ServerConnection, | 9 | ServerConnection, |
| 9 | DataStoreConnection | 10 | DataStoreConnection |
| 10 | } | 11 | } |
| 11 | |||
| 12 | object RDFoxUtil { | 12 | object RDFoxUtil { |
| 13 | 13 | ||
| 14 | implicit def owlapi2rdfox(iri: org.semanticweb.owlapi.model.IRI): IRI = { | ||
| 15 | IRI.create(iri.getIRIString()) | ||
| 16 | } | ||
| 17 | |||
| 14 | def openConnection( | 18 | def openConnection( |
| 15 | dataStore: String | 19 | dataStore: String |
| 16 | ): (ServerConnection, DataStoreConnection) = { | 20 | ): (ServerConnection, DataStoreConnection) = { |
| @@ -25,8 +29,9 @@ object RDFoxUtil { | |||
| 25 | /* Create datastore connection | 29 | /* Create datastore connection |
| 26 | */ | 30 | */ |
| 27 | val parameters = new HashMap[String, String]() | 31 | val parameters = new HashMap[String, String]() |
| 32 | parameters.put("owl-in-rdf-support", "relaxed") | ||
| 28 | //parameters.put("equality", "noUNA") | 33 | //parameters.put("equality", "noUNA") |
| 29 | server.createDataStore(dataStore, "seq", parameters) | 34 | server.createDataStore(dataStore, "par-complex-nn", parameters) |
| 30 | val data = server.newDataStoreConnection(dataStore) | 35 | val data = server.newDataStoreConnection(dataStore) |
| 31 | 36 | ||
| 32 | (server, data) | 37 | (server, data) |
diff --git a/src/main/scala/rsacomb/RSA.scala b/src/main/scala/rsacomb/RSA.scala index 229255c..1fa0fc1 100644 --- a/src/main/scala/rsacomb/RSA.scala +++ b/src/main/scala/rsacomb/RSA.scala | |||
| @@ -8,8 +8,14 @@ import org.semanticweb.owlapi.model.OWLOntology | |||
| 8 | 8 | ||
| 9 | object RSA extends RSAOntology { | 9 | object RSA extends RSAOntology { |
| 10 | 10 | ||
| 11 | val PrefixBase = "http://example.com/rsa_example.owl#" | ||
| 12 | val PrefixInternal = "http://127.0.0.1/" | ||
| 13 | val PredicatePE = PrefixInternal + "PE" | ||
| 14 | val PredicateU = PrefixInternal + "U" | ||
| 15 | val PredicateE = PrefixInternal + "E" | ||
| 16 | |||
| 11 | // TODO: move this somewhere else... maybe an OntoUtils class or something. | 17 | // TODO: move this somewhere else... maybe an OntoUtils class or something. |
| 12 | def loadOntology(onto: File ): OWLOntology = { | 18 | def loadOntology(onto: File): OWLOntology = { |
| 13 | val manager = OWLManager.createOWLOntologyManager() | 19 | val manager = OWLManager.createOWLOntologyManager() |
| 14 | manager.loadOntologyFromOntologyDocument(onto) | 20 | manager.loadOntologyFromOntologyDocument(onto) |
| 15 | } | 21 | } |
diff --git a/src/main/scala/rsacomb/RSAOntology.scala b/src/main/scala/rsacomb/RSAOntology.scala index c658227..681dbb0 100644 --- a/src/main/scala/rsacomb/RSAOntology.scala +++ b/src/main/scala/rsacomb/RSAOntology.scala | |||
| @@ -12,6 +12,7 @@ import org.semanticweb.owlapi.reasoner.structural.StructuralReasonerFactory | |||
| 12 | import tech.oxfordsemantic.jrdfox.Prefixes | 12 | import tech.oxfordsemantic.jrdfox.Prefixes |
| 13 | import tech.oxfordsemantic.jrdfox.logic.Variable | 13 | import tech.oxfordsemantic.jrdfox.logic.Variable |
| 14 | import tech.oxfordsemantic.jrdfox.client.UpdateType | 14 | import tech.oxfordsemantic.jrdfox.client.UpdateType |
| 15 | import tech.oxfordsemantic.jrdfox.logic.{Rule, Atom, Variable, IRI} | ||
| 15 | 16 | ||
| 16 | /* Scala imports */ | 17 | /* Scala imports */ |
| 17 | import scala.collection.JavaConverters._ | 18 | import scala.collection.JavaConverters._ |
| @@ -69,8 +70,14 @@ trait RSAOntology { | |||
| 69 | rule <- axiom.accept(visitor) | 70 | rule <- axiom.accept(visitor) |
| 70 | } yield rule | 71 | } yield rule |
| 71 | 72 | ||
| 73 | /* DEBUG: print datalog rules */ | ||
| 74 | println("\nDatalog roles:") | ||
| 75 | datalog.foreach(println) | ||
| 76 | |||
| 77 | // TODO: Define Prefixes in RSA object | ||
| 72 | val prefixes = new Prefixes() | 78 | val prefixes = new Prefixes() |
| 73 | prefixes.declarePrefix(":", "http://example.com/rsa_example.owl#") | 79 | prefixes.declarePrefix(":", RSA.PrefixBase) |
| 80 | prefixes.declarePrefix("internal:", RSA.PrefixInternal) | ||
| 74 | prefixes.declarePrefix( | 81 | prefixes.declarePrefix( |
| 75 | "rdf:", | 82 | "rdf:", |
| 76 | "http://www.w3.org/1999/02/22-rdf-syntax-ns#" | 83 | "http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
| @@ -99,30 +106,29 @@ trait RSAOntology { | |||
| 99 | data.importData( | 106 | data.importData( |
| 100 | UpdateType.ADDITION, | 107 | UpdateType.ADDITION, |
| 101 | prefixes, | 108 | prefixes, |
| 102 | "<internal:E>[?X,?Y] :- <internal:PE>[?X,?Y], <internal:U>[?X], <internal:U>[?Y] ." | 109 | "<http://127.0.0.1/E>[?X,?Y] :- <http://127.0.0.1/PE>[?X,?Y], <http://127.0.0.1/U>[?X], <http://127.0.0.1/U>[?Y] ." |
| 103 | ) | 110 | ) |
| 104 | 111 | ||
| 105 | /* Add ontology rules | 112 | /* Add ontology rules |
| 106 | */ | 113 | */ |
| 107 | data.importData( | 114 | data.addRules(datalog.asJava) |
| 108 | UpdateType.ADDITION, | ||
| 109 | prefixes, | ||
| 110 | datalog.foldLeft("")((str, rule) => | ||
| 111 | str ++ "\n" ++ rule.toString().replace("(", "[").replace(")", "]") | ||
| 112 | ) | ||
| 113 | ) | ||
| 114 | 115 | ||
| 115 | // Retrieve all instances of PE | 116 | // Retrieve all instances of PE |
| 116 | println("\nQueries:") | 117 | println("\nQueries:") |
| 117 | RDFoxUtil.query( | 118 | RDFoxUtil.query( |
| 118 | data, | 119 | data, |
| 119 | prefixes, | 120 | prefixes, |
| 120 | "SELECT ?X ?Y WHERE { ?X <internal:PE> ?Y }" | 121 | "SELECT ?X ?Y WHERE { ?X internal:PE ?Y }" |
| 122 | ) | ||
| 123 | RDFoxUtil.query( | ||
| 124 | data, | ||
| 125 | prefixes, | ||
| 126 | "SELECT ?X ?Y WHERE { ?X internal:E ?Y }" | ||
| 121 | ) | 127 | ) |
| 122 | RDFoxUtil.query( | 128 | RDFoxUtil.query( |
| 123 | data, | 129 | data, |
| 124 | prefixes, | 130 | prefixes, |
| 125 | "SELECT ?X ?Y WHERE { ?X <internal:E> ?Y }" | 131 | "SELECT ?X WHERE { ?X rdf:type owl:Thing }" |
| 126 | ) | 132 | ) |
| 127 | 133 | ||
| 128 | // Close connection to RDFox | 134 | // Close connection to RDFox |
diff --git a/src/main/scala/rsacomb/SkolemStrategy.scala b/src/main/scala/rsacomb/SkolemStrategy.scala index bcf6828..9d45b4c 100644 --- a/src/main/scala/rsacomb/SkolemStrategy.scala +++ b/src/main/scala/rsacomb/SkolemStrategy.scala | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | package rsacomb | 1 | package rsacomb |
| 2 | 2 | ||
| 3 | import tech.oxfordsemantic.jrdfox.logic.IRI | ||
| 4 | |||
| 3 | sealed trait SkolemStrategy | 5 | sealed trait SkolemStrategy |
| 4 | 6 | ||
| 5 | object SkolemStrategy { | 7 | object SkolemStrategy { |
| @@ -8,7 +10,7 @@ object SkolemStrategy { | |||
| 8 | 10 | ||
| 9 | /* No skolemization at all. | 11 | /* No skolemization at all. |
| 10 | * | 12 | * |
| 11 | * From | 13 | * From |
| 12 | * ∃R.A ⊑ B | 14 | * ∃R.A ⊑ B |
| 13 | * to | 15 | * to |
| 14 | * R(x,y), B(y) -> B(x) | 16 | * R(x,y), B(y) -> B(x) |
| @@ -17,46 +19,48 @@ object SkolemStrategy { | |||
| 17 | 19 | ||
| 18 | /* Functional skolemization | 20 | /* Functional skolemization |
| 19 | * | 21 | * |
| 20 | * From | 22 | * From |
| 21 | * A ⊑ ∃R.B | 23 | * A ⊑ ∃R.B |
| 22 | * to | 24 | * to |
| 23 | * A(y) -> R(x,f(x)), B(f(x)) | 25 | * A(y) -> R(x,f(x)), B(f(x)) |
| 24 | * for f, fresh function associated with the input axiom | 26 | * for f, fresh function associated with the input axiom |
| 25 | */ | 27 | */ |
| 26 | case class Standard(func : String) extends SkolemStrategy | 28 | case class Standard(func: IRI) extends SkolemStrategy |
| 27 | object Standard { | 29 | object Standard { |
| 28 | def apply(axiom : String) = new Standard(genFunctionString(axiom)) | 30 | def apply(axiom: String) = |
| 29 | def genFunctionString(str : String) = "f_" ++ str.hashCode.toString | 31 | new Standard(IRI.create(genFunctionString(axiom))) |
| 32 | def genFunctionString(str: String) = "f_" ++ str.hashCode.toString | ||
| 30 | } | 33 | } |
| 31 | 34 | ||
| 32 | /* Constant skolemization | 35 | /* Constant skolemization |
| 33 | * | 36 | * |
| 34 | * From | 37 | * From |
| 35 | * A ⊑ ∃R.B | 38 | * A ⊑ ∃R.B |
| 36 | * to | 39 | * to |
| 37 | * A(y) -> R(x,c), B(c) | 40 | * A(y) -> R(x,c), B(c) |
| 38 | * for c, fresh constant associated with the input axiom | 41 | * for c, fresh constant associated with the input axiom |
| 39 | */ | 42 | */ |
| 40 | case class Constant(const : String) extends SkolemStrategy | 43 | case class Constant(const: IRI) extends SkolemStrategy |
| 41 | object Constant { | 44 | object Constant { |
| 42 | def apply(axiom : String) = new Constant(genConstantString(axiom)) | 45 | def apply(axiom: String) = |
| 43 | def genConstantString(str : String) = "internal:c_" ++ str.hashCode.toString | 46 | new Constant(IRI.create(genConstantString(axiom))) |
| 47 | def genConstantString(str: String) = "c_" ++ str.hashCode.toString | ||
| 44 | } | 48 | } |
| 45 | 49 | ||
| 46 | /* (RSA) Constant skolemization | 50 | /* (RSA) Constant skolemization |
| 47 | * This is a special skolemization option to introduce additional atoms for RSA | 51 | * This is a special skolemization option to introduce additional atoms for RSA |
| 48 | * checking algorithm. | 52 | * checking algorithm. |
| 49 | * | 53 | * |
| 50 | * From | 54 | * From |
| 51 | * A ⊑ ∃R.B | 55 | * A ⊑ ∃R.B |
| 52 | * to | 56 | * to |
| 53 | * A(y) -> R(x,c), PE(x,c), B(c) | 57 | * A(y) -> R(x,c), PE(x,c), B(c) |
| 54 | * for c, fresh constant associated with the input axiom and PE an internal predicate. | 58 | * for c, fresh constant associated with the input axiom and PE an internal predicate. |
| 55 | */ | 59 | */ |
| 56 | case class ConstantRSA(const : String) extends SkolemStrategy | 60 | case class ConstantRSA(const: IRI) extends SkolemStrategy |
| 57 | object ConstantRSA { | 61 | object ConstantRSA { |
| 58 | def apply(axiom : String) = new ConstantRSA(genConstantString(axiom)) | 62 | def apply(axiom: String) = |
| 59 | def genConstantString(str : String) = "internal:c_" ++ str.hashCode.toString | 63 | new ConstantRSA(IRI.create(genConstantString(axiom))) |
| 64 | def genConstantString(str: String) = "c_" ++ str.hashCode.toString | ||
| 60 | } | 65 | } |
| 61 | } | 66 | } |
| 62 | |||
