public function run()
    {
        cecho("\n\n");
        cecho("Data validation test: " . $this->description . "...\n\n", 'LIGHT_BLUE');
        $sparql = new SparqlQuery($this->network);
        $from = '';
        foreach ($this->checkOnDatasets as $dataset) {
            $from .= 'from named <' . $dataset . '> ';
        }
        foreach ($this->checkUsingOntologies as $ontology) {
            $from .= 'from <' . $ontology . '> ';
        }
        // Get the list of all the object properties used within the datasets
        $sparql->mime("application/sparql-results+json")->query('select distinct ?p ?range
                      ' . $from . '
                      where
                      {
                        graph ?g {
                          ?s ?p ?o .
                          filter(isIRI(?o))                          
                        } 
                        
                        optional
                        {                                                          
                          ?p <http://www.w3.org/2000/01/rdf-schema#range> ?range .
                        }
                        
                        filter(str(?p) != "http://purl.org/dc/terms/isPartOf" && str(?p) != "http://www.w3.org/1999/02/22-rdf-syntax-ns#value" && str(?p) != "http://www.w3.org/1999/02/22-rdf-syntax-ns#type")
                      }')->send();
        if ($sparql->isSuccessful()) {
            $results = json_decode($sparql->getResultset(), TRUE);
            if (isset($results['results']['bindings']) && count($results['results']['bindings']) > 0) {
                $objectProperties = array();
                $thereAreEmptyRanges = FALSE;
                foreach ($results['results']['bindings'] as $result) {
                    $objectProperty = $result['p']['value'];
                    $objectProperties[$objectProperty] = '';
                    if (isset($result['range'])) {
                        $objectProperties[$objectProperty] = $result['range']['value'];
                    } else {
                        $thereAreEmptyRanges = TRUE;
                    }
                }
                // Display warnings
                if ($thereAreEmptyRanges) {
                    cecho("The following object properties are used to describe records, but their range is not specified in the ontologies. owl:Thing is assumed as the range, but you may want to define it further and re-run this check:\n", 'YELLOW');
                    foreach ($objectProperties as $objectProperty => $range) {
                        if (empty($range)) {
                            cecho('  -> object property: ' . $objectProperty . "\n", 'YELLOW');
                            $this->errors[] = array('id' => 'OBJECT-PROPERTIES-RANGE-50', 'type' => 'warning', 'objectProperty' => $objectProperty);
                        }
                    }
                }
                // Now, for each object properties that have a range defined,
                // we:
                //
                //  (a) List all values used for a given property
                //  (b) For each of these values, make sure they comply with what is defined in the ontology as
                //      the range of the
                foreach ($objectProperties as $objectProperty => $range) {
                    // If the range is empty, we consider it owl:Thing.
                    // If the range is owl:Thing, then we simply skip this check since everything is an owl:Thing
                    if (!empty($range) && $range != 'http://www.w3.org/2002/07/owl#Thing') {
                        $values = array();
                        $sparql = new SparqlQuery($this->network);
                        $from = '';
                        foreach ($this->checkOnDatasets as $dataset) {
                            $from .= 'from <' . $dataset . '> ';
                            $from .= 'from named <' . $dataset . '> ';
                        }
                        foreach ($this->checkUsingOntologies as $ontology) {
                            $from .= 'from <' . $ontology . '> ';
                        }
                        $sparql->mime("application/sparql-results+json")->query('select distinct ?value ?value_type
                              ' . $from . '
                              where
                              {
                                graph ?g {
                                  ?s <' . $objectProperty . '> ?value.
                                  filter(isIRI(?value))
                                }

                                optional
                                {
                                  ?value a ?value_type
                                }
                              }')->send();
                        if ($sparql->isSuccessful()) {
                            // Create the array of object-values/types
                            $results = json_decode($sparql->getResultset(), TRUE);
                            if (isset($results['results']['bindings']) && count($results['results']['bindings']) > 0) {
                                foreach ($results['results']['bindings'] as $result) {
                                    $value = $result['value']['value'];
                                    $type = '';
                                    if (isset($result['value_type'])) {
                                        $type = $result['value_type']['value'];
                                    }
                                    if (!isset($values[$value])) {
                                        $values[$value] = array();
                                    }
                                    if (!empty($type) && !in_array($type, $values[$value])) {
                                        $values[$value][] = $type;
                                    }
                                }
                            }
                            // For each value/type(s), we do validate that the range is valid
                            foreach ($values as $value => $types) {
                                // First, check if we have a type defined for the value. If not, then we infer it is owl:Thing
                                if (empty($types)) {
                                    $types = array('http://www.w3.org/2002/07/owl#Thing');
                                }
                                // Then, check if the $range and the $types directly match
                                if (in_array($range, $types)) {
                                    continue;
                                } else {
                                    // If they are not, then we check in the ontology to see if the range is not
                                    // one of the super class of one of the type(s)
                                    $superClasses = array();
                                    foreach ($types as $type) {
                                        $ontologyURI = $this->getTypeOntology($type);
                                        if ($ontologyURI !== FALSE) {
                                            $ontologyRead = new OntologyReadQuery($this->network);
                                            $getSuperClassesFunc = new GetSuperClassesFunction();
                                            $getSuperClassesFunc->allSuperClasses()->getClassesUris()->uri($type);
                                            $ontologyRead->enableReasoner()->ontology($ontologyURI)->getSuperClasses($getSuperClassesFunc)->mime('resultset')->send();
                                            if ($ontologyRead->isSuccessful()) {
                                                $scs = $ontologyRead->getResultset()->getResultset();
                                                // If empty, then there is no super-classes
                                                if (!empty($scs)) {
                                                    $scs = $scs[key($scs)];
                                                    foreach ($scs as $superClass => $description) {
                                                        if (!in_array($superClass, $superClasses)) {
                                                            $superClasses[] = $superClass;
                                                        }
                                                    }
                                                }
                                            } else {
                                                cecho("We couldn't get the list of super-classes of a target type from the structWSF instance\n", 'YELLOW');
                                                // Log a warning
                                                // Can't get the super classes of the target type
                                                $this->errors[] = array('id' => 'OBJECT-PROPERTIES-RANGE-51', 'type' => 'warning', 'objectProperty' => $objectProperty);
                                            }
                                        } else {
                                            cecho("We couldn't find the ontology where the {$type} is defined on the structWSF instance\n", 'YELLOW');
                                            // Log a warning
                                            // Can't find ontology where the type $type is defined
                                            $this->errors[] = array('id' => 'OBJECT-PROPERTIES-RANGE-52', 'type' => 'warning', 'objectProperty' => $objectProperty);
                                        }
                                    }
                                    $rangeMatch = FALSE;
                                    foreach ($superClasses as $superClass) {
                                        if ($superClass == $range) {
                                            $rangeMatch = TRUE;
                                            break;
                                        }
                                    }
                                    if (!$rangeMatch) {
                                        // Log an error
                                        // Couldn't match one of the super classe with the specified range
                                        cecho('  -> Object property "' . $objectProperty . '" doesn\'t match range "' . $range . '" for value "' . $value . '"' . "\n", 'LIGHT_RED');
                                        $this->errors[] = array('id' => 'OBJECT-PROPERTIES-RANGE-100', 'type' => 'error', 'objectProperty' => $objectProperty, 'definedRange' => $range, 'value' => $value, 'valueTypes' => $types, 'valueSuperTypes' => $superClasses, 'affectedRecords' => $this->getAffectedRecords($objectProperty, $value));
                                    }
                                }
                            }
                        } else {
                            cecho("We couldn't get the range of the {$objectProperty} object property from the structWSF instance\n", 'YELLOW');
                            $this->errors[] = array('id' => 'OBJECT-PROPERTIES-RANGE-54', 'type' => 'warning');
                        }
                    }
                }
            }
        } else {
            cecho("We couldn't get the list of object properties from the structWSF instance\n", 'YELLOW');
            $this->errors[] = array('id' => 'OBJECT-PROPERTIES-RANGE-53', 'type' => 'warning');
        }
    }