diff --git a/lib/arc2/.coveralls.yml b/lib/arc2/.coveralls.yml
new file mode 100644
index 0000000000000000000000000000000000000000..23e6ef4f66f25697f83fd0ca50e44de3e4e7c947
--- /dev/null
+++ b/lib/arc2/.coveralls.yml
@@ -0,0 +1,3 @@
+coverage_clover: gen/coverage/clover.xml
+json_path: gen/coverage/coveralls-upload.json
+service_name: travis-ci
diff --git a/lib/arc2/.editorconfig b/lib/arc2/.editorconfig
new file mode 100644
index 0000000000000000000000000000000000000000..3c44241cc4f49d29009e01f1f221d04f0d64b68b
--- /dev/null
+++ b/lib/arc2/.editorconfig
@@ -0,0 +1,9 @@
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
diff --git a/lib/arc2/.gitignore b/lib/arc2/.gitignore
index 12ff1adb2ceb46e49e455681cb3dd27fa8627a0f..d657def05c6b36fd151e4e84d79fac901f2e81e1 100644
--- a/lib/arc2/.gitignore
+++ b/lib/arc2/.gitignore
@@ -1,3 +1,10 @@
-*.DS_Store
-plugins/*
-triggers/*
+*.DS_Store
+.php_cs.cache
+.phpunit.result.cache
+composer.lock
+docker/docker-compose.yml
+plugins/*
+triggers/*
+tests/coverage/*
+tests/config.php
+vendor/
diff --git a/lib/arc2/.php_cs b/lib/arc2/.php_cs
new file mode 100644
index 0000000000000000000000000000000000000000..7da6e23544a60b5b77f28bb25a55cce921c3a76f
--- /dev/null
+++ b/lib/arc2/.php_cs
@@ -0,0 +1,22 @@
+<?php
+
+return PhpCsFixer\Config::create()
+    ->setRules(
+        [
+            '@Symfony' => true,
+            '@Symfony:risky' => true,
+            'align_multiline_comment' => true,
+            'array_syntax' => ['syntax' => 'short'],
+            'array_indentation' => true,
+        ]
+    )
+    ->setRiskyAllowed(true)
+    ->setFinder(
+        PhpCsFixer\Finder::create()
+        ->files()
+        ->in(__DIR__ . '/parsers')
+        ->in(__DIR__ . '/serializers')
+        ->in(__DIR__ . '/src')
+        ->in(__DIR__ . '/store')
+        ->name('*.php')
+    );
diff --git a/lib/arc2/.travis.yml b/lib/arc2/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..aab172703ff11ca9fafcd7577ae237ebf46a3792
--- /dev/null
+++ b/lib/arc2/.travis.yml
@@ -0,0 +1,170 @@
+sudo: required
+
+language: php
+
+services:
+  - docker
+
+matrix:
+    fast_finish: true
+    include:
+        #
+        # Define versions of MySQL and MariaDB to test against.
+        #
+        # For each DB version also tests with different adapters are run (mysqli, PDO).
+        #
+        #
+        # mysql 5.7
+        #
+        - php: 7.2
+          env: DB=mysql:5.7 DB_ADAPTER=mysqli
+        - php: 7.2
+          env: DB=mysql:5.7 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.2
+          env: DB=mysql:5.7 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        - php: 7.3
+          env: DB=mysql:5.7 DB_ADAPTER=mysqli
+        - php: 7.3
+          env: DB=mysql:5.7 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.3
+          env: DB=mysql:5.7 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        - php: 7.4
+          env: DB=mysql:5.7 DB_ADAPTER=mysqli
+        - php: 7.4
+          env: DB=mysql:5.7 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.4
+          env: DB=mysql:5.7 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        #
+        # mariadb 10.1
+        #
+        - php: 7.2
+          env: DB=mariadb:10.1 DB_ADAPTER=mysqli
+        - php: 7.2
+          env: DB=mariadb:10.1 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.2
+          env: DB=mariadb:10.1 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        - php: 7.3
+          env: DB=mariadb:10.1 DB_ADAPTER=mysqli
+        - php: 7.3
+          env: DB=mariadb:10.1 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.3
+          env: DB=mariadb:10.1 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        - php: 7.4
+          env: DB=mariadb:10.1 DB_ADAPTER=mysqli
+        - php: 7.4
+          env: DB=mariadb:10.1 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.4
+          env: DB=mariadb:10.1 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        #
+        # mariadb 10.2
+        #
+        - php: 7.2
+          env: DB=mariadb:10.2 DB_ADAPTER=mysqli
+        - php: 7.2
+          env: DB=mariadb:10.2 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.2
+          env: DB=mariadb:10.2 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        - php: 7.3
+          env: DB=mariadb:10.2 DB_ADAPTER=mysqli
+        - php: 7.3
+          env: DB=mariadb:10.2 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.3
+          env: DB=mariadb:10.2 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        - php: 7.4
+          env: DB=mariadb:10.2 DB_ADAPTER=mysqli
+        - php: 7.4
+          env: DB=mariadb:10.2 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.4
+          env: DB=mariadb:10.2 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        #
+        # mariadb 10.3
+        #
+        - php: 7.2
+          env: DB=mariadb:10.3 DB_ADAPTER=mysqli
+        - php: 7.2
+          env: DB=mariadb:10.3 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.2
+          env: DB=mariadb:10.3 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        - php: 7.3
+          env: DB=mariadb:10.3 DB_ADAPTER=mysqli
+        - php: 7.3
+          env: DB=mariadb:10.3 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.3
+          env: DB=mariadb:10.3 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        - php: 7.4
+          env: DB=mariadb:10.3 DB_ADAPTER=mysqli
+        - php: 7.4
+          env: DB=mariadb:10.3 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.4
+          env: DB=mariadb:10.3 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        #
+        # mariadb 10.4
+        #
+        - php: 7.2
+          env: DB=mariadb:10.4 DB_ADAPTER=mysqli
+        - php: 7.2
+          env: DB=mariadb:10.4 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.2
+          env: DB=mariadb:10.4 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        - php: 7.3
+          env: DB=mariadb:10.4 DB_ADAPTER=mysqli
+        - php: 7.3
+          env: DB=mariadb:10.4 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.3
+          env: DB=mariadb:10.4 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        - php: 7.4
+          env: DB=mariadb:10.4 DB_ADAPTER=mysqli
+        - php: 7.4
+          env: DB=mariadb:10.4 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.4
+          env: DB=mariadb:10.4 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        #
+        # mariadb 10.5
+        #
+        - php: 7.2
+          env: DB=mariadb:10.5 DB_ADAPTER=mysqli
+        - php: 7.2
+          env: DB=mariadb:10.5 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.2
+          env: DB=mariadb:10.5 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        - php: 7.3
+          env: DB=mariadb:10.5 DB_ADAPTER=mysqli
+        - php: 7.3
+          env: DB=mariadb:10.5 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.3
+          env: DB=mariadb:10.5 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+        - php: 7.4
+          env: DB=mariadb:10.5 DB_ADAPTER=mysqli
+        - php: 7.4
+          env: DB=mariadb:10.5 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql
+        - php: 7.4
+          env: DB=mariadb:10.5 DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true
+git:
+    depth: 1
+
+cache:
+  directories:
+    - $HOME/.composer/cache/files
+
+before_script:
+    #
+    # install and init database (see matrix => include => env)
+    #
+    - ./.travis/install-and-init-db.sh
+
+    #
+    # setup and run tests
+    #
+    # Install composer packages, will also trigger dump-autoload
+    - travis_retry composer install --no-interaction --prefer-dist
+    # Install coveralls.phar
+    - travis_retry wget -c -nc --retry-connrefused --tries=0 https://github.com/satooshi/php-coveralls/releases/download/v1.1.0/coveralls.phar
+    - chmod +x coveralls.phar
+    - php coveralls.phar --version
+
+script:
+    - vendor/bin/phpunit --coverage-clover gen/coverage/clover.xml
+
+after_success:
+    # Submit coverage report to Coveralls servers, see .coveralls.yml
+    - travis_retry php coveralls.phar -v
diff --git a/lib/arc2/.travis/install-and-init-db.sh b/lib/arc2/.travis/install-and-init-db.sh
new file mode 100755
index 0000000000000000000000000000000000000000..f66014ed27a919100d347320e6e5d16ec745baa7
--- /dev/null
+++ b/lib/arc2/.travis/install-and-init-db.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+#
+# acknowledgement:
+# copied from https://github.com/PyMySQL/PyMySQL/blob/master/.travis/initializedb.sh
+#
+
+# debug
+set -x
+# verbose
+set -v
+
+if [ ! -z "${DB}" ]; then
+    # disable existing database server in case of accidential connection
+    sudo service mysql stop
+
+    docker pull ${DB}
+    docker run -it --name=mysqld -d -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -p 3306:3306 ${DB}
+    sleep 20
+
+    mysql() {
+        docker exec mysqld mysql "${@}"
+    }
+    while :
+    do
+        sleep 5
+        mysql -e 'select version()'
+        if [ $? = 0 ]; then
+            break
+        fi
+        echo "server logs"
+        docker logs --tail 5 mysqld
+    done
+
+    mysql -e 'select VERSION()'
+
+    if [ $DB == 'mysql:8.0' ]; then
+        WITH_PLUGIN='with mysql_native_password'
+        mysql -e 'SET GLOBAL local_infile=on'
+        docker cp mysqld:/var/lib/mysql/public_key.pem "${HOME}"
+        docker cp mysqld:/var/lib/mysql/ca.pem "${HOME}"
+        docker cp mysqld:/var/lib/mysql/server-cert.pem "${HOME}"
+        docker cp mysqld:/var/lib/mysql/client-key.pem "${HOME}"
+        docker cp mysqld:/var/lib/mysql/client-cert.pem "${HOME}"
+    else
+        WITH_PLUGIN=''
+    fi
+
+    mysql -uroot -e 'create database testdb DEFAULT CHARACTER SET utf8mb4'
+else
+    cat ~/.my.cnf
+
+    mysql -e 'select VERSION()'
+    mysql -e 'create database testdb DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;'
+fi
diff --git a/lib/arc2/ARC2.php b/lib/arc2/ARC2.php
index 826169ca57f25f47eedb6abc6d59ead2a26c98f9..471ad651e70b303e9daca1ab5c659b2ed4b2720b 100644
--- a/lib/arc2/ARC2.php
+++ b/lib/arc2/ARC2.php
@@ -3,10 +3,8 @@
  * ARC2 core class (static, not instantiated)
  *
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
+ * @homepage <https://github.com/semsol/arc2>
  * @package ARC2
- * @version 2011-01-07
  */
 
 /* E_STRICT hack */
@@ -17,7 +15,7 @@ if (function_exists('date_default_timezone_get')) {
 class ARC2 {
 
   static function getVersion() {
-    return '2011-01-07';
+    return '2011-12-01';
   }
 
   /*  */
@@ -42,10 +40,10 @@ class ARC2 {
   }
   
   static function getScriptURI() {
-    if (isset($_SERVER) && isset($_SERVER['SERVER_NAME'])) {
+    if (isset($_SERVER) && (isset($_SERVER['SERVER_NAME']) || isset($_SERVER['HTTP_HOST']))) {
       $proto = preg_replace('/^([a-z]+)\/.*$/', '\\1', strtolower($_SERVER['SERVER_PROTOCOL']));
       $port = $_SERVER['SERVER_PORT'];
-      $server = $_SERVER['SERVER_NAME'];
+      $server = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];
       $script = $_SERVER['SCRIPT_NAME'];
       /* https */
       if (($proto == 'http') && $port == 443) {
@@ -53,12 +51,6 @@ class ARC2 {
         $port = 80;
       }
       return $proto . '://' . $server . ($port != 80 ? ':' . $port : '') . $script;
-      /*
-      return preg_replace('/^([a-z]+)\/.*$/', '\\1', strtolower($_SERVER['SERVER_PROTOCOL'])) . 
-        '://' . $_SERVER['SERVER_NAME'] .
-        ($_SERVER['SERVER_PORT'] != 80 ? ':' . $_SERVER['SERVER_PORT'] : '') .
-        $_SERVER['SCRIPT_NAME'];
-      */
     }
     elseif (isset($_SERVER['SCRIPT_FILENAME'])) {
       return 'file://' . realpath($_SERVER['SCRIPT_FILENAME']);
@@ -69,7 +61,7 @@ class ARC2 {
   static function getRequestURI() {
     if (isset($_SERVER) && isset($_SERVER['REQUEST_URI'])) {
       return preg_replace('/^([a-z]+)\/.*$/', '\\1', strtolower($_SERVER['SERVER_PROTOCOL'])) . 
-        '://' . $_SERVER['SERVER_NAME'] .
+        '://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']) .
         ($_SERVER['SERVER_PORT'] != 80 ? ':' . $_SERVER['SERVER_PORT'] : '') .
         $_SERVER['REQUEST_URI'];
     }
@@ -100,8 +92,7 @@ class ARC2 {
   /*  */
 
   static function mtime(){
-    list($msec, $sec) = explode(" ", microtime());
-    return ((float)$msec + (float)$sec);
+	  return microtime(true);
   }
   
   static function x($re, $v, $options = 'si') {
@@ -358,6 +349,12 @@ class ARC2 {
     return new $cls($a, $caller);
   }
   
+  /* graph */
+
+  static function getGraph($a = '') {
+    return ARC2::getComponent('Graph', $a);
+  }
+
   /* resource */
 
   static function getResource($a = '') {
@@ -476,6 +473,10 @@ class ARC2 {
     return ARC2::getSer('RSS10', $a);
   }
 
+  static function getJSONLDSerializer($a = '') {
+    return ARC2::getSer('JSONLD', $a);
+  }
+
   /* sparqlscript */
 
   static function getSPARQLScriptProcessor($a = '') {
diff --git a/lib/arc2/ARC2_Class.php b/lib/arc2/ARC2_Class.php
index 127b818524417736f2f1926d22f8791957840fca..48763898b6d8c0a8e590b251737e7db5ea3d52ad 100644
--- a/lib/arc2/ARC2_Class.php
+++ b/lib/arc2/ARC2_Class.php
@@ -3,20 +3,20 @@
  * ARC2 base class
  *
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
  * @package ARC2
- * @version 2010-11-16
  */
 
 class ARC2_Class {
-  
+    protected $db_object;
+
   function __construct($a, &$caller) {
     $this->a = is_array($a) ? $a : array();
     $this->caller = $caller;
     $this->__init();
   }
-  
+
   function __init() {/* base, time_limit */
     if (!$_POST && isset($GLOBALS['HTTP_RAW_POST_DATA'])) parse_str($GLOBALS['HTTP_RAW_POST_DATA'], $_POST); /* php5 bug */
     $this->inc_path = ARC2::getIncPath();
@@ -31,10 +31,11 @@ class ARC2_Class {
     $this->warnings = array();
     $this->adjust_utf8 = $this->v('adjust_utf8', 0, $this->a);
     $this->max_errors = $this->v('max_errors', 25, $this->a);
+    $this->has_pcre_unicode = @preg_match('/\pL/u', 'test');/* \pL = block/point which is a Letter */
   }
 
   /*  */
-  
+
   function v($name, $default = false, $o = false) {/* value if set */
     if ($o === false) $o = $this;
     if (is_array($o)) {
@@ -42,7 +43,7 @@ class ARC2_Class {
     }
     return isset($o->$name) ? $o->$name : $default;
   }
-  
+
   function v1($name, $default = false, $o = false) {/* value if 1 (= not empty) */
     if ($o === false) $o = $this;
     if (is_array($o)) {
@@ -50,7 +51,7 @@ class ARC2_Class {
     }
     return (isset($o->$name) && $o->$name) ? $o->$name : $default;
   }
-  
+
   function m($name, $a = false, $default = false, $o = false) {/* call method */
     if ($o === false) $o = $this;
     return method_exists($o, $name) ? $o->$name($a) : $default;
@@ -75,7 +76,9 @@ class ARC2_Class {
 
   function deCamelCase($v, $uc_first = 0) {
     $r = str_replace('_', ' ', $v);
-    $r = preg_replace('/([a-z0-9])([A-Z])/e', '"\\1 " . strtolower("\\2")', $r);
+    $r = preg_replace_callback('/([a-z0-9])([A-Z])/', function($matches) {
+      return $matches[1] . ' ' . strtolower($matches[2]);
+    }, $r);
     return $uc_first ? ucfirst($r) : $r;
   }
 
@@ -92,7 +95,7 @@ class ARC2_Class {
     /* decode apostrophe + s */
     $r = str_replace(' apostrophes ', "'s ", $r);
     /* typical RDF non-info URI */
-    if (($loops < 1) && preg_match('/^(self|it|this|me)$/i', $r)) {
+    if (($loops < 1) && preg_match('/^(self|it|this|me|id)$/i', $r)) {
       return $this->extractTermLabel(preg_replace('/\#.+$/', '', $uri), $loops + 1);
     }
     /* trailing hash or slash */
@@ -117,7 +120,7 @@ class ARC2_Class {
   }
 
   /*  */
-  
+
   function addError($v) {
     if (!in_array($v, $this->errors)) {
       $this->errors[] = $v;
@@ -131,11 +134,11 @@ class ARC2_Class {
     }
     return false;
   }
-  
+
   function getErrors() {
     return $this->errors;
   }
-  
+
   function getWarnings() {
     return $this->warnings;
   }
@@ -146,9 +149,9 @@ class ARC2_Class {
       $this->caller->resetErrors();
     }
   }
-  
+
   /*  */
-  
+
   function splitURI($v) {
     return ARC2::splitURI($v);
   }
@@ -191,6 +194,12 @@ class ARC2_Class {
     return $this->ns[$m[1]];
   }
 
+  function setPrefix($prefix, $ns) {
+	 $this->ns[$prefix] = $ns;
+	 $this->nsp[$ns] = $prefix;
+	 return $this;
+  }
+
   function getPrefix($ns) {
     if (!isset($this->nsp[$ns])) {
       $this->ns['ns' . $this->ns_count] = $ns;
@@ -237,7 +246,7 @@ class ARC2_Class {
   }
 
   /*  */
-  
+
   function calcURI($path, $base = "") {
     /* quick check */
     if (preg_match("/^[a-z0-9\_]+\:/i", $path)) {/* abs path or bnode */
@@ -282,9 +291,9 @@ class ARC2_Class {
     }
     return $base . $path;
   }
-  
+
   /*  */
-  
+
   function calcBase($path) {
     $r = $path;
     $r = preg_replace('/\#.*$/', '', $r);/* remove hash */
@@ -311,7 +320,7 @@ class ARC2_Class {
     }
     return $res;
   }
-  
+
   function toIndex($v) {
     if (is_array($v)) {
       if (isset($v[0]) && isset($v[0]['s'])) return ARC2::getSimpleIndex($v, 0);
@@ -350,14 +359,14 @@ class ARC2_Class {
     $ser = new ARC2_NTriplesSerializer(array_merge($this->a, array('ns' => $ns)), $this);
     return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v, $raw) : $ser->getSerializedIndex($v, $raw);
   }
-  
+
   function toTurtle($v, $ns = '', $raw = 0) {
     ARC2::inc('TurtleSerializer');
     if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
     $ser = new ARC2_TurtleSerializer(array_merge($this->a, array('ns' => $ns)), $this);
     return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v, $raw) : $ser->getSerializedIndex($v, $raw);
   }
-  
+
   function toRDFXML($v, $ns = '', $raw = 0) {
     ARC2::inc('RDFXMLSerializer');
     if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
@@ -416,7 +425,7 @@ class ARC2_Class {
     $parser->parse($g, $this->getTurtleHead() . $t);
     return $parser->getSimpleIndex(0, $vals);
   }
-  
+
   function getTurtleHead() {
     $r = '';
     $ns = $this->v('ns', array(), $this->a);
@@ -425,7 +434,7 @@ class ARC2_Class {
     }
     return $r;
   }
-  
+
   function completeQuery($q, $ns = '') {
     if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
     $added_prefixes = array();
@@ -460,7 +469,7 @@ class ARC2_Class {
   function checkRegex($str) {
     return addslashes($str); // @@todo extend
   }
-  
+
   /* Microdata methods */
 
   function getMicrodataAttrs($id, $type = '') {
@@ -472,19 +481,97 @@ class ARC2_Class {
     return $this->getMicrodataAttrs($id, $type);
   }
 
-  /* central DB query hook */
+    /* central DB query hook */
+
+    public function getDBObjectFromARC2Class($con = null)
+    {
+        if (null == $this->db_object) {
+            if (false === class_exists('\\ARC2\\Store\\Adapter\\AdapterFactory')) {
+                require __DIR__.'/src/ARC2/Store/Adapter/AdapterFactory.php';
+            }
+            if (false == isset($this->a['db_adapter'])) {
+                $this->a['db_adapter'] = 'mysqli';
+            }
+            $factory = new \ARC2\Store\Adapter\AdapterFactory();
+            $this->db_object = $factory->getInstanceFor($this->a['db_adapter'], $this->a);
+            if ($con) {
+                $this->db_object->connect($con);
+            } else {
+                $this->db_object->connect();
+            }
+        }
+        return $this->db_object;
+    }
+
+    /**
+     * Dont use this function to directly query the database. It currently works only with mysqli DB adapter.
+     *
+     * @param string $sql SQL query
+     * @param mysqli $con Connection
+     * @param int    $log_errors 1 if you want to log errors. Default is 0
+     *
+     * @return mysqli Result
+     *
+     * @deprecated since 2.4.0
+     */
+    public function queryDB($sql, $con, $log_errors = 0)
+    {
+        $t1 = ARC2::mtime();
+
+        // create connection using an adapter, if not available yet
+        $this->getDBObjectFromARC2Class($con);
+
+        $r = $this->db_object->mysqliQuery($sql);
+
+        // TODO check if this is ever called. it seems not and therefore could be removed.
+        if (0) {
+            $t2 = ARC2::mtime() - $t1;
+            $call_obj = $this;
+            $call_path = '';
+            while ($call_obj) {
+                $call_path = get_class($call_obj) . ' / ' . $call_path;
+                $call_obj = isset($call_obj->caller) ? $call_obj->caller : false;
+            }
+            echo "\n" . $call_path . " needed " . $t2 . ' secs for ' . str_replace("\n" , ' ', $sql);;
+        }
 
-  function queryDB($sql, $con, $log_errors = 0) {
-    $t1 = ARC2::mtime();
-    $r = mysql_query($sql, $con);
-    $t2 = ARC2::mtime() - $t1;
-    if ($t2 > 1) {
-      //echo "\n needed " . $t2 . ' secs for ' . $sql;
+        if ($log_errors && !empty($this->db_object->getErrorMessage())) {
+            $this->addError($this->db_object->getErrorMessage());
+        }
+        return $r;
     }
-    if ($log_errors && ($er = mysql_error($con))) $this->addError($er);
-    return $r;
-  }
 
-  /*  */
+  /**
+   * Shortcut method to create an RDF/XML backup dump from an RDF Store object.
+   */
+  function backupStoreData($store, $target_path, $offset = 0) {
+    $limit = 10;
+    $q = '
+      SELECT DISTINCT ?s WHERE {
+        ?s ?p ?o .
+      }
+      ORDER BY ?s
+      LIMIT ' . $limit . '
+      ' . ($offset ? 'OFFSET ' . $offset : '') . '
+    ';
+    $rows = $store->query($q, 'rows');
+    $tc = count($rows);
+    $full_tc = $tc + $offset;
+    $mode = $offset ? 'ab' : 'wb';
+    $fp = fopen($target_path, $mode);
+    foreach ($rows as $row) {
+      $index = $store->query('DESCRIBE <' . $row['s'] . '>', 'raw');
+      if ($index) {
+        $doc = $this->toRDFXML($index);
+        fwrite($fp, $doc . "\n\n");
+      }
+    }
+    fclose($fp);
+    if ($tc == 10) {
+      set_time_limit(300);
+      $this->backupStoreData($store, $target_path, $offset + $limit);
+    }
+    return $full_tc;
+  }
 
 }
diff --git a/lib/arc2/ARC2_Graph.php b/lib/arc2/ARC2_Graph.php
new file mode 100644
index 0000000000000000000000000000000000000000..af1aca6bcf2a460a55f37250cbd845cd46031d3c
--- /dev/null
+++ b/lib/arc2/ARC2_Graph.php
@@ -0,0 +1,178 @@
+<?php
+/**
+ * ARC2 Graph object
+ *
+ * @author Benjamin Nowack <mail@bnowack.de>
+ * @license W3C Software License
+ * @homepage <https://github.com/semsol/arc2>
+ * @package ARC2
+*/
+
+ARC2::inc('Class');
+
+class ARC2_Graph extends ARC2_Class {
+	
+	protected $index;
+
+	function __construct($a, &$caller) {
+		parent::__construct($a, $caller);
+	}
+  
+	function __init() {
+		parent::__init();
+		$this->index = array();
+	}
+  
+	function setIndex($index) {
+		$this->index = $index;
+		return $this;
+	}
+
+	function getIndex() {
+		return $this->index;
+	}
+	
+	function addIndex($index) {
+		$this->index = ARC2::getMergedIndex($this->index, $index);
+		return $this;
+	}
+	
+	function addGraph($graph) {
+		// namespaces
+		foreach ($graph->ns as $prefix => $ns) {
+			$this->setPrefix($prefix, $ns);
+		}
+		// index
+		$this->addIndex($graph->getIndex());
+		return $this;
+	}
+	
+	function addRdf($data, $format = null) {
+		if ($format == 'json') {
+			return $this->addIndex(json_decode($data, true));
+		}
+		else {// parse any other rdf format
+			return $this->addIndex($this->toIndex($data));
+		}
+	}
+	
+	function hasSubject($s) {
+		return isset($this->index[$s]);
+	}
+		
+	function hasTriple($s, $p, $o) {
+		if (!is_array($o)) {
+			return $this->hasLiteralTriple($s, $p, $o) || $this->hasLinkTriple($s, $p, $o);
+		}
+		if (!isset($this->index[$s])) return false;
+		$p = $this->expandPName($p);
+		if (!isset($this->index[$s][$p])) return false;
+		return in_array($o, $this->index[$s][$p]);
+	}
+	
+	function hasLiteralTriple($s, $p, $o) {
+		if (!isset($this->index[$s])) return false;
+		$p = $this->expandPName($p);
+		if (!isset($this->index[$s][$p])) return false;
+		$os = $this->getObjects($s, $p, false);
+		foreach ($os as $object) {
+			if ($object['value'] == $o && $object['type'] == 'literal') {
+				return true;
+			}
+		}
+		return false;
+	}
+  
+	function hasLinkTriple($s, $p, $o) {
+		if (!isset($this->index[$s])) return false;
+		$p = $this->expandPName($p);
+		if (!isset($this->index[$s][$p])) return false;
+		$os = $this->getObjects($s, $p, false);
+		foreach ($os as $object) {
+			if ($object['value'] == $o && ($object['type'] == 'uri' || $object['type'] == 'bnode')) {
+				return true;
+			}
+		}
+		return false;
+	}
+  
+	function addTriple($s, $p, $o, $oType = 'literal') {
+		$p = $this->expandPName($p);
+		if (!is_array($o)) $o = array('value' => $o, 'type' => $oType);
+		if ($this->hasTriple($s, $p, $o)) return;
+		if (!isset($this->index[$s])) $this->index[$s] = array();
+		if (!isset($this->index[$s][$p])) $this->index[$s][$p] = array();
+		$this->index[$s][$p][] = $o;
+		return $this;
+	}
+	
+	function getSubjects($p = null, $o = null) {
+		if (!$p && !$o) return array_keys($this->index);
+		$result = array();
+		foreach ($this->index as $s => $ps) {
+			foreach ($ps as $predicate => $os) {
+				if ($p && $predicate != $p) continue;
+				foreach ($os as $object) {
+					if (!$o) {
+						$result[] = $s;
+						break;
+					}
+					else if (is_array($o) && $object == $o) {
+						$result[] = $s;
+						break;
+					}
+					else if ($o && $object['value'] == $o) {
+						$result[] = $s;
+						break;
+					}
+				}
+			}
+		}
+		return array_unique($result);
+	}
+	
+	function getPredicates($s = null) {
+		$result = array();
+		$index = $s ? (array($s => isset($this->index[$s]) ? $this->index[$s] : array())) : $this->index;
+		foreach ($index as $subject => $ps) {
+			if ($s && $s != $subject) continue;
+			$result = array_merge($result, array_keys($ps));
+		}
+		return array_unique($result);
+	}
+	
+	function getObjects($s, $p, $plain = false) {
+		if (!isset($this->index[$s])) return array();
+		$p = $this->expandPName($p);
+		if (!isset($this->index[$s][$p])) return array();
+		$os = $this->index[$s][$p];
+		if ($plain) {
+			array_walk($os, function(&$o) {
+				$o = $o['value'];
+			});
+		}
+		return $os;
+	}
+	
+	function getObject($s, $p, $plain = false, $default = null) {
+		$os = $this->getObjects($s, $p, $plain);
+		return empty($os) ? $default : $os[0];
+	}
+
+	function getNTriples() {
+		return parent::toNTriples($this->index, $this->ns);
+	}
+
+	function getTurtle() {
+		return parent::toTurtle($this->index, $this->ns);
+	}
+
+	function getRDFXML() {
+		return parent::toRDFXML($this->index, $this->ns);
+	}
+
+	function getJSON() {
+		return json_encode($this->index);
+	}
+	
+}
diff --git a/lib/arc2/ARC2_Reader.php b/lib/arc2/ARC2_Reader.php
old mode 100644
new mode 100755
index 945406c578c8e021a918890ef8077f2822fb4cfc..6ad0b6215ee90fea4d706ffbfe4ebda06f225ad3
--- a/lib/arc2/ARC2_Reader.php
+++ b/lib/arc2/ARC2_Reader.php
@@ -3,8 +3,8 @@
  * ARC2 Web Client
  *
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
  * @package ARC2
  * @version 2010-11-16
 */
@@ -21,8 +21,8 @@ class ARC2_Reader extends ARC2_Class {
     parent::__init();
     $this->http_method = $this->v('http_method', 'GET', $this->a);
     $this->message_body = $this->v('message_body', '', $this->a);;
-    $this->http_accept_header = $this->v('http_accept_header', 'Accept: application/rdf+xml; q=0.9, */*; q=0.1', $this->a);
-    $this->http_user_agent_header = $this->v('http_user_agent_header', 'User-Agent: ARC Reader (http://arc.semsol.org/)', $this->a);
+    $this->http_accept_header = $this->v('http_accept_header', 'Accept: application/rdf+xml; q=0.9, text/turtle; q=0.8, */*; q=0.1', $this->a);
+    $this->http_user_agent_header = $this->v('http_user_agent_header', 'User-Agent: ARC Reader (https://github.com/semsol/arc2)', $this->a);
     $this->http_custom_headers = $this->v('http_custom_headers', '', $this->a);
     $this->max_redirects = $this->v('max_redirects', 3, $this->a);
     $this->format = $this->v('format', false, $this->a);
@@ -208,16 +208,14 @@ class ARC2_Reader extends ARC2_Class {
     }
     return array('type' => 'socket', 'socket' =>& $s, 'headers' => array(), 'pos' => 0, 'size' => filesize($parts['path']), 'buffer' => '');
   }
-  
+ 
   function getHTTPSocket($url, $redirs = 0, $prev_parts = '') {
-    $parts = parse_url($url);
-    /* relative redirect */
-    if (!isset($parts['scheme']) && $prev_parts) $parts['scheme'] = $prev_parts['scheme'];
-    if (!isset($parts['host']) && $prev_parts) $parts['host'] = $prev_parts['host'];
-    /* no scheme */
-    if (!$this->v('scheme', '', $parts)) return $this->addError('Socket error: Missing URI scheme.');
-    /* port tweaks */
-    $parts['port'] = ($parts['scheme'] == 'https') ? $this->v1('port', 443, $parts) : $this->v1('port', 80, $parts);
+    $parts = $this->getURIPartsFromURIAndPreviousURIParts($url, $prev_parts);
+
+    if(!is_array($parts)) {
+      return false;
+    }
+
     $nl = "\r\n";
     $http_mthd = strtoupper($this->http_method);
     if ($this->v1('user', 0, $parts) || $this->useProxy($url)) {
@@ -226,7 +224,8 @@ class ARC2_Reader extends ARC2_Class {
     else {
       $h_code = $http_mthd . ' ' . $this->v1('path', '/', $parts) . (($v = $this->v1('query', 0, $parts)) ? '?' . $v : '') . (($v = $this->v1('fragment', 0, $parts)) ? '#' . $v : '');
     }
-    $port_code = ($parts['port'] != 80) ? ':' . $parts['port'] : '';
+    $scheme_default_port = ($parts['scheme'] == 'https') ? 443 : 80;
+    $port_code = ($parts['port'] != $scheme_default_port) ? ':' . $parts['port'] : '';
     $h_code .= ' HTTP/1.0' . $nl.
       'Host: ' . $parts['host'] . $port_code . $nl .
       (($v = $this->http_accept_header) ? $v . $nl : '') .
@@ -251,7 +250,7 @@ class ARC2_Reader extends ARC2_Class {
           stream_context_set_option($context, 'ssl', $m[1], $v);
         }
       }
-      $s = stream_socket_client('ssl://' . $parts['host'] . $port_code, $errno, $errstr, $this->timeout, STREAM_CLIENT_CONNECT, $context);
+      $s = stream_socket_client('ssl://' . $parts['host'] . ":" . $parts['port'], $errno, $errstr, $this->timeout, STREAM_CLIENT_CONNECT, $context);
     }
     elseif ($parts['scheme'] == 'https') {
       $s = @fsockopen('ssl://' . $parts['host'], $parts['port'], $errno, $errstr, $this->timeout);
@@ -332,6 +331,25 @@ class ARC2_Reader extends ARC2_Class {
     return array('type' => 'socket', 'url' => $url, 'socket' =>& $s, 'headers' => $h, 'pos' => 0, 'size' => $this->v('content-length', 0, $h), 'buffer' => '');
   }
 
+  function getURIPartsFromURIAndPreviousURIParts($uri, $previous_uri_parts) {
+    $parts = parse_url($uri);
+
+    /* relative redirect */
+    if (!isset($parts['port']) && $previous_uri_parts && (!isset($parts['scheme']) || $parts['scheme'] == $previous_uri_parts['scheme'])) {
+      /* only set the port if the scheme has not changed. If the scheme changes to https assuming the port will stay as port 80 is a bad idea */
+      $parts['port'] = $previous_uri_parts['port'];
+    }
+    if (!isset($parts['scheme']) && $previous_uri_parts) $parts['scheme'] = $previous_uri_parts['scheme'];
+    if (!isset($parts['host']) && $previous_uri_parts) $parts['host'] = $previous_uri_parts['host'];
+
+    /* no scheme */
+    if (!$this->v('scheme', '', $parts)) return $this->addError('Socket error: Missing URI scheme.');
+    /* port tweaks */
+    $parts['port'] = ($parts['scheme'] == 'https') ? $this->v1('port', 443, $parts) : $this->v1('port', 80, $parts);
+
+    return $parts;
+  }
+
   function readStream($buffer_xml = true, $d_size = 1024) {
     //if (!$s = $this->v('stream')) return '';
     if (!$s = $this->v('stream')) return $this->addError('missing stream in "readStream" ' . $this->uri);
@@ -370,7 +388,7 @@ class ARC2_Reader extends ARC2_Class {
   
   function closeStream() {
     if (isset($this->stream)) {
-      if ($this->v('type', 0, $this->stream) == 'socket') {
+      if ($this->v('type', 0, $this->stream) == 'socket' && !empty($this->stream['socket'])) {
         @fclose($this->stream['socket']);
       }
       unset($this->stream);
diff --git a/lib/arc2/ARC2_Resource.php b/lib/arc2/ARC2_Resource.php
index 3423223649c0a5f85623ad7c42e5a2facd130de4..9588ca1ec5c54a59b58d2e57143a2df55538edb4 100644
--- a/lib/arc2/ARC2_Resource.php
+++ b/lib/arc2/ARC2_Resource.php
@@ -3,10 +3,10 @@
  * ARC2 Resource object
  *
  * @author Benjamin Nowack <bnowack@semsol.com>
- * @license http://arc.semsol.org/license
- * @homepage <http://arc.semsol.org/>
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
  * @package ARC2
- * @version 2010-11-16
+ * @version 2011-01-19
 */
 
 ARC2::inc('Class');
@@ -35,6 +35,10 @@ class ARC2_Resource extends ARC2_Class {
     $this->index = $index;
   }
 
+  function getIndex() {
+    return $this->index;
+  }
+
   function setProps($props, $s = '') {
     if (!$s) $s = $this->uri;
     $this->index[$s] = $props;
@@ -53,6 +57,35 @@ class ARC2_Resource extends ARC2_Class {
     $this->index[$s][$this->expandPName($p)] = $os;
   }
 
+  /* add a relation to a URI. Allows for instance $res->setRel('rdf:type', 'doap:Project') */
+  function setRel($p, $r, $s = '') {
+    if(!is_array($r)) {
+      $uri = array (
+		    'type' => 'uri',
+		    'value' => $this->expandPName($r));
+      $this->setProp($p, $uri, $s);
+    } else {
+      if (!$s) $s = $this->uri;
+      foreach($r as $i => $x) {
+	if(!is_array($x)) {
+	  $uri = array (
+			'type' => 'uri',
+			'value' => $this->expandPName($x));
+	  $r[$i] = $uri;
+	}
+      }
+      $this->index[$s][$this->expandPName($p)] = $r;
+    }
+  }
+
+  /* Specialize setProp to set an xsd:dateTime typed literal. Example : $res->setPropXSDdateTime('dcterms:created', date('c')) */
+  function setPropXSDdateTime($p, $dt, $s = '') {
+	$datecreated=array('value' => $dt,
+		'type' => 'literal',
+		'datatype' => 'http://www.w3.org/2001/XMLSchema#dateTime');
+	$this->setProp($p, $datecreated, $s);
+  }
+
   function setStore($store) {
     $this->store = $store;
   }
diff --git a/lib/arc2/ARC2_getFormat.php b/lib/arc2/ARC2_getFormat.php
old mode 100644
new mode 100755
index faec03963c996ad41c01e7529ebaf5645c3ae4a7..39288730d5b64eeb0b8e96eb06d49e0cdd918ea9
--- a/lib/arc2/ARC2_getFormat.php
+++ b/lib/arc2/ARC2_getFormat.php
@@ -3,7 +3,7 @@
  * ARC2 format detection function
  *
  * @author Benjamin Nowack <bnowack@semsol.com>
- * @license http://arc.semsol.org/license
+ * @license W3C Software License and GPL
  * @package ARC2
  * @version 2010-11-16
 */
@@ -22,9 +22,7 @@ function ARC2_getFormat($v, $mtype = '', $ext = '') {
     /* starts with angle brackets */
     preg_match('/^\s*\<[^\s]/s', $v) &&
     /* has an xmlns:* declaration or a matching pair of tags */
-    (preg_match('/\sxmlns\:?/', $v) || preg_match('/\<([^\s]+).+\<\/\\1\>/s', $v)) &&
-    /* not a typical ntriples/turtle/n3 file */
-    !preg_match('/[\>\"\']\s*\.\s*$/s', $v)
+    (preg_match('/\sxmlns\:?/', $v) || preg_match('/\<([^\s]+).+\<\/\\1\>/s', $v)) // &&
   ) {
     while (preg_match('/^\s*\<\?xml[^\r\n]+\?\>\s*/s', $v)) {
       $v = preg_replace('/^\s*\<\?xml[^\r\n]+\?\>\s*/s', '', $v);
diff --git a/lib/arc2/ARC2_getPreferredFormat.php b/lib/arc2/ARC2_getPreferredFormat.php
old mode 100644
new mode 100755
index 382d83d2e4ca14c56339322bd5a3edc8352bab78..e91caf6da33c170e1423948c4bf54e9eeda06498
--- a/lib/arc2/ARC2_getPreferredFormat.php
+++ b/lib/arc2/ARC2_getPreferredFormat.php
@@ -3,8 +3,8 @@
  * ARC2 result format detection
  *
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
  * @package ARC2
  * @version 2010-11-16
 */
diff --git a/lib/arc2/LICENSE b/lib/arc2/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..cbd60bad9591e51e11919a37db2dbec66d471866
--- /dev/null
+++ b/lib/arc2/LICENSE
@@ -0,0 +1,282 @@
+# LICENSE
+
+ARC2 is dual-licensed, under the following 2 licenses:
+
+* W3C Software License (https://www.w3.org/Consortium/Legal/2002/copyright-software-20021231)
+* GPL 2 or later (http://www.gnu.org/copyleft/gpl.html)
+
+In the following you will find the license texts of both licenses.
+First from the W3C Software License, afterwards from the GPL.
+
+
+
+
+-----------------------------------------------------------------------------------------------
+W3C Software License
+-----------------------------------------------------------------------------------------------
+
+This work (and included software, documentation such as READMEs, or other related items) is being provided by the copyright holders under the following license.
+
+License
+By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions.
+
+Permission to copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications:
+
+The full text of this NOTICE in a location viewable to users of the redistributed or derivative work.
+Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software Short Notice should be included (hypertext is preferred, text is permitted) within the body of any redistributed or derivative code.
+Notice of any changes or modifications to the files, including the date changes were made. (We recommend you provide URIs to the location from which the code is derived.)
+Disclaimers
+THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
+
+COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION.
+
+The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the software without specific, written prior permission. Title to copyright in this software and any associated documentation will at all times remain with copyright holders.
+
+
+
+
+-----------------------------------------------------------------------------------------------
+GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
+-----------------------------------------------------------------------------------------------
+
+Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
+
+Preamble
+
+The GNU General Public License is a free, copyleft license for software and other kinds of works.
+
+The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
+
+To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.
+
+For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
+
+Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.
+
+For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.
+
+Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.
+
+Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+TERMS AND CONDITIONS
+
+0. Definitions.
+
+"This License" refers to version 3 of the GNU General Public License.
+
+"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
+
+"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations.
+
+To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.
+
+A "covered work" means either the unmodified Program or a work based on the Program.
+
+To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
+
+To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
+
+An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
+
+1. Source Code.
+
+The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work.
+
+A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
+
+The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
+
+The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
+
+The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
+
+The Corresponding Source for a work in source code form is that same work.
+
+2. Basic Permissions.
+
+All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
+
+You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
+
+Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
+
+3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
+
+When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
+
+4. Conveying Verbatim Copies.
+
+You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
+
+You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
+
+5. Conveying Modified Source Versions.
+
+You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
+
+a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
+
+b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices".
+
+c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
+
+d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
+
+A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
+
+6. Conveying Non-Source Forms.
+
+You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
+
+a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
+
+b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
+
+c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
+
+d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
+
+e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
+
+A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
+
+A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
+
+"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
+
+If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
+
+The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
+
+Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
+
+7. Additional Terms.
+
+"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
+
+Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
+
+a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
+
+b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
+
+c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
+
+d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
+
+e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
+
+f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
+
+All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
+
+8. Termination.
+
+You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
+
+However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
+
+Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
+
+9. Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
+
+10. Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
+
+An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
+
+11. Patents.
+
+A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version".
+
+A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
+
+In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
+
+A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
+
+12. No Surrender of Others' Freedom.
+
+If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
+
+13. Use with the GNU Affero General Public License.
+
+Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.
+
+14. Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.
+
+If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
+
+Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
+
+15. Disclaimer of Warranty.
+
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+16. Limitation of Liability.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+17. Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
+
+<one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author>
+
+This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:
+
+<program> Copyright (C) <year> <name of author> This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box".
+
+You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <http://www.gnu.org/licenses/>.
+
+The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/lib/arc2/Makefile b/lib/arc2/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..a5f493215b3056995352c4d01c10f3dd33bd35f8
--- /dev/null
+++ b/lib/arc2/Makefile
@@ -0,0 +1,33 @@
+default:
+	@echo "Please run make test to start test environment."
+
+test:
+	@echo ""
+	@echo "##########"
+	@echo "Unit Tests"
+	@echo "##########"
+	@echo ""
+	vendor/bin/phpunit --testsuite unit
+	# run DB adapter depended test using different adapters each time
+	# this allows us to check coverage using the same tests
+	@echo ""
+	@echo ""
+	@echo "##############################################"
+	@echo "mysqli adapter depended tests (Store uncached)"
+	@echo "##############################################"
+	@echo ""
+	DB_ADAPTER=mysqli vendor/bin/phpunit --testsuite db_adapter_depended
+	@echo ""
+	@echo ""
+	@echo "#########################################################"
+	@echo "PDO adapter depended tests (Store uncached, PDO uncached)"
+	@echo "#########################################################"
+	@echo ""
+	DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql vendor/bin/phpunit --testsuite db_adapter_depended
+	@echo ""
+	@echo ""
+	@echo "#####################################################"
+	@echo "PDO adapter depended tests (Store cached, PDO cached)"
+	@echo "#####################################################"
+	@echo ""
+	DB_ADAPTER=pdo DB_PDO_PROTOCOL=mysql CACHE_ENABLED=true vendor/bin/phpunit --testsuite db_adapter_depended
diff --git a/lib/arc2/README.md b/lib/arc2/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..b9b6dce835bd29178a01efb7a4bc2c5f0a855e93
--- /dev/null
+++ b/lib/arc2/README.md
@@ -0,0 +1,114 @@
+# ARC2
+
+[![Build](https://travis-ci.org/semsol/arc2.svg?branch=master)](https://travis-ci.org/semsol/arc2)
+[![Coverage Status](https://coveralls.io/repos/github/semsol/arc2/badge.svg?branch=master)](https://coveralls.io/github/semsol/arc2?branch=master)
+[![Latest Stable Version](https://poser.pugx.org/semsol/arc2/v/stable.svg)](https://packagist.org/packages/semsol/arc2)
+[![Total Downloads](https://poser.pugx.org/semsol/arc2/downloads.svg)](https://packagist.org/packages/semsol/arc2)
+[![Latest Unstable Version](https://poser.pugx.org/semsol/arc2/v/unstable.svg)](https://packagist.org/packages/semsol/arc2)
+[![License](https://poser.pugx.org/semsol/arc2/license.svg)](https://packagist.org/packages/semsol/arc2)
+
+ARC2 is a PHP 7.2 library for working with RDF. It also provides a MySQL-based triplestore with SPARQL support.
+Older versions of PHP may work, but are not longer tested.
+
+## Documentation
+
+For the documentation, see the [Wiki](https://github.com/semsol/arc2/wiki#core-documentation). To quickly get started, see the [Getting started guide](https://github.com/semsol/arc2/wiki/Getting-started-with-ARC2).
+
+## Installation
+
+Package available on [Composer](https://packagist.org/packages/semsol/arc2).
+
+If you're using Composer to manage dependencies, you can use
+
+```bash
+composer require semsol/arc2:^2
+```
+
+Further information about composer usage can be found [here](https://getcomposer.org/doc/01-basic-usage.md#autoloading), for instance about autoloading ARC2 classes.
+
+## Requirements
+
+#### PHP
+
+|   5.6   | 7.0  | 7.1  | 7.2  | 7.3  | 7.4  |
+|:-------:|:----:|:----:|:----:|:----:|:----:|
+| :+1:(1) | :+1:(1) | :+1:(1) | :+1: | :+1: | :+1: |
+
+(1) It is compatible with PHP 5.3+ but old versions are no longer tested.
+
+#### Database systems
+
+|           | 5.5  | 5.6  | 5.7  |       8.0       |
+|:---------:|:----:|:----:|:----:|:---------------:|
+| **MySQL** | :+1: | :+1: | :+1: | :collision: (1) |
+
+|             |     10.0      | 10.1 | 10.2 | 10.3 | 10.4 | 10.5 |
+|:-----------:|:-------------:|:----:|:----:|:----:|:----:|:----:|
+| **MariaDB** | :question:(2) | :+1: | :+1: | :+1: | :+1: | :+1: |
+
+(1) As long as ARC2 uses mysqli, a connection to MySQL Server 8.0 is not possible. For more information, please look [here](https://github.com/semsol/arc2/commit/0ad48d61753b15ae02ff19f615b14aa52b6557f1). But its planned to switch to PDO ([issue](https://github.com/semsol/arc2/issues/109))
+
+(2) Not tested anymore, because outdated version.
+
+
+## RDF triple store
+
+### SPARQL support
+
+Please have a look into [SPARQL-support.md](doc/SPARQL-support.md) to see which SPARQL 1.0/1.1 features are currently supported.
+
+### Use cache
+
+The RDF store implementation provides a hash-based query cache. It works on two levels: SQL and SPARQL, which means, that it checks given SPARQL queries as well as internally generated SQL queries.
+
+To use it, just add the following to the database configuration:
+
+```php
+$store = ARC2::getStore(array(
+    'db_name' => 'testdb',
+    'db_user' => 'root',
+    'db_pwd'  => '',
+    'db_host' => '127.0.0.1',
+    // ...
+    'cache_enabled' => true // <== activates cache
+));
+```
+
+Per default it uses a file based cache, which stores items in the default temp folder of the system (in Linux its usually `/tmp`). But you can use another cache solution, such as memcached.
+
+#### PSR-16 compatibility
+
+Our cache solution is [PSR-16](https://www.php-fig.org/psr/psr-16/) compatible, which means, that you can use your own cache instance. To do that, add the following to the database configuration:
+
+```php
+$store = ARC2::getStore(array(
+    'db_name' => 'testdb',
+    'db_user' => 'root',
+    'db_pwd'  => '',
+    'db_host' => '127.0.0.1',
+    // ...
+    'cache_enabled' => true
+    'cache_instance' => new ArrayCache() // <=== example Cache instance, managed by yourself
+));
+```
+
+ARC2 uses [Symfony Cache](https://symfony.com/doc/4.1/components/cache.html) , which provides many connectors out of the box ([Overview](https://github.com/symfony/cache/tree/master/Simple)).
+
+### Known problems/restrictions with database systems
+
+In this section you find known problems with MariaDB or MySQL, regarding certain features. E.g. MySQL 5.5 doesn't allow FULLTEXT indexes in InnoDB. We try to encapsulate any differences in the DB adapters, so that you don't have to care about them. In case you run into problems, this section might be of help.
+
+#### MySQL 8.0 and mysqli
+
+Using mysqli with MySQL 8.0 as backend throws the following exception:
+
+> mysqli_connect(): The server requested authentication method unknown to the client [caching_sha2_password]
+
+Based on this [source](https://mysqlserverteam.com/upgrading-to-mysql-8-0-default-authentication-plugin-considerations/), one has to change the my.cnf, adding the following entry:
+
+> [mysqld]
+> default-authentication-plugin=mysql_native_password
+
+## Internal information for developers
+
+Please have a look [here](doc/developer.md) to find information about maintaining and extending ARC2 as well as our docker setup for local development.
diff --git a/lib/arc2/build.xml b/lib/arc2/build.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a9806c9f8c216e1a6655d8a653bd0c7dd16c9452
--- /dev/null
+++ b/lib/arc2/build.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project default="run-tests" name="arc2" basedir=".">
+
+	<property environment="env" />
+	<property name="tests-dir" location="${basedir}/tests"/>
+	<property name="coverage-dir" location="${tests-dir}/coverage"/>
+
+	<target name="run-tests" depends="run-unit-tests, run-functional-tests"/>
+	
+	<target name="run-unit-tests">
+		<exec dir="${tests-dir}/unit" executable="phpunit" failonerror="true">
+			<arg line="--coverage-html ${coverage-dir} --filter Test ." />
+		</exec>
+	</target>
+
+	<target name="run-functional-tests">
+		<exec dir="${tests-dir}/functional" executable="phpunit" failonerror="true">
+			<arg line="--filter Test ." />
+		</exec>
+	</target>
+
+</project>
\ No newline at end of file
diff --git a/lib/arc2/composer.json b/lib/arc2/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..c252af2197632338e2c12519d63f14fcdc0f8897
--- /dev/null
+++ b/lib/arc2/composer.json
@@ -0,0 +1,62 @@
+{
+    "name": "semsol/arc2",
+    "type": "library",
+    "description": "ARC2 is a PHP 5.6+ library for working with RDF (It may be compatible with PHP 5.3+ but outdated versions are no longer tested). It also provides a MySQL-based triplestore with SPARQL support.",
+    "keywords": ["rdf","sparql"],
+    "homepage": "https://github.com/semsol/arc2",
+    "license": [
+       "GPL-2.0-or-later",
+       "W3C"
+    ],
+    "support": {
+        "issues": "https://github.com/semsol/arc2/issues"
+    },
+    "authors": [
+        {
+            "name": "Benji Nowack",
+            "homepage": "http://bnowack.de/",
+            "role": "Creator, Developer"
+        },
+        {
+            "name": "Konrad Abicht",
+            "homepage": "https://inspirito.de",
+            "email": "hi@inspirito.de",
+            "role": "Maintainer, Developer"
+        }
+    ],
+    "require": {
+        "php": ">=7.2",
+        "psr/simple-cache": "^1.0",
+        "symfony/cache": "^4.4",
+        "thingengineer/mysqli-database-class": "2.*"
+    },
+    "require-dev": {
+        "doctrine/instantiator": "^1.3",
+        "friendsofphp/php-cs-fixer": "^2.16.1",
+        "phpunit/phpunit": "^8.0"
+    },
+    "autoload": {
+        "classmap": ["parsers/", "serializers/", "store/"],
+        "files": [
+            "./ARC2.php",
+            "./ARC2_Class.php",
+            "./ARC2_getFormat.php",
+            "./ARC2_getPreferredFormat.php",
+            "./ARC2_Graph.php",
+            "./ARC2_Reader.php",
+            "./ARC2_Resource.php"
+        ],
+        "psr-4": {
+            "ARC2\\": [
+                "src/ARC2/"
+            ]
+        }
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "Tests\\": [
+                "tests"
+            ]
+        }
+    }
+}
diff --git a/lib/arc2/doc/SPARQL-support.md b/lib/arc2/doc/SPARQL-support.md
new file mode 100644
index 0000000000000000000000000000000000000000..d38f713ee23f901fb48471fb735ed0def9065104
--- /dev/null
+++ b/lib/arc2/doc/SPARQL-support.md
@@ -0,0 +1,142 @@
+# SPARQL support
+
+**Source**: Based on the following ARC2 wiki page: https://github.com/semsol/arc2/wiki/SPARQL-
+
+## Introduction
+
+ARC supports all [SPARQL Query Language](http://www.w3.org/TR/rdf-sparql-query/) features ([to a certain extent](http://www.w3.org/2001/sw/DataAccess/tests/implementations)) and also a number of pragmatic extensions such as aggregates (AVG / COUNT / MAX / MIN / SUM) and write mechanisms. I tried to keep the changes to the SPARQL specification at a minimum, so that the existing grammar parser and store functionality can be re-used, and also to stick to ARC's flat learning curve.
+
+This page documents the core differences between SPARQL and what is called "SPARQL+" in ARC2.
+
+## SELECT
+
+### Aggregates
+```sql
+SELECT COUNT(?contact) AS ?contacts WHERE {
+  <#me> foaf:knows ?contact .
+}
+ORDER BY DESC(?contacts)
+```
+Note that the alias (... AS ...) has to be specified.
+
+
+If you have more than a single result variable, you also have to provide GROUP BY information:
+```sql
+SELECT ?who COUNT(?contact) AS ?contacts WHERE {
+  ?who foaf:knows ?contact .
+}
+GROUP BY ?who
+```
+
+ARC2 currently has a bug in the `SUM` ([100](https://github.com/semsol/arc2/issues/100)) and `AVG` ([99](https://github.com/semsol/arc2/issues/99)) function.
+
+#### Supported aggregate functions
+
+|         |                            AVG                             | COUNT | MIN | MAX | SUM |
+|:--------|:----------------------------------------------------------:|:-----:|:---:|:---:|:---:|
+| Support | x (but [bugged](https://github.com/semsol/arc2/issues/99)) |   x   |  x  |  x  |  x  |
+
+
+### Supported relational terms
+
+|         | = | != | < | > |
+|:--------|:-:|:--:|:-:|:-:|
+| Support | x | x  | x | x |
+
+### Supported FILTER functions
+
+|         | bound | datatype | isBlank | isIri | isLiteral | isUri | lang | langMatches | regex | str |
+|:--------|:-----:|:--------:|:-------:|:-----:|:---------:|:-----:|:----:|:-----------:|:-----:|:---:|
+| Support |   x   |    x     |    x    |   x   |     x     |   x   |  x   |      x      |   x   |  x  |
+
+## LOAD
+```sql
+LOAD <http://example.com/>
+```
+ARC can extract triples from a variety of formats such as RDF/XML, Turtle, and HTML (eRDF, RDFa, microformats, basic Dublin Core data, OpenID Hooks, Feed links).
+
+
+It is possible to add data to an existing graph:
+```sql
+LOAD <http://example.com/> INTO <http://example.com/archive>
+```
+(LOAD in SPARQL+ is syntactically compatible with SPARUL.)
+
+
+## INSERT INTO
+```sql
+INSERT INTO <http://example.com/> {
+ <#foo> <bar> "baz" .
+}
+```
+In this INSERT form the triples have to be fully specified, variables are not allowed.
+
+
+It is possible to dynamically generate the triples that should be inserted:
+```sql
+INSERT INTO <http://example.com/inferred> CONSTRUCT {
+  ?s foaf:knows ?o .
+}
+WHERE {
+  ?s xfn:contact ?o .
+}
+```
+This is a simple extension to SPARQL's existing CONSTRUCT query type. It adds the triples generated in the construction step to the specified graph. **Note**: The CONSTRUCT keyword was made optional with the Jan 7th, 2008 revision, to increase the compatibility with SPARUL.
+
+
+## DELETE
+
+```sql
+DELETE {
+ <#foo> <bar> "baz" .
+ <#foo2> <bar2> ?any .
+}
+```
+Each specified triple will be deleted from the RDF store. It is possible to specify variables as wildcards, but they can't be used to build connected patterns. Each triple is handled as a stand-alone pattern.
+
+
+FROM can be used to restrict the delete operations to selected graphs. It's also possible to not specify any triples. The whole graph will then be deleted.
+```sql
+DELETE FROM <http://example.com/archive>
+```
+
+DELETE can (like INSERT) be combined with a CONSTRUCT query (the CONSTRUCT keyword was made optional with the Jan 7th, 2008 revision):
+
+```sql
+DELETE FROM <http://example.com/inferred> {
+  ?s rel:wouldLikeToKnow ?o .
+}
+WHERE {
+  ?s kiss:kissed ?o .
+}
+```
+
+Instead of deleting triples only in one graph, you can in all graphs by using:
+
+```sql
+DELETE {
+  ?s rel:wouldLikeToKnow ?o .
+}
+WHERE {
+  ?s kiss:kissed ?o .
+}
+```
+
+## SPARQL Grammar Changes and Additions
+```sql
+Query ::= Prologue ( SelectQuery | ConstructQuery | DescribeQuery | AskQuery | LoadQuery | InsertQuery | DeleteQuery )
+
+SelectQuery ::= 'SELECT' ( 'DISTINCT' | 'REDUCED' )? ( Aggregate+ | Var+ | '*' ) DatasetClause* WhereClause SolutionModifier
+
+Aggregate ::= ( 'AVG' | 'COUNT' | 'MAX' | 'MIN' | 'SUM' ) '(' Var | '*' ')' 'AS' Var
+
+LoadQuery ::= 'LOAD' IRIref ( 'INTO' IRIref )?
+
+InsertQuery ::= 'INSERT' 'INTO' IRIref 'CONSTRUCT'? ConstructTemplate DatasetClause* WhereClause? SolutionModifier
+
+DeleteQuery ::= 'DELETE' ( 'FROM' IRIref )* 'CONSTRUCT'? ConstructTemplate? DatasetClause* WhereClause? SolutionModifier
+
+SolutionModifier ::= GroupClause? OrderClause? LimitOffsetClauses?
+
+GroupClause ::= 'GROUP' 'BY' Var ( ',' Var )*
+```
diff --git a/lib/arc2/doc/developer.md b/lib/arc2/doc/developer.md
new file mode 100644
index 0000000000000000000000000000000000000000..209dad6b6bbe42df81366f476c3c35bd437981f3
--- /dev/null
+++ b/lib/arc2/doc/developer.md
@@ -0,0 +1,53 @@
+# Developer information
+
+This document contains information about ARC2 internals which are relevant for maintaining and extending ARC2.
+
+## Run test environment
+
+To run test environment execute:
+
+```bash
+make test
+```
+
+Tests are split into different groups, currently:
+* unit
+* db_adapter_depended
+
+You can run the `unit` group directly, but you need to set some environment variables for `db_adapter_depended`.
+For more information please have a look into our `Makefile`.
+
+#### config.php
+
+Currently, we use the following standard db credentials to connect with the database:
+
+```php
+$dbConfig = array(
+    'db_name' => 'testdb',
+    'db_user' => 'root',
+    'db_pwd'  => '',
+    'db_host' => '127.0.0.1',
+);
+```
+
+The is used in the travis environment. If you have different credentials, copy the `tests/config.php.dist` to `tests/config.php` and set your credentials.
+
+## Editor
+
+Please make sure your editor uses our `.editorconfig` file.
+
+## Docker setup
+
+For ARC2 developers we recommend using our docker setup (see folder `docker`). It provides a pre-configured set of software (for PHP, DBS etc.) and allows quick switches between different software versions.
+
+No matter if one needs a MariaDB 10.3 with PHP 7.2 or a PHP 5.6 with MySQL 5.7.0. If there is a docker container, it runs.
+
+### Start
+
+In your terminal go to `docker` folder and run `make`. It will build and start the docker environment as well as log you in.
+
+### Docker and Travis
+
+We use a very wide range of software-combinations to test ARC2 ([Travis](https://travis-ci.org/semsol/arc2)). Currently, all combinations of supported versions of PHP and database systems (currently MySQL and MariaDB only) are checked.
+
+Using a Docker setup for local development allows to switch the backend very easily. So, if a test with a certain DBS/PHP version combination fails on travis, its very likely that you can reproduce it locally. Dont forget to run `composer update` after a switch to make sure appropriate software is used.
diff --git a/lib/arc2/docker/Docker/arc2/Dockerfile b/lib/arc2/docker/Docker/arc2/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..39ec6eb7f4c148cc12a5d289db8601676bcbbed1
--- /dev/null
+++ b/lib/arc2/docker/Docker/arc2/Dockerfile
@@ -0,0 +1,42 @@
+FROM php:7.3-apache
+
+RUN apt-get update && apt-get install -y curl git gnupg libicu-dev libzip-dev make nano net-tools zip zlib1g-dev
+
+RUN docker-php-ext-install intl mysqli pdo pdo_mysql zip \
+    && docker-php-ext-enable intl mysqli pdo pdo_mysql zip
+
+# install composer globally
+RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
+RUN composer selfupdate
+
+# fix terminal error
+RUN echo "export TERM=xterm" > /etc/bash.bashrc
+
+# configure apache2
+COPY ./arc2.conf /etc/apache2/sites-enabled/000-default.conf
+
+# add custom PHP.ini settings
+RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
+
+COPY ./arc2.sh /arc2.sh
+RUN chmod +x /arc2.sh
+
+RUN rm -rf /var/www/html/*
+WORKDIR /var/www/html/
+
+# Dummy file to test later on
+RUN echo "html/index" >> /var/www/html/index.html
+
+RUN a2enmod rewrite
+
+# adds user "arc2", adds him to group "www-data" and sets his home folder
+# for more background information see:
+# https://medium.com/@mccode/understanding-how-uid-and-gid-work-in-docker-containers-c37a01d01cf
+RUN useradd -r --home /home/arc2 -u 1000 arc2
+RUN usermod -a -G www-data arc2
+RUN mkdir /home/arc2
+RUN chown arc2:www-data /home/arc2
+
+EXPOSE 80 3306
+
+CMD ["/arc2.sh"]
diff --git a/lib/arc2/docker/Docker/arc2/arc2.conf b/lib/arc2/docker/Docker/arc2/arc2.conf
new file mode 100644
index 0000000000000000000000000000000000000000..584dcfdd9a2989ac8c713002592c0d922623963f
--- /dev/null
+++ b/lib/arc2/docker/Docker/arc2/arc2.conf
@@ -0,0 +1,26 @@
+<VirtualHost *:80>
+	# The ServerName directive sets the request scheme, hostname and port that
+	# the server uses to identify itself. This is used when creating
+	# redirection URLs. In the context of virtual hosts, the ServerName
+	# specifies what hostname must appear in the request's Host: header to
+	# match this virtual host. For the default virtual host (this file) this
+	# value is not decisive as it is used as a last resort host regardless.
+	# However, you must set it for any further virtual host explicitly.
+	# ServerName www.example.com
+
+	# ServerAdmin webmaster@localhost
+	DocumentRoot /var/www/html/public
+
+    <Directory /var/www/html/public>
+        AllowOverride All
+        Order Allow,Deny
+        Allow from All
+    </Directory>
+
+	# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
+	# error, crit, alert, emerg.
+	# It is also possible to configure the loglevel for particular
+	# modules, e.g.
+	# ErrorLog /var/www/html/var/log/apache-error.log
+
+</VirtualHost>
diff --git a/lib/arc2/docker/Docker/arc2/arc2.sh b/lib/arc2/docker/Docker/arc2/arc2.sh
new file mode 100644
index 0000000000000000000000000000000000000000..668d4dbf925d17ff9fb83968690056880c2a6c91
--- /dev/null
+++ b/lib/arc2/docker/Docker/arc2/arc2.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+apache2-foreground
+
+tail -f /dev/null
diff --git a/lib/arc2/docker/Docker/arc2/custom.ini b/lib/arc2/docker/Docker/arc2/custom.ini
new file mode 100644
index 0000000000000000000000000000000000000000..9f8298152ffc562ab3c7a7b645cc79bf33c4fac8
--- /dev/null
+++ b/lib/arc2/docker/Docker/arc2/custom.ini
@@ -0,0 +1,31 @@
+; phpmyadmin related, for bigger uploads
+file_uploads = On
+memory_limit = 512M
+upload_max_filesize = 64M
+post_max_size = 64M
+max_execution_time = 600
+
+; error reporting
+error_reporting = E_ALL
+display_errors = On
+display_startup_errors = On
+
+; opcache
+; https://symfony.com/doc/current/performance.html;configure-opcache-for-maximum-performance
+;
+; important note: if active, it also caches templates!
+;
+; [opcache]
+; zend_extension=opcache.so
+; opcache.enable=1
+; opcache.enable_cli=1
+; 0 means it will check on every request
+; 0 is irrelevant if opcache.validate_timestamps=0 which is desirable in production
+; opcache.fast_shutdown=1
+; opcache.interned_strings_buffer=16
+; opcache.max_accelerated_files=20000
+; opcache.max_wasted_percentage=10
+; opcache.memory_consumption=256
+; opcache.revalidate_freq=0
+; opcache.save_comments=1
+; opcache.validate_timestamps=0
diff --git a/lib/arc2/docker/Makefile b/lib/arc2/docker/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..68f8b94b033968b5593232c9de1cc19d1f19e8bb
--- /dev/null
+++ b/lib/arc2/docker/Makefile
@@ -0,0 +1,16 @@
+default:
+	make build
+	make run
+	docker exec -it --user arc2 docker_arc2_1 bash
+
+build:
+	docker-compose build
+
+clean:
+	-@docker ps -a -q | xargs docker stop
+	-@docker ps -a -q | xargs docker rm
+	-@docker volume ls -f dangling=true -q| xargs docker volume rm
+	docker images --quiet --filter=dangling=true | xargs --no-run-if-empty docker rmi -f
+
+run:
+	docker-compose up --build -d --remove-orphans
diff --git a/lib/arc2/docker/docker-compose.yml-dist b/lib/arc2/docker/docker-compose.yml-dist
new file mode 100644
index 0000000000000000000000000000000000000000..aba691e4b9c68538b2a9924d40c3a1e65e2188a1
--- /dev/null
+++ b/lib/arc2/docker/docker-compose.yml-dist
@@ -0,0 +1,52 @@
+version: '2'
+services:
+    # for development, acting like a real one
+    db:
+      image: mysql:5.7
+      environment:
+          MYSQL_DATABASE: arc2
+          MYSQL_ROOT_PASSWORD: Pass123
+      volumes:
+          - /path/to/your/html:/var/lib/mysql
+
+    # for tests
+    dbtest:
+        image: mysql:5.7
+        environment:
+            MYSQL_DATABASE: arc2
+            MYSQL_ROOT_PASSWORD: Pass123
+        volumes:
+            - data:/var/cache
+            - data:/var/lib/mysql
+
+    phpmyadmin:
+        image: phpmyadmin/phpmyadmin
+        links:
+            - db:mysql
+        ports:
+            - 8022:80
+        environment:
+            MYSQL_USERNAME: root
+            MYSQL_ROOT_PASSWORD: Pass123
+            PMA_HOST: db
+        volumes:
+            # custom php.ini settings (change upload restrictions)
+            - ./Docker/arc2/custom.ini:/usr/local/etc/php/conf.d/custom.ini
+
+    arc2:
+        build:
+            ./Docker/arc2
+        volumes:
+            - /path/to/your/html:/var/www/html
+            # custom php.ini settings (change error reporting etc.)
+            - ./Docker/arc2/custom.ini:/usr/local/etc/php/conf.d/custom.ini
+        ports:
+            - 8023:80
+        links:
+            - db:mysql
+
+volumes:
+    data:
+        driver_opts:
+            type: tmpfs
+            device: tmpfs
diff --git a/lib/arc2/extractors/ARC2_DcExtractor.php b/lib/arc2/extractors/ARC2_DcExtractor.php
index 778c335ba1305f99f04e9681268099fab97e7b83..cab978f86e816b03d90cbdec95222bb02c6a6d56 100644
--- a/lib/arc2/extractors/ARC2_DcExtractor.php
+++ b/lib/arc2/extractors/ARC2_DcExtractor.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 DC Extractor
 author:   Benjamin Nowack
diff --git a/lib/arc2/extractors/ARC2_ErdfExtractor.php b/lib/arc2/extractors/ARC2_ErdfExtractor.php
index 4da20bc8c59b88c17694791b0b5561ac765fbe41..1edb2197e3b1c18fb6d8bc76346764ad7f520f48 100644
--- a/lib/arc2/extractors/ARC2_ErdfExtractor.php
+++ b/lib/arc2/extractors/ARC2_ErdfExtractor.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 eRDF Extractor (w/o link title generation)
 author:   Benjamin Nowack
diff --git a/lib/arc2/extractors/ARC2_MicroformatsExtractor.php b/lib/arc2/extractors/ARC2_MicroformatsExtractor.php
index 67ebb68b80ba0b70de93cb8abbe76ce8562a31cc..2fdfd950aabb199c2f0556a90919da1abc2b7c04 100644
--- a/lib/arc2/extractors/ARC2_MicroformatsExtractor.php
+++ b/lib/arc2/extractors/ARC2_MicroformatsExtractor.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 microformats Extractor
 author:   Benjamin Nowack
diff --git a/lib/arc2/extractors/ARC2_OpenidExtractor.php b/lib/arc2/extractors/ARC2_OpenidExtractor.php
index 57e708875e72927d58ebad6b88a64a822bb73dbd..73e5287e3038771d2a8d07b7dbcc8b029a08a4cc 100644
--- a/lib/arc2/extractors/ARC2_OpenidExtractor.php
+++ b/lib/arc2/extractors/ARC2_OpenidExtractor.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 foaf:openid Extractor
 author:   Benjamin Nowack
diff --git a/lib/arc2/extractors/ARC2_PoshRdfExtractor.php b/lib/arc2/extractors/ARC2_PoshRdfExtractor.php
old mode 100644
new mode 100755
index 40d83685382392bcd11b5daf57f236733f4dc3a5..56e5e5e9ed73da09dbfeb06192798210615ed314
--- a/lib/arc2/extractors/ARC2_PoshRdfExtractor.php
+++ b/lib/arc2/extractors/ARC2_PoshRdfExtractor.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 poshRDF Extractor
 author:   Benjamin Nowack
diff --git a/lib/arc2/extractors/ARC2_RDFExtractor.php b/lib/arc2/extractors/ARC2_RDFExtractor.php
index df9ec2379d7e97859fcce1e6162ff07c2b8b9a28..232c5863d960b71ae6b5cd7795bb8d8f87f942a2 100644
--- a/lib/arc2/extractors/ARC2_RDFExtractor.php
+++ b/lib/arc2/extractors/ARC2_RDFExtractor.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 RDF Extractor
 author:   Benjamin Nowack
diff --git a/lib/arc2/extractors/ARC2_RdfaExtractor.php b/lib/arc2/extractors/ARC2_RdfaExtractor.php
index b0a00b07f52cc4ce3d3509688def568467cadbb3..45ad144de1d69df3cc85b0bf49aebc8bde67df0f 100644
--- a/lib/arc2/extractors/ARC2_RdfaExtractor.php
+++ b/lib/arc2/extractors/ARC2_RdfaExtractor.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 RDFa Extractor
 author:   Benjamin Nowack
diff --git a/lib/arc2/extractors/ARC2_TwitterProfilePicExtractor.php b/lib/arc2/extractors/ARC2_TwitterProfilePicExtractor.php
old mode 100644
new mode 100755
index 048cc63f524771c871dc0af66ae9fcf98e5c236c..80eda80c8f0ccbbdb1af6f14c90a4f04c6b4607b
--- a/lib/arc2/extractors/ARC2_TwitterProfilePicExtractor.php
+++ b/lib/arc2/extractors/ARC2_TwitterProfilePicExtractor.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 Extractor
 author:   Benjamin Nowack
diff --git a/lib/arc2/parsers/ARC2_AtomParser.php b/lib/arc2/parsers/ARC2_AtomParser.php
index cabef407d01efc84910a286baed2a2663845c96e..e6a61ab9aafa4fd499ac4a180a49a89062c3569d 100644
--- a/lib/arc2/parsers/ARC2_AtomParser.php
+++ b/lib/arc2/parsers/ARC2_AtomParser.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 Atom Parser
 author:   Benjamin Nowack
@@ -10,236 +10,252 @@ version:  2010-11-16
 
 ARC2::inc('LegacyXMLParser');
 
-class ARC2_AtomParser extends ARC2_LegacyXMLParser {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* reader */
-    parent::__init();
-    $this->triples = array();
-    $this->target_encoding = '';
-    $this->t_count = 0;
-    $this->added_triples = array();
-    $this->skip_dupes = false;
-    $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
-    $this->bnode_id = 0;
-    $this->cache = array();
-    $this->allowCDataNodes = 0;
-  }
-  
-  /*  */
-  
-  function done() {
-    $this->extractRDF();
-  }
-  
-  /*  */
-  
-  function setReader(&$reader) {
-    $this->reader = $reader;
-  }
-  
-  function createBnodeID(){
-    $this->bnode_id++;
-    return '_:' . $this->bnode_prefix . $this->bnode_id;
-  }
-  
-  function addT($t) {
-    //if (!isset($t['o_datatype']))
-    if ($this->skip_dupes) {
-      //$h = md5(print_r($t, 1));
-      $h = md5(serialize($t));
-      if (!isset($this->added_triples[$h])) {
-        $this->triples[$this->t_count] = $t;
-        $this->t_count++;
-        $this->added_triples[$h] = true;
-      }
+class ARC2_AtomParser extends ARC2_LegacyXMLParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
     }
-    else {
-      $this->triples[$this->t_count] = $t;
-      $this->t_count++;
+
+    public function __init()
+    {/* reader */
+        parent::__init();
+        $this->triples = [];
+        $this->target_encoding = '';
+        $this->t_count = 0;
+        $this->added_triples = [];
+        $this->skip_dupes = false;
+        $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
+        $this->bnode_id = 0;
+        $this->cache = [];
+        $this->allowCDataNodes = 0;
     }
-  }
-
-  function getTriples() {
-    return $this->v('triples', array());
-  }
-
-  function countTriples() {
-    return $this->t_count;
-  }
-  
-  function getSimpleIndex($flatten_objects = 1, $vals = '') {
-    return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
-  }
-
-  /*  */
-
-  function extractRDF() {
-    $index = $this->getNodeIndex();
-    //print_r($index);
-    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
-    $this->atom = 'http://www.w3.org/2005/Atom';
-    $this->rss = 'http://purl.org/rss/1.0/';
-    $this->dc = 'http://purl.org/dc/elements/1.1/';
-    $this->sioc = 'http://rdfs.org/sioc/ns#';
-    $this->dct = 'http://purl.org/dc/terms/';
-    $this->content = 'http://purl.org/rss/1.0/modules/content/';
-    $this->enc = 'http://purl.oclc.org/net/rss_2.0/enc#';
-    $this->mappings = array(
-      'feed' => $this->rss . 'channel',
-      'entry' => $this->rss . 'item',
-      'title' => $this->rss . 'title',
-      'link' => $this->rss . 'link',
-      'summary' => $this->rss . 'description',
-      'content' => $this->content . 'encoded',
-      'id' => $this->dc . 'identifier',
-      'author' => $this->dc . 'creator',
-      'category' => $this->dc . 'subject',
-      'updated' => $this->dc . 'date',
-      'source' => $this->dc . 'source',
-    );
-    $this->dt_props = array(
-      $this->dc . 'identifier',
-      $this->rss . 'link'
-    );
-    foreach ($index as $p_id => $nodes) {
-      foreach ($nodes as $pos => $node) {
-        $tag = $this->v('tag', '', $node);
-        if ($tag == 'feed') {
-          $struct = $this->extractChannel($index[$node['id']]);
-          $triples = ARC2::getTriplesFromIndex($struct);
-          foreach ($triples as $t) {
-            $this->addT($t);
-          }
-        }
-        elseif ($tag == 'entry') {
-          $struct = $this->extractItem($index[$node['id']]);
-          $triples = ARC2::getTriplesFromIndex($struct);
-          foreach ($triples as $t) {
-            $this->addT($t);
-          }
-        }
-      }
+
+    public function done()
+    {
+        $this->extractRDF();
     }
-  }
-  
-  function extractChannel($els) {
-    list($props, $sub_index) = $this->extractProps($els, 'channel');
-    $uri = $props[$this->rss . 'link'][0]['value'];
-    return ARC2::getMergedIndex(array($uri => $props), $sub_index);
-  }
-  
-  function extractItem($els) {
-    list($props, $sub_index) = $this->extractProps($els, 'item');
-    $uri = $props[$this->rss . 'link'][0]['value'];
-    return ARC2::getMergedIndex(array($uri => $props), $sub_index);
-  }
-  
-  function extractProps($els, $container) {
-    $r = array($this->rdf . 'type' => array(array('value' => $this->rss . $container, 'type' => 'uri')));
-    $sub_index = array();
-    foreach ($els as $info) {
-      /* key */
-      $tag = $info['tag'];
-      if (!preg_match('/^[a-z0-9]+\:/i', $tag)) {
-        $k = isset($this->mappings[$tag]) ? $this->mappings[$tag] : '';
-      }
-      elseif (isset($this->mappings[$tag])) {
-        $k = $this->mappings[$tag];
-      }
-      else {/* qname */
-        $k = $this->expandPName($tag);
-      }
-      //echo $k . "\n";
-      if (($container == 'channel') && ($k == $this->rss . 'item')) continue;
-      /* val */
-      $v = trim($info['cdata']);
-      if (!$v) $v = $this->v('href uri', '', $info['a']);
-      /* prop */
-      if ($k) {
-        /* content handling */
-        if (in_array($k, array($this->rss . 'description', $this->content . 'encoded'))) {
-          $v = $this->getNodeContent($info);
-        }
-        /* source handling */
-        elseif ($k == $this->dc . 'source') {
-          $sub_nodes = $this->node_index[$info['id']];
-          foreach ($sub_nodes as $sub_pos => $sub_info) {
-            if ($sub_info['tag'] == 'id') {
-              $v = trim($sub_info['cdata']);
-            }
-          }
-        }
-        /* link handling */
-        elseif ($k == $this->rss . 'link') {
-          if ($link_type = $this->v('type', '', $info['a'])) {
-            $k2 = $this->dc . 'format';
-            if (!isset($sub_index[$v])) $sub_index[$v] = array();
-            if (!isset($sub_index[$v][$k2])) $sub_index[$v][$k2] = array();
-            $sub_index[$v][$k2][] = array('value' => $link_type, 'type' => 'literal');
-          }
-        }
-        /* author handling */
-        elseif ($k == $this->dc . 'creator') {
-          $sub_nodes = $this->node_index[$info['id']];
-          foreach ($sub_nodes as $sub_pos => $sub_info) {
-            if ($sub_info['tag'] == 'name') {
-              $v = trim($sub_info['cdata']);
-            }
-            if ($sub_info['tag'] == 'uri') {
-              $k2 = $this->sioc . 'has_creator';
-              $v2 = trim($sub_info['cdata']);
-              if (!isset($r[$k2])) $r[$k2] = array();
-              $r[$k2][] = array('value' => $v2, 'type' => 'uri');
+
+    public function setReader(&$reader)
+    {
+        $this->reader = $reader;
+    }
+
+    public function createBnodeID()
+    {
+        ++$this->bnode_id;
+
+        return '_:'.$this->bnode_prefix.$this->bnode_id;
+    }
+
+    public function addT($t)
+    {
+        //if (!isset($t['o_datatype']))
+        if ($this->skip_dupes) {
+            //$h = md5(print_r($t, 1));
+            $h = md5(serialize($t));
+            if (!isset($this->added_triples[$h])) {
+                $this->triples[$this->t_count] = $t;
+                ++$this->t_count;
+                $this->added_triples[$h] = true;
             }
-          }
+        } else {
+            $this->triples[$this->t_count] = $t;
+            ++$this->t_count;
         }
-        /* date handling */
-        elseif (in_array($k, array($this->dc . 'date', $this->dct . 'modified'))) {
-          if (!preg_match('/^[0-9]{4}/', $v) && ($sub_v = strtotime($v)) && ($sub_v != -1)) {
-            $tz = date('Z', $sub_v); /* timezone offset */
-            $sub_v -= $tz; /* utc */
-            $v = date('Y-m-d\TH:i:s\Z', $sub_v);
-          }
-        }
-        /* tag handling */
-        elseif ($k == $this->dc . 'subject') {
-          $v = $this->v('term', '', $info['a']);
-        }
-        /* other attributes in closed tags */
-        elseif (!$v && ($info['state'] == 'closed') && $info['a']) {
-          foreach ($info['a'] as $sub_k => $sub_v) {
-            if (!preg_match('/(xmlns|\:|type)/', $sub_k)) {
-              $v = $sub_v;
-              break;
+    }
+
+    public function getTriples()
+    {
+        return $this->v('triples', []);
+    }
+
+    public function countTriples()
+    {
+        return $this->t_count;
+    }
+
+    public function getSimpleIndex($flatten_objects = 1, $vals = '')
+    {
+        return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
+    }
+
+    public function extractRDF()
+    {
+        $index = $this->getNodeIndex();
+        //print_r($index);
+        $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+        $this->atom = 'http://www.w3.org/2005/Atom';
+        $this->rss = 'http://purl.org/rss/1.0/';
+        $this->dc = 'http://purl.org/dc/elements/1.1/';
+        $this->sioc = 'http://rdfs.org/sioc/ns#';
+        $this->dct = 'http://purl.org/dc/terms/';
+        $this->content = 'http://purl.org/rss/1.0/modules/content/';
+        $this->enc = 'http://purl.oclc.org/net/rss_2.0/enc#';
+        $this->mappings = [
+            'feed' => $this->rss.'channel',
+            'entry' => $this->rss.'item',
+            'title' => $this->rss.'title',
+            'link' => $this->rss.'link',
+            'summary' => $this->rss.'description',
+            'content' => $this->content.'encoded',
+            'id' => $this->dc.'identifier',
+            'author' => $this->dc.'creator',
+            'category' => $this->dc.'subject',
+            'updated' => $this->dc.'date',
+            'source' => $this->dc.'source',
+        ];
+        $this->dt_props = [
+            $this->dc.'identifier',
+            $this->rss.'link',
+        ];
+        foreach ($index as $p_id => $nodes) {
+            foreach ($nodes as $pos => $node) {
+                $tag = $this->v('tag', '', $node);
+                if ('feed' == $tag) {
+                    $struct = $this->extractChannel($index[$node['id']]);
+                    $triples = ARC2::getTriplesFromIndex($struct);
+                    foreach ($triples as $t) {
+                        $this->addT($t);
+                    }
+                } elseif ('entry' == $tag) {
+                    $struct = $this->extractItem($index[$node['id']]);
+                    $triples = ARC2::getTriplesFromIndex($struct);
+                    foreach ($triples as $t) {
+                        $this->addT($t);
+                    }
+                }
             }
-          }
         }
-        if (!isset($r[$k])) $r[$k] = array();
-        $r[$k][] = array('value' => $v, 'type' => in_array($k, $this->dt_props) || !preg_match('/^[a-z0-9]+\:[^\s]+$/is', $v) ? 'literal' : 'uri');
-      }
     }
-    return array($r, $sub_index);
-  }
-  
-  function initXMLParser() {
-    if (!isset($this->xml_parser)) {
-      $enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
-      $parser = xml_parser_create($enc);
-      xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
-      xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
-      xml_set_element_handler($parser, 'open', 'close');
-      xml_set_character_data_handler($parser, 'cData');
-      xml_set_start_namespace_decl_handler($parser, 'nsDecl');
-      xml_set_object($parser, $this);
-      $this->xml_parser = $parser;
+
+    public function extractChannel($els)
+    {
+        list($props, $sub_index) = $this->extractProps($els, 'channel');
+        $uri = $props[$this->rss.'link'][0]['value'];
+
+        return ARC2::getMergedIndex([$uri => $props], $sub_index);
     }
-  }
 
-  /*  */
+    public function extractItem($els)
+    {
+        list($props, $sub_index) = $this->extractProps($els, 'item');
+        $uri = $props[$this->rss.'link'][0]['value'];
 
+        return ARC2::getMergedIndex([$uri => $props], $sub_index);
+    }
 
+    public function extractProps($els, $container)
+    {
+        $r = [$this->rdf.'type' => [['value' => $this->rss.$container, 'type' => 'uri']]];
+        $sub_index = [];
+        foreach ($els as $info) {
+            /* key */
+            $tag = $info['tag'];
+            if (!preg_match('/^[a-z0-9]+\:/i', $tag)) {
+                $k = isset($this->mappings[$tag]) ? $this->mappings[$tag] : '';
+            } elseif (isset($this->mappings[$tag])) {
+                $k = $this->mappings[$tag];
+            } else {/* qname */
+                $k = $this->expandPName($tag);
+            }
+            //echo $k . "\n";
+            if (('channel' == $container) && ($k == $this->rss.'item')) {
+                continue;
+            }
+            /* val */
+            $v = trim($info['cdata']);
+            if (!$v) {
+                $v = $this->v('href uri', '', $info['a']);
+            }
+            /* prop */
+            if ($k) {
+                /* content handling */
+                if (in_array($k, [$this->rss.'description', $this->content.'encoded'])) {
+                    $v = $this->getNodeContent($info);
+                }
+                /* source handling */
+                elseif ($k == $this->dc.'source') {
+                    $sub_nodes = $this->node_index[$info['id']];
+                    foreach ($sub_nodes as $sub_pos => $sub_info) {
+                        if ('id' == $sub_info['tag']) {
+                            $v = trim($sub_info['cdata']);
+                        }
+                    }
+                }
+                /* link handling */
+                elseif ($k == $this->rss.'link') {
+                    if ($link_type = $this->v('type', '', $info['a'])) {
+                        $k2 = $this->dc.'format';
+                        if (!isset($sub_index[$v])) {
+                            $sub_index[$v] = [];
+                        }
+                        if (!isset($sub_index[$v][$k2])) {
+                            $sub_index[$v][$k2] = [];
+                        }
+                        $sub_index[$v][$k2][] = ['value' => $link_type, 'type' => 'literal'];
+                    }
+                }
+                /* author handling */
+                elseif ($k == $this->dc.'creator') {
+                    $sub_nodes = $this->node_index[$info['id']];
+                    foreach ($sub_nodes as $sub_pos => $sub_info) {
+                        if ('name' == $sub_info['tag']) {
+                            $v = trim($sub_info['cdata']);
+                        }
+                        if ('uri' == $sub_info['tag']) {
+                            $k2 = $this->sioc.'has_creator';
+                            $v2 = trim($sub_info['cdata']);
+                            if (!isset($r[$k2])) {
+                                $r[$k2] = [];
+                            }
+                            $r[$k2][] = ['value' => $v2, 'type' => 'uri'];
+                        }
+                    }
+                }
+                /* date handling */
+                elseif (in_array($k, [$this->dc.'date', $this->dct.'modified'])) {
+                    if (!preg_match('/^[0-9]{4}/', $v) && ($sub_v = strtotime($v)) && ($sub_v != -1)) {
+                        $tz = date('Z', $sub_v); /* timezone offset */
+                        $sub_v -= $tz; /* utc */
+                        $v = date('Y-m-d\TH:i:s\Z', $sub_v);
+                    }
+                }
+                /* tag handling */
+                elseif ($k == $this->dc.'subject') {
+                    $v = $this->v('term', '', $info['a']);
+                }
+                /* other attributes in closed tags */
+                elseif (!$v && ('closed' == $info['state']) && $info['a']) {
+                    foreach ($info['a'] as $sub_k => $sub_v) {
+                        if (!preg_match('/(xmlns|\:|type)/', $sub_k)) {
+                            $v = $sub_v;
+                            break;
+                        }
+                    }
+                }
+                if (!isset($r[$k])) {
+                    $r[$k] = [];
+                }
+                $r[$k][] = ['value' => $v, 'type' => in_array($k, $this->dt_props) || !preg_match('/^[a-z0-9]+\:[^\s]+$/is', $v) ? 'literal' : 'uri'];
+            }
+        }
+
+        return [$r, $sub_index];
+    }
+
+    public function initXMLParser()
+    {
+        if (!isset($this->xml_parser)) {
+            $enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
+            $parser = xml_parser_create($enc);
+            xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
+            xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
+            xml_set_element_handler($parser, 'open', 'close');
+            xml_set_character_data_handler($parser, 'cData');
+            xml_set_start_namespace_decl_handler($parser, 'nsDecl');
+            xml_set_object($parser, $this);
+            $this->xml_parser = $parser;
+        }
+    }
 }
diff --git a/lib/arc2/parsers/ARC2_CBJSONParser.php b/lib/arc2/parsers/ARC2_CBJSONParser.php
old mode 100644
new mode 100755
index d59f77ea61067dd66073393542f678e01136d7a8..d1cbf5a8313c7c90fde679838b0de57f4d077673
--- a/lib/arc2/parsers/ARC2_CBJSONParser.php
+++ b/lib/arc2/parsers/ARC2_CBJSONParser.php
@@ -1,267 +1,343 @@
 <?php
 /**
- * ARC2 CrunchBase API JSON Parser
+ * ARC2 CrunchBase API JSON Parser.
  *
  * @author Benjamin Nowack <bnowack@semsol.com>
- * @license http://arc.semsol.org/license
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('JSONParser');
 
-class ARC2_CBJSONParser extends ARC2_JSONParser {
+class ARC2_CBJSONParser extends ARC2_JSONParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
+
+    public function __init()
+    {/* reader */
+        parent::__init();
+        $this->base = 'http://cb.semsol.org/';
+        $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+        $this->default_ns = $this->base.'ns#';
+        $this->nsp = [$this->rdf => 'rdf'];
+    }
 
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* reader */
-    parent::__init();
-    $this->base = 'http://cb.semsol.org/';
-    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
-    $this->default_ns = $this->base . 'ns#';
-    $this->nsp = array($this->rdf => 'rdf');
-  }
-  
-  /*  */
+    public function done()
+    {
+        $this->extractRDF();
+    }
 
-  function done() {
-    $this->extractRDF();
-  }
-  
-  function extractRDF() {
-    $struct = $this->struct;
-    if ($type = $this->getStructType($struct)) {
-      $s = $this->getResourceID($struct, $type);
-      /* rdf:type */
-      $this->addT($s, $this->rdf . 'type', $this->default_ns . $this->camelCase($type), 'uri', 'uri');
-      /* explicit triples */
-      $this->extractResourceRDF($struct, $s);
+    public function extractRDF($formats = '')
+    {
+        $struct = $this->struct;
+        if ($type = $this->getStructType($struct)) {
+            $s = $this->getResourceID($struct, $type);
+            /* rdf:type */
+            $this->addT($s, $this->rdf.'type', $this->default_ns.$this->camelCase($type), 'uri', 'uri');
+            /* explicit triples */
+            $this->extractResourceRDF($struct, $s);
+        }
     }
-  }
-  
-  function getStructType($struct, $rel = '') {
-    /* url-based */
-    if ($url = $this->v('crunchbase_url', '', $struct)) {
-      return preg_replace('/^.*crunchbase\.com\/([^\/]+)\/.*$/', '\\1', $url);
+
+    public function getStructType($struct, $rel = '')
+    {
+        /* url-based */
+        if ($url = $this->v('crunchbase_url', '', $struct)) {
+            return preg_replace('/^.*crunchbase\.com\/([^\/]+)\/.*$/', '\\1', $url);
+        }
+        /* rel-based */
+        if ('person' == $rel) {
+            return 'person';
+        }
+        if ('company' == $rel) {
+            return 'company';
+        }
+        if ('acquiring_company' == $rel) {
+            return 'company';
+        }
+        if ('firm' == $rel) {
+            return 'company';
+        }
+        if ('provider' == $rel) {
+            return 'service-provider';
+        }
+        /* struct-based */
+        if (isset($struct['_type'])) {
+            return $struct['_type'];
+        }
+        if (isset($struct['round_code'])) {
+            return 'funding_round';
+        }
+        if (isset($struct['products'])) {
+            return 'company';
+        }
+        if (isset($struct['first_name'])) {
+            return 'person';
+        }
+        if (isset($struct['investments'])) {
+            return 'financial-organization';
+        }
+        if (isset($struct['launched_year'])) {
+            return 'product';
+        }
+        if (isset($struct['providerships']) && is_array($struct['providerships'])) {
+            return 'service-provider';
+        }
+
+        return '';
     }
-    /* rel-based */
-    if ($rel == 'person') return 'person';
-    if ($rel == 'company') return 'company';
-    if ($rel == 'acquiring_company') return 'company';
-    if ($rel == 'firm') return 'company';
-    if ($rel == 'provider') return 'service-provider';
-    /* struct-based */
-    if (isset($struct['_type'])) return $struct['_type'];
-    if (isset($struct['round_code'])) return 'funding_round';
-    if (isset($struct['products'])) return 'company';
-    if (isset($struct['first_name'])) return 'person';
-    if (isset($struct['investments'])) return 'financial-organization';
-    if (isset($struct['launched_year'])) return 'product';
-    if (isset($struct['providerships']) && is_array($struct['providerships'])) return 'service-provider';
-    return '';
-  }
-  
-  function getResourceID($struct, $type) {
-    if ($type && isset($struct['permalink'])) {
-      return $this->base . $type . '/' . $struct['permalink'] . '#self';
+
+    public function getResourceID($struct, $type)
+    {
+        if ($type && isset($struct['permalink'])) {
+            return $this->base.$type.'/'.$struct['permalink'].'#self';
+        }
+
+        return $this->createBnodeID();
     }
-    return $this->createBnodeID();
-  }
-  
-  function getPropertyURI($name, $ns = '') {
-    if (!$ns) $ns = $this->default_ns;
-    if (preg_match('/^(product|funding_round|investment|acquisition|.+ship|office|milestone|.+embed|.+link|degree|fund)s/', $name, $m)) $name = $m[1];
-    if ($name == 'tag_list') $name = 'tag';
-    if ($name == 'competitions') $name = 'competitor';
-    return $ns . $name;
-  }
 
-  function createSubURI($s, $k, $pos) {
-    $s = str_replace('#self', '/', $s);
-    if (preg_match('/(office|ship|investment|milestone|fund|embed|link)s$/', $k)) $k = substr($k, 0, -1);
-    return $s . $k . '-' . ($pos + 1) . '#self';
-  }
-  
-  /*  */
-  
-  function extractResourceRDF($struct, $s, $pos = 0) {
-    $s_type = preg_match('/^\_\:/', $s) ? 'bnode' : 'uri';
-    $date_prefixes = array();
-    foreach ($struct as $k => $v) {
-      if ($k == 'acquisition') $k = 'exit';
-      if (preg_match('/^(.*)\_(year|month|day)$/', $k, $m)) {
-        if (!in_array($m[1], $date_prefixes)) $date_prefixes[] = $m[1];
-      }
-      $sub_m = 'extract' . $this->camelCase($k) . 'RDF';
-      if (method_exists($this, $sub_m)) {
-        $this->$sub_m($s, $s_type, $v);
-        continue;
-      }
-      $p = $this->getPropertyURI($k);
-      if (!$v) continue;
-      /* simple, single v */
-      if (!is_array($v)) {
-        $o_type = preg_match('/^[a-z]+\:[^\s]+$/is', $v) ? 'uri' : 'literal';
-        $v = trim($v);
-        if (preg_match('/^https?\:\/\/[^\/]+$/', $v)) $v .= '/';
-        $this->addT($s, $p, $v, $s_type, $o_type);
-        /* rdfs:label */
-        if ($k == 'name') $this->addT($s, 'http://www.w3.org/2000/01/rdf-schema#label', $v, $s_type, $o_type);
-        /* dc:identifier */
-        //if ($k == 'permalink') $this->addT($s, 'http://purl.org/dc/elements/1.1/identifier', $v, $s_type, $o_type);
-      }
-      /* structured, single v */
-      elseif (!$this->isFlatArray($v)) {
-        if ($o_type = $this->getStructType($v, $k)) {/* known type */
-          $o = $this->getResourceID($v, $o_type);
-          $this->addT($s, $p, $o, $s_type, 'uri');
-          $this->addT($o, $this->rdf . 'type', $this->default_ns . $this->camelCase($o_type), 'uri', 'uri');
-        }
-        else {/* unknown type */
-          $o = $this->createSubURI($s, $k, $pos);
-          $this->addT($s, $p, $o, $s_type, 'uri');
-          $this->extractResourceRDF($v, $o);
-        }
-      }
-      /* value list */
-      else {
-        foreach ($v as $sub_pos => $sub_v) {
-          $this->extractResourceRDF(array($k => $sub_v), $s, $sub_pos);
-        }
-      }
+    public function getPropertyURI($name, $ns = '')
+    {
+        if (!$ns) {
+            $ns = $this->default_ns;
+        }
+        if (preg_match('/^(product|funding_round|investment|acquisition|.+ship|office|milestone|.+embed|.+link|degree|fund)s/', $name, $m)) {
+            $name = $m[1];
+        }
+        if ('tag_list' == $name) {
+            $name = 'tag';
+        }
+        if ('competitions' == $name) {
+            $name = 'competitor';
+        }
+
+        return $ns.$name;
     }
-    /* infer XSD triples */
-    foreach ($date_prefixes as $prefix) {
-      $this->inferDate($prefix, $s, $struct);
+
+    public function createSubURI($s, $k, $pos)
+    {
+        $s = str_replace('#self', '/', $s);
+        if (preg_match('/(office|ship|investment|milestone|fund|embed|link)s$/', $k)) {
+            $k = substr($k, 0, -1);
+        }
+
+        return $s.$k.'-'.($pos + 1).'#self';
     }
-  }
 
-  function isFlatArray($v) {
-    foreach ($v as $k => $sub_v) {
-      return is_numeric($k) ? 1 : 0;
+    public function extractResourceRDF($struct, $s, $pos = 0)
+    {
+        $s_type = preg_match('/^\_\:/', $s) ? 'bnode' : 'uri';
+        $date_prefixes = [];
+        foreach ($struct as $k => $v) {
+            if ('acquisition' == $k) {
+                $k = 'exit';
+            }
+            if (preg_match('/^(.*)\_(year|month|day)$/', $k, $m)) {
+                if (!in_array($m[1], $date_prefixes)) {
+                    $date_prefixes[] = $m[1];
+                }
+            }
+            $sub_m = 'extract'.$this->camelCase($k).'RDF';
+            if (method_exists($this, $sub_m)) {
+                $this->$sub_m($s, $s_type, $v);
+                continue;
+            }
+            $p = $this->getPropertyURI($k);
+            if (!$v) {
+                continue;
+            }
+            /* simple, single v */
+            if (!is_array($v)) {
+                $o_type = preg_match('/^[a-z]+\:[^\s]+$/is', $v) ? 'uri' : 'literal';
+                $v = trim($v);
+                if (preg_match('/^https?\:\/\/[^\/]+$/', $v)) {
+                    $v .= '/';
+                }
+                $this->addT($s, $p, $v, $s_type, $o_type);
+                /* rdfs:label */
+                if ('name' == $k) {
+                    $this->addT($s, 'http://www.w3.org/2000/01/rdf-schema#label', $v, $s_type, $o_type);
+                }
+                /* dc:identifier */
+        //if ($k == 'permalink') $this->addT($s, 'http://purl.org/dc/elements/1.1/identifier', $v, $s_type, $o_type);
+            }
+            /* structured, single v */
+            elseif (!$this->isFlatArray($v)) {
+                if ($o_type = $this->getStructType($v, $k)) {/* known type */
+                    $o = $this->getResourceID($v, $o_type);
+                    $this->addT($s, $p, $o, $s_type, 'uri');
+                    $this->addT($o, $this->rdf.'type', $this->default_ns.$this->camelCase($o_type), 'uri', 'uri');
+                } else {/* unknown type */
+                    $o = $this->createSubURI($s, $k, $pos);
+                    $this->addT($s, $p, $o, $s_type, 'uri');
+                    $this->extractResourceRDF($v, $o);
+                }
+            }
+            /* value list */
+            else {
+                foreach ($v as $sub_pos => $sub_v) {
+                    $this->extractResourceRDF([$k => $sub_v], $s, $sub_pos);
+                }
+            }
+        }
+        /* infer XSD triples */
+        foreach ($date_prefixes as $prefix) {
+            $this->inferDate($prefix, $s, $struct);
+        }
     }
-  }
-  
-  /*  */
-  
-  function extractTagListRDF($s, $s_type,  $v) {
-    if (!$v) return 0;
-    $tags = preg_split('/\, /', $v);
-    foreach ($tags as $tag) {
-      if (!trim($tag)) continue;
-      $this->addT($s, $this->getPropertyURI('tag'), $tag, $s_type, 'literal');
+
+    public function isFlatArray($v)
+    {
+        foreach ($v as $k => $sub_v) {
+            return is_numeric($k) ? 1 : 0;
+        }
     }
-  }
 
-  function extractImageRDF($s, $s_type, $v, $rel = 'image') {
-    if (!$v) return 1;
-    $sizes = $v['available_sizes'];
-    foreach ($sizes as $size) {
-      $w = $size[0][0];
-      $h = $size[0][1];
-      $img = 'http://www.crunchbase.com/' . $size[1];
-      $this->addT($s, $this->getPropertyURI($rel), $img, $s_type, 'uri');
-      $this->addT($img, $this->getPropertyURI('width'), $w, 'uri', 'literal');
-      $this->addT($img, $this->getPropertyURI('height'), $h, 'uri', 'literal');
+    public function extractTagListRDF($s, $s_type, $v)
+    {
+        if (!$v) {
+            return 0;
+        }
+        $tags = preg_split('/\, /', $v);
+        foreach ($tags as $tag) {
+            if (!trim($tag)) {
+                continue;
+            }
+            $this->addT($s, $this->getPropertyURI('tag'), $tag, $s_type, 'literal');
+        }
     }
-  }
 
-  function extractScreenshotsRDF($s, $s_type, $v) {
-    if (!$v) return 1;
-    foreach ($v as $sub_v) {
-      $this->extractImageRDF($s, $s_type, $sub_v, 'screenshot');
+    public function extractImageRDF($s, $s_type, $v, $rel = 'image')
+    {
+        if (!$v) {
+            return 1;
+        }
+        $sizes = $v['available_sizes'];
+        foreach ($sizes as $size) {
+            $w = $size[0][0];
+            $h = $size[0][1];
+            $img = 'http://www.crunchbase.com/'.$size[1];
+            $this->addT($s, $this->getPropertyURI($rel), $img, $s_type, 'uri');
+            $this->addT($img, $this->getPropertyURI('width'), $w, 'uri', 'literal');
+            $this->addT($img, $this->getPropertyURI('height'), $h, 'uri', 'literal');
+        }
     }
-  }
-  
-  function extractProductsRDF($s, $s_type, $v) {
-    foreach ($v as $sub_v) {
-      $o = $this->getResourceID($sub_v, 'product');
-      $this->addT($s, $this->getPropertyURI('product'), $o, $s_type, 'uri');
+
+    public function extractScreenshotsRDF($s, $s_type, $v)
+    {
+        if (!$v) {
+            return 1;
+        }
+        foreach ($v as $sub_v) {
+            $this->extractImageRDF($s, $s_type, $sub_v, 'screenshot');
+        }
     }
-  }
 
-  function extractCompetitionsRDF($s, $s_type, $v) {
-    foreach ($v as $sub_v) {
-      $o = $this->getResourceID($sub_v['competitor'], 'company');
-      $this->addT($s, $this->getPropertyURI('competitor'), $o, $s_type, 'uri');
+    public function extractProductsRDF($s, $s_type, $v)
+    {
+        foreach ($v as $sub_v) {
+            $o = $this->getResourceID($sub_v, 'product');
+            $this->addT($s, $this->getPropertyURI('product'), $o, $s_type, 'uri');
+        }
     }
-  }
 
-  function extractFundingRoundsRDF($s, $s_type, $v) {
-    foreach ($v as $pos => $sub_v) {
-      $o = $this->createSubURI($s, 'funding_round', $pos);
-      $this->addT($s, $this->getPropertyURI('funding_round'), $o, $s_type, 'uri');
-      $this->extractResourceRDF($sub_v, $o, $pos);
+    public function extractCompetitionsRDF($s, $s_type, $v)
+    {
+        foreach ($v as $sub_v) {
+            $o = $this->getResourceID($sub_v['competitor'], 'company');
+            $this->addT($s, $this->getPropertyURI('competitor'), $o, $s_type, 'uri');
+        }
     }
-  }
 
-  function extractInvestmentsRDF($s, $s_type, $v) {
-    foreach ($v as $pos => $sub_v) {
-      /* incoming */
-      foreach (array('person' => 'person', 'company' => 'company', 'financial_org' => 'financial-organization') as $k => $type) {
-        if (isset($sub_v[$k])) $this->addT($s, $this->getPropertyURI('investment'), $this->getResourceID($sub_v[$k], $type), $s_type, 'uri');
-      }
-      /* outgoing */
-      if (isset($sub_v['funding_round'])) {
-        $o = $this->createSubURI($s, 'investment', $pos);
-        $this->addT($s, $this->getPropertyURI('investment'), $o, $s_type, 'uri');
-        $this->extractResourceRDF($sub_v['funding_round'], $o, $pos);
-      }
+    public function extractFundingRoundsRDF($s, $s_type, $v)
+    {
+        foreach ($v as $pos => $sub_v) {
+            $o = $this->createSubURI($s, 'funding_round', $pos);
+            $this->addT($s, $this->getPropertyURI('funding_round'), $o, $s_type, 'uri');
+            $this->extractResourceRDF($sub_v, $o, $pos);
+        }
     }
-  }
-  
-  function extractExternalLinksRDF($s, $s_type, $v) {
-    foreach ($v as $sub_v) {
-      $href = $sub_v['external_url'];
-      if (preg_match('/^https?\:\/\/[^\/]+$/', $href)) $href .= '/';
-      $this->addT($s, $this->getPropertyURI('external_link'), $href, $s_type, 'uri');
-      $this->addT($href, $this->getPropertyURI('title'), $sub_v['title'], $s_type, 'literal');
+
+    public function extractInvestmentsRDF($s, $s_type, $v)
+    {
+        foreach ($v as $pos => $sub_v) {
+            /* incoming */
+            foreach (['person' => 'person', 'company' => 'company', 'financial_org' => 'financial-organization'] as $k => $type) {
+                if (isset($sub_v[$k])) {
+                    $this->addT($s, $this->getPropertyURI('investment'), $this->getResourceID($sub_v[$k], $type), $s_type, 'uri');
+                }
+            }
+            /* outgoing */
+            if (isset($sub_v['funding_round'])) {
+                $o = $this->createSubURI($s, 'investment', $pos);
+                $this->addT($s, $this->getPropertyURI('investment'), $o, $s_type, 'uri');
+                $this->extractResourceRDF($sub_v['funding_round'], $o, $pos);
+            }
+        }
     }
-  }
 
-  function extractWebPresencesRDF($s, $s_type, $v) {
-    foreach ($v as $sub_v) {
-      $href = $sub_v['external_url'];
-      if (preg_match('/^https?\:\/\/[^\/]+$/', $href)) $href .= '/';
-      $this->addT($s, $this->getPropertyURI('web_presence'), $href, $s_type, 'uri');
-      $this->addT($href, $this->getPropertyURI('title'), $sub_v['title'], $s_type, 'literal');
+    public function extractExternalLinksRDF($s, $s_type, $v)
+    {
+        foreach ($v as $sub_v) {
+            $href = $sub_v['external_url'];
+            if (preg_match('/^https?\:\/\/[^\/]+$/', $href)) {
+                $href .= '/';
+            }
+            $this->addT($s, $this->getPropertyURI('external_link'), $href, $s_type, 'uri');
+            $this->addT($href, $this->getPropertyURI('title'), $sub_v['title'], $s_type, 'literal');
+        }
     }
-  }
 
-  function extractCreatedAtRDF($s, $s_type,  $v) {
-    $v = $this->getAPIDateXSD($v);
-    $this->addT($s, $this->getPropertyURI('created_at'), $v, $s_type, 'literal');
-  }
+    public function extractWebPresencesRDF($s, $s_type, $v)
+    {
+        foreach ($v as $sub_v) {
+            $href = $sub_v['external_url'];
+            if (preg_match('/^https?\:\/\/[^\/]+$/', $href)) {
+                $href .= '/';
+            }
+            $this->addT($s, $this->getPropertyURI('web_presence'), $href, $s_type, 'uri');
+            $this->addT($href, $this->getPropertyURI('title'), $sub_v['title'], $s_type, 'literal');
+        }
+    }
 
-  function extractUpdatedAtRDF($s, $s_type,  $v) {
-    $v = $this->getAPIDateXSD($v);
-    $this->addT($s, $this->getPropertyURI('updated_at'), $v, $s_type, 'literal');
-  }
+    public function extractCreatedAtRDF($s, $s_type, $v)
+    {
+        $v = $this->getAPIDateXSD($v);
+        $this->addT($s, $this->getPropertyURI('created_at'), $v, $s_type, 'literal');
+    }
 
-  function getAPIDateXSD($val) {
-    //Fri Jan 16 21:11:48 UTC 2009
-    if (preg_match('/^[a-z]+ ([a-z]+) ([0-9]+) ([0-9]{2}\:[0-9]{2}\:[0-9]{2}) UTC ([0-9]{4})/i', $val, $m)) {
-      $months = array('Jan' => '01', 'Feb' => '02', 'Mar' =>'03', 'Apr' => '04', 'May' => '05', 'Jun' => '06', 'Jul' => '07', 'Aug' => '08', 'Sep' => '09', 'Oct' => '10', 'Nov' => '11', 'Dec' => '12');
-      return $m[4] . '-' . $months[$m[1]] . '-' . $m[2] . 'T' . $m[3] . 'Z';
+    public function extractUpdatedAtRDF($s, $s_type, $v)
+    {
+        $v = $this->getAPIDateXSD($v);
+        $this->addT($s, $this->getPropertyURI('updated_at'), $v, $s_type, 'literal');
     }
-    return '2000-01-01';
-  }
 
-  /*  */
+    public function getAPIDateXSD($val)
+    {
+        //Fri Jan 16 21:11:48 UTC 2009
+        if (preg_match('/^[a-z]+ ([a-z]+) ([0-9]+) ([0-9]{2}\:[0-9]{2}\:[0-9]{2}) UTC ([0-9]{4})/i', $val, $m)) {
+            $months = ['Jan' => '01', 'Feb' => '02', 'Mar' => '03', 'Apr' => '04', 'May' => '05', 'Jun' => '06', 'Jul' => '07', 'Aug' => '08', 'Sep' => '09', 'Oct' => '10', 'Nov' => '11', 'Dec' => '12'];
+
+            return $m[4].'-'.$months[$m[1]].'-'.$m[2].'T'.$m[3].'Z';
+        }
 
-  function inferDate($prefix, $s, $struct) {
-    $s_type = preg_match('/^\_\:/', $s) ? 'bnode' : 'uri';
-    $r = '';
-    foreach (array('year', 'month', 'day') as $suffix) {
-      $val = $this->v1($prefix . '_' . $suffix, '00', $struct);
-      $r .= ($r ? '-' : '') . str_pad($val, 2, '0', STR_PAD_LEFT);
+        return '2000-01-01';
     }
-    if ($r != '00-00-00') {
-      $this->addT($s, $this->getPropertyURI($prefix . '_date'), $r, $s_type, 'literal');
+
+    public function inferDate($prefix, $s, $struct)
+    {
+        $s_type = preg_match('/^\_\:/', $s) ? 'bnode' : 'uri';
+        $r = '';
+        foreach (['year', 'month', 'day'] as $suffix) {
+            $val = $this->v1($prefix.'_'.$suffix, '00', $struct);
+            $r .= ($r ? '-' : '').str_pad($val, 2, '0', STR_PAD_LEFT);
+        }
+        if ('00-00-00' != $r) {
+            $this->addT($s, $this->getPropertyURI($prefix.'_date'), $r, $s_type, 'literal');
+        }
     }
-  }
-  
 }
diff --git a/lib/arc2/parsers/ARC2_JSONParser.php b/lib/arc2/parsers/ARC2_JSONParser.php
old mode 100644
new mode 100755
index f4d9b958d7643d7dd6792dc339c795b3b9f4c822..280214759d24d9f82208c156165d90eeec0e4dd7
--- a/lib/arc2/parsers/ARC2_JSONParser.php
+++ b/lib/arc2/parsers/ARC2_JSONParser.php
@@ -1,165 +1,183 @@
 <?php
 /**
  * ARC2 JSON Parser
- * Does not extract triples, needs sub-class for RDF extraction
+ * Does not extract triples, needs sub-class for RDF extraction.
  *
  * @author Benjamin Nowack <bnowack@semsol.com>
- * @license http://arc.semsol.org/license
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('RDFParser');
 
-class ARC2_JSONParser extends ARC2_RDFParser {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-  }
-  
-  /*  */
-
-  function x($re, $v, $options = 'si') {
-    while (preg_match('/^\s*(\/\*.*\*\/)(.*)$/Usi', $v, $m)) {/* comment removal */
-      $v = $m[2];
-    }
-    $this->unparsed_code = (strlen($this->unparsed_code) > strlen($v)) ? $v : $this->unparsed_code;
-    return ARC2::x($re, $v, $options);
-  }
-
-  function parse($path, $data = '') {
-    $this->state = 0;
-    /* reader */
-    if (!$this->v('reader')) {
-      ARC2::inc('Reader');
-      $this->reader = new ARC2_Reader($this->a, $this);
+class ARC2_JSONParser extends ARC2_RDFParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
     }
-    $this->reader->setAcceptHeader('Accept: application/json; q=0.9, */*; q=0.1');
-    $this->reader->activate($path, $data);
-    $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
-    /* parse */
-    $doc = '';
-    while ($d = $this->reader->readStream()) {
-      $doc .= $d;
-    }
-    $this->reader->closeStream();
-    unset($this->reader);
-    $doc = preg_replace('/^[^\{]*(.*\})[^\}]*$/is', '\\1', $doc);
-    $this->unparsed_code = $doc;
-    list($this->struct, $rest) = $this->extractObject($doc);
-    return $this->done();
-  }
-  
-  /*  */
-  
-  function extractObject($v) {
-    if (function_exists('json_decode')) return array(json_decode($v, 1), '');
-    $r = array();
-    /* sub-object */
-    if ($sub_r = $this->x('\{', $v)) {
-      $v = $sub_r[1];
-      while ((list($sub_r, $v) = $this->extractEntry($v)) && $sub_r) {
-        $r[$sub_r['key']] = $sub_r['value'];
-      }
-      if ($sub_r = $this->x('\}', $v)) $v = $sub_r[1];
-    }
-    /* sub-list */
-    elseif ($sub_r = $this->x('\[', $v)) {
-      $v = $sub_r[1];
-      while ((list($sub_r, $v) = $this->extractObject($v)) && $sub_r) {
-        $r[] = $sub_r;
-        $v = ltrim($v, ',');
-      }
-      if ($sub_r = $this->x('\]', $v)) $v = $sub_r[1];
+
+    public function __init()
+    {
+        parent::__init();
     }
-    /* sub-value */
-    elseif ((list($sub_r, $v) = $this->extractValue($v)) && ($sub_r !== false)) {
-      $r = $sub_r;
+
+    public function x($re, $v, $options = 'si')
+    {
+        while (preg_match('/^\s*(\/\*.*\*\/)(.*)$/Usi', $v, $m)) {/* comment removal */
+            $v = $m[2];
+        }
+        $this->unparsed_code = (strlen($this->unparsed_code) > strlen($v)) ? $v : $this->unparsed_code;
+
+        return ARC2::x($re, $v, $options);
     }
-    return array($r, $v);
-  }
-  
-  function extractEntry($v) {
-    if ($r = $this->x('\,', $v)) $v = $r[1];
-    /* k */
-    if ($r = $this->x('\"([^\"]+)\"\s*\:', $v)) {
-      $k = $r[1];
-      $sub_v = $r[2];
-      if (list($sub_r, $sub_v) = $this->extractObject($sub_v)) {
-        return array(
-          array('key' => $k, 'value' => $sub_r),
-          $sub_v
-        );
-      }
+
+    public function parse($path, $data = '')
+    {
+        $this->state = 0;
+        /* reader */
+        if (!$this->v('reader')) {
+            ARC2::inc('Reader');
+            $this->reader = new ARC2_Reader($this->a, $this);
+        }
+        $this->reader->setAcceptHeader('Accept: application/json; q=0.9, */*; q=0.1');
+        $this->reader->activate($path, $data);
+        $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
+        /* parse */
+        $doc = '';
+        while ($d = $this->reader->readStream()) {
+            $doc .= $d;
+        }
+        $this->reader->closeStream();
+        unset($this->reader);
+        $doc = preg_replace('/^[^\{]*(.*\})[^\}]*$/is', '\\1', $doc);
+        $this->unparsed_code = $doc;
+        list($this->struct, $rest) = $this->extractObject($doc);
+
+        return $this->done();
     }
-    return array(0, $v);
-  }
-  
-  function extractValue($v) {
-    if ($r = $this->x('\,', $v)) $v = $r[1];
-    if ($sub_r = $this->x('null', $v)) {
-      return array(null, $sub_r[1]);
+
+    public function extractObject($v)
+    {
+        if (function_exists('json_decode')) {
+            return [json_decode($v, 1), ''];
+        }
+        $r = [];
+        /* sub-object */
+        if ($sub_r = $this->x('\{', $v)) {
+            $v = $sub_r[1];
+            while ((list($sub_r, $v) = $this->extractEntry($v)) && $sub_r) {
+                $r[$sub_r['key']] = $sub_r['value'];
+            }
+            if ($sub_r = $this->x('\}', $v)) {
+                $v = $sub_r[1];
+            }
+        }
+        /* sub-list */
+        elseif ($sub_r = $this->x('\[', $v)) {
+            $v = $sub_r[1];
+            while ((list($sub_r, $v) = $this->extractObject($v)) && $sub_r) {
+                $r[] = $sub_r;
+                $v = ltrim($v, ',');
+            }
+            if ($sub_r = $this->x('\]', $v)) {
+                $v = $sub_r[1];
+            }
+        }
+        /* sub-value */
+        elseif ((list($sub_r, $v) = $this->extractValue($v)) && (false !== $sub_r)) {
+            $r = $sub_r;
+        }
+
+        return [$r, $v];
     }
-    if ($sub_r = $this->x('(true|false)', $v)) {
-      return array($sub_r[1], $sub_r[2]);
+
+    public function extractEntry($v)
+    {
+        if ($r = $this->x('\,', $v)) {
+            $v = $r[1];
+        }
+        /* k */
+        if ($r = $this->x('\"([^\"]+)\"\s*\:', $v)) {
+            $k = $r[1];
+            $sub_v = $r[2];
+            if (list($sub_r, $sub_v) = $this->extractObject($sub_v)) {
+                return [
+                    ['key' => $k, 'value' => $sub_r],
+                    $sub_v,
+                ];
+            }
+        }
+
+        return [0, $v];
     }
-    if ($sub_r = $this->x('([\-\+]?[0-9\.]+)', $v)) {
-      return array($sub_r[1], $sub_r[2]);
+
+    public function extractValue($v)
+    {
+        if ($r = $this->x('\,', $v)) {
+            $v = $r[1];
+        }
+        if ($sub_r = $this->x('null', $v)) {
+            return [null, $sub_r[1]];
+        }
+        if ($sub_r = $this->x('(true|false)', $v)) {
+            return [$sub_r[1], $sub_r[2]];
+        }
+        if ($sub_r = $this->x('([\-\+]?[0-9\.]+)', $v)) {
+            return [$sub_r[1], $sub_r[2]];
+        }
+        if ($sub_r = $this->x('\"', $v)) {
+            $rest = $sub_r[1];
+            if (preg_match('/^([^\x5c]*|.*[^\x5c]|.*\x5c{2})\"(.*)$/sU', $rest, $m)) {
+                $val = $m[1];
+                /* unescape chars (single-byte) */
+                $val = preg_replace_callback('/\\\u(.{4})/', function ($matches) {
+                    return chr(hexdec($matches[1]));
+                }, $val);
+                //$val = preg_replace_callback('/\\\u00(.{2})', function($matches) { return rawurldecode("%" . $matches[1]); }, $val);
+                /* other escaped chars */
+                $from = ['\\\\', '\r', '\t', '\n', '\"', '\b', '\f', '\/'];
+                $to = ['\\', "\r", "\t", "\n", '"', "\b", "\f", '/'];
+                $val = str_replace($from, $to, $val);
+
+                return [$val, $m[2]];
+            }
+        }
+
+        return [false, $v];
     }
-    if ($sub_r = $this->x('\"', $v)) {
-      $rest = $sub_r[1];
-      if (preg_match('/^([^\x5c]*|.*[^\x5c]|.*\x5c{2})\"(.*)$/sU', $rest, $m)) {
-        $val = $m[1];
-        /* unescape chars (single-byte) */
-        $val = preg_replace('/\\\u(.{4})/e', 'chr(hexdec("\\1"))', $val);
-        //$val = preg_replace('/\\\u00(.{2})/e', 'rawurldecode("%\\1")', $val);
-        /* other escaped chars */
-        $from = array('\\\\', '\r', '\t', '\n', '\"', '\b', '\f', '\/');
-        $to = array("\\", "\r", "\t", "\n", '"', "\b", "\f", "/");
-        $val = str_replace($from, $to, $val);
-        return array($val, $m[2]);
-      }
+
+    public function getObject()
+    {
+        return $this->v('struct', []);
     }
-    return array(false, $v);
-  }
-  
-  /*  */
-
-  function getObject() {
-    return $this->v('struct', array());
-  }
-  
-  function getTriples() {
-    return $this->v('triples', array());
-  }
-  
-  function countTriples() {
-    return $this->t_count;
-  }
-
-  function addT($s = '', $p = '', $o = '', $s_type = '', $o_type = '', $o_dt = '', $o_lang = '') {
-    $o = $this->toUTF8($o);
-    //echo str_replace($this->base, '', "-----\n adding $s / $p / $o\n-----\n");
-    $t = array('s' => $s, 'p' => $p, 'o' => $o, 's_type' => $s_type, 'o_type' => $o_type, 'o_datatype' => $o_dt, 'o_lang' => $o_lang);
-    if ($this->skip_dupes) {
-      $h = md5(serialize($t));
-      if (!isset($this->added_triples[$h])) {
-        $this->triples[$this->t_count] = $t;
-        $this->t_count++;
-        $this->added_triples[$h] = true;
-      }
+
+    public function getTriples()
+    {
+        return $this->v('triples', []);
     }
-    else {
-      $this->triples[$this->t_count] = $t;
-      $this->t_count++;
+
+    public function countTriples()
+    {
+        return $this->t_count;
     }
-  }
 
-  /*  */
-  
+    public function addT($s = '', $p = '', $o = '', $s_type = '', $o_type = '', $o_dt = '', $o_lang = '')
+    {
+        $o = $this->toUTF8($o);
+        //echo str_replace($this->base, '', "-----\n adding $s / $p / $o\n-----\n");
+        $t = ['s' => $s, 'p' => $p, 'o' => $o, 's_type' => $s_type, 'o_type' => $o_type, 'o_datatype' => $o_dt, 'o_lang' => $o_lang];
+        if ($this->skip_dupes) {
+            $h = md5(serialize($t));
+            if (!isset($this->added_triples[$h])) {
+                $this->triples[$this->t_count] = $t;
+                ++$this->t_count;
+                $this->added_triples[$h] = true;
+            }
+        } else {
+            $this->triples[$this->t_count] = $t;
+            ++$this->t_count;
+        }
+    }
 }
diff --git a/lib/arc2/parsers/ARC2_LegacyXMLParser.php b/lib/arc2/parsers/ARC2_LegacyXMLParser.php
index 3c3564da94955b9cc0471f1ea541780c3dfa4ebf..817e9795ece0e2edf4a06554f37e7e51665b7c91 100644
--- a/lib/arc2/parsers/ARC2_LegacyXMLParser.php
+++ b/lib/arc2/parsers/ARC2_LegacyXMLParser.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 Legaxy XML Parser
 author:   Benjamin Nowack
@@ -10,302 +10,306 @@ version:  2010-11-16
 
 ARC2::inc('Class');
 
-class ARC2_LegacyXMLParser extends ARC2_Class {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* reader */
-    parent::__init();
-    $this->encoding = $this->v('encoding', false, $this->a);
-    $this->state = 0;
-    $this->x_base = $this->base;
-    $this->xml = 'http://www.w3.org/XML/1998/namespace';
-    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
-    $this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf');
-    $this->allowCDataNodes = 1;
-    $this->target_encoding = '';
-    $this->keep_cdata_ws = $this->v('keep_cdata_whitespace', 0, $this->a);
-  }
-  
-  /*  */
+class ARC2_LegacyXMLParser extends ARC2_Class
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
 
-  function setReader(&$reader) {
-    $this->reader = $reader;
-  }
+    public function __init()
+    {/* reader */
+        parent::__init();
+        $this->encoding = $this->v('encoding', false, $this->a);
+        $this->state = 0;
+        $this->x_base = $this->base;
+        $this->xml = 'http://www.w3.org/XML/1998/namespace';
+        $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+        $this->nsp = [$this->xml => 'xml', $this->rdf => 'rdf'];
+        $this->allowCDataNodes = 1;
+        $this->target_encoding = '';
+        $this->keep_cdata_ws = $this->v('keep_cdata_whitespace', 0, $this->a);
+    }
 
-  function parse($path, $data = '', $iso_fallback = false) {
-    $this->nodes = array();
-    $this->node_count = 0;
-    $this->level = 0;
-    /* reader */
-    if (!$this->v('reader')) {
-      ARC2::inc('Reader');
-      $this->reader = new ARC2_Reader($this->a, $this);
+    public function setReader(&$reader)
+    {
+        $this->reader = $reader;
     }
-    $this->reader->setAcceptHeader('Accept: application/xml; q=0.9, */*; q=0.1');
-    $this->reader->activate($path, $data);
-    $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
-    $this->base = $this->x_base;
-    $this->doc_url = $this->reader->base;
-    /* xml parser */
-    $this->initXMLParser();
-    /* parse */
-    $first = true;
-    while ($d = $this->reader->readStream(1)) {
-      if ($iso_fallback && $first) {
-        $d = '<?xml version="1.0" encoding="ISO-8859-1"?>' . "\n" . preg_replace('/^\<\?xml [^\>]+\?\>\s*/s', '', $d);
-      }
-      if (!xml_parse($this->xml_parser, $d, false)) {
-        $error_str = xml_error_string(xml_get_error_code($this->xml_parser));
-        $line = xml_get_current_line_number($this->xml_parser);
-        if (!$iso_fallback && preg_match("/Invalid character/i", $error_str)) {
-          xml_parser_free($this->xml_parser);
-          unset($this->xml_parser);
-          $this->reader->closeStream();
-          unset($this->reader);
-          $this->__init();
-          $this->encoding = 'ISO-8859-1';
-          $this->initXMLParser();
-          return $this->parse($path, $data, true);
+
+    public function parse($path, $data = '', $iso_fallback = false)
+    {
+        $this->nodes = [];
+        $this->node_count = 0;
+        $this->level = 0;
+        /* reader */
+        if (!$this->v('reader')) {
+            ARC2::inc('Reader');
+            $this->reader = new ARC2_Reader($this->a, $this);
         }
-        else {
-          return $this->addError('XML error: "' . $error_str . '" at line ' . $line . ' (parsing as ' . $this->getEncoding() . ')');
+        $this->reader->setAcceptHeader('Accept: application/xml; q=0.9, */*; q=0.1');
+        $this->reader->activate($path, $data);
+        $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
+        $this->base = $this->x_base;
+        $this->doc_url = $this->reader->base;
+        /* xml parser */
+        $this->initXMLParser();
+        /* parse */
+        $first = true;
+        while ($d = $this->reader->readStream(1)) {
+            if ($iso_fallback && $first) {
+                $d = '<?xml version="1.0" encoding="ISO-8859-1"?>'."\n".preg_replace('/^\<\?xml [^\>]+\?\>\s*/s', '', $d);
+            }
+            if (!xml_parse($this->xml_parser, $d, false)) {
+                $error_str = xml_error_string(xml_get_error_code($this->xml_parser));
+                $line = xml_get_current_line_number($this->xml_parser);
+                if (!$iso_fallback && preg_match('/Invalid character/i', $error_str)) {
+                    xml_parser_free($this->xml_parser);
+                    unset($this->xml_parser);
+                    $this->reader->closeStream();
+                    unset($this->reader);
+                    $this->__init();
+                    $this->encoding = 'ISO-8859-1';
+                    $this->initXMLParser();
+
+                    return $this->parse($path, $data, true);
+                } else {
+                    return $this->addError('XML error: "'.$error_str.'" at line '.$line.' (parsing as '.$this->getEncoding().')');
+                }
+            }
+            $first = false;
         }
-      }
-      $first = false;
+        $this->target_encoding = xml_parser_get_option($this->xml_parser, XML_OPTION_TARGET_ENCODING);
+        xml_parser_free($this->xml_parser);
+        $this->reader->closeStream();
+        unset($this->reader);
+
+        return $this->done();
     }
-    $this->target_encoding = xml_parser_get_option($this->xml_parser, XML_OPTION_TARGET_ENCODING);
-    xml_parser_free($this->xml_parser);
-    $this->reader->closeStream();
-    unset($this->reader);
-    return $this->done();
-  }
-  
-  /*  */
-  
-  function getEncoding($src = 'config') {
-    if ($src == 'parser') {
-      return $this->target_encoding;
+
+    public function getEncoding($src = 'config')
+    {
+        if ('parser' == $src) {
+            return $this->target_encoding;
+        } elseif (('config' == $src) && $this->encoding) {
+            return $this->encoding;
+        }
+
+        return $this->reader->getEncoding();
     }
-    elseif (($src == 'config') && $this->encoding) {
-      return $this->encoding;
+
+    public function done()
+    {
     }
-    return $this->reader->getEncoding();
-  }
 
-  /*  */
-  
-  function done() {
-  
-  }
-  
-  /*  */
-  
-  function getStructure() {
-    return array('nodes' => $this->v('nodes', array()));
-  }
-  
-  /*  */
+    public function getStructure()
+    {
+        return ['nodes' => $this->v('nodes', [])];
+    }
 
-  function getNodeIndex(){
-    if (!isset($this->node_index)) {
-      /* index by parent */
-      $index = array();
-      for ($i = 0, $i_max = count($this->nodes); $i < $i_max; $i++) {
-        $node = $this->nodes[$i];
-        $node['id'] = $i;
-        $node['doc_base'] = $this->base;
-        if (isset($this->doc_url)) $node['doc_url'] = $this->doc_url;
-        $this->updateNode($node);
-        $p_id = $node['p_id'];
-        if (!isset($index[$p_id])) {
-          $index[$p_id] = array();
+    public function getNodeIndex()
+    {
+        if (!isset($this->node_index)) {
+            /* index by parent */
+            $index = [];
+            for ($i = 0, $i_max = count($this->nodes); $i < $i_max; ++$i) {
+                $node = $this->nodes[$i];
+                $node['id'] = $i;
+                $node['doc_base'] = $this->base;
+                if (isset($this->doc_url)) {
+                    $node['doc_url'] = $this->doc_url;
+                }
+                $this->updateNode($node);
+                $p_id = $node['p_id'];
+                if (!isset($index[$p_id])) {
+                    $index[$p_id] = [];
+                }
+                $index[$p_id][$node['pos']] = $node;
+            }
+            $this->node_index = $index;
         }
-        $index[$p_id][$node['pos']] = $node;
-      }
-      $this->node_index = $index;
+
+        return $this->node_index;
     }
-    return $this->node_index;
-  }
 
-  function getNodes() {
-    return $this->nodes;
-  }
-  
-  function getSubNodes($n) {
-    return $this->v($n['id'], array(), $this->getNodeIndex());
-  }
-  
-  function getNodeContent($n, $outer = 0, $trim = 1) {
-    //echo '<pre>' . htmlspecialchars(print_r($n, 1)) . '</pre>';
-    if ($n['tag'] == 'cdata') {
-      $r = $n['a']['value'];
+    public function getNodes()
+    {
+        return $this->nodes;
     }
-    else {
-      $r = '';
-      if ($outer) {
-        $r .= '<' . $n['tag'];
-        asort($n['a']);
-        if (isset($n['a']['xmlns']) && $n['a']['xmlns']['']) {
-          $r .= ' xmlns="' . $n['a']['xmlns'][''] . '"';
-        }
-        foreach ($n['a'] as $a => $val) {
-          $r .= preg_match('/^[^\s]+$/', $a) && !is_array($val) ? ' ' . $a . '="' . addslashes($val) . '"' : '';
-        }
-        $r .= $n['empty'] ? '/>' : '>';
-      }
-      if (!$n['empty']) {
-        $r .= $this->v('cdata', '', $n);
-        $sub_nodes = $this->getSubNodes($n);
-        foreach ($sub_nodes as $sub_n) {
-          $r .= $this->getNodeContent($sub_n, 1, 0);
-        }
-        if ($outer) {
-          $r .= '</' . $n['tag'] . '>';
-        }
-      }
+
+    public function getSubNodes($n)
+    {
+        return $this->v($n['id'], [], $this->getNodeIndex());
     }
-    return ($trim && !$this->keep_cdata_ws) ? trim($r) : $r;
-  }
 
-  /*  */
-  
-  function pushNode($n) {
-    $n['id'] = $this->node_count;
-    $this->nodes[$this->node_count] = $n;
-    $this->node_count++;
-  }
-  
-  function getCurNode($t = '') {
-    $i = 1;
-    do {
-      $r = $this->node_count ? $this->nodes[$this->node_count - $i] : 0;
-      $found = (!$t || ($r['tag'] == $t)) ? 1 : 0;
-      $i++;
-    } while (!$found && isset($this->nodes[$this->node_count - $i]));
-    return $r;
-  }
-  
-  function updateNode($node) {/* php4-save */
-    $this->nodes[$node['id']] = $node;
-  }
+    public function getNodeContent($n, $outer = 0, $trim = 1)
+    {
+        //echo '<pre>' . htmlspecialchars(print_r($n, 1)) . '</pre>';
+        if ('cdata' == $n['tag']) {
+            $r = $n['a']['value'];
+        } else {
+            $r = '';
+            if ($outer) {
+                $r .= '<'.$n['tag'];
+                asort($n['a']);
+                if (isset($n['a']['xmlns']) && $n['a']['xmlns']['']) {
+                    $r .= ' xmlns="'.$n['a']['xmlns'][''].'"';
+                }
+                foreach ($n['a'] as $a => $val) {
+                    $r .= preg_match('/^[^\s]+$/', $a) && !is_array($val) ? ' '.$a.'="'.addslashes($val).'"' : '';
+                }
+                $r .= $n['empty'] ? '/>' : '>';
+            }
+            if (!$n['empty']) {
+                $r .= $this->v('cdata', '', $n);
+                $sub_nodes = $this->getSubNodes($n);
+                foreach ($sub_nodes as $sub_n) {
+                    $r .= $this->getNodeContent($sub_n, 1, 0);
+                }
+                if ($outer) {
+                    $r .= '</'.$n['tag'].'>';
+                }
+            }
+        }
 
-  /*  */
+        return ($trim && !$this->keep_cdata_ws) ? trim($r) : $r;
+    }
 
-  function initXMLParser() {
-    if (!isset($this->xml_parser)) {
-      $enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
-      $parser = xml_parser_create_ns($enc, '');
-      xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
-      xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
-      xml_set_element_handler($parser, 'open', 'close');
-      xml_set_character_data_handler($parser, 'cData');
-      xml_set_start_namespace_decl_handler($parser, 'nsDecl');
-      xml_set_object($parser, $this);
-      $this->xml_parser = $parser;
+    public function pushNode($n)
+    {
+        $n['id'] = $this->node_count;
+        $this->nodes[$this->node_count] = $n;
+        ++$this->node_count;
     }
-  }
 
-  /*  */
-  
-  function open($p, $t, $a) {
-    $t_exact = $t;
-    //echo "<br />\n".'opening '.$t . ' ' . print_r($a, 1); flush();
-    //echo "<br />\n".'opening '.$t; flush();
-    $t = strpos($t, ':') ? $t : strtolower($t);
-    /* base check */
-    $base = '';
-    if (($t == 'base') && isset($a['href'])) {
-      $this->base = $a['href'];
-      $base = $a['href'];
+    public function getCurNode($t = '')
+    {
+        $i = 1;
+        do {
+            $r = $this->node_count ? $this->nodes[$this->node_count - $i] : 0;
+            $found = (!$t || ($r['tag'] == $t)) ? 1 : 0;
+            ++$i;
+        } while (!$found && isset($this->nodes[$this->node_count - $i]));
+
+        return $r;
     }
-    /* URIs */
-    foreach (array('href', 'src', 'id') as $uri_a) {
-      if (isset($a[$uri_a])) {
-        $a[$uri_a . ' uri'] = ($uri_a == 'id') ? $this->calcURI('#'.$a[$uri_a]) : $this->calcURI($a[$uri_a]);
-      }
+
+    public function updateNode($node)
+    {/* php4-save */
+        $this->nodes[$node['id']] = $node;
     }
-    /* ns */
-    if ($a) {
-      foreach ($a as $k => $v) {
-        if (strpos($k, 'xmlns') === 0) {
-          $this->nsDecl($p, trim(substr($k, 5), ':'), $v);
+
+    public function initXMLParser()
+    {
+        if (!isset($this->xml_parser)) {
+            $enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
+            $parser = xml_parser_create_ns($enc, '');
+            xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
+            xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
+            xml_set_element_handler($parser, 'open', 'close');
+            xml_set_character_data_handler($parser, 'cData');
+            xml_set_start_namespace_decl_handler($parser, 'nsDecl');
+            xml_set_object($parser, $this);
+            $this->xml_parser = $parser;
         }
-      }
     }
-    /* node */
-    $node = array(
-      'tag' => $t,
-      'tag_exact' => $t_exact,
-      'a' => $a, 
-      'level' => $this->level, 
-      'pos' => 0,
-      'p_id' => $this->node_count-1,
-      'state' => 'open',
-      'empty' => 0,
-      'cdata' =>''
-    );
-    if ($base) {
-      $node['base'] = $base;
-    }
-    /* parent/sibling */
-    if ($this->node_count) {
-      $l = $this->level;
-      $prev_node = $this->getCurNode();
-      if ($prev_node['level'] == $l) {
-        $node['p_id'] = $prev_node['p_id'];
-        $node['pos'] = $prev_node['pos']+1;
-      }
-      elseif($prev_node['level'] > $l) {
-        while($prev_node['level'] > $l) {
-          if (!isset($this->nodes[$prev_node['p_id']])) {
-            //$this->addError('nesting mismatch: tag is ' . $t . ', level is ' . $l . ', prev_level is ' . $prev_node['level'] . ', prev_node p_id is ' . $prev_node['p_id']);
-            break;
-          }
-          $prev_node = $this->nodes[$prev_node['p_id']];
+
+    public function open($p, $t, $a)
+    {
+        $t_exact = $t;
+        //echo "<br />\n".'opening '.$t . ' ' . print_r($a, 1); flush();
+        //echo "<br />\n".'opening '.$t; flush();
+        $t = strpos($t, ':') ? $t : strtolower($t);
+        /* base check */
+        $base = '';
+        if (('base' == $t) && isset($a['href'])) {
+            $this->base = $a['href'];
+            $base = $a['href'];
+        }
+        /* URIs */
+        foreach (['href', 'src', 'id'] as $uri_a) {
+            if (isset($a[$uri_a])) {
+                $a[$uri_a.' uri'] = ('id' == $uri_a) ? $this->calcURI('#'.$a[$uri_a]) : $this->calcURI($a[$uri_a]);
+            }
+        }
+        /* ns */
+        if ($a) {
+            foreach ($a as $k => $v) {
+                if (0 === strpos($k, 'xmlns')) {
+                    $this->nsDecl($p, trim(substr($k, 5), ':'), $v);
+                }
+            }
         }
-        $node['p_id'] = $prev_node['p_id'];
-        $node['pos'] = $prev_node['pos']+1;
-      }
+        /* node */
+        $node = [
+            'tag' => $t,
+            'tag_exact' => $t_exact,
+            'a' => $a,
+            'level' => $this->level,
+            'pos' => 0,
+            'p_id' => $this->node_count - 1,
+            'state' => 'open',
+            'empty' => 0,
+            'cdata' => '',
+        ];
+        if ($base) {
+            $node['base'] = $base;
+        }
+        /* parent/sibling */
+        if ($this->node_count) {
+            $l = $this->level;
+            $prev_node = $this->getCurNode();
+            if ($prev_node['level'] == $l) {
+                $node['p_id'] = $prev_node['p_id'];
+                $node['pos'] = $prev_node['pos'] + 1;
+            } elseif ($prev_node['level'] > $l) {
+                while ($prev_node['level'] > $l) {
+                    if (!isset($this->nodes[$prev_node['p_id']])) {
+                        //$this->addError('nesting mismatch: tag is ' . $t . ', level is ' . $l . ', prev_level is ' . $prev_node['level'] . ', prev_node p_id is ' . $prev_node['p_id']);
+                        break;
+                    }
+                    $prev_node = $this->nodes[$prev_node['p_id']];
+                }
+                $node['p_id'] = $prev_node['p_id'];
+                $node['pos'] = $prev_node['pos'] + 1;
+            }
+        }
+        $this->pushNode($node);
+        ++$this->level;
+        /* cdata */
+        $this->cur_cdata = '';
     }
-    $this->pushNode($node);
-    $this->level++;
-    /* cdata */
-    $this->cur_cdata="";
-  }
 
-  function close($p, $t, $empty = 0) {
-    //echo "<br />\n".'closing '.$t; flush();
-    $node = $this->getCurNode($t);
-    $node['state'] = 'closed';
-    $node['empty'] = $empty;
-    $this->updateNode($node);
-    $this->level--;
-  }
-
-  function cData($p, $d) {
-    //echo trim($d) ? "<br />\n".'cdata: ' . $d : ''; flush();
-    $node = $this->getCurNode();
-    if($node['state'] == 'open') {
-      $node['cdata'] .= $d;
-      $this->updateNode($node);
+    public function close($p, $t, $empty = 0)
+    {
+        //echo "<br />\n".'closing '.$t; flush();
+        $node = $this->getCurNode($t);
+        $node['state'] = 'closed';
+        $node['empty'] = $empty;
+        $this->updateNode($node);
+        --$this->level;
     }
-    else {/* cdata is sibling of node */
-      if ($this->allowCDataNodes) {
-        $this->open($p, 'cdata', array('value' => $d));
-        $this->close($p, 'cdata');
-      }
+
+    public function cData($p, $d)
+    {
+        //echo trim($d) ? "<br />\n".'cdata: ' . $d : ''; flush();
+        $node = $this->getCurNode();
+        if ('open' == $node['state']) {
+            $node['cdata'] .= $d;
+            $this->updateNode($node);
+        } else {/* cdata is sibling of node */
+            if ($this->allowCDataNodes) {
+                $this->open($p, 'cdata', ['value' => $d]);
+                $this->close($p, 'cdata');
+            }
+        }
     }
-  }
-  
-  function nsDecl($p, $prf, $uri) {
-    if (is_array($uri)) return 1;
-    $this->ns[$prf] = $uri;
-    $this->nsp[$uri] = isset($this->nsp[$uri]) ? $this->nsp[$uri] : $prf;
-  }
 
-  /*  */
-  
-}
\ No newline at end of file
+    public function nsDecl($p, $prf, $uri)
+    {
+        if (is_array($uri)) {
+            return 1;
+        }
+        $this->ns[$prf] = $uri;
+        $this->nsp[$uri] = isset($this->nsp[$uri]) ? $this->nsp[$uri] : $prf;
+    }
+}
diff --git a/lib/arc2/parsers/ARC2_RDFParser.php b/lib/arc2/parsers/ARC2_RDFParser.php
old mode 100644
new mode 100755
index 44dd7782470bb26294904a33038b83167a0cbedf..75902f16d6b988cebe458c5a833c4fcf2f23ef1d
--- a/lib/arc2/parsers/ARC2_RDFParser.php
+++ b/lib/arc2/parsers/ARC2_RDFParser.php
@@ -1,139 +1,144 @@
 <?php
 /**
- * ARC2 RDF Parser (generic)
+ * ARC2 RDF Parser (generic).
  *
  * @author Benjamin Nowack <bnowack@semsol.com>
- * @license http://arc.semsol.org/license
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('Class');
 
-class ARC2_RDFParser extends ARC2_Class {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* proxy_host, proxy_port, proxy_skip, http_accept_header, http_user_agent_header, max_redirects, reader, skip_dupes */
-    parent::__init();
-    $this->a['format'] = $this->v('format', false, $this->a);
-    $this->keep_time_limit = $this->v('keep_time_limit', 0, $this->a);
-    $this->triples = array();
-    $this->t_count = 0;
-    $this->added_triples = array();
-    $this->skip_dupes = $this->v('skip_dupes', false, $this->a);
-    $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
-    $this->bnode_id = 0;
-    $this->format = '';
-  }
-
-  /*  */
-  
-  function setReader(&$reader) {
-    $this->reader = $reader;
-  }
-  
-  function parse($path, $data = '') {
-    /* reader */
-    if (!isset($this->reader)) {
-      ARC2::inc('Reader');
-      $this->reader = new ARC2_Reader($this->a, $this);
+class ARC2_RDFParser extends ARC2_Class
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
+
+    public function __init()
+    {/* proxy_host, proxy_port, proxy_skip, http_accept_header, http_user_agent_header, max_redirects, reader, skip_dupes */
+        parent::__init();
+        $this->a['format'] = $this->v('format', false, $this->a);
+        $this->keep_time_limit = $this->v('keep_time_limit', 0, $this->a);
+        $this->triples = [];
+        $this->t_count = 0;
+        $this->added_triples = [];
+        $this->skip_dupes = $this->v('skip_dupes', false, $this->a);
+        $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
+        $this->bnode_id = 0;
+        $this->format = '';
+    }
+
+    public function setReader(&$reader)
+    {
+        $this->reader = $reader;
+    }
+
+    public function parse($path, $data = '')
+    {
+        /* reader */
+        if (!isset($this->reader)) {
+            ARC2::inc('Reader');
+            $this->reader = new ARC2_Reader($this->a, $this);
+        }
+        $this->reader->activate($path, $data);
+        /* format detection */
+        $mappings = [
+            'rdfxml' => 'RDFXML',
+            'turtle' => 'Turtle',
+            'sparqlxml' => 'SPOG',
+            'ntriples' => 'Turtle',
+            'html' => 'SemHTML',
+            'rss' => 'RSS',
+            'atom' => 'Atom',
+            'sgajson' => 'SGAJSON',
+            'cbjson' => 'CBJSON',
+        ];
+        $format = $this->reader->getFormat();
+        if (!$format || !isset($mappings[$format])) {
+            return $this->addError('No parser available for "'.$format.'".');
+        }
+        $this->format = $format;
+        /* format parser */
+        $suffix = $mappings[$format].'Parser';
+        ARC2::inc($suffix);
+        $cls = 'ARC2_'.$suffix;
+        $this->parser = new $cls($this->a, $this);
+        $this->parser->setReader($this->reader);
+
+        return $this->parser->parse($path, $data);
+    }
+
+    public function parseData($data)
+    {
+        return $this->parse(ARC2::getScriptURI(), $data);
     }
-    $this->reader->activate($path, $data) ;
-    /* format detection */
-    $mappings = array(
-      'rdfxml' => 'RDFXML', 
-      'turtle' => 'Turtle', 
-      'sparqlxml' => 'SPOG', 
-      'ntriples' => 'Turtle', 
-      'html' => 'SemHTML',
-      'rss' => 'RSS',
-      'atom' => 'Atom',
-      'sgajson' => 'SGAJSON',
-      'cbjson' => 'CBJSON'
-    );
-    $format = $this->reader->getFormat();
-    if (!$format || !isset($mappings[$format])) {
-      return $this->addError('No parser available for "' . $format . '".');
+
+    public function done()
+    {
     }
-    $this->format = $format;
-    /* format parser */
-    $suffix = $mappings[$format] . 'Parser';
-    ARC2::inc($suffix);
-    $cls = 'ARC2_' . $suffix;
-    $this->parser = new $cls($this->a, $this);
-    $this->parser->setReader($this->reader);
-    return $this->parser->parse($path, $data);
-  }
-  
-  function parseData($data) {
-    return $this->parse(ARC2::getScriptURI(), $data);
-  }
-  
-  /*  */
-
-  function done() {
-  }
-
-  /*  */
-  
-  function createBnodeID(){
-    $this->bnode_id++;
-    return '_:' . $this->bnode_prefix . $this->bnode_id;
-  }
-
-  function getTriples() {
-    return $this->v('parser') ? $this->m('getTriples', false, array(), $this->v('parser')) : array();
-  }
-  
-  function countTriples() {
-    return $this->v('parser') ? $this->m('countTriples', false, 0, $this->v('parser')) : 0;
-  }
-  
-  function getSimpleIndex($flatten_objects = 1, $vals = '') {
-    return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
-  }
-  
-  function reset() {
-    $this->__init();
-    if (isset($this->reader)) unset($this->reader);
-    if (isset($this->parser)) {
-      $this->parser->__init();
-      unset($this->parser);
+
+    public function createBnodeID()
+    {
+        ++$this->bnode_id;
+
+        return '_:'.$this->bnode_prefix.$this->bnode_id;
     }
-  }
-  
-  /*  */
-  
-  function extractRDF($formats = '') {
-    if (method_exists($this->parser, 'extractRDF')) {
-      return $this->parser->extractRDF($formats);
+
+    public function getTriples()
+    {
+        return $this->v('parser') ? $this->m('getTriples', false, [], $this->v('parser')) : [];
     }
-  }
-  
-  /*  */
-  
-  function getEncoding($src = 'config') {
-    if (method_exists($this->parser, 'getEncoding')) {
-      return $this->parser->getEncoding($src);
+
+    public function countTriples()
+    {
+        return $this->v('parser') ? $this->m('countTriples', false, 0, $this->v('parser')) : 0;
     }
-  }
 
-  /**
-   * returns the array of namespace prefixes encountered during parsing
-   * @return array (keys = namespace URI / values = prefix used)
-  */
+    public function getSimpleIndex($flatten_objects = 1, $vals = '')
+    {
+        return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
+    }
 
-  function getParsedNamespacePrefixes() {
-    if (isset($this->parser)) {
-      return $this->v('nsp', array(), $this->parser);
+    public function reset()
+    {
+        $this->__init();
+        if (isset($this->reader)) {
+            unset($this->reader);
+        }
+        if (isset($this->parser)) {
+            $this->parser->__init();
+            unset($this->parser);
+        }
     }
-    return $this->v('nsp', array());
-  }
 
-  /*  */
+    public function extractRDF($formats = '')
+    {
+        if (method_exists($this->parser, 'extractRDF')) {
+            return $this->parser->extractRDF($formats);
+        }
+    }
+
+    public function getEncoding($src = 'config')
+    {
+        if (method_exists($this->parser, 'getEncoding')) {
+            return $this->parser->getEncoding($src);
+        }
+    }
 
+    /**
+     * returns the array of namespace prefixes encountered during parsing.
+     *
+     * @return array (keys = namespace URI / values = prefix used)
+     */
+    public function getParsedNamespacePrefixes()
+    {
+        if (isset($this->parser)) {
+            return $this->v('nsp', [], $this->parser);
+        }
+
+        return $this->v('nsp', []);
+    }
 }
diff --git a/lib/arc2/parsers/ARC2_RDFXMLParser.php b/lib/arc2/parsers/ARC2_RDFXMLParser.php
index cb5f254363ade24745b98bbf1bb8c9300ed622bc..02e8d6c65b6dd858b1afe64c0f1d20229ff6a99a 100644
--- a/lib/arc2/parsers/ARC2_RDFXMLParser.php
+++ b/lib/arc2/parsers/ARC2_RDFXMLParser.php
@@ -1,641 +1,622 @@
 <?php
 /**
- * ARC2 RDF/XML Parser
+ * ARC2 RDF/XML Parser.
  *
  * @author Benjamin Nowack <bnowack@semsol.com>
- * @license http://arc.semsol.org/license
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
- * @version 2010-11-16
-*/
-
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ */
 ARC2::inc('RDFParser');
 
-class ARC2_RDFXMLParser extends ARC2_RDFParser {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* reader */
-    parent::__init();
-    $this->encoding = $this->v('encoding', false, $this->a);
-    $this->state = 0;
-    $this->x_lang = '';
-    $this->x_base = $this->base;
-    $this->xml = 'http://www.w3.org/XML/1998/namespace';
-    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
-    $this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf');
-    $this->s_stack = array();
-    $this->s_count = 0;
-    $this->target_encoding = '';
-  }
-  
-  /*  */
-
-  function parse($path, $data = '', $iso_fallback = false) {
-    /* reader */
-    if (!$this->v('reader')) {
-      ARC2::inc('Reader');
-      $this->reader = new ARC2_Reader($this->a, $this);
-    }
-    $this->reader->setAcceptHeader('Accept: application/rdf+xml; q=0.9, */*; q=0.1');
-    $this->reader->activate($path, $data);
-    $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
-    /* xml parser */
-    $this->initXMLParser();
-    /* parse */
-    $first = true;
-    while ($d = $this->reader->readStream()) {
-      if (!$this->keep_time_limit) @set_time_limit($this->v('time_limit', 60, $this->a));
-      if ($iso_fallback && $first) {
-        $d = '<?xml version="1.0" encoding="ISO-8859-1"?>' . "\n" . preg_replace('/^\<\?xml [^\>]+\?\>\s*/s', '', $d);
-        $first = false;
-      }
-      if (!xml_parse($this->xml_parser, $d, false)) {
-        $error_str = xml_error_string(xml_get_error_code($this->xml_parser));
-        $line = xml_get_current_line_number($this->xml_parser);
-        $this->tmp_error = 'XML error: "' . $error_str . '" at line ' . $line . ' (parsing as ' . $this->getEncoding() . ')';
-        if (!$iso_fallback && preg_match("/Invalid character/i", $error_str)) {
-          xml_parser_free($this->xml_parser);
-          unset($this->xml_parser);
-          $this->reader->closeStream();
-          $this->__init();
-          $this->encoding = 'ISO-8859-1';
-          unset($this->xml_parser);
-          unset($this->reader);
-          return $this->parse($path, $data, true);
+class ARC2_RDFXMLParser extends ARC2_RDFParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
+
+    public function __init()
+    {/* reader */
+        parent::__init();
+        $this->encoding = $this->v('encoding', false, $this->a);
+        $this->state = 0;
+        $this->x_lang = '';
+        $this->x_base = $this->base;
+        $this->xml = 'http://www.w3.org/XML/1998/namespace';
+        $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+        $this->nsp = [$this->xml => 'xml', $this->rdf => 'rdf'];
+        $this->s_stack = [];
+        $this->s_count = 0;
+        $this->target_encoding = '';
+    }
+
+    public function parse($path, $data = '', $iso_fallback = false)
+    {
+        /* reader */
+        if (!$this->v('reader')) {
+            ARC2::inc('Reader');
+            $this->reader = new ARC2_Reader($this->a, $this);
         }
-        else {
-          return $this->addError($this->tmp_error);
-        }
-      }
-    }
-    $this->target_encoding = xml_parser_get_option($this->xml_parser, XML_OPTION_TARGET_ENCODING);
-    xml_parser_free($this->xml_parser);
-    $this->reader->closeStream();
-    unset($this->reader);
-    return $this->done();
-  }
-  
-  /*  */
-  
-  function initXMLParser() {
-    if (!isset($this->xml_parser)) {
-      $enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
-      $parser = xml_parser_create_ns($enc, '');
-      xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
-      xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
-      xml_set_element_handler($parser, 'open', 'close');
-      xml_set_character_data_handler($parser, 'cdata');
-      xml_set_start_namespace_decl_handler($parser, 'nsDecl');
-      xml_set_object($parser, $this);
-      $this->xml_parser = $parser;
-    }
-  }
-
-  /*  */
-  
-  function getEncoding($src = 'config') {
-    if ($src == 'parser') {
-      return $this->target_encoding;
-    }
-    elseif (($src == 'config') && $this->encoding) {
-      return $this->encoding;
-    }
-    return $this->reader->getEncoding();
-  }
-  
-  /*  */
-  
-  function getTriples() {
-    return $this->v('triples', array());
-  }
-  
-  function countTriples() {
-    return $this->t_count;
-  }
-
-  /*  */
-  
-  function pushS(&$s) {
-    $s['pos'] = $this->s_count;
-    $this->s_stack[$this->s_count] = $s;
-    $this->s_count++;
-  }
-  
-  function popS(){/* php 4.0.x-safe */
-    $r = array();
-    $this->s_count--;
-    for ($i = 0, $i_max = $this->s_count; $i < $i_max; $i++) {
-      $r[$i] = $this->s_stack[$i];
-    }
-    $this->s_stack = $r;
-  }
-  
-  function updateS($s) {
-    $this->s_stack[$s['pos']] = $s;
-  }
-  
-  function getParentS() {
-    return ($this->s_count && isset($this->s_stack[$this->s_count - 1])) ? $this->s_stack[$this->s_count - 1] : false;
-  }
-  
-  function getParentXBase() {
-    if ($p = $this->getParentS()) {
-      return isset($p['p_x_base']) && $p['p_x_base'] ? $p['p_x_base'] : (isset($p['x_base']) ? $p['x_base'] : '');
-    }
-    return $this->x_base;
-  }
-
-  function getParentXLang() {
-    if ($p = $this->getParentS()) {
-      return isset($p['p_x_lang']) && $p['p_x_lang'] ? $p['p_x_lang'] : (isset($p['x_lang']) ? $p['x_lang'] : '');
-    }
-    return $this->x_lang;
-  }
-
-  /*  */
-  
-  function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
-    //echo "-----\nadding $s / $p / $o\n-----\n";
-    $t = array('s' => $s, 'p' => $p, 'o' => $o, 's_type' => $s_type, 'o_type' => $o_type, 'o_datatype' => $o_dt, 'o_lang' => $o_lang);
-    if ($this->skip_dupes) {
-      $h = md5(serialize($t));
-      if (!isset($this->added_triples[$h])) {
-        $this->triples[$this->t_count] = $t;
-        $this->t_count++;
-        $this->added_triples[$h] = true;
-      }
-    }
-    else {
-      $this->triples[$this->t_count] = $t;
-      $this->t_count++;
-    }
-  }
-
-  function reify($t, $s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
-    $this->addT($t, $this->rdf.'type', $this->rdf.'Statement', 'uri', 'uri');
-    $this->addT($t, $this->rdf.'subject', $s, 'uri', $s_type);
-    $this->addT($t, $this->rdf.'predicate', $p, 'uri', 'uri');
-    $this->addT($t, $this->rdf.'object', $o, 'uri', $o_type, $o_dt, $o_lang);
-  }
-  
-  /*  */
-  
-  function open($p, $t, $a) {
-    //echo "state is $this->state\n";
-    //echo "opening $t\n";
-    switch($this->state) {
+        $this->reader->setAcceptHeader('Accept: application/rdf+xml; q=0.9, */*; q=0.1');
+        $this->reader->activate($path, $data);
+        $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
+        /* xml parser */
+        $this->initXMLParser();
+        /* parse */
+        $first = true;
+        while ($d = $this->reader->readStream()) {
+            if (!$this->keep_time_limit) {
+                @set_time_limit($this->v('time_limit', 60, $this->a));
+            }
+            if ($iso_fallback && $first) {
+                $d = '<?xml version="1.0" encoding="ISO-8859-1"?>'."\n".preg_replace('/^\<\?xml [^\>]+\?\>\s*/s', '', $d);
+                $first = false;
+            }
+            if (!xml_parse($this->xml_parser, $d, false)) {
+                $error_str = xml_error_string(xml_get_error_code($this->xml_parser));
+                $line = xml_get_current_line_number($this->xml_parser);
+                $this->tmp_error = 'XML error: "'.$error_str.'" at line '.$line.' (parsing as '.$this->getEncoding().')';
+                if (!$iso_fallback && preg_match('/Invalid character/i', $error_str)) {
+                    xml_parser_free($this->xml_parser);
+                    unset($this->xml_parser);
+                    $this->reader->closeStream();
+                    $this->__init();
+                    $this->encoding = 'ISO-8859-1';
+                    unset($this->xml_parser);
+                    unset($this->reader);
+
+                    return $this->parse($path, $data, true);
+                } else {
+                    return $this->addError($this->tmp_error);
+                }
+            }
+        }
+        $this->target_encoding = xml_parser_get_option($this->xml_parser, XML_OPTION_TARGET_ENCODING);
+        xml_parser_free($this->xml_parser);
+        $this->reader->closeStream();
+        unset($this->reader);
+
+        return $this->done();
+    }
+
+    public function initXMLParser()
+    {
+        if (!isset($this->xml_parser)) {
+            $enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
+            $parser = xml_parser_create_ns($enc, '');
+            xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
+            xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
+            xml_set_element_handler($parser, 'open', 'close');
+            xml_set_character_data_handler($parser, 'cdata');
+            xml_set_start_namespace_decl_handler($parser, 'nsDecl');
+            xml_set_object($parser, $this);
+            $this->xml_parser = $parser;
+        }
+    }
+
+    public function getEncoding($src = 'config')
+    {
+        if ('parser' == $src) {
+            return $this->target_encoding;
+        } elseif (('config' == $src) && $this->encoding) {
+            return $this->encoding;
+        }
+
+        return $this->reader->getEncoding();
+    }
+
+    public function getTriples()
+    {
+        return $this->v('triples', []);
+    }
+
+    public function countTriples()
+    {
+        return $this->t_count;
+    }
+
+    public function pushS(&$s)
+    {
+        $s['pos'] = $this->s_count;
+        $this->s_stack[$this->s_count] = $s;
+        ++$this->s_count;
+    }
+
+    public function popS()
+    {/* php 4.0.x-safe */
+        $r = [];
+        --$this->s_count;
+        for ($i = 0, $i_max = $this->s_count; $i < $i_max; ++$i) {
+            $r[$i] = $this->s_stack[$i];
+        }
+        $this->s_stack = $r;
+    }
+
+    public function updateS($s)
+    {
+        $this->s_stack[$s['pos']] = $s;
+    }
+
+    public function getParentS()
+    {
+        return ($this->s_count && isset($this->s_stack[$this->s_count - 1])) ? $this->s_stack[$this->s_count - 1] : false;
+    }
+
+    public function getParentXBase()
+    {
+        if ($p = $this->getParentS()) {
+            return isset($p['p_x_base']) && $p['p_x_base'] ? $p['p_x_base'] : (isset($p['x_base']) ? $p['x_base'] : '');
+        }
+
+        return $this->x_base;
+    }
+
+    public function getParentXLang()
+    {
+        if ($p = $this->getParentS()) {
+            return isset($p['p_x_lang']) && $p['p_x_lang'] ? $p['p_x_lang'] : (isset($p['x_lang']) ? $p['x_lang'] : '');
+        }
+
+        return $this->x_lang;
+    }
+
+    public function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '')
+    {
+        //echo "-----\nadding $s / $p / $o\n-----\n";
+        $t = ['s' => $s, 'p' => $p, 'o' => $o, 's_type' => $s_type, 'o_type' => $o_type, 'o_datatype' => $o_dt, 'o_lang' => $o_lang];
+        if ($this->skip_dupes) {
+            $h = md5(serialize($t));
+            if (!isset($this->added_triples[$h])) {
+                $this->triples[$this->t_count] = $t;
+                ++$this->t_count;
+                $this->added_triples[$h] = true;
+            }
+        } else {
+            $this->triples[$this->t_count] = $t;
+            ++$this->t_count;
+        }
+    }
+
+    public function reify($t, $s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '')
+    {
+        $this->addT($t, $this->rdf.'type', $this->rdf.'Statement', 'uri', 'uri');
+        $this->addT($t, $this->rdf.'subject', $s, 'uri', $s_type);
+        $this->addT($t, $this->rdf.'predicate', $p, 'uri', 'uri');
+        $this->addT($t, $this->rdf.'object', $o, 'uri', $o_type, $o_dt, $o_lang);
+    }
+
+    public function open($p, $t, $a)
+    {
+        //echo "state is $this->state\n";
+        //echo "opening $t\n";
+        switch ($this->state) {
       case 0: return $this->h0Open($t, $a);
       case 1: return $this->h1Open($t, $a);
       case 2: return $this->h2Open($t, $a);
       case 4: return $this->h4Open($t, $a);
       case 5: return $this->h5Open($t, $a);
       case 6: return $this->h6Open($t, $a);
-      default: $this->addError('open() called at state ' . $this->state . ' in '.$t);
+      default: $this->addError('open() called at state '.$this->state.' in '.$t);
+    }
     }
-  }
 
-  function close($p, $t) {
-    //echo "state is $this->state\n";
-    //echo "closing $t\n";
-    switch($this->state){
+    public function close($p, $t)
+    {
+        //echo "state is $this->state\n";
+        //echo "closing $t\n";
+        switch ($this->state) {
       case 1: return $this->h1Close($t);
       case 2: return $this->h2Close($t);
       case 3: return $this->h3Close($t);
       case 4: return $this->h4Close($t);
       case 5: return $this->h5Close($t);
       case 6: return $this->h6Close($t);
-      default: $this->addError('close() called at state ' . $this->state . ' in '.$t);
+      default: $this->addError('close() called at state '.$this->state.' in '.$t);
+    }
     }
-  }
 
-  function cdata($p, $d) {
-    //echo "state is $this->state\n";
-    //echo "cdata\n";
-    switch($this->state){
+    public function cdata($p, $d)
+    {
+        //echo "state is $this->state\n";
+        //echo "cdata\n";
+        switch ($this->state) {
       case 4: return $this->h4Cdata($d);
       case 6: return $this->h6Cdata($d);
       default: return false;
     }
-  }
-  
-  function nsDecl($p, $prf, $uri) {
-    $this->nsp[$uri] = isset($this->nsp[$uri]) ? $this->nsp[$uri] : $prf;
-  }
-
-  /*  */
-  
-  function h0Open($t, $a) {
-    $this->x_lang = $this->v($this->xml.'lang', $this->x_lang, $a);
-    $this->x_base = $this->calcURI($this->v($this->xml.'base', $this->x_base, $a));
-    $this->state = 1;
-    if ($t !== $this->rdf.'RDF') {
-      $this->h1Open($t, $a);
-    }
-  }
-  
-  /*  */
-
-  function h1Open($t, $a) {
-    $s = array(
-      'x_base' => isset($a[$this->xml.'base']) ? $this->calcURI($a[$this->xml.'base']) : $this->getParentXBase(), 
-      'x_lang' => isset($a[$this->xml.'lang']) ? $a[$this->xml.'lang'] : $this->getParentXLang(),
-      'li_count' => 0,
-    );
-    /* ID */
-    if (isset($a[$this->rdf.'ID'])) {
-      $s['type'] = 'uri';
-      $s['value'] = $this->calcURI('#'.$a[$this->rdf.'ID'], $s['x_base']);
-    }
-    /* about */
-    elseif (isset($a[$this->rdf.'about'])) {
-      $s['type'] = 'uri';
-      $s['value'] = $this->calcURI($a[$this->rdf.'about'], $s['x_base']);
-    }
-    /* bnode */
-    else {
-      $s['type'] = 'bnode';
-      if (isset($a[$this->rdf.'nodeID'])) {
-        $s['value'] = '_:'.$a[$this->rdf.'nodeID'];
-      }
-      else {
-        $s['value'] = $this->createBnodeID();
-      }
-    }
-    /* sub-node */
-    if ($this->state === 4) {
-      $sup_s = $this->getParentS();
-      /* new collection */
-      if (isset($sup_s['o_is_coll']) && $sup_s['o_is_coll']) {
-        $coll = array('value' => $this->createBnodeID(), 'type' => 'bnode', 'is_coll' => true, 'x_base' => $s['x_base'], 'x_lang' => $s['x_lang']);
-        $this->addT($sup_s['value'], $sup_s['p'], $coll['value'], $sup_s['type'], $coll['type']);
-        $this->addT($coll['value'], $this->rdf . 'first', $s['value'], $coll['type'], $s['type']);
-        $this->pushS($coll);
-      }
-      /* new entry in existing coll */
-      elseif (isset($sup_s['is_coll']) && $sup_s['is_coll']) {
-        $coll = array('value' => $this->createBnodeID(), 'type' => 'bnode', 'is_coll' => true, 'x_base' => $s['x_base'], 'x_lang' => $s['x_lang']);
-        $this->addT($sup_s['value'], $this->rdf . 'rest', $coll['value'], $sup_s['type'], $coll['type']);
-        $this->addT($coll['value'], $this->rdf . 'first', $s['value'], $coll['type'], $s['type']);
-        $this->pushS($coll);
-      }
-      /* normal sub-node */
-      elseif(isset($sup_s['p']) && $sup_s['p']) {
-        $this->addT($sup_s['value'], $sup_s['p'], $s['value'], $sup_s['type'], $s['type']);
-      }
-    }
-    /* typed node */
-    if ($t !== $this->rdf.'Description') {
-      $this->addT($s['value'], $this->rdf.'type', $t, $s['type'], 'uri');
-    }
-    /* (additional) typing attr */
-    if (isset($a[$this->rdf.'type'])) {
-      $this->addT($s['value'], $this->rdf.'type', $a[$this->rdf.'type'], $s['type'], 'uri');
-    }
-    /* Seq|Bag|Alt */
-    if (in_array($t, array($this->rdf.'Seq', $this->rdf.'Bag', $this->rdf.'Alt'))) {
-      $s['is_con'] = true;
-    }
-    /* any other attrs (skip rdf and xml, except rdf:_, rdf:value, rdf:Seq) */
-    foreach($a as $k => $v) {
-      if (((strpos($k, $this->xml) === false) && (strpos($k, $this->rdf) === false)) || preg_match('/(\_[0-9]+|value|Seq|Bag|Alt|Statement|Property|List)$/', $k)) {
-        if (strpos($k, ':')) {
-          $this->addT($s['value'], $k, $v, $s['type'], 'literal', '', $s['x_lang']);
-        }
-      }
-    }
-    $this->pushS($s);
-    $this->state = 2;
-  }
-
-  /*  */
-
-  function h2Open($t, $a) {
-    $s = $this->getParentS();
-    foreach (array('p_x_base', 'p_x_lang', 'p_id', 'o_is_coll') as $k) {
-      unset($s[$k]);
-    }
-    /* base */
-    if (isset($a[$this->xml.'base'])) {
-      $s['p_x_base'] = $this->calcURI($a[$this->xml.'base'], $s['x_base']);
-    }
-    $b = isset($s['p_x_base']) && $s['p_x_base'] ? $s['p_x_base'] : $s['x_base'];
-    /* lang */
-    if (isset($a[$this->xml.'lang'])) {
-      $s['p_x_lang'] = $a[$this->xml.'lang'];
-    }
-    $l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : $s['x_lang'];
-    /* adjust li */
-    if ($t === $this->rdf.'li') {
-      $s['li_count']++;
-      $t = $this->rdf.'_'.$s['li_count'];
-    }
-    /* set p */
-    $s['p'] = $t;
-		/* reification */
-    if (isset($a[$this->rdf.'ID'])) {
-      $s['p_id'] = $a[$this->rdf.'ID'];
-    }
-    $o = array('value' => '', 'type' => '', 'x_base' => $b, 'x_lang' => $l);
-    /* resource/rdf:resource */
-    if (isset($a['resource'])) {
-      $a[$this->rdf . 'resource'] = $a['resource'];
-      unset($a['resource']);
-    }
-    if (isset($a[$this->rdf.'resource'])) {
-      $o['value'] = $this->calcURI($a[$this->rdf.'resource'], $b);
-      $o['type'] = 'uri';
-      $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
-      /* type */
-      if (isset($a[$this->rdf.'type'])) {
-        $this->addT($o['value'], $this->rdf.'type', $a[$this->rdf.'type'], 'uri', 'uri');
-      }
-      /* reification */
-      if (isset($s['p_id'])) {
-        $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
-        unset($s['p_id']);
-      }
-      $this->state = 3;
-    }
-    /* named bnode */
-    elseif (isset($a[$this->rdf.'nodeID'])) {
-      $o['value'] = '_:' . $a[$this->rdf.'nodeID'];
-      $o['type'] = 'bnode';
-      $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
-      $this->state = 3;
-      /* reification */
-      if (isset($s['p_id'])) {
-        $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
-      }
-    }
-    /* parseType */
-    elseif (isset($a[$this->rdf.'parseType'])) {
-      if ($a[$this->rdf.'parseType'] === 'Literal') {
-        $s['o_xml_level'] = 0;
-        $s['o_xml_data'] = '';
-        $s['p_xml_literal_level'] = 0;
-        $s['ns'] = array();
-        $this->state = 6;
-      }
-      elseif ($a[$this->rdf.'parseType'] === 'Resource') {
-        $o['value'] = $this->createBnodeID();
-        $o['type'] = 'bnode';
-        $o['has_closing_tag'] = 0;
-        $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
-        $this->pushS($o);
-        /* reification */
-        if (isset($s['p_id'])) {
-          $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
-          unset($s['p_id']);
+    }
+
+    public function nsDecl($p, $prf, $uri)
+    {
+        $this->nsp[$uri] = isset($this->nsp[$uri]) ? $this->nsp[$uri] : $prf;
+    }
+
+    public function h0Open($t, $a)
+    {
+        $this->x_lang = $this->v($this->xml.'lang', $this->x_lang, $a);
+        $this->x_base = $this->calcURI($this->v($this->xml.'base', $this->x_base, $a));
+        $this->state = 1;
+        if ($t !== $this->rdf.'RDF') {
+            $this->h1Open($t, $a);
+        }
+    }
+
+    public function h1Open($t, $a)
+    {
+        $s = [
+            'x_base' => isset($a[$this->xml.'base']) ? $this->calcURI($a[$this->xml.'base']) : $this->getParentXBase(),
+            'x_lang' => isset($a[$this->xml.'lang']) ? $a[$this->xml.'lang'] : $this->getParentXLang(),
+            'li_count' => 0,
+        ];
+        /* ID */
+        if (isset($a[$this->rdf.'ID'])) {
+            $s['type'] = 'uri';
+            $s['value'] = $this->calcURI('#'.$a[$this->rdf.'ID'], $s['x_base']);
+        }
+        /* about */
+        elseif (isset($a[$this->rdf.'about'])) {
+            $s['type'] = 'uri';
+            $s['value'] = $this->calcURI($a[$this->rdf.'about'], $s['x_base']);
+        }
+        /* bnode */
+        else {
+            $s['type'] = 'bnode';
+            if (isset($a[$this->rdf.'nodeID'])) {
+                $s['value'] = '_:'.$a[$this->rdf.'nodeID'];
+            } else {
+                $s['value'] = $this->createBnodeID();
+            }
         }
+        /* sub-node */
+        if (4 === $this->state) {
+            $sup_s = $this->getParentS();
+            /* new collection */
+            if (isset($sup_s['o_is_coll']) && $sup_s['o_is_coll']) {
+                $coll = ['value' => $this->createBnodeID(), 'type' => 'bnode', 'is_coll' => true, 'x_base' => $s['x_base'], 'x_lang' => $s['x_lang']];
+                $this->addT($sup_s['value'], $sup_s['p'], $coll['value'], $sup_s['type'], $coll['type']);
+                $this->addT($coll['value'], $this->rdf.'first', $s['value'], $coll['type'], $s['type']);
+                $this->pushS($coll);
+            }
+            /* new entry in existing coll */
+            elseif (isset($sup_s['is_coll']) && $sup_s['is_coll']) {
+                $coll = ['value' => $this->createBnodeID(), 'type' => 'bnode', 'is_coll' => true, 'x_base' => $s['x_base'], 'x_lang' => $s['x_lang']];
+                $this->addT($sup_s['value'], $this->rdf.'rest', $coll['value'], $sup_s['type'], $coll['type']);
+                $this->addT($coll['value'], $this->rdf.'first', $s['value'], $coll['type'], $s['type']);
+                $this->pushS($coll);
+            }
+            /* normal sub-node */
+            elseif (isset($sup_s['p']) && $sup_s['p']) {
+                $this->addT($sup_s['value'], $sup_s['p'], $s['value'], $sup_s['type'], $s['type']);
+            }
+        }
+        /* typed node */
+        if ($t !== $this->rdf.'Description') {
+            $this->addT($s['value'], $this->rdf.'type', $t, $s['type'], 'uri');
+        }
+        /* (additional) typing attr */
+        if (isset($a[$this->rdf.'type'])) {
+            $this->addT($s['value'], $this->rdf.'type', $a[$this->rdf.'type'], $s['type'], 'uri');
+        }
+        /* Seq|Bag|Alt */
+        if (in_array($t, [$this->rdf.'Seq', $this->rdf.'Bag', $this->rdf.'Alt'])) {
+            $s['is_con'] = true;
+        }
+        /* any other attrs (skip rdf and xml, except rdf:_, rdf:value, rdf:Seq) */
+        foreach ($a as $k => $v) {
+            if (((false === strpos($k, $this->xml)) && (false === strpos($k, $this->rdf))) || preg_match('/(\_[0-9]+|value|Seq|Bag|Alt|Statement|Property|List)$/', $k)) {
+                if (strpos($k, ':')) {
+                    $this->addT($s['value'], $k, $v, $s['type'], 'literal', '', $s['x_lang']);
+                }
+            }
+        }
+        $this->pushS($s);
         $this->state = 2;
-      }
-      elseif ($a[$this->rdf.'parseType'] === 'Collection') {
-        $s['o_is_coll'] = true;
-        $this->state = 4;
-      }
-    }
-    /* sub-node or literal */
-    else {
-      $s['o_cdata'] = '';
-      if (isset($a[$this->rdf.'datatype'])) {
-        $s['o_datatype'] = $a[$this->rdf.'datatype'];
-      }
-      $this->state = 4;
-    }
-    /* any other attrs (skip rdf and xml) */
-    foreach($a as $k => $v) {
-      if (((strpos($k, $this->xml) === false) && (strpos($k, $this->rdf) === false)) || preg_match('/(\_[0-9]+|value)$/', $k)) {
-        if (strpos($k, ':')) {
-          if (!$o['value']) {
-            $o['value'] = $this->createBnodeID();
+    }
+
+    public function h2Open($t, $a)
+    {
+        $s = $this->getParentS();
+        foreach (['p_x_base', 'p_x_lang', 'p_id', 'o_is_coll'] as $k) {
+            unset($s[$k]);
+        }
+        /* base */
+        if (isset($a[$this->xml.'base'])) {
+            $s['p_x_base'] = $this->calcURI($a[$this->xml.'base'], $s['x_base']);
+        }
+        $b = isset($s['p_x_base']) && $s['p_x_base'] ? $s['p_x_base'] : $s['x_base'];
+        /* lang */
+        if (isset($a[$this->xml.'lang'])) {
+            $s['p_x_lang'] = $a[$this->xml.'lang'];
+        }
+        $l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : $s['x_lang'];
+        /* adjust li */
+        if ($t === $this->rdf.'li') {
+            ++$s['li_count'];
+            $t = $this->rdf.'_'.$s['li_count'];
+        }
+        /* set p */
+        $s['p'] = $t;
+        /* reification */
+        if (isset($a[$this->rdf.'ID'])) {
+            $s['p_id'] = $a[$this->rdf.'ID'];
+        }
+        $o = ['value' => '', 'type' => '', 'x_base' => $b, 'x_lang' => $l];
+        /* resource/rdf:resource */
+        if (isset($a['resource'])) {
+            $a[$this->rdf.'resource'] = $a['resource'];
+            unset($a['resource']);
+        }
+        if (isset($a[$this->rdf.'resource'])) {
+            $o['value'] = $this->calcURI($a[$this->rdf.'resource'], $b);
+            $o['type'] = 'uri';
+            $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+            /* type */
+            if (isset($a[$this->rdf.'type'])) {
+                $this->addT($o['value'], $this->rdf.'type', $a[$this->rdf.'type'], 'uri', 'uri');
+            }
+            /* reification */
+            if (isset($s['p_id'])) {
+                $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+                unset($s['p_id']);
+            }
+            $this->state = 3;
+        }
+        /* named bnode */
+        elseif (isset($a[$this->rdf.'nodeID'])) {
+            $o['value'] = '_:'.$a[$this->rdf.'nodeID'];
             $o['type'] = 'bnode';
             $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
-          }
-          /* reification */
-          if (isset($s['p_id'])) {
-            $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
-            unset($s['p_id']);
-          }
-          $this->addT($o['value'], $k, $v, $o['type'], 'literal');
-          $this->state = 3;
-        }
-      }
-    }
-    $this->updateS($s);
-  }
-
-  /*  */
-
-  function h4Open($t, $a) {
-    return $this->h1Open($t, $a);
-  }
-  
-  /*  */
-
-  function h5Open($t, $a) {
-    $this->state = 4;
-    return $this->h4Open($t, $a);
-  }
-  
-  /*  */
-  
-  function h6Open($t, $a) {
-    $s = $this->getParentS();
-    $data = isset($s['o_xml_data']) ? $s['o_xml_data'] : '';
-    $ns = isset($s['ns']) ? $s['ns'] : array();
-    $parts = $this->splitURI($t);
-    if (count($parts) === 1) {
-      $data .= '<'.$t;
-    }
-    else {
-      $ns_uri = $parts[0];
-      $name = $parts[1];
-      if (!isset($this->nsp[$ns_uri])) {
-        foreach ($this->nsp as $tmp1 => $tmp2) {
-          if (strpos($t, $tmp1) === 0) {
-            $ns_uri = $tmp1;
-            $name = substr($t, strlen($tmp1));
-            break;
-          }
-        }
-      }
-      $nsp = $this->nsp[$ns_uri];
-      $data .= $nsp ? '<' . $nsp . ':' . $name : '<' . $name;
-      /* ns */
-      if (!isset($ns[$nsp.'='.$ns_uri]) || !$ns[$nsp.'='.$ns_uri]) {
-        $data .= $nsp ? ' xmlns:'.$nsp.'="'.$ns_uri.'"' : ' xmlns="'.$ns_uri.'"';
-        $ns[$nsp.'='.$ns_uri] = true;
-        $s['ns'] = $ns;
-      }
-    }
-    foreach ($a as $k => $v) {
-      $parts = $this->splitURI($k);
-      if (count($parts) === 1) {
-        $data .= ' '.$k.'="'.$v.'"';
-      }
-      else {
-        $ns_uri = $parts[0];
-        $name = $parts[1];
-        $nsp = $this->v($ns_uri, '', $this->nsp);
-        $data .= $nsp ? ' '.$nsp.':'.$name.'="'.$v.'"' : ' '.$name.'="'.$v.'"' ;
-      }
-    }
-    $data .= '>';
-    $s['o_xml_data'] = $data;
-    $s['o_xml_level'] = isset($s['o_xml_level']) ? $s['o_xml_level'] + 1 : 1;
-    if ($t == $s['p']) {/* xml container prop */
-      $s['p_xml_literal_level'] = isset($s['p_xml_literal_level']) ? $s['p_xml_literal_level'] + 1 : 1;
-    }
-    $this->updateS($s);
-  }
-
-  /*  */
-
-  function h1Close($t) {/* end of doc */
-    $this->state = 0;
-  }
-  
-  /*  */
-  
-  function h2Close($t) {/* expecting a prop, getting a close */
-    if ($s = $this->getParentS()) {
-      $has_closing_tag = (isset($s['has_closing_tag']) && !$s['has_closing_tag']) ? 0 : 1;
-      $this->popS();
-      $this->state = 5;
-      if ($s = $this->getParentS()) {/* new s */
-        if (!isset($s['p']) || !$s['p']) {/* p close after collection|parseType=Resource|node close after p close */
-          $this->state = $this->s_count ? 4 : 1;
-          if (!$has_closing_tag) {
-            $this->state = 2;
-          }
-        }
-        elseif (!$has_closing_tag) {
-          $this->state = 2;
-        }
-      }
-    }
-  }
-  
-  /*  */
-  
-  function h3Close($t) {/* p close */
-    $this->state = 2;
-  }
-  
-  /*  */
-  
-  function h4Close($t) {/* empty p | pClose after cdata | pClose after collection */
-    if ($s = $this->getParentS()) {
-      $b = isset($s['p_x_base']) && $s['p_x_base'] ? $s['p_x_base'] : (isset($s['x_base']) ? $s['x_base'] : '');
-      if (isset($s['is_coll']) && $s['is_coll']) {
-        $this->addT($s['value'], $this->rdf . 'rest', $this->rdf . 'nil', $s['type'], 'uri');
-        /* back to collection start */
-        while ((!isset($s['p']) || ($s['p'] != $t))) {
-          $sub_s = $s;
-          $this->popS();
-          $s = $this->getParentS();
+            $this->state = 3;
+            /* reification */
+            if (isset($s['p_id'])) {
+                $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+            }
         }
-        /* reification */
-        if (isset($s['p_id']) && $s['p_id']) {
-          $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $sub_s['value'], $s['type'], $sub_s['type']);
+        /* parseType */
+        elseif (isset($a[$this->rdf.'parseType'])) {
+            if ('Literal' === $a[$this->rdf.'parseType']) {
+                $s['o_xml_level'] = 0;
+                $s['o_xml_data'] = '';
+                $s['p_xml_literal_level'] = 0;
+                $s['ns'] = [];
+                $this->state = 6;
+            } elseif ('Resource' === $a[$this->rdf.'parseType']) {
+                $o['value'] = $this->createBnodeID();
+                $o['type'] = 'bnode';
+                $o['has_closing_tag'] = 0;
+                $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+                $this->pushS($o);
+                /* reification */
+                if (isset($s['p_id'])) {
+                    $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+                    unset($s['p_id']);
+                }
+                $this->state = 2;
+            } elseif ('Collection' === $a[$this->rdf.'parseType']) {
+                $s['o_is_coll'] = true;
+                $this->state = 4;
+            }
         }
-        unset($s['p']);
-        $this->updateS($s);
-      }
-      else {
-        $dt = isset($s['o_datatype']) ? $s['o_datatype'] : '';
-        $l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : (isset($s['x_lang']) ? $s['x_lang'] : '');
-        $o = array('type' => 'literal', 'value' => $s['o_cdata']);
-        $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type'], $dt, $l);
-        /* reification */
-        if (isset($s['p_id']) && $s['p_id']) {
-          $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type'], $dt, $l);
+        /* sub-node or literal */
+        else {
+            $s['o_cdata'] = '';
+            if (isset($a[$this->rdf.'datatype'])) {
+                $s['o_datatype'] = $a[$this->rdf.'datatype'];
+            }
+            $this->state = 4;
+        }
+        /* any other attrs (skip rdf and xml) */
+        foreach ($a as $k => $v) {
+            if (((false === strpos($k, $this->xml)) && (false === strpos($k, $this->rdf))) || preg_match('/(\_[0-9]+|value)$/', $k)) {
+                if (strpos($k, ':')) {
+                    if (!$o['value']) {
+                        $o['value'] = $this->createBnodeID();
+                        $o['type'] = 'bnode';
+                        $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+                    }
+                    /* reification */
+                    if (isset($s['p_id'])) {
+                        $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+                        unset($s['p_id']);
+                    }
+                    $this->addT($o['value'], $k, $v, $o['type'], 'literal');
+                    $this->state = 3;
+                }
+            }
         }
-        unset($s['o_cdata']);
-        unset($s['o_datatype']);
-        unset($s['p']);
         $this->updateS($s);
-      }
-      $this->state = 2;
-    }
-  }
-  
-  /*  */
-  
-  function h5Close($t) {/* p close */
-    if ($s = $this->getParentS()) {
-      unset($s['p']);
-      $this->updateS($s);
-      $this->state = 2;
-    }
-  }
-
-  /*  */
-
-  function h6Close($t) {
-    if ($s = $this->getParentS()) {
-      $l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : (isset($s['x_lang']) ? $s['x_lang'] : '');
-      $data = $s['o_xml_data'];
-      $level = $s['o_xml_level'];
-      if ($level === 0) {/* pClose */
-        $this->addT($s['value'], $s['p'], trim($data, ' '), $s['type'], 'literal', $this->rdf.'XMLLiteral', $l);
-        unset($s['o_xml_data']);
-        $this->state = 2;
-      }
-      else {
+    }
+
+    public function h4Open($t, $a)
+    {
+        return $this->h1Open($t, $a);
+    }
+
+    public function h5Open($t, $a)
+    {
+        $this->state = 4;
+
+        return $this->h4Open($t, $a);
+    }
+
+    public function h6Open($t, $a)
+    {
+        $s = $this->getParentS();
+        $data = isset($s['o_xml_data']) ? $s['o_xml_data'] : '';
+        $ns = isset($s['ns']) ? $s['ns'] : [];
         $parts = $this->splitURI($t);
-        if (count($parts) == 1) {
-          $data .= '</'.$t.'>';
+        if ((1 === count($parts)) || empty($parts[1])) {
+            $data .= '<'.$t;
+        } else {
+            $ns_uri = $parts[0];
+            $name = $parts[1];
+            if (!isset($this->nsp[$ns_uri])) {
+                foreach ($this->nsp as $tmp1 => $tmp2) {
+                    if (0 === strpos($t, $tmp1)) {
+                        $ns_uri = $tmp1;
+                        $name = substr($t, strlen($tmp1));
+                        break;
+                    }
+                }
+            }
+            $nsp = $this->nsp[$ns_uri];
+            $data .= $nsp ? '<'.$nsp.':'.$name : '<'.$name;
+            /* ns */
+            if (!isset($ns[$nsp.'='.$ns_uri]) || !$ns[$nsp.'='.$ns_uri]) {
+                $data .= $nsp ? ' xmlns:'.$nsp.'="'.$ns_uri.'"' : ' xmlns="'.$ns_uri.'"';
+                $ns[$nsp.'='.$ns_uri] = true;
+                $s['ns'] = $ns;
+            }
         }
-        else {
-          $ns_uri = $parts[0];
-          $name = $parts[1];
-          if (!isset($this->nsp[$ns_uri])) {
-            foreach ($this->nsp as $tmp1 => $tmp2) {
-              if (strpos($t, $tmp1) === 0) {
-                $ns_uri = $tmp1;
-                $name = substr($t, strlen($tmp1));
-                break;
-              }
+        foreach ($a as $k => $v) {
+            $parts = $this->splitURI($k);
+            if (1 === count($parts)) {
+                $data .= ' '.$k.'="'.$v.'"';
+            } else {
+                $ns_uri = $parts[0];
+                $name = $parts[1];
+                $nsp = $this->v($ns_uri, '', $this->nsp);
+                $data .= $nsp ? ' '.$nsp.':'.$name.'="'.$v.'"' : ' '.$name.'="'.$v.'"';
             }
-          }
-          $nsp = $this->nsp[$ns_uri];
-          $data .= $nsp ? '</'.$nsp.':'.$name.'>' : '</'.$name.'>';
         }
+        $data .= '>';
         $s['o_xml_data'] = $data;
-        $s['o_xml_level'] = $level - 1;
+        $s['o_xml_level'] = isset($s['o_xml_level']) ? $s['o_xml_level'] + 1 : 1;
         if ($t == $s['p']) {/* xml container prop */
-          $s['p_xml_literal_level']--;
-        }
-      }
-      $this->updateS($s);
-    }
-  }
-  
-  /*  */
-  
-  function h4Cdata($d) {
-    if ($s = $this->getParentS()) {
-      $s['o_cdata'] = isset($s['o_cdata']) ? $s['o_cdata'] . $d : $d;
-      $this->updateS($s);
-    }
-  }
-  
-  /*  */
-
-  function h6Cdata($d) {
-    if ($s = $this->getParentS()) {
-      if (isset($s['o_xml_data']) || preg_match("/[\n\r]/", $d) || trim($d)) {
-        $d = htmlspecialchars($d, ENT_NOQUOTES);
-        $s['o_xml_data'] = isset($s['o_xml_data']) ? $s['o_xml_data'] . $d : $d;
-      }
-      $this->updateS($s);
-    }
-  }
-  
-  /*  */
-  
+            $s['p_xml_literal_level'] = isset($s['p_xml_literal_level']) ? $s['p_xml_literal_level'] + 1 : 1;
+        }
+        $this->updateS($s);
+    }
+
+    public function h1Close($t)
+    {/* end of doc */
+        $this->state = 0;
+    }
+
+    public function h2Close($t)
+    {/* expecting a prop, getting a close */
+        if ($s = $this->getParentS()) {
+            $has_closing_tag = (isset($s['has_closing_tag']) && !$s['has_closing_tag']) ? 0 : 1;
+            $this->popS();
+            $this->state = 5;
+            if ($s = $this->getParentS()) {/* new s */
+                if (!isset($s['p']) || !$s['p']) {/* p close after collection|parseType=Resource|node close after p close */
+                    $this->state = $this->s_count ? 4 : 1;
+                    if (!$has_closing_tag) {
+                        $this->state = 2;
+                    }
+                } elseif (!$has_closing_tag) {
+                    $this->state = 2;
+                }
+            }
+        }
+    }
+
+    public function h3Close($t)
+    {/* p close */
+        $this->state = 2;
+    }
+
+    public function h4Close($t)
+    {/* empty p | pClose after cdata | pClose after collection */
+        if ($s = $this->getParentS()) {
+            $b = isset($s['p_x_base']) && $s['p_x_base'] ? $s['p_x_base'] : (isset($s['x_base']) ? $s['x_base'] : '');
+            if (isset($s['is_coll']) && $s['is_coll']) {
+                $this->addT($s['value'], $this->rdf.'rest', $this->rdf.'nil', $s['type'], 'uri');
+                /* back to collection start */
+                while ((!isset($s['p']) || ($s['p'] != $t))) {
+                    $sub_s = $s;
+                    $this->popS();
+                    $s = $this->getParentS();
+                }
+                /* reification */
+                if (isset($s['p_id']) && $s['p_id']) {
+                    $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $sub_s['value'], $s['type'], $sub_s['type']);
+                }
+                unset($s['p']);
+                $this->updateS($s);
+            } else {
+                $dt = isset($s['o_datatype']) ? $s['o_datatype'] : '';
+                $l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : (isset($s['x_lang']) ? $s['x_lang'] : '');
+                $o = ['type' => 'literal', 'value' => $s['o_cdata']];
+                $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type'], $dt, $l);
+                /* reification */
+                if (isset($s['p_id']) && $s['p_id']) {
+                    $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type'], $dt, $l);
+                }
+                unset($s['o_cdata']);
+                unset($s['o_datatype']);
+                unset($s['p']);
+                $this->updateS($s);
+            }
+            $this->state = 2;
+        }
+    }
+
+    public function h5Close($t)
+    {/* p close */
+        if ($s = $this->getParentS()) {
+            unset($s['p']);
+            $this->updateS($s);
+            $this->state = 2;
+        }
+    }
+
+    public function h6Close($t)
+    {
+        if ($s = $this->getParentS()) {
+            $l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : (isset($s['x_lang']) ? $s['x_lang'] : '');
+            $data = $s['o_xml_data'];
+            $level = $s['o_xml_level'];
+            if (0 === $level) {/* pClose */
+                $this->addT($s['value'], $s['p'], trim($data, ' '), $s['type'], 'literal', $this->rdf.'XMLLiteral', $l);
+                unset($s['o_xml_data']);
+                $this->state = 2;
+            } else {
+                $parts = $this->splitURI($t);
+                if ((1 === count($parts)) || empty($parts[1])) {
+                    $data .= '</'.$t.'>';
+                } else {
+                    $ns_uri = $parts[0];
+                    $name = $parts[1];
+                    if (!isset($this->nsp[$ns_uri])) {
+                        foreach ($this->nsp as $tmp1 => $tmp2) {
+                            if (0 === strpos($t, $tmp1)) {
+                                $ns_uri = $tmp1;
+                                $name = substr($t, strlen($tmp1));
+                                break;
+                            }
+                        }
+                    }
+                    $nsp = $this->nsp[$ns_uri];
+                    $data .= $nsp ? '</'.$nsp.':'.$name.'>' : '</'.$name.'>';
+                }
+                $s['o_xml_data'] = $data;
+                $s['o_xml_level'] = $level - 1;
+                if ($t == $s['p']) {/* xml container prop */
+                    --$s['p_xml_literal_level'];
+                }
+            }
+            $this->updateS($s);
+        }
+    }
+
+    public function h4Cdata($d)
+    {
+        if ($s = $this->getParentS()) {
+            $s['o_cdata'] = isset($s['o_cdata']) ? $s['o_cdata'].$d : $d;
+            $this->updateS($s);
+        }
+    }
+
+    public function h6Cdata($d)
+    {
+        if ($s = $this->getParentS()) {
+            if (isset($s['o_xml_data']) || preg_match("/[\n\r]/", $d) || trim($d)) {
+                $d = htmlspecialchars($d, ENT_NOQUOTES);
+                $s['o_xml_data'] = isset($s['o_xml_data']) ? $s['o_xml_data'].$d : $d;
+            }
+            $this->updateS($s);
+        }
+    }
 }
diff --git a/lib/arc2/parsers/ARC2_RSSParser.php b/lib/arc2/parsers/ARC2_RSSParser.php
index cf21e69a3af592772bd17b372e6108a47b534493..3af286d4a45923672a00c5c25702748fa84cea04 100644
--- a/lib/arc2/parsers/ARC2_RSSParser.php
+++ b/lib/arc2/parsers/ARC2_RSSParser.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 RSS Parser
 author:   Benjamin Nowack
@@ -10,176 +10,191 @@ version:  2010-11-16
 
 ARC2::inc('LegacyXMLParser');
 
-class ARC2_RSSParser extends ARC2_LegacyXMLParser {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* reader */
-    parent::__init();
-    $this->triples = array();
-    $this->target_encoding = '';
-    $this->t_count = 0;
-    $this->added_triples = array();
-    $this->skip_dupes = false;
-    $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
-    $this->bnode_id = 0;
-    $this->cache = array();
-    $this->allowCDataNodes = 0;
-  }
-  
-  /*  */
-  
-  function done() {
-    $this->extractRDF();
-  }
-  
-  /*  */
-  
-  function setReader(&$reader) {
-    $this->reader = $reader;
-  }
-  
-  function createBnodeID(){
-    $this->bnode_id++;
-    return '_:' . $this->bnode_prefix . $this->bnode_id;
-  }
-  
-  function addT($t) {
-    //if (!isset($t['o_datatype']))
-    if ($this->skip_dupes) {
-      $h = md5(serialize($t));
-      if (!isset($this->added_triples[$h])) {
-        $this->triples[$this->t_count] = $t;
-        $this->t_count++;
-        $this->added_triples[$h] = true;
-      }
+class ARC2_RSSParser extends ARC2_LegacyXMLParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
     }
-    else {
-      $this->triples[$this->t_count] = $t;
-      $this->t_count++;
+
+    public function __init()
+    {/* reader */
+        parent::__init();
+        $this->triples = [];
+        $this->target_encoding = '';
+        $this->t_count = 0;
+        $this->added_triples = [];
+        $this->skip_dupes = false;
+        $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
+        $this->bnode_id = 0;
+        $this->cache = [];
+        $this->allowCDataNodes = 0;
     }
-  }
-
-  function getTriples() {
-    return $this->v('triples', array());
-  }
-
-  function countTriples() {
-    return $this->t_count;
-  }
-  
-  function getSimpleIndex($flatten_objects = 1, $vals = '') {
-    return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
-  }
-
-  /*  */
-
-  function extractRDF() {
-    $index = $this->getNodeIndex();
-    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
-    $this->rss = 'http://purl.org/rss/1.0/';
-    $this->dc = 'http://purl.org/dc/elements/1.1/';
-    $this->dct = 'http://purl.org/dc/terms/';
-    $this->content = 'http://purl.org/rss/1.0/modules/content/';
-    $this->enc = 'http://purl.oclc.org/net/rss_2.0/enc#';
-    $this->mappings = array(
-      'channel' => $this->rss . 'channel',
-      'item' => $this->rss . 'item',
-      'title' => $this->rss . 'title',
-      'link' => $this->rss . 'link',
-      'description' => $this->rss . 'description',
-      'guid' => $this->dc . 'identifier',
-      'author' => $this->dc . 'creator',
-      'category' => $this->dc . 'subject',
-      'pubDate' => $this->dc . 'date',
-      'pubdate' => $this->dc . 'date',
-      'source' => $this->dc . 'source',
-      'enclosure' => $this->enc . 'enclosure',
-    );
-    $this->dt_props = array(
-      $this->dc . 'identifier',
-      $this->rss . 'link'
-    );
-    foreach ($index as $p_id => $nodes) {
-      foreach ($nodes as $pos => $node) {
-        $tag = $this->v('tag', '', $node);
-        if ($tag == 'channel') {
-          $struct = $this->extractChannel($index[$node['id']]);
-          $triples = ARC2::getTriplesFromIndex($struct);
-          foreach ($triples as $t) {
-            $this->addT($t);
-          }
-        }
-        elseif ($tag == 'item') {
-          $struct = $this->extractItem($index[$node['id']]);
-          $triples = ARC2::getTriplesFromIndex($struct);
-          foreach ($triples as $t) {
-            $this->addT($t);
-          }
+
+    public function done()
+    {
+        $this->extractRDF();
+    }
+
+    public function setReader(&$reader)
+    {
+        $this->reader = $reader;
+    }
+
+    public function createBnodeID()
+    {
+        ++$this->bnode_id;
+
+        return '_:'.$this->bnode_prefix.$this->bnode_id;
+    }
+
+    public function addT($t)
+    {
+        //if (!isset($t['o_datatype']))
+        if ($this->skip_dupes) {
+            $h = md5(serialize($t));
+            if (!isset($this->added_triples[$h])) {
+                $this->triples[$this->t_count] = $t;
+                ++$this->t_count;
+                $this->added_triples[$h] = true;
+            }
+        } else {
+            $this->triples[$this->t_count] = $t;
+            ++$this->t_count;
         }
-      }
     }
-  }
-  
-  function extractChannel($els) {
-    $res = array($this->rdf . 'type' => array(array('value' => $this->rss . 'channel', 'type' => 'uri')));
-    $res = array_merge($res, $this->extractProps($els, 'channel'));
-    return array($res[$this->rss . 'link'][0]['value'] => $res);
-  }
-  
-  function extractItem($els) {
-    $res = array($this->rdf . 'type' => array(array('value' => $this->rss . 'item', 'type' => 'uri')));
-    $res = array_merge($res, $this->extractProps($els, 'item'));
-    if (isset($res[$this->rss . 'link'])) return array($res[$this->rss . 'link'][0]['value'] => $res);
-    if (isset($res[$this->dc . 'identifier'])) return array($res[$this->dc . 'identifier'][0]['value'] => $res);
-  }
-  
-  function extractProps($els, $container) {
-    $res = array();
-    foreach ($els as $info) {
-      /* key */
-      $tag = $info['tag'];
-      if (!preg_match('/^[a-z0-9]+\:/i', $tag)) {
-        $k = isset($this->mappings[$tag]) ? $this->mappings[$tag] : '';
-      }
-      else {
-        $k = $tag;
-      }
-      if (($container == 'channel') && ($k == $this->rss . 'item')) continue;
-      /* val */
-      $v = $info['cdata'];
-      if (!$v) $v = $this->v('url', '', $info['a']);
-      if (!$v) $v = $this->v('href', '', $info['a']);
-      /* prop */
-      if ($k) {
-        /* enclosure handling */
-        if ($k == $this->enc . 'enclosure') {
-          $sub_res = array();
-          foreach (array('length', 'type') as $attr) {
-            if ($attr_v = $this->v($attr, 0, $info['a'])) {
-              $sub_res[$this->enc . $attr] = array(array('value' => $attr_v, 'type' => 'literal'));
+
+    public function getTriples()
+    {
+        return $this->v('triples', []);
+    }
+
+    public function countTriples()
+    {
+        return $this->t_count;
+    }
+
+    public function getSimpleIndex($flatten_objects = 1, $vals = '')
+    {
+        return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
+    }
+
+    public function extractRDF()
+    {
+        $index = $this->getNodeIndex();
+        $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+        $this->rss = 'http://purl.org/rss/1.0/';
+        $this->dc = 'http://purl.org/dc/elements/1.1/';
+        $this->dct = 'http://purl.org/dc/terms/';
+        $this->content = 'http://purl.org/rss/1.0/modules/content/';
+        $this->enc = 'http://purl.oclc.org/net/rss_2.0/enc#';
+        $this->mappings = [
+            'channel' => $this->rss.'channel',
+            'item' => $this->rss.'item',
+            'title' => $this->rss.'title',
+            'link' => $this->rss.'link',
+            'description' => $this->rss.'description',
+            'guid' => $this->dc.'identifier',
+            'author' => $this->dc.'creator',
+            'category' => $this->dc.'subject',
+            'pubDate' => $this->dc.'date',
+            'pubdate' => $this->dc.'date',
+            'source' => $this->dc.'source',
+            'enclosure' => $this->enc.'enclosure',
+        ];
+        $this->dt_props = [
+            $this->dc.'identifier',
+            $this->rss.'link',
+        ];
+        foreach ($index as $p_id => $nodes) {
+            foreach ($nodes as $pos => $node) {
+                $tag = $this->v('tag', '', $node);
+                if ('channel' == $tag) {
+                    $struct = $this->extractChannel($index[$node['id']]);
+                    $triples = ARC2::getTriplesFromIndex($struct);
+                    foreach ($triples as $t) {
+                        $this->addT($t);
+                    }
+                } elseif ('item' == $tag) {
+                    $struct = $this->extractItem($index[$node['id']]);
+                    $triples = ARC2::getTriplesFromIndex($struct);
+                    foreach ($triples as $t) {
+                        $this->addT($t);
+                    }
+                }
             }
-          }
-          $struct[$v] = $sub_res;
         }
-        /* date handling */
-        if (in_array($k, array($this->dc . 'date', $this->dct . 'modified'))) {
-          if (!preg_match('/^[0-9]{4}/', $v) && ($sub_v = strtotime($v)) && ($sub_v != -1)) {
-            $tz = date('Z', $sub_v); /* timezone offset */
-            $sub_v -= $tz; /* utc */
-            $v = date('Y-m-d\TH:i:s\Z', $sub_v);
-          }
+    }
+
+    public function extractChannel($els)
+    {
+        $res = [$this->rdf.'type' => [['value' => $this->rss.'channel', 'type' => 'uri']]];
+        $res = array_merge($res, $this->extractProps($els, 'channel'));
+
+        return [$res[$this->rss.'link'][0]['value'] => $res];
+    }
+
+    public function extractItem($els)
+    {
+        $res = [$this->rdf.'type' => [['value' => $this->rss.'item', 'type' => 'uri']]];
+        $res = array_merge($res, $this->extractProps($els, 'item'));
+        if (isset($res[$this->rss.'link'])) {
+            return [$res[$this->rss.'link'][0]['value'] => $res];
+        }
+        if (isset($res[$this->dc.'identifier'])) {
+            return [$res[$this->dc.'identifier'][0]['value'] => $res];
         }
-        if (!isset($res[$k])) $res[$k] = array();
-        $res[$k][] = array('value' => $v, 'type' => in_array($k, $this->dt_props) || !preg_match('/^[a-z0-9]+\:[^\s]+$/is', $v) ? 'literal' : 'uri');
-      }
     }
-    return $res;
-  }
-  
-  /*  */
 
-  
+    public function extractProps($els, $container)
+    {
+        $res = [];
+        foreach ($els as $info) {
+            /* key */
+            $tag = $info['tag'];
+            if (!preg_match('/^[a-z0-9]+\:/i', $tag)) {
+                $k = isset($this->mappings[$tag]) ? $this->mappings[$tag] : '';
+            } else {
+                $k = $tag;
+            }
+            if (('channel' == $container) && ($k == $this->rss.'item')) {
+                continue;
+            }
+            /* val */
+            $v = $info['cdata'];
+            if (!$v) {
+                $v = $this->v('url', '', $info['a']);
+            }
+            if (!$v) {
+                $v = $this->v('href', '', $info['a']);
+            }
+            /* prop */
+            if ($k) {
+                /* enclosure handling */
+                if ($k == $this->enc.'enclosure') {
+                    $sub_res = [];
+                    foreach (['length', 'type'] as $attr) {
+                        if ($attr_v = $this->v($attr, 0, $info['a'])) {
+                            $sub_res[$this->enc.$attr] = [['value' => $attr_v, 'type' => 'literal']];
+                        }
+                    }
+                    $struct[$v] = $sub_res;
+                }
+                /* date handling */
+                if (in_array($k, [$this->dc.'date', $this->dct.'modified'])) {
+                    if (!preg_match('/^[0-9]{4}/', $v) && ($sub_v = strtotime($v)) && ($sub_v != -1)) {
+                        $tz = date('Z', $sub_v); /* timezone offset */
+                        $sub_v -= $tz; /* utc */
+                        $v = date('Y-m-d\TH:i:s\Z', $sub_v);
+                    }
+                }
+                if (!isset($res[$k])) {
+                    $res[$k] = [];
+                }
+                $res[$k][] = ['value' => $v, 'type' => in_array($k, $this->dt_props) || !preg_match('/^[a-z0-9]+\:[^\s]+$/is', $v) ? 'literal' : 'uri'];
+            }
+        }
+
+        return $res;
+    }
 }
diff --git a/lib/arc2/parsers/ARC2_SGAJSONParser.php b/lib/arc2/parsers/ARC2_SGAJSONParser.php
old mode 100644
new mode 100755
index d41812356799597c2013e74b05bc9c4eae2efed9..71357e088fccffe3a82137a242be541f8435e6cd
--- a/lib/arc2/parsers/ARC2_SGAJSONParser.php
+++ b/lib/arc2/parsers/ARC2_SGAJSONParser.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 SG API JSON Parser
 author:   Benjamin Nowack
@@ -10,54 +10,65 @@ version:  2010-11-16
 
 ARC2::inc('JSONParser');
 
-class ARC2_SGAJSONParser extends ARC2_JSONParser {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* reader */
-    parent::__init();
-    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
-    $this->nsp = array($this->rdf => 'rdf');
-  }
-  
-  /*  */
-
-  function done() {
-    $this->extractRDF();
-  }
-  
-  function extractRDF() {
-    $s = $this->getContext();
-    $os = $this->getURLs($this->struct);
-    foreach ($os as $o) {
-      if ($o != $s) $this->addT($s, 'http://www.w3.org/2000/01/rdf-schema#seeAlso', $o, 'uri', 'uri');
+class ARC2_SGAJSONParser extends ARC2_JSONParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
     }
-  }
-  
-  function getContext() {
-    if (!isset($this->struct['canonical_mapping'])) return '';
-    foreach ($this->struct['canonical_mapping'] as $k => $v) return $v;
-  }
-  
-  function getURLs($struct) {
-    $r =array();
-    if (is_array($struct)) {
-      foreach ($struct as $k => $v) {
-        if (preg_match('/^http:\/\//', $k) && !in_array($k, $r)) $r[] = $k;
-        $sub_r = $this->getURLs($v);
-        foreach ($sub_r as $sub_v) {
-          if (!in_array($sub_v, $r)) $r[] = $sub_v;
+
+    public function __init()
+    {/* reader */
+        parent::__init();
+        $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+        $this->nsp = [$this->rdf => 'rdf'];
+    }
+
+    public function done()
+    {
+        $this->extractRDF();
+    }
+
+    public function extractRDF($formats = '')
+    {
+        $s = $this->getContext();
+        $os = $this->getURLs($this->struct);
+        foreach ($os as $o) {
+            if ($o != $s) {
+                $this->addT($s, 'http://www.w3.org/2000/01/rdf-schema#seeAlso', $o, 'uri', 'uri');
+            }
         }
-      }
     }
-    elseif (preg_match('/^http:\/\//', $struct) && !in_array($struct, $r)) {
-      $r[] = $struct;
+
+    public function getContext()
+    {
+        if (!isset($this->struct['canonical_mapping'])) {
+            return '';
+        }
+        foreach ($this->struct['canonical_mapping'] as $k => $v) {
+            return $v;
+        }
     }
-    return $r;
-  }
-  
-  /*  */
 
+    public function getURLs($struct)
+    {
+        $r = [];
+        if (is_array($struct)) {
+            foreach ($struct as $k => $v) {
+                if (preg_match('/^http:\/\//', $k) && !in_array($k, $r)) {
+                    $r[] = $k;
+                }
+                $sub_r = $this->getURLs($v);
+                foreach ($sub_r as $sub_v) {
+                    if (!in_array($sub_v, $r)) {
+                        $r[] = $sub_v;
+                    }
+                }
+            }
+        } elseif (preg_match('/^http:\/\//', $struct) && !in_array($struct, $r)) {
+            $r[] = $struct;
+        }
+
+        return $r;
+    }
 }
diff --git a/lib/arc2/parsers/ARC2_SPARQLParser.php b/lib/arc2/parsers/ARC2_SPARQLParser.php
index 401e20d3965080fe992b3cbc5067504f2b275b57..f34a537adf113941a29c329767da3862d40856ee 100644
--- a/lib/arc2/parsers/ARC2_SPARQLParser.php
+++ b/lib/arc2/parsers/ARC2_SPARQLParser.php
@@ -1,777 +1,841 @@
 <?php
 /**
- * ARC2 SPARQL Parser
+ * ARC2 SPARQL Parser.
  *
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('TurtleParser');
 
-class ARC2_SPARQLParser extends ARC2_TurtleParser {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-
-  function __init() {
-    parent::__init();
-    $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
-    $this->bnode_id = 0;
-    $this->bnode_pattern_index = array('patterns' => array(), 'bnodes' => array());
-  }
-
-  /*  */
-
-  function parse($q, $src = '', $iso_fallback = 'ignore') {
-    $this->setDefaultPrefixes();
-    $this->base = $src ? $this->calcBase($src) : ARC2::getRequestURI();
-    $this->r = array(
-      'base' => '',
-      'vars' => array(),
-      'prefixes' => array()
-    );
-    $this->unparsed_code = $q;
-    list($r, $v) = $this->xQuery($q);
-    if ($r) {
-      $this->r['query'] = $r;
-      $this->unparsed_code = trim($v);
-    }
-    elseif (!$this->getErrors() && !$this->unparsed_code) {
-      $this->addError('Query not properly closed');
-    }
-    $this->r['prefixes'] = $this->prefixes;
-    $this->r['base'] = $this->base;
-    /* remove trailing comments */
-    while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $this->unparsed_code, $m)) $this->unparsed_code = $m[2];
-    if ($this->unparsed_code && !$this->getErrors()) {
-      $rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($this->unparsed_code, 0, 30));
-      $msg = trim($rest) ? 'Could not properly handle "' . $rest . '"' : 'Syntax error, probably an incomplete pattern';
-      $this->addError($msg);
-    }
-  }
-
-  function getQueryInfos() {
-    return $this->v('r', array());
-  }
-
-  /* 1 */
-
-  function xQuery($v) {
-    list($r, $v) = $this->xPrologue($v);
-    foreach (array('Select', 'Construct', 'Describe', 'Ask') as $type) {
-      $m = 'x' . $type . 'Query';
-      if ((list($r, $v) = $this->$m($v)) && $r) {
-        return array($r, $v);
-      }
-    }
-    return array(0, $v);
-  }
-
-  /* 2 */
-
-  function xPrologue($v) {
-    $r = 0;
-    if ((list($sub_r, $v) = $this->xBaseDecl($v)) && $sub_r) {
-      $this->base = $sub_r;
-      $r = 1;
-    }
-    while ((list($sub_r, $v) = $this->xPrefixDecl($v)) && $sub_r) {
-      $this->prefixes[$sub_r['prefix']] = $sub_r['uri'];
-      $r = 1;
-    }
-    return array($r, $v);
-  }
-
-  /* 5.. */
-
-  function xSelectQuery($v) {
-    if ($sub_r = $this->x('SELECT\s+', $v)) {
-      $r = array(
-        'type' => 'select',
-        'result_vars' => array(),
-        'dataset' => array(),
-      );
-      $all_vars = 0;
-      $sub_v = $sub_r[1];
-      /* distinct, reduced */
-      if ($sub_r = $this->x('(DISTINCT|REDUCED)\s+', $sub_v)) {
-        $r[strtolower($sub_r[1])] = 1;
-        $sub_v = $sub_r[2];
-      }
-      /* result vars */
-      if ($sub_r = $this->x('\*\s+', $sub_v)) {
-        $all_vars = 1;
-        $sub_v = $sub_r[1];
-      }
-      else {
-        while ((list($sub_r, $sub_v) = $this->xResultVar($sub_v)) && $sub_r) {
-          $r['result_vars'][] = $sub_r;
-        }
-      }
-      if (!$all_vars && !count($r['result_vars'])) {
-        $this->addError('No result bindings specified.');
-      }
-      /* dataset */
-      while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
-        $r['dataset'][] = $sub_r;
-      }
-      /* where */
-      if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
-        $r['pattern'] = $sub_r;
-      }
-      else {
-        return array(0, $v);
-      }
-      /* solution modifier */
-      if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
-        $r = array_merge($r, $sub_r);
-      }
-      /* all vars */
-      if ($all_vars) {
-        foreach ($this->r['vars'] as $var) {
-          $r['result_vars'][] = array('var' => $var, 'aggregate' => 0, 'alias' => '');
-        }
-        if (!$r['result_vars']) {
-          $r['result_vars'][] = '*';
-        }
-      }
-      return array($r, $sub_v);
-    }
-    return array(0, $v);
-  }
-
-  function xResultVar($v) {
-    return $this->xVar($v);
-  }
-
-  /* 6.. */
-
-  function xConstructQuery($v) {
-    if ($sub_r = $this->x('CONSTRUCT\s*', $v)) {
-      $r = array(
-        'type' => 'construct',
-        'dataset' => array(),
-      );
-      $sub_v = $sub_r[1];
-      /* construct template */
-      if ((list($sub_r, $sub_v) = $this->xConstructTemplate($sub_v)) && is_array($sub_r)) {
-        $r['construct_triples'] = $sub_r;
-      }
-      else {
-        $this->addError('Construct Template not found');
-        return array(0, $v);
-      }
-      /* dataset */
-      while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
-        $r['dataset'][] = $sub_r;
-      }
-      /* where */
-      if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
-        $r['pattern'] = $sub_r;
-      }
-      else {
-        return array(0, $v);
-      }
-      /* solution modifier */
-      if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
-        $r = array_merge($r, $sub_r);
-      }
-      return array($r, $sub_v);
-    }
-    return array(0, $v);
-  }
-
-  /* 7.. */
-
-  function xDescribeQuery($v) {
-    if ($sub_r = $this->x('DESCRIBE\s+', $v)) {
-      $r = array(
-        'type' => 'describe',
-        'result_vars' => array(),
-        'result_uris' => array(),
-        'dataset' => array(),
-      );
-      $sub_v = $sub_r[1];
-      $all_vars = 0;
-      /* result vars/uris */
-      if ($sub_r = $this->x('\*\s+', $sub_v)) {
-        $all_vars = 1;
-        $sub_v = $sub_r[1];
-      }
-      else {
+class ARC2_SPARQLParser extends ARC2_TurtleParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
+
+    public function __init()
+    {
+        parent::__init();
+        $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
+        $this->bnode_id = 0;
+        $this->bnode_pattern_index = ['patterns' => [], 'bnodes' => []];
+    }
+
+    public function parse($q, $src = '', $iso_fallback = 'ignore')
+    {
+        $this->setDefaultPrefixes();
+        $this->base = $src ? $this->calcBase($src) : ARC2::getRequestURI();
+        $this->r = [
+            'base' => '',
+            'vars' => [],
+            'prefixes' => [],
+        ];
+        $this->unparsed_code = $q;
+        list($r, $v) = $this->xQuery($q);
+        if ($r) {
+            $this->r['query'] = $r;
+            $this->unparsed_code = trim($v);
+        } elseif (!$this->getErrors() && !$this->unparsed_code) {
+            $this->addError('Query not properly closed');
+        }
+        $this->r['prefixes'] = $this->prefixes;
+        $this->r['base'] = $this->base;
+        /* remove trailing comments */
+        while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $this->unparsed_code, $m)) {
+            $this->unparsed_code = $m[2];
+        }
+        if ($this->unparsed_code && !$this->getErrors()) {
+            $rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($this->unparsed_code, 0, 30));
+            $msg = trim($rest) ? 'Could not properly handle "'.$rest.'"' : 'Syntax error, probably an incomplete pattern';
+            $this->addError($msg);
+        }
+    }
+
+    public function getQueryInfos()
+    {
+        return $this->v('r', []);
+    }
+
+    /* 1 */
+
+    public function xQuery($v)
+    {
+        list($r, $v) = $this->xPrologue($v);
+        foreach (['Select', 'Construct', 'Describe', 'Ask'] as $type) {
+            $m = 'x'.$type.'Query';
+            if ((list($r, $v) = $this->$m($v)) && $r) {
+                return [$r, $v];
+            }
+        }
+
+        return [0, $v];
+    }
+
+    /* 2 */
+
+    public function xPrologue($v)
+    {
+        $r = 0;
+        if ((list($sub_r, $v) = $this->xBaseDecl($v)) && $sub_r) {
+            $this->base = $sub_r;
+            $r = 1;
+        }
+        while ((list($sub_r, $v) = $this->xPrefixDecl($v)) && $sub_r) {
+            $this->prefixes[$sub_r['prefix']] = $sub_r['uri'];
+            $r = 1;
+        }
+
+        return [$r, $v];
+    }
+
+    /* 5.. */
+
+    public function xSelectQuery($v)
+    {
+        if ($sub_r = $this->x('SELECT\s+', $v)) {
+            $r = [
+                'type' => 'select',
+                'result_vars' => [],
+                'dataset' => [],
+            ];
+            $all_vars = 0;
+            $sub_v = $sub_r[1];
+            /* distinct, reduced */
+            if ($sub_r = $this->x('(DISTINCT|REDUCED)\s+', $sub_v)) {
+                $r[strtolower($sub_r[1])] = 1;
+                $sub_v = $sub_r[2];
+            }
+            /* result vars */
+            if ($sub_r = $this->x('\*\s+', $sub_v)) {
+                $all_vars = 1;
+                $sub_v = $sub_r[1];
+            } else {
+                while ((list($sub_r, $sub_v) = $this->xResultVar($sub_v)) && $sub_r) {
+                    $r['result_vars'][] = $sub_r;
+                }
+            }
+            if (!$all_vars && !count($r['result_vars'])) {
+                $this->addError('No result bindings specified.');
+            }
+            /* dataset */
+            while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
+                $r['dataset'][] = $sub_r;
+            }
+            /* where */
+            if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
+                $r['pattern'] = $sub_r;
+            } else {
+                return [0, $v];
+            }
+            /* solution modifier */
+            if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
+                $r = array_merge($r, $sub_r);
+            }
+            /* all vars */
+            if ($all_vars) {
+                foreach ($this->r['vars'] as $var) {
+                    $r['result_vars'][] = ['var' => $var, 'aggregate' => 0, 'alias' => ''];
+                }
+                if (!$r['result_vars']) {
+                    $r['result_vars'][] = '*';
+                }
+            }
+
+            return [$r, $sub_v];
+        }
+
+        return [0, $v];
+    }
+
+    public function xResultVar($v)
+    {
+        return $this->xVar($v);
+    }
+
+    /* 6.. */
+
+    public function xConstructQuery($v)
+    {
+        if ($sub_r = $this->x('CONSTRUCT\s*', $v)) {
+            $r = [
+                'type' => 'construct',
+                'dataset' => [],
+            ];
+            $sub_v = $sub_r[1];
+            /* construct template */
+            if ((list($sub_r, $sub_v) = $this->xConstructTemplate($sub_v)) && is_array($sub_r)) {
+                $r['construct_triples'] = $sub_r;
+            } else {
+                $this->addError('Construct Template not found');
+
+                return [0, $v];
+            }
+            /* dataset */
+            while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
+                $r['dataset'][] = $sub_r;
+            }
+            /* where */
+            if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
+                $r['pattern'] = $sub_r;
+            } else {
+                return [0, $v];
+            }
+            /* solution modifier */
+            if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
+                $r = array_merge($r, $sub_r);
+            }
+
+            return [$r, $sub_v];
+        }
+
+        return [0, $v];
+    }
+
+    /* 7.. */
+
+    public function xDescribeQuery($v)
+    {
+        if ($sub_r = $this->x('DESCRIBE\s+', $v)) {
+            $r = [
+                'type' => 'describe',
+                'result_vars' => [],
+                'result_uris' => [],
+                'dataset' => [],
+            ];
+            $sub_v = $sub_r[1];
+            $all_vars = 0;
+            /* result vars/uris */
+            if ($sub_r = $this->x('\*\s+', $sub_v)) {
+                $all_vars = 1;
+                $sub_v = $sub_r[1];
+            } else {
+                do {
+                    $proceed = 0;
+                    if ((list($sub_r, $sub_v) = $this->xResultVar($sub_v)) && $sub_r) {
+                        $r['result_vars'][] = $sub_r;
+                        $proceed = 1;
+                    }
+                    if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
+                        $r['result_uris'][] = $sub_r;
+                        $proceed = 1;
+                    }
+                } while ($proceed);
+            }
+            if (!$all_vars && !count($r['result_vars']) && !count($r['result_uris'])) {
+                $this->addError('No result bindings specified.');
+            }
+            /* dataset */
+            while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
+                $r['dataset'][] = $sub_r;
+            }
+            /* where */
+            if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
+                $r['pattern'] = $sub_r;
+            }
+            /* solution modifier */
+            if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
+                $r = array_merge($r, $sub_r);
+            }
+            /* all vars */
+            if ($all_vars) {
+                foreach ($this->r['vars'] as $var) {
+                    $r['result_vars'][] = ['var' => $var, 'aggregate' => 0, 'alias' => ''];
+                }
+            }
+
+            return [$r, $sub_v];
+        }
+
+        return [0, $v];
+    }
+
+    /* 8.. */
+
+    public function xAskQuery($v)
+    {
+        if ($sub_r = $this->x('ASK\s+', $v)) {
+            $r = [
+                'type' => 'ask',
+                'dataset' => [],
+            ];
+            $sub_v = $sub_r[1];
+            /* dataset */
+            while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
+                $r['dataset'][] = $sub_r;
+            }
+            /* where */
+            if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
+                $r['pattern'] = $sub_r;
+
+                return [$r, $sub_v];
+            } else {
+                $this->addError('Missing or invalid WHERE clause.');
+            }
+        }
+
+        return [0, $v];
+    }
+
+    /* 9, 10, 11, 12 */
+
+    public function xDatasetClause($v)
+    {
+        if ($r = $this->x('FROM(\s+NAMED)?\s+', $v)) {
+            $named = $r[1] ? 1 : 0;
+            if ((list($r, $sub_v) = $this->xIRIref($r[2])) && $r) {
+                return [['graph' => $r, 'named' => $named], $sub_v];
+            }
+        }
+
+        return [0, $v];
+    }
+
+    /* 13 */
+
+    public function xWhereClause($v)
+    {
+        if ($r = $this->x('(WHERE)?', $v)) {
+            $v = $r[2];
+        }
+        if ((list($r, $v) = $this->xGroupGraphPattern($v)) && $r) {
+            return [$r, $v];
+        }
+
+        return [0, $v];
+    }
+
+    /* 14, 15 */
+
+    public function xSolutionModifier($v)
+    {
+        $r = [];
+        if ((list($sub_r, $sub_v) = $this->xOrderClause($v)) && $sub_r) {
+            $r['order_infos'] = $sub_r;
+        }
+        while ((list($sub_r, $sub_v) = $this->xLimitOrOffsetClause($sub_v)) && $sub_r) {
+            $r = array_merge($r, $sub_r);
+        }
+
+        return ($v == $sub_v) ? [0, $v] : [$r, $sub_v];
+    }
+
+    /* 18, 19 */
+
+    public function xLimitOrOffsetClause($v)
+    {
+        if ($sub_r = $this->x('(LIMIT|OFFSET)', $v)) {
+            $key = strtolower($sub_r[1]);
+            $sub_v = $sub_r[2];
+            if ((list($sub_r, $sub_v) = $this->xINTEGER($sub_v)) && (false !== $sub_r)) {
+                return [[$key => $sub_r], $sub_v];
+            }
+            if ((list($sub_r, $sub_v) = $this->xPlaceholder($sub_v)) && (false !== $sub_r)) {
+                return [[$key => $sub_r], $sub_v];
+            }
+        }
+
+        return [0, $v];
+    }
+
+    /* 16 */
+
+    public function xOrderClause($v)
+    {
+        if ($sub_r = $this->x('ORDER BY\s+', $v)) {
+            $sub_v = $sub_r[1];
+            $r = [];
+            while ((list($sub_r, $sub_v) = $this->xOrderCondition($sub_v)) && $sub_r) {
+                $r[] = $sub_r;
+            }
+            if (count($r)) {
+                return [$r, $sub_v];
+            } else {
+                $this->addError('No order conditions specified.');
+            }
+        }
+
+        return [0, $v];
+    }
+
+    /* 17, 27 */
+
+    public function xOrderCondition($v)
+    {
+        if ($sub_r = $this->x('(ASC|DESC)', $v)) {
+            $dir = strtolower($sub_r[1]);
+            $sub_v = $sub_r[2];
+            if ((list($sub_r, $sub_v) = $this->xBrackettedExpression($sub_v)) && $sub_r) {
+                $sub_r['direction'] = $dir;
+
+                return [$sub_r, $sub_v];
+            }
+        } elseif ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
+            $sub_r['direction'] = 'asc';
+
+            return [$sub_r, $sub_v];
+        } elseif ((list($sub_r, $sub_v) = $this->xBrackettedExpression($v)) && $sub_r) {
+            return [$sub_r, $sub_v];
+        } elseif ((list($sub_r, $sub_v) = $this->xBuiltInCall($v)) && $sub_r) {
+            $sub_r['direction'] = 'asc';
+
+            return [$sub_r, $sub_v];
+        } elseif ((list($sub_r, $sub_v) = $this->xFunctionCall($v)) && $sub_r) {
+            $sub_r['direction'] = 'asc';
+
+            return [$sub_r, $sub_v];
+        }
+
+        return [0, $v];
+    }
+
+    /* 20 */
+
+    public function xGroupGraphPattern($v)
+    {
+        $pattern_id = substr(md5(uniqid(rand())), 0, 4);
+        if ($sub_r = $this->x('\{', $v)) {
+            $r = ['type' => 'group', 'patterns' => []];
+            $sub_v = $sub_r[1];
+            if ((list($sub_r, $sub_v) = $this->xTriplesBlock($sub_v)) && $sub_r) {
+                $this->indexBnodes($sub_r, $pattern_id);
+                $r['patterns'][] = ['type' => 'triples', 'patterns' => $sub_r];
+            }
+            do {
+                $proceed = 0;
+                if ((list($sub_r, $sub_v) = $this->xGraphPatternNotTriples($sub_v)) && $sub_r) {
+                    $r['patterns'][] = $sub_r;
+                    $pattern_id = substr(md5(uniqid(rand())), 0, 4);
+                    $proceed = 1;
+                } elseif ((list($sub_r, $sub_v) = $this->xFilter($sub_v)) && $sub_r) {
+                    $r['patterns'][] = ['type' => 'filter', 'constraint' => $sub_r];
+                    $proceed = 1;
+                }
+                if ($sub_r = $this->x('\.', $sub_v)) {
+                    $sub_v = $sub_r[1];
+                }
+                if ((list($sub_r, $sub_v) = $this->xTriplesBlock($sub_v)) && $sub_r) {
+                    $this->indexBnodes($sub_r, $pattern_id);
+                    $r['patterns'][] = ['type' => 'triples', 'patterns' => $sub_r];
+                    $proceed = 1;
+                }
+                if ((list($sub_r, $sub_v) = $this->xPlaceholder($sub_v)) && $sub_r) {
+                    $r['patterns'][] = $sub_r;
+                    $proceed = 1;
+                }
+            } while ($proceed);
+            if ($sub_r = $this->x('\}', $sub_v)) {
+                $sub_v = $sub_r[1];
+
+                return [$r, $sub_v];
+            }
+            $rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($sub_v, 0, 30));
+            $this->addError('Incomplete or invalid Group Graph pattern. Could not handle "'.$rest.'"');
+        }
+
+        return [0, $v];
+    }
+
+    public function indexBnodes($triples, $pattern_id)
+    {
+        $index_id = count($this->bnode_pattern_index['patterns']);
+        $index_id = $pattern_id;
+        $this->bnode_pattern_index['patterns'][] = $triples;
+        foreach ($triples as $t) {
+            foreach (['s', 'p', 'o'] as $term) {
+                if ('bnode' == $t[$term.'_type']) {
+                    $val = $t[$term];
+                    if (isset($this->bnode_pattern_index['bnodes'][$val]) && ($this->bnode_pattern_index['bnodes'][$val] != $index_id)) {
+                        $this->addError('Re-used bnode label "'.$val.'" across graph patterns');
+                    } else {
+                        $this->bnode_pattern_index['bnodes'][$val] = $index_id;
+                    }
+                }
+            }
+        }
+    }
+
+    /* 22.., 25.. */
+
+    public function xGraphPatternNotTriples($v)
+    {
+        if ((list($sub_r, $sub_v) = $this->xOptionalGraphPattern($v)) && $sub_r) {
+            return [$sub_r, $sub_v];
+        }
+        if ((list($sub_r, $sub_v) = $this->xGraphGraphPattern($v)) && $sub_r) {
+            return [$sub_r, $sub_v];
+        }
+        $r = ['type' => 'union', 'patterns' => []];
+        $sub_v = $v;
         do {
-          $proceed = 0;
-          if ((list($sub_r, $sub_v) = $this->xResultVar($sub_v)) && $sub_r) {
-            $r['result_vars'][] = $sub_r;
-            $proceed = 1;
-          }
-          if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
-            $r['result_uris'][] = $sub_r;
-            $proceed =1;
-          }
+            $proceed = 0;
+            if ((list($sub_r, $sub_v) = $this->xGroupGraphPattern($sub_v)) && $sub_r) {
+                $r['patterns'][] = $sub_r;
+                if ($sub_r = $this->x('UNION', $sub_v)) {
+                    $sub_v = $sub_r[1];
+                    $proceed = 1;
+                }
+            }
         } while ($proceed);
-      }
-      if (!$all_vars && !count($r['result_vars']) && !count($r['result_uris'])) {
-        $this->addError('No result bindings specified.');
-      }
-      /* dataset */
-      while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
-        $r['dataset'][] = $sub_r;
-      }
-      /* where */
-      if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
-        $r['pattern'] = $sub_r;
-      }
-      /* solution modifier */
-      if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
-        $r = array_merge($r, $sub_r);
-      }
-      /* all vars */
-      if ($all_vars) {
-        foreach ($this->r['vars'] as $var) {
-          $r['result_vars'][] = array('var' => $var, 'aggregate' => 0, 'alias' => '');
-        }
-      }
-      return array($r, $sub_v);
-    }
-    return array(0, $v);
-  }
-
-  /* 8.. */
-
-  function xAskQuery($v) {
-    if ($sub_r = $this->x('ASK\s+', $v)) {
-      $r = array(
-        'type' => 'ask',
-        'dataset' => array(),
-      );
-      $sub_v = $sub_r[1];
-      /* dataset */
-      while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
-        $r['dataset'][] = $sub_r;
-      }
-      /* where */
-      if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
-        $r['pattern'] = $sub_r;
-        return array($r, $sub_v);
-      }
-      else {
-        $this->addError('Missing or invalid WHERE clause.');
-      }
-    }
-    return array(0, $v);
-  }
-
-  /* 9, 10, 11, 12 */
-
-  function xDatasetClause($v) {
-    if ($r = $this->x('FROM(\s+NAMED)?\s+', $v)) {
-      $named = $r[1] ? 1 : 0;
-      if ((list($r, $sub_v) = $this->xIRIref($r[2])) && $r) {
-        return array(array('graph' => $r, 'named' => $named), $sub_v);
-      }
-    }
-    return array(0, $v);
-  }
-
-  /* 13 */
-
-  function xWhereClause($v) {
-    if ($r = $this->x('(WHERE)?', $v)) {
-      $v = $r[2];
-    }
-    if ((list($r, $v) = $this->xGroupGraphPattern($v)) && $r) {
-      return array($r, $v);
-    }
-    return array(0, $v);
-  }
-
-  /* 14, 15 */
-
-  function xSolutionModifier($v) {
-    $r = array();
-    if ((list($sub_r, $sub_v) = $this->xOrderClause($v)) && $sub_r) {
-      $r['order_infos'] = $sub_r;
-    }
-    while ((list($sub_r, $sub_v) = $this->xLimitOrOffsetClause($sub_v)) && $sub_r) {
-      $r = array_merge($r, $sub_r);
-    }
-    return ($v == $sub_v) ? array(0, $v) : array($r, $sub_v);
-  }
-
-  /* 18, 19 */
-
-  function xLimitOrOffsetClause($v) {
-    if ($sub_r = $this->x('(LIMIT|OFFSET)', $v)) {
-      $key = strtolower($sub_r[1]);
-      $sub_v = $sub_r[2];
-      if ((list($sub_r, $sub_v) = $this->xINTEGER($sub_v)) && ($sub_r !== false)) {
-        return array(array($key =>$sub_r), $sub_v);
-      }
-      if ((list($sub_r, $sub_v) = $this->xPlaceholder($sub_v)) && ($sub_r !== false)) {
-        return array(array($key =>$sub_r), $sub_v);
-      }
-    }
-    return array(0, $v);
-  }
-
-  /* 16 */
-
-  function xOrderClause($v) {
-    if ($sub_r = $this->x('ORDER BY\s+', $v)) {
-      $sub_v = $sub_r[1];
-      $r = array();
-      while ((list($sub_r, $sub_v) = $this->xOrderCondition($sub_v)) && $sub_r) {
-        $r[] = $sub_r;
-      }
-      if (count($r)) {
-        return array($r, $sub_v);
-      }
-      else {
-        $this->addError('No order conditions specified.');
-      }
-    }
-    return array(0, $v);
-  }
-
-  /* 17, 27 */
-
-  function xOrderCondition($v) {
-    if ($sub_r = $this->x('(ASC|DESC)', $v)) {
-      $dir = strtolower($sub_r[1]);
-      $sub_v = $sub_r[2];
-      if ((list($sub_r, $sub_v) = $this->xBrackettedExpression($sub_v)) && $sub_r) {
-        $sub_r['direction'] = $dir;
-        return array($sub_r, $sub_v);
-      }
-    }
-    elseif ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
-      $sub_r['direction'] = 'asc';
-      return array($sub_r, $sub_v);
-    }
-    elseif ((list($sub_r, $sub_v) = $this->xBrackettedExpression($v)) && $sub_r) {
-      return array($sub_r, $sub_v);
-    }
-    elseif ((list($sub_r, $sub_v) = $this->xBuiltInCall($v)) && $sub_r) {
-      $sub_r['direction'] = 'asc';
-      return array($sub_r, $sub_v);
-    }
-    elseif ((list($sub_r, $sub_v) = $this->xFunctionCall($v)) && $sub_r) {
-      $sub_r['direction'] = 'asc';
-      return array($sub_r, $sub_v);
-    }
-    return array(0, $v);
-  }
-
-  /* 20 */
-
-  function xGroupGraphPattern($v) {
-    $pattern_id = substr(md5(uniqid(rand())), 0, 4);
-    if ($sub_r = $this->x('\{', $v)) {
-      $r = array('type' => 'group', 'patterns' => array());
-      $sub_v = $sub_r[1];
-      if ((list($sub_r, $sub_v) = $this->xTriplesBlock($sub_v)) && $sub_r) {
-        $this->indexBnodes($sub_r, $pattern_id);
-        $r['patterns'][] = array('type' => 'triples', 'patterns' => $sub_r);
-      }
-      do {
-        $proceed = 0;
-        if ((list($sub_r, $sub_v) = $this->xGraphPatternNotTriples($sub_v)) && $sub_r) {
-          $r['patterns'][] = $sub_r;
-          $pattern_id = substr(md5(uniqid(rand())), 0, 4);
-          $proceed = 1;
-        }
-        elseif ((list($sub_r, $sub_v) = $this->xFilter($sub_v)) && $sub_r) {
-          $r['patterns'][] = array('type' => 'filter', 'constraint' => $sub_r);
-          $proceed = 1;
-        }
-        if ($sub_r = $this->x('\.', $sub_v)) {
-          $sub_v = $sub_r[1];
-        }
-        if ((list($sub_r, $sub_v) = $this->xTriplesBlock($sub_v)) && $sub_r) {
-          $this->indexBnodes($sub_r, $pattern_id);
-          $r['patterns'][] = array('type' => 'triples', 'patterns' => $sub_r);
-          $proceed = 1;
-        }
-        if ((list($sub_r, $sub_v) = $this->xPlaceholder($sub_v)) && $sub_r) {
-          $r['patterns'][] = $sub_r;
-          $proceed = 1;
-        }
-      } while ($proceed);
-      if ($sub_r = $this->x('\}', $sub_v)) {
-        $sub_v = $sub_r[1];
-        return array($r, $sub_v);
-      }
-      $rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($sub_v, 0, 30));
-      $this->addError('Incomplete or invalid Group Graph pattern. Could not handle "' . $rest . '"');
-    }
-    return array(0, $v);
-  }
-
-  function indexBnodes($triples, $pattern_id) {
-    $index_id = count($this->bnode_pattern_index['patterns']);
-    $index_id = $pattern_id;
-    $this->bnode_pattern_index['patterns'][] = $triples;
-    foreach ($triples as $t) {
-      foreach (array('s', 'p', 'o') as $term) {
-        if ($t[$term . '_type'] == 'bnode') {
-          $val = $t[$term];
-          if (isset($this->bnode_pattern_index['bnodes'][$val]) && ($this->bnode_pattern_index['bnodes'][$val] != $index_id)) {
-            $this->addError('Re-used bnode label "' .$val. '" across graph patterns');
-          }
-          else {
-            $this->bnode_pattern_index['bnodes'][$val] = $index_id;
-          }
-        }
-      }
-    }
-  }
-
-  /* 22.., 25.. */
-
-  function xGraphPatternNotTriples($v) {
-    if ((list($sub_r, $sub_v) = $this->xOptionalGraphPattern($v)) && $sub_r) {
-      return array($sub_r, $sub_v);
-    }
-    if ((list($sub_r, $sub_v) = $this->xGraphGraphPattern($v)) && $sub_r) {
-      return array($sub_r, $sub_v);
-    }
-    $r = array('type' => 'union', 'patterns' => array());
-    $sub_v = $v;
-    do {
-      $proceed = 0;
-      if ((list($sub_r, $sub_v) = $this->xGroupGraphPattern($sub_v)) && $sub_r) {
-        $r['patterns'][] = $sub_r;
-        if ($sub_r = $this->x('UNION', $sub_v)) {
-          $sub_v = $sub_r[1];
-          $proceed = 1;
-        }
-      }
-    } while ($proceed);
-    $pc = count($r['patterns']);
-    if ($pc == 1) {
-      return array($r['patterns'][0], $sub_v);
-    }
-    elseif ($pc > 1) {
-      return array($r, $sub_v);
-    }
-    return array(0, $v);
-  }
-
-  /* 23 */
-
-  function xOptionalGraphPattern($v) {
-    if ($sub_r = $this->x('OPTIONAL', $v)) {
-      $sub_v = $sub_r[1];
-      if ((list($sub_r, $sub_v) = $this->xGroupGraphPattern($sub_v)) && $sub_r) {
-        return array(array('type' => 'optional', 'patterns' => $sub_r['patterns']), $sub_v);
-      }
-      $this->addError('Missing or invalid Group Graph Pattern after OPTIONAL');
-    }
-    return array(0, $v);
-  }
-
-  /* 24.. */
-
-  function xGraphGraphPattern($v) {
-    if ($sub_r = $this->x('GRAPH', $v)) {
-      $sub_v = $sub_r[1];
-      $r = array('type' => 'graph', 'var' => '', 'uri' => '', 'patterns' => array());
-      if ((list($sub_r, $sub_v) = $this->xVar($sub_v)) && $sub_r) {
-        $r['var'] = $sub_r;
-      }
-      elseif ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
-        $r['uri'] = $sub_r;
-      }
-      if ($r['var'] || $r['uri']) {
-        if ((list($sub_r, $sub_v) = $this->xGroupGraphPattern($sub_v)) && $sub_r) {
-          $r['patterns'][] = $sub_r;
-          return array($r, $sub_v);
-        }
-        $this->addError('Missing or invalid Graph Pattern');
-      }
-    }
-    return array(0, $v);
-  }
-
-  /* 26.., 27.. */
-
-  function xFilter($v) {
-    if ($r = $this->x('FILTER', $v)) {
-      $sub_v = $r[1];
-      if ((list($r, $sub_v) = $this->xBrackettedExpression($sub_v)) && $r) {
-        return array($r, $sub_v);
-      }
-      if ((list($r, $sub_v) = $this->xBuiltInCall($sub_v)) && $r) {
-        return array($r, $sub_v);
-      }
-      if ((list($r, $sub_v) = $this->xFunctionCall($sub_v)) && $r) {
-        return array($r, $sub_v);
-      }
-      $this->addError('Incomplete FILTER');
-    }
-    return array(0, $v);
-  }
-
-  /* 28.. */
-
-  function xFunctionCall($v) {
-    if ((list($r, $sub_v) = $this->xIRIref($v)) && $r) {
-      if ((list($sub_r, $sub_v) = $this->xArgList($sub_v)) && $sub_r) {
-        return array(array('type' => 'function_call', 'uri' => $r, 'args' => $sub_r), $sub_v);
-      }
-    }
-    return array(0, $v);
-  }
-
-  /* 29 */
-
-  function xArgList($v) {
-    $r = array();
-    $sub_v = $v;
-    $closed = 0;
-    if ($sub_r = $this->x('\(', $sub_v)) {
-      $sub_v = $sub_r[1];
-      do {
-        $proceed = 0;
-        if ((list($sub_r, $sub_v) = $this->xExpression($sub_v)) && $sub_r) {
-          $r[] = $sub_r;
-          if ($sub_r = $this->x('\,', $sub_v)) {
+        $pc = count($r['patterns']);
+        if (1 == $pc) {
+            return [$r['patterns'][0], $sub_v];
+        } elseif ($pc > 1) {
+            return [$r, $sub_v];
+        }
+
+        return [0, $v];
+    }
+
+    /* 23 */
+
+    public function xOptionalGraphPattern($v)
+    {
+        if ($sub_r = $this->x('OPTIONAL', $v)) {
             $sub_v = $sub_r[1];
-            $proceed = 1;
-          }
-        }
-        if ($sub_r = $this->x('\)', $sub_v)) {
-         $sub_v = $sub_r[1];
-         $closed = 1;
-         $proceed = 0;
-        }
-      } while ($proceed);
-    }
-    return $closed ? array($r, $sub_v) : array(0, $v);
-  }
-
-  /* 30, 31 */
-
-  function xConstructTemplate($v) {
-    if ($sub_r = $this->x('\{', $v)) {
-      $r = array();
-      if ((list($sub_r, $sub_v) = $this->xTriplesBlock($sub_r[1])) && is_array($sub_r)) {
-        $r = $sub_r;
-      }
-      if ($sub_r = $this->x('\}', $sub_v)) {
-        return array($r, $sub_r[1]);
-      }
-    }
-    return array(0, $v);
-  }
-
-  /* 46, 47 */
-
-  function xExpression($v) {
-    if ((list($sub_r, $sub_v) = $this->xConditionalAndExpression($v)) && $sub_r) {
-      $r = array('type' => 'expression', 'sub_type' => 'or', 'patterns' => array($sub_r));
-      do {
-        $proceed = 0;
-        if ($sub_r = $this->x('\|\|', $sub_v)) {
-          $sub_v = $sub_r[1];
-          if ((list($sub_r, $sub_v) = $this->xConditionalAndExpression($sub_v)) && $sub_r) {
-            $r['patterns'][] = $sub_r;
-            $proceed = 1;
-          }
-        }
-      } while ($proceed);
-      return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v);
-    }
-    return array(0, $v);
-  }
-
-  /* 48.., 49.. */
-
-  function xConditionalAndExpression($v) {
-    if ((list($sub_r, $sub_v) = $this->xRelationalExpression($v)) && $sub_r) {
-      $r = array('type' => 'expression', 'sub_type' => 'and', 'patterns' => array($sub_r));
-      do {
-        $proceed = 0;
-        if ($sub_r = $this->x('\&\&', $sub_v)) {
-          $sub_v = $sub_r[1];
-          if ((list($sub_r, $sub_v) = $this->xRelationalExpression($sub_v)) && $sub_r) {
-            $r['patterns'][] = $sub_r;
-            $proceed = 1;
-          }
-        }
-      } while ($proceed);
-      return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v);
-    }
-    return array(0, $v);
-  }
-
-  /* 50, 51 */
-
-  function xRelationalExpression($v) {
-    if ((list($sub_r, $sub_v) = $this->xAdditiveExpression($v)) && $sub_r) {
-      $r = array('type' => 'expression', 'sub_type' => 'relational', 'patterns' => array($sub_r));
-      do {
-        $proceed = 0;
-        /* don't mistake '<' + uriref with '<'-operator ("longest token" rule) */
-        if ((list($sub_r, $sub_v) = $this->xIRI_REF($sub_v)) && $sub_r) {
-          $this->addError('Expected operator, found IRIref: "'.$sub_r.'".');
-        }
-        if ($sub_r = $this->x('(\!\=|\=\=|\=|\<\=|\>\=|\<|\>)', $sub_v)) {
-          $op = $sub_r[1];
-          $sub_v = $sub_r[2];
-          $r['operator'] = $op;
-          if ((list($sub_r, $sub_v) = $this->xAdditiveExpression($sub_v)) && $sub_r) {
-            //$sub_r['operator'] = $op;
-            $r['patterns'][] = $sub_r;
-            $proceed = 1;
-          }
-        }
-      } while ($proceed);
-      return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v);
-    }
-    return array(0, $v);
-  }
-
-  /* 52 */
-
-  function xAdditiveExpression($v) {
-    if ((list($sub_r, $sub_v) = $this->xMultiplicativeExpression($v)) && $sub_r) {
-      $r = array('type' => 'expression', 'sub_type' => 'additive', 'patterns' => array($sub_r));
-      do {
-        $proceed = 0;
-        if ($sub_r = $this->x('(\+|\-)', $sub_v)) {
-          $op = $sub_r[1];
-          $sub_v = $sub_r[2];
-          if ((list($sub_r, $sub_v) = $this->xMultiplicativeExpression($sub_v)) && $sub_r) {
-            $sub_r['operator'] = $op;
-            $r['patterns'][] = $sub_r;
-            $proceed = 1;
-          }
-          elseif ((list($sub_r, $sub_v) = $this->xNumericLiteral($sub_v)) && $sub_r) {
-            $r['patterns'][] = array('type' => 'numeric', 'operator' => $op, 'value' => $sub_r);
-            $proceed = 1;
-          }
-        }
-      } while ($proceed);
-      //return array($r, $sub_v);
-      return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v);
-    }
-    return array(0, $v);
-  }
-
-  /* 53 */
-
-  function xMultiplicativeExpression($v) {
-    if ((list($sub_r, $sub_v) = $this->xUnaryExpression($v)) && $sub_r) {
-      $r = array('type' => 'expression', 'sub_type' => 'multiplicative', 'patterns' => array($sub_r));
-      do {
-        $proceed = 0;
-        if ($sub_r = $this->x('(\*|\/)', $sub_v)) {
-          $op = $sub_r[1];
-          $sub_v = $sub_r[2];
-          if ((list($sub_r, $sub_v) = $this->xUnaryExpression($sub_v)) && $sub_r) {
-            $sub_r['operator'] = $op;
-            $r['patterns'][] = $sub_r;
-            $proceed = 1;
-          }
+            if ((list($sub_r, $sub_v) = $this->xGroupGraphPattern($sub_v)) && $sub_r) {
+                return [['type' => 'optional', 'patterns' => $sub_r['patterns']], $sub_v];
+            }
+            $this->addError('Missing or invalid Group Graph Pattern after OPTIONAL');
         }
-      } while ($proceed);
-      return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v);
+
+        return [0, $v];
     }
-    return array(0, $v);
-  }
 
-  /* 54 */
+    /* 24.. */
+
+    public function xGraphGraphPattern($v)
+    {
+        if ($sub_r = $this->x('GRAPH', $v)) {
+            $sub_v = $sub_r[1];
+            $r = ['type' => 'graph', 'var' => '', 'uri' => '', 'patterns' => []];
+            if ((list($sub_r, $sub_v) = $this->xVar($sub_v)) && $sub_r) {
+                $r['var'] = $sub_r;
+            } elseif ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
+                $r['uri'] = $sub_r;
+            }
+            if ($r['var'] || $r['uri']) {
+                if ((list($sub_r, $sub_v) = $this->xGroupGraphPattern($sub_v)) && $sub_r) {
+                    $r['patterns'][] = $sub_r;
+
+                    return [$r, $sub_v];
+                }
+                $this->addError('Missing or invalid Graph Pattern');
+            }
+        }
+
+        return [0, $v];
+    }
+
+    /* 26.., 27.. */
+
+    public function xFilter($v)
+    {
+        if ($r = $this->x('FILTER', $v)) {
+            $sub_v = $r[1];
+            if ((list($r, $sub_v) = $this->xBrackettedExpression($sub_v)) && $r) {
+                return [$r, $sub_v];
+            }
+            if ((list($r, $sub_v) = $this->xBuiltInCall($sub_v)) && $r) {
+                return [$r, $sub_v];
+            }
+            if ((list($r, $sub_v) = $this->xFunctionCall($sub_v)) && $r) {
+                return [$r, $sub_v];
+            }
+            $this->addError('Incomplete FILTER');
+        }
 
-  function xUnaryExpression($v) {
-    $sub_v = $v;
-    $op = '';
-    if ($sub_r = $this->x('(\!|\+|\-)', $sub_v)) {
-      $op = $sub_r[1];
-      $sub_v = $sub_r[2];
+        return [0, $v];
     }
-    if ((list($sub_r, $sub_v) = $this->xPrimaryExpression($sub_v)) && $sub_r) {
-      if (!is_array($sub_r)) {
-        $sub_r = array('type' => 'unary', 'expression' => $sub_r);
-      }
-      elseif ($sub_op = $this->v1('operator', '', $sub_r)) {
-        $ops = array('!!' => '', '++' => '+', '--' => '+', '+-' => '-', '-+' => '-');
-        $op = isset($ops[$op . $sub_op]) ? $ops[$op . $sub_op] : $op . $sub_op;
-      }
-      $sub_r['operator'] = $op;
-      return array($sub_r, $sub_v);
+
+    /* 28.. */
+
+    public function xFunctionCall($v)
+    {
+        if ((list($r, $sub_v) = $this->xIRIref($v)) && $r) {
+            if ((list($sub_r, $sub_v) = $this->xArgList($sub_v)) && $sub_r) {
+                return [['type' => 'function_call', 'uri' => $r, 'args' => $sub_r], $sub_v];
+            }
+        }
+
+        return [0, $v];
     }
-    return array(0, $v);
-  }
 
-  /* 55 */
+    /* 29 */
+
+    public function xArgList($v)
+    {
+        $r = [];
+        $sub_v = $v;
+        $closed = 0;
+        if ($sub_r = $this->x('\(', $sub_v)) {
+            $sub_v = $sub_r[1];
+            do {
+                $proceed = 0;
+                if ((list($sub_r, $sub_v) = $this->xExpression($sub_v)) && $sub_r) {
+                    $r[] = $sub_r;
+                    if ($sub_r = $this->x('\,', $sub_v)) {
+                        $sub_v = $sub_r[1];
+                        $proceed = 1;
+                    }
+                }
+                if ($sub_r = $this->x('\)', $sub_v)) {
+                    $sub_v = $sub_r[1];
+                    $closed = 1;
+                    $proceed = 0;
+                }
+            } while ($proceed);
+        }
 
-  function xPrimaryExpression($v) {
-    foreach (array('BrackettedExpression', 'BuiltInCall', 'IRIrefOrFunction', 'RDFLiteral', 'NumericLiteral', 'BooleanLiteral', 'Var', 'Placeholder') as $type) {
-      $m = 'x' . $type;
-      if ((list($sub_r, $sub_v) = $this->$m($v)) && $sub_r) {
-        return array($sub_r, $sub_v);
-      }
+        return $closed ? [$r, $sub_v] : [0, $v];
     }
-    return array(0, $v);
-  }
 
-  /* 56 */
+    /* 30, 31 */
 
-  function xBrackettedExpression($v) {
-    if ($r = $this->x('\(', $v)) {
-      if ((list($r, $sub_v) = $this->xExpression($r[1])) && $r) {
-        if ($sub_r = $this->x('\)', $sub_v)) {
-          return array($r, $sub_r[1]);
+    public function xConstructTemplate($v)
+    {
+        if ($sub_r = $this->x('\{', $v)) {
+            $r = [];
+            if ((list($sub_r, $sub_v) = $this->xTriplesBlock($sub_r[1])) && is_array($sub_r)) {
+                $r = $sub_r;
+            }
+            if ($sub_r = $this->x('\}', $sub_v)) {
+                return [$r, $sub_r[1]];
+            }
         }
-      }
+
+        return [0, $v];
     }
-    return array(0, $v);
-  }
 
-  /* 57.., 58.. */
+    /* 46, 47 */
+
+    public function xExpression($v)
+    {
+        if ((list($sub_r, $sub_v) = $this->xConditionalAndExpression($v)) && $sub_r) {
+            $r = ['type' => 'expression', 'sub_type' => 'or', 'patterns' => [$sub_r]];
+            do {
+                $proceed = 0;
+                if ($sub_r = $this->x('\|\|', $sub_v)) {
+                    $sub_v = $sub_r[1];
+                    if ((list($sub_r, $sub_v) = $this->xConditionalAndExpression($sub_v)) && $sub_r) {
+                        $r['patterns'][] = $sub_r;
+                        $proceed = 1;
+                    }
+                }
+            } while ($proceed);
+
+            return 1 == count($r['patterns']) ? [$r['patterns'][0], $sub_v] : [$r, $sub_v];
+        }
 
-  function xBuiltInCall($v) {
-    if ($sub_r = $this->x('(str|lang|langmatches|datatype|bound|sameterm|isiri|isuri|isblank|isliteral|regex)\s*\(', $v)) {
-      $r = array('type' => 'built_in_call', 'call' => strtolower($sub_r[1]));
-      if ((list($sub_r, $sub_v) = $this->xArgList('(' . $sub_r[2])) && is_array($sub_r)) {
-        $r['args'] = $sub_r;
-        return array($r, $sub_v);
-      }
+        return [0, $v];
     }
-    return array(0, $v);
-  }
 
-  /* 59.. */
+    /* 48.., 49.. */
 
-  function xIRIrefOrFunction($v) {
-    if ((list($r, $v) = $this->xIRIref($v)) && $r) {
-      if ((list($sub_r, $sub_v) = $this->xArgList($v)) && is_array($sub_r)) {
-        return array(array('type' => 'function', 'uri' => $r, 'args' => $sub_r), $sub_v);
-      }
-      return array(array('type' => 'uri', 'uri' => $r), $sub_v);
+    public function xConditionalAndExpression($v)
+    {
+        if ((list($sub_r, $sub_v) = $this->xRelationalExpression($v)) && $sub_r) {
+            $r = ['type' => 'expression', 'sub_type' => 'and', 'patterns' => [$sub_r]];
+            do {
+                $proceed = 0;
+                if ($sub_r = $this->x('\&\&', $sub_v)) {
+                    $sub_v = $sub_r[1];
+                    if ((list($sub_r, $sub_v) = $this->xRelationalExpression($sub_v)) && $sub_r) {
+                        $r['patterns'][] = $sub_r;
+                        $proceed = 1;
+                    }
+                }
+            } while ($proceed);
+
+            return 1 == count($r['patterns']) ? [$r['patterns'][0], $sub_v] : [$r, $sub_v];
+        }
+
+        return [0, $v];
+    }
+
+    /* 50, 51 */
+
+    public function xRelationalExpression($v)
+    {
+        if ((list($sub_r, $sub_v) = $this->xAdditiveExpression($v)) && $sub_r) {
+            $r = ['type' => 'expression', 'sub_type' => 'relational', 'patterns' => [$sub_r]];
+            do {
+                $proceed = 0;
+                /* don't mistake '<' + uriref with '<'-operator ("longest token" rule) */
+                if ((list($sub_r, $sub_v) = $this->xIRI_REF($sub_v)) && $sub_r) {
+                    $this->addError('Expected operator, found IRIref: "'.$sub_r.'".');
+                }
+                if ($sub_r = $this->x('(\!\=|\=\=|\=|\<\=|\>\=|\<|\>)', $sub_v)) {
+                    $op = $sub_r[1];
+                    $sub_v = $sub_r[2];
+                    $r['operator'] = $op;
+                    if ((list($sub_r, $sub_v) = $this->xAdditiveExpression($sub_v)) && $sub_r) {
+                        //$sub_r['operator'] = $op;
+                        $r['patterns'][] = $sub_r;
+                        $proceed = 1;
+                    }
+                }
+            } while ($proceed);
+
+            return 1 == count($r['patterns']) ? [$r['patterns'][0], $sub_v] : [$r, $sub_v];
+        }
+
+        return [0, $v];
+    }
+
+    /* 52 */
+
+    public function xAdditiveExpression($v)
+    {
+        if ((list($sub_r, $sub_v) = $this->xMultiplicativeExpression($v)) && $sub_r) {
+            $r = ['type' => 'expression', 'sub_type' => 'additive', 'patterns' => [$sub_r]];
+            do {
+                $proceed = 0;
+                if ($sub_r = $this->x('(\+|\-)', $sub_v)) {
+                    $op = $sub_r[1];
+                    $sub_v = $sub_r[2];
+                    if ((list($sub_r, $sub_v) = $this->xMultiplicativeExpression($sub_v)) && $sub_r) {
+                        $sub_r['operator'] = $op;
+                        $r['patterns'][] = $sub_r;
+                        $proceed = 1;
+                    } elseif ((list($sub_r, $sub_v) = $this->xNumericLiteral($sub_v)) && $sub_r) {
+                        $r['patterns'][] = ['type' => 'numeric', 'operator' => $op, 'value' => $sub_r];
+                        $proceed = 1;
+                    }
+                }
+            } while ($proceed);
+            //return array($r, $sub_v);
+            return 1 == count($r['patterns']) ? [$r['patterns'][0], $sub_v] : [$r, $sub_v];
+        }
+
+        return [0, $v];
+    }
+
+    /* 53 */
+
+    public function xMultiplicativeExpression($v)
+    {
+        if ((list($sub_r, $sub_v) = $this->xUnaryExpression($v)) && $sub_r) {
+            $r = ['type' => 'expression', 'sub_type' => 'multiplicative', 'patterns' => [$sub_r]];
+            do {
+                $proceed = 0;
+                if ($sub_r = $this->x('(\*|\/)', $sub_v)) {
+                    $op = $sub_r[1];
+                    $sub_v = $sub_r[2];
+                    if ((list($sub_r, $sub_v) = $this->xUnaryExpression($sub_v)) && $sub_r) {
+                        $sub_r['operator'] = $op;
+                        $r['patterns'][] = $sub_r;
+                        $proceed = 1;
+                    }
+                }
+            } while ($proceed);
+
+            return 1 == count($r['patterns']) ? [$r['patterns'][0], $sub_v] : [$r, $sub_v];
+        }
+
+        return [0, $v];
+    }
+
+    /* 54 */
+
+    public function xUnaryExpression($v)
+    {
+        $sub_v = $v;
+        $op = '';
+        if ($sub_r = $this->x('(\!|\+|\-)', $sub_v)) {
+            $op = $sub_r[1];
+            $sub_v = $sub_r[2];
+        }
+        if ((list($sub_r, $sub_v) = $this->xPrimaryExpression($sub_v)) && $sub_r) {
+            if (!is_array($sub_r)) {
+                $sub_r = ['type' => 'unary', 'expression' => $sub_r];
+            } elseif ($sub_op = $this->v1('operator', '', $sub_r)) {
+                $ops = ['!!' => '', '++' => '+', '--' => '+', '+-' => '-', '-+' => '-'];
+                $op = isset($ops[$op.$sub_op]) ? $ops[$op.$sub_op] : $op.$sub_op;
+            }
+            $sub_r['operator'] = $op;
+
+            return [$sub_r, $sub_v];
+        }
+
+        return [0, $v];
+    }
+
+    /* 55 */
+
+    public function xPrimaryExpression($v)
+    {
+        foreach (['BrackettedExpression', 'BuiltInCall', 'IRIrefOrFunction', 'RDFLiteral', 'NumericLiteral', 'BooleanLiteral', 'Var', 'Placeholder'] as $type) {
+            $m = 'x'.$type;
+            if ((list($sub_r, $sub_v) = $this->$m($v)) && $sub_r) {
+                return [$sub_r, $sub_v];
+            }
+        }
+
+        return [0, $v];
     }
-  }
 
-  /* 70.. @@sync with TurtleParser */
+    /* 56 */
+
+    public function xBrackettedExpression($v)
+    {
+        if ($r = $this->x('\(', $v)) {
+            if ((list($r, $sub_v) = $this->xExpression($r[1])) && $r) {
+                if ($sub_r = $this->x('\)', $sub_v)) {
+                    return [$r, $sub_r[1]];
+                }
+            }
+        }
 
-  function xIRI_REF($v) {
-    if (($r = $this->x('\<(\$\{[^\>]*\})\>', $v)) && ($sub_r = $this->xPlaceholder($r[1]))) {
-      return array($r[1], $r[2]);
+        return [0, $v];
     }
-    elseif ($r = $this->x('\<([^\<\>\s\"\|\^`]*)\>', $v)) {
-      return array($r[1] ? $r[1] : true, $r[2]);
+
+    /* 57.., 58.. */
+
+    public function xBuiltInCall($v)
+    {
+        if ($sub_r = $this->x('(str|lang|langmatches|datatype|bound|sameterm|isiri|isuri|isblank|isliteral|regex)\s*\(', $v)) {
+            $r = ['type' => 'built_in_call', 'call' => strtolower($sub_r[1])];
+            if ((list($sub_r, $sub_v) = $this->xArgList('('.$sub_r[2])) && is_array($sub_r)) {
+                $r['args'] = $sub_r;
+
+                return [$r, $sub_v];
+            }
+        }
+
+        return [0, $v];
     }
-    /* allow reserved chars in obvious IRIs */
-    elseif ($r = $this->x('\<(https?\:[^\s][^\<\>]*)\>', $v)) {
-      return array($r[1] ? $r[1] : true, $r[2]);
+
+    /* 59.. */
+
+    public function xIRIrefOrFunction($v)
+    {
+        if ((list($r, $v) = $this->xIRIref($v)) && $r) {
+            if ((list($sub_r, $sub_v) = $this->xArgList($v)) && is_array($sub_r)) {
+                return [['type' => 'function', 'uri' => $r, 'args' => $sub_r], $sub_v];
+            }
+
+            return [['type' => 'uri', 'uri' => $r], $sub_v];
+        }
     }
-    return array(0, $v);
-  }
 
+    /* 70.. @@sync with TurtleParser */
+
+    public function xIRI_REF($v)
+    {
+        if (($r = $this->x('\<(\$\{[^\>]*\})\>', $v)) && ($sub_r = $this->xPlaceholder($r[1]))) {
+            return [$r[1], $r[2]];
+        } elseif ($r = $this->x('\<([^\<\>\s\"\|\^`]*)\>', $v)) {
+            return [$r[1] ? $r[1] : true, $r[2]];
+        }
+        /* allow reserved chars in obvious IRIs */
+        elseif ($r = $this->x('\<(https?\:[^\s][^\<\>]*)\>', $v)) {
+            return [$r[1] ? $r[1] : true, $r[2]];
+        }
+
+        return [0, $v];
+    }
 }
diff --git a/lib/arc2/parsers/ARC2_SPARQLPlusParser.php b/lib/arc2/parsers/ARC2_SPARQLPlusParser.php
index e8048025dd9717310c73b8bc3ebdd4c097b3aa44..c0571a91169bfd9a11243997926452e58e523375 100644
--- a/lib/arc2/parsers/ARC2_SPARQLPlusParser.php
+++ b/lib/arc2/parsers/ARC2_SPARQLPlusParser.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 SPARQL+ Parser (SPARQL + Aggregates + LOAD + INSERT + DELETE)
 author:   Benjamin Nowack
@@ -10,201 +10,218 @@ version:  2010-11-16
 
 ARC2::inc('SPARQLParser');
 
-class ARC2_SPARQLPlusParser extends ARC2_SPARQLParser {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-  }
-
-  /* +1 */
-  
-  function xQuery($v) {
-    list($r, $v) = $this->xPrologue($v);
-    foreach (array('Select', 'Construct', 'Describe', 'Ask', 'Insert', 'Delete', 'Load') as $type) {
-      $m = 'x' . $type . 'Query';
-      if ((list($r, $v) = $this->$m($v)) && $r) {
-        return array($r, $v);
-      }
+class ARC2_SPARQLPlusParser extends ARC2_SPARQLParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
     }
-    return array(0, $v);
-  }
-
-  /* +3 */
-  
-  function xResultVar($v) {
-    $aggregate = '';
-    /* aggregate */
-    if ($sub_r = $this->x('\(?(AVG|COUNT|MAX|MIN|SUM)\s*\(\s*([^\)]+)\)\s+AS\s+([^\s\)]+)\)?', $v)) {
-      $aggregate = $sub_r[1];
-      $result_var = $sub_r[3];
-      $v = $sub_r[2] . $sub_r[4];
-    }
-    if ($sub_r && (list($sub_r, $sub_v) = $this->xVar($result_var)) && $sub_r) {
-      $result_var = $sub_r['value'];
+
+    public function __init()
+    {
+        parent::__init();
     }
-    /* * or var */
-    if ((list($sub_r, $sub_v) = $this->x('\*', $v)) && $sub_r) {
-      return array(array('var' => $sub_r['value'], 'aggregate' => $aggregate, 'alias' => $aggregate ? $result_var : ''), $sub_v);
+
+    /* +1 */
+
+    public function xQuery($v)
+    {
+        list($r, $v) = $this->xPrologue($v);
+        foreach (['Select', 'Construct', 'Describe', 'Ask', 'Insert', 'Delete', 'Load'] as $type) {
+            $m = 'x'.$type.'Query';
+            if ((list($r, $v) = $this->$m($v)) && $r) {
+                return [$r, $v];
+            }
+        }
+
+        return [0, $v];
     }
-    if ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
-      return array(array('var' => $sub_r['value'], 'aggregate' => $aggregate, 'alias' => $aggregate ? $result_var : ''), $sub_v);
+
+    /* +3 */
+
+    public function xResultVar($v)
+    {
+        $aggregate = '';
+        /* aggregate */
+        if ($sub_r = $this->x('\(?(AVG|COUNT|MAX|MIN|SUM)\s*\(\s*([^\)]+)\)\s+AS\s+([^\s\)]+)\)?', $v)) {
+            $aggregate = $sub_r[1];
+            $result_var = $sub_r[3];
+            $v = $sub_r[2].$sub_r[4];
+        }
+        if ($sub_r && (list($sub_r, $sub_v) = $this->xVar($result_var)) && $sub_r) {
+            $result_var = $sub_r['value'];
+        }
+        /* * or var */
+        if ((list($sub_r, $sub_v) = $this->x('\*', $v)) && $sub_r) {
+            return [['var' => '*', 'aggregate' => $aggregate, 'alias' => $aggregate ? $result_var : ''], $sub_v];
+        }
+        if ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
+            return [['var' => $sub_r['value'], 'aggregate' => $aggregate, 'alias' => $aggregate ? $result_var : ''], $sub_v];
+        }
+
+        return [0, $v];
     }
-    return array(0, $v);
-  }
-
-  /* +4 */
- 
-  function xLoadQuery($v) {
-    if ($sub_r = $this->x('LOAD\s+', $v)) {
-      $sub_v = $sub_r[1];
-      if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
-        $r = array('type' => 'load', 'url' => $sub_r, 'target_graph' => '');
-        if ($sub_r = $this->x('INTO\s+', $sub_v)) {
-          $sub_v = $sub_r[1];
-          if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
-            $r['target_graph'] = $sub_r;
-          }
+
+    /* +4 */
+
+    public function xLoadQuery($v)
+    {
+        if ($sub_r = $this->x('LOAD\s+', $v)) {
+            $sub_v = $sub_r[1];
+            if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
+                $r = ['type' => 'load', 'url' => $sub_r, 'target_graph' => ''];
+                if ($sub_r = $this->x('INTO\s+', $sub_v)) {
+                    $sub_v = $sub_r[1];
+                    if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
+                        $r['target_graph'] = $sub_r;
+                    }
+                }
+
+                return [$r, $sub_v];
+            }
         }
-        return array($r, $sub_v);
-      }
+
+        return [0, $v];
     }
-    return array(0, $v);
-  }
-  
-  /* +5 */
-  
-  function xInsertQuery($v) {
-    if ($sub_r = $this->x('INSERT\s+', $v)) {
-      $r = array(
-        'type' => 'insert',
-        'dataset' => array(),
-      );
-      $sub_v = $sub_r[1];
-      /* target */
-      if ($sub_r = $this->x('INTO\s+', $sub_v)) {
-        $sub_v = $sub_r[1];
-        if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
-          $r['target_graph'] = $sub_r;
-          /* CONSTRUCT keyword, optional */
-          if ($sub_r = $this->x('CONSTRUCT\s+', $sub_v)) {
+
+    /* +5 */
+
+    public function xInsertQuery($v)
+    {
+        if ($sub_r = $this->x('INSERT\s+', $v)) {
+            $r = [
+                'type' => 'insert',
+                'dataset' => [],
+            ];
             $sub_v = $sub_r[1];
-          }
-          /* construct template */
-          if ((list($sub_r, $sub_v) = $this->xConstructTemplate($sub_v)) && is_array($sub_r)) {
-            $r['construct_triples'] = $sub_r;
-          }
-          else {
-            $this->addError('Construct Template not found');
-            return array(0, $v);
-          }
-          /* dataset */
-          while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
-            $r['dataset'][] = $sub_r;
-          }
-          /* where */
-          if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
-            $r['pattern'] = $sub_r;
-          }
-          /* solution modifier */
-          if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
-            $r = array_merge($r, $sub_r);
-          }
-          return array($r, $sub_v);
+            /* target */
+            if ($sub_r = $this->x('INTO\s+', $sub_v)) {
+                $sub_v = $sub_r[1];
+                if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
+                    $r['target_graph'] = $sub_r;
+                    /* CONSTRUCT keyword, optional */
+                    if ($sub_r = $this->x('CONSTRUCT\s+', $sub_v)) {
+                        $sub_v = $sub_r[1];
+                    }
+                    /* construct template */
+                    if ((list($sub_r, $sub_v) = $this->xConstructTemplate($sub_v)) && is_array($sub_r)) {
+                        $r['construct_triples'] = $sub_r;
+                    } else {
+                        $this->addError('Construct Template not found');
+
+                        return [0, $v];
+                    }
+                    /* dataset */
+                    while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
+                        $r['dataset'][] = $sub_r;
+                    }
+                    /* where */
+                    if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
+                        $r['pattern'] = $sub_r;
+                    }
+                    /* solution modifier */
+                    if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
+                        $r = array_merge($r, $sub_r);
+                    }
+
+                    return [$r, $sub_v];
+                }
+            }
         }
-      }
+
+        return [0, $v];
     }
-    return array(0, $v);
-  }
-
-  /* +6 */
-  
-  function xDeleteQuery($v) {
-    if ($sub_r = $this->x('DELETE\s+', $v)) {
-      $r = array(
-        'type' => 'delete',
-        'target_graphs' => array()
-      );
-      $sub_v = $sub_r[1];
-      /* target */
-      do {
-        $proceed = false;
-        if ($sub_r = $this->x('FROM\s+', $sub_v)) {
-          $sub_v = $sub_r[1];
-          if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
-            $r['target_graphs'][] = $sub_r;
-            $proceed = 1;
-          }
+
+    /* +6 */
+
+    public function xDeleteQuery($v)
+    {
+        if ($sub_r = $this->x('DELETE\s+', $v)) {
+            $r = [
+                'type' => 'delete',
+                'target_graphs' => [],
+            ];
+            $sub_v = $sub_r[1];
+            /* target */
+            do {
+                $proceed = false;
+                if ($sub_r = $this->x('FROM\s+', $sub_v)) {
+                    $sub_v = $sub_r[1];
+                    if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
+                        $r['target_graphs'][] = $sub_r;
+                        $proceed = 1;
+                    }
+                }
+            } while ($proceed);
+            /* CONSTRUCT keyword, optional */
+            if ($sub_r = $this->x('CONSTRUCT\s+', $sub_v)) {
+                $sub_v = $sub_r[1];
+            }
+            /* construct template */
+            if ((list($sub_r, $sub_v) = $this->xConstructTemplate($sub_v)) && is_array($sub_r)) {
+                $r['construct_triples'] = $sub_r;
+                /* dataset */
+                while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
+                    $r['dataset'][] = $sub_r;
+                }
+                /* where */
+                if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
+                    $r['pattern'] = $sub_r;
+                }
+                /* solution modifier */
+                if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
+                    $r = array_merge($r, $sub_r);
+                }
+            }
+
+            return [$r, $sub_v];
         }
-      } while ($proceed);
-      /* CONSTRUCT keyword, optional */
-      if ($sub_r = $this->x('CONSTRUCT\s+', $sub_v)) {
-        $sub_v = $sub_r[1];
-      }
-      /* construct template */
-      if ((list($sub_r, $sub_v) = $this->xConstructTemplate($sub_v)) && is_array($sub_r)) {
-        $r['construct_triples'] = $sub_r;
-        /* dataset */
-        while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
-          $r['dataset'][] = $sub_r;
+
+        return [0, $v];
+    }
+
+    /* +7 */
+
+    public function xSolutionModifier($v)
+    {
+        $r = [];
+        if ((list($sub_r, $sub_v) = $this->xGroupClause($v)) && $sub_r) {
+            $r['group_infos'] = $sub_r;
         }
-        /* where */
-        if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
-          $r['pattern'] = $sub_r;
+        if ((list($sub_r, $sub_v) = $this->xOrderClause($sub_v)) && $sub_r) {
+            $r['order_infos'] = $sub_r;
         }
-        /* solution modifier */
-        if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
-          $r = array_merge($r, $sub_r);
+        while ((list($sub_r, $sub_v) = $this->xLimitOrOffsetClause($sub_v)) && $sub_r) {
+            $r = array_merge($r, $sub_r);
         }
-      }
-      return array($r, $sub_v);
-    }
-    return array(0, $v);
-  }
-  
-  /* +7 */
-  
-  function xSolutionModifier($v) {
-    $r = array();
-    if ((list($sub_r, $sub_v) = $this->xGroupClause($v)) && $sub_r) {
-      $r['group_infos'] = $sub_r;
-    }
-    if ((list($sub_r, $sub_v) = $this->xOrderClause($sub_v)) && $sub_r) {
-      $r['order_infos'] = $sub_r;
-    }
-    while ((list($sub_r, $sub_v) = $this->xLimitOrOffsetClause($sub_v)) && $sub_r) {
-      $r = array_merge($r, $sub_r);
+
+        return ($v == $sub_v) ? [0, $v] : [$r, $sub_v];
     }
-    return ($v == $sub_v) ? array(0, $v) : array($r, $sub_v);
-  }
-
-  /* +8 */
-
-  function xGroupClause($v) {
-    if ($sub_r = $this->x('GROUP BY\s+', $v)) {
-      $sub_v = $sub_r[1];
-      $r = array();
-      do {
-        $proceed = 0;
-        if ((list($sub_r, $sub_v) = $this->xVar($sub_v)) && $sub_r) {
-          $r[] = $sub_r;
-          $proceed = 1;
-          if ($sub_r = $this->x('\,', $sub_v)) {
+
+    /* +8 */
+
+    public function xGroupClause($v)
+    {
+        if ($sub_r = $this->x('GROUP BY\s+', $v)) {
             $sub_v = $sub_r[1];
-          }
+            $r = [];
+            do {
+                $proceed = 0;
+                if ((list($sub_r, $sub_v) = $this->xVar($sub_v)) && $sub_r) {
+                    $r[] = $sub_r;
+                    $proceed = 1;
+                    if ($sub_r = $this->x('\,', $sub_v)) {
+                        $sub_v = $sub_r[1];
+                    }
+                }
+            } while ($proceed);
+            if (count($r)) {
+                return [$r, $sub_v];
+            } else {
+                $this->addError('No columns specified in GROUP BY clause.');
+            }
         }
-      } while ($proceed);
-      if (count($r)) {
-        return array($r, $sub_v);
-      }
-      else {
-        $this->addError('No columns specified in GROUP BY clause.');
-      }
-    }
-    return array(0, $v);
-  }
 
-}  
+        return [0, $v];
+    }
+}
diff --git a/lib/arc2/parsers/ARC2_SPARQLXMLResultParser.php b/lib/arc2/parsers/ARC2_SPARQLXMLResultParser.php
index 28d00494f24174ec5cc52bf387aadf1f1f939362..480a146a8a0789e8af2fe2d3acdee9772defaaaf 100644
--- a/lib/arc2/parsers/ARC2_SPARQLXMLResultParser.php
+++ b/lib/arc2/parsers/ARC2_SPARQLXMLResultParser.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 SPARQL Result XML Parser
 author:   Benjamin Nowack
@@ -10,103 +10,102 @@ version:  2010-11-16
 
 ARC2::inc('LegacyXMLParser');
 
-class ARC2_SPARQLXMLResultParser extends ARC2_LegacyXMLParser {
+class ARC2_SPARQLXMLResultParser extends ARC2_LegacyXMLParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
 
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* reader */
-    parent::__init();
-    $this->srx = 'http://www.w3.org/2005/sparql-results#';
-    $this->nsp[$this->srx] = 'srx';
-    $this->allowCDataNodes = 0;
-  }
-  
-  /*  */
-  
-  function done() {
-  }
-  
-  /*  */
-  
-  function getVariables() {
-    $r = array();
-    foreach ($this->nodes as $node) {
-      if ($node['tag'] == $this->srx . 'variable') {
-        $r[] = $node['a']['name'];
-      }
+    public function __init()
+    {/* reader */
+        parent::__init();
+        $this->srx = 'http://www.w3.org/2005/sparql-results#';
+        $this->nsp[$this->srx] = 'srx';
+        $this->allowCDataNodes = 0;
     }
-    return $r;
-  }
-  
-  function getRows() {
-    $r = array();
-    $index = $this->getNodeIndex();
-    foreach ($this->nodes as $node) {
-      if ($node['tag'] == $this->srx . 'result') {
-        $row = array();
-        $row_id = $node['id'];
-        $bindings = isset($index[$row_id])? $index[$row_id] : array();
-        foreach ($bindings as $binding) {
-          $row = array_merge($row, $this->getBinding($binding));
-        }
-        if ($row) {
-          $r[] = $row;
-        }
-      }
+
+    public function done()
+    {
     }
-    return $r;
-  }
 
-  function getBinding($node) {
-    $r = array();
-    $index = $this->getNodeIndex();
-    $var = $node['a']['name'];
-    $term = $index[$node['id']][0];
-    $r[$var . ' type'] = preg_replace('/^uri$/', 'uri', substr($term['tag'], strlen($this->srx)));
-    $r[$var] = ($r[$var . ' type'] == 'bnode') ? '_:' . $term['cdata'] : $term['cdata'];
-    if (isset($term['a']['datatype'])) {
-      $r[$var . ' datatype'] = $term['a']['datatype'];
+    public function getVariables()
+    {
+        $r = [];
+        foreach ($this->nodes as $node) {
+            if ($node['tag'] == $this->srx.'variable') {
+                $r[] = $node['a']['name'];
+            }
+        }
+
+        return $r;
     }
-    elseif (isset($term['a'][$this->xml . 'lang'])) {
-      $r[$var . ' lang'] = $term['a'][$this->xml . 'lang'];
+
+    public function getRows()
+    {
+        $r = [];
+        $index = $this->getNodeIndex();
+        foreach ($this->nodes as $node) {
+            if ($node['tag'] == $this->srx.'result') {
+                $row = [];
+                $row_id = $node['id'];
+                $bindings = isset($index[$row_id]) ? $index[$row_id] : [];
+                foreach ($bindings as $binding) {
+                    $row = array_merge($row, $this->getBinding($binding));
+                }
+                if ($row) {
+                    $r[] = $row;
+                }
+            }
+        }
+
+        return $r;
     }
-    return $r;
-  }
 
-  function getBooleanInsertedDeleted() {
-    foreach ($this->nodes as $node) {
-      if ($node['tag'] == $this->srx . 'boolean') {
-        return ($node['cdata'] == 'true') ? array('boolean' => true) : array('boolean' => false);
-      }
-      elseif ($node['tag'] == $this->srx . 'inserted') {
-        return array('inserted' => $node['cdata']);
-      }
-      elseif ($node['tag'] == $this->srx . 'deleted') {
-        return array('deleted' => $node['cdata']);
-      }
-      elseif ($node['tag'] == $this->srx . 'results') {
-        return '';
-      }
+    public function getBinding($node)
+    {
+        $r = [];
+        $index = $this->getNodeIndex();
+        $var = $node['a']['name'];
+        $term = $index[$node['id']][0];
+        $r[$var.' type'] = preg_replace('/^uri$/', 'uri', substr($term['tag'], strlen($this->srx)));
+        $r[$var] = ('bnode' == $r[$var.' type']) ? '_:'.$term['cdata'] : $term['cdata'];
+        if (isset($term['a']['datatype'])) {
+            $r[$var.' datatype'] = $term['a']['datatype'];
+        } elseif (isset($term['a'][$this->xml.'lang'])) {
+            $r[$var.' lang'] = $term['a'][$this->xml.'lang'];
+        }
+
+        return $r;
     }
-    return '';
-  }
 
-  /*  */
-  
-  function getStructure() {
-    $r = array('variables' => $this->getVariables(), 'rows' => $this->getRows());
-    /* boolean|inserted|deleted */
-    if ($sub_r = $this->getBooleanInsertedDeleted()) {
-      foreach ($sub_r as $k => $v) {
-        $r[$k] = $v;
-      }
+    public function getBooleanInsertedDeleted()
+    {
+        foreach ($this->nodes as $node) {
+            if ($node['tag'] == $this->srx.'boolean') {
+                return ('true' == $node['cdata']) ? ['boolean' => true] : ['boolean' => false];
+            } elseif ($node['tag'] == $this->srx.'inserted') {
+                return ['inserted' => $node['cdata']];
+            } elseif ($node['tag'] == $this->srx.'deleted') {
+                return ['deleted' => $node['cdata']];
+            } elseif ($node['tag'] == $this->srx.'results') {
+                return '';
+            }
+        }
+
+        return '';
     }
-    return $r;
-  }
 
-  /*  */
+    public function getStructure()
+    {
+        $r = ['variables' => $this->getVariables(), 'rows' => $this->getRows()];
+        /* boolean|inserted|deleted */
+        if ($sub_r = $this->getBooleanInsertedDeleted()) {
+            foreach ($sub_r as $k => $v) {
+                $r[$k] = $v;
+            }
+        }
 
-  
+        return $r;
+    }
 }
diff --git a/lib/arc2/parsers/ARC2_SPOGParser.php b/lib/arc2/parsers/ARC2_SPOGParser.php
old mode 100644
new mode 100755
index 71c41e63232c045ea53fd4f62d6d8901f7b9950f..de6bed6944733257e707fd4efd73ee983ad0d4bc
--- a/lib/arc2/parsers/ARC2_SPOGParser.php
+++ b/lib/arc2/parsers/ARC2_SPOGParser.php
@@ -1,188 +1,185 @@
 <?php
 /**
- * ARC2 streaming SPOG parser
+ * ARC2 streaming SPOG parser.
  *
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('RDFParser');
 
-class ARC2_SPOGParser extends ARC2_RDFParser {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* reader */
-    parent::__init();
-    $this->encoding = $this->v('encoding', false, $this->a);
-    $this->xml = 'http://www.w3.org/XML/1998/namespace';
-    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
-    $this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf');
-    $this->target_encoding = '';
-  }
-  
-  /*  */
-
-  function parse($path, $data = '', $iso_fallback = false) {
-    $this->state = 0;
-    /* reader */
-    if (!$this->v('reader')) {
-      ARC2::inc('Reader');
-      $this->reader = new ARC2_Reader($this->a, $this);
+class ARC2_SPOGParser extends ARC2_RDFParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
+
+    public function __init()
+    {/* reader */
+        parent::__init();
+        $this->encoding = $this->v('encoding', false, $this->a);
+        $this->xml = 'http://www.w3.org/XML/1998/namespace';
+        $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+        $this->nsp = [$this->xml => 'xml', $this->rdf => 'rdf'];
+        $this->target_encoding = '';
     }
-    $this->reader->setAcceptHeader('Accept: sparql-results+xml; q=0.9, */*; q=0.1');
-    $this->reader->activate($path, $data);
-    $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
-    /* xml parser */
-    $this->initXMLParser();
-    /* parse */
-    $first = true;
-    while ($d = $this->reader->readStream()) {
-      if ($iso_fallback && $first) {
-        $d = '<?xml version="1.0" encoding="ISO-8859-1"?>' . "\n" . preg_replace('/^\<\?xml [^\>]+\?\>\s*/s', '', $d);
-        $first = false;
-      }
-      if (!xml_parse($this->xml_parser, $d, false)) {
-        $error_str = xml_error_string(xml_get_error_code($this->xml_parser));
-        $line = xml_get_current_line_number($this->xml_parser);
-        $this->tmp_error = 'XML error: "' . $error_str . '" at line ' . $line . ' (parsing as ' . $this->getEncoding() . ')';
-        $this->tmp_error .= $d . urlencode($d);
-        if (0 && !$iso_fallback && preg_match("/Invalid character/i", $error_str)) {
-          xml_parser_free($this->xml_parser);
-          unset($this->xml_parser);
-          $this->reader->closeStream();
-          $this->__init();
-          $this->encoding = 'ISO-8859-1';
-          unset($this->xml_parser);
-          unset($this->reader);
-          return $this->parse($path, $data, true);
+
+    public function parse($path, $data = '', $iso_fallback = false)
+    {
+        $this->state = 0;
+        /* reader */
+        if (!$this->v('reader')) {
+            ARC2::inc('Reader');
+            $this->reader = new ARC2_Reader($this->a, $this);
         }
-        else {
-          return $this->addError($this->tmp_error);
+        $this->reader->setAcceptHeader('Accept: sparql-results+xml; q=0.9, */*; q=0.1');
+        $this->reader->activate($path, $data);
+        $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
+        /* xml parser */
+        $this->initXMLParser();
+        /* parse */
+        $first = true;
+        while ($d = $this->reader->readStream()) {
+            if ($iso_fallback && $first) {
+                $d = '<?xml version="1.0" encoding="ISO-8859-1"?>'."\n".preg_replace('/^\<\?xml [^\>]+\?\>\s*/s', '', $d);
+                $first = false;
+            }
+            if (!xml_parse($this->xml_parser, $d, false)) {
+                $error_str = xml_error_string(xml_get_error_code($this->xml_parser));
+                $line = xml_get_current_line_number($this->xml_parser);
+                $this->tmp_error = 'XML error: "'.$error_str.'" at line '.$line.' (parsing as '.$this->getEncoding().')';
+                $this->tmp_error .= $d.urlencode($d);
+                if (0 && !$iso_fallback && preg_match('/Invalid character/i', $error_str)) {
+                    xml_parser_free($this->xml_parser);
+                    unset($this->xml_parser);
+                    $this->reader->closeStream();
+                    $this->__init();
+                    $this->encoding = 'ISO-8859-1';
+                    unset($this->xml_parser);
+                    unset($this->reader);
+
+                    return $this->parse($path, $data, true);
+                } else {
+                    return $this->addError($this->tmp_error);
+                }
+            }
         }
-      }
-    }
-    $this->target_encoding = xml_parser_get_option($this->xml_parser, XML_OPTION_TARGET_ENCODING);
-    xml_parser_free($this->xml_parser);
-    $this->reader->closeStream();
-    unset($this->reader);
-    return $this->done();
-  }
-  
-  /*  */
-  
-  function initXMLParser() {
-    if (!isset($this->xml_parser)) {
-      $enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
-      $parser = xml_parser_create($enc);
-      xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
-      xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
-      xml_set_element_handler($parser, 'open', 'close');
-      xml_set_character_data_handler($parser, 'cdata');
-      xml_set_start_namespace_decl_handler($parser, 'nsDecl');
-      xml_set_object($parser, $this);
-      $this->xml_parser = $parser;
-    }
-  }
+        $this->target_encoding = xml_parser_get_option($this->xml_parser, XML_OPTION_TARGET_ENCODING);
+        xml_parser_free($this->xml_parser);
+        $this->reader->closeStream();
+        unset($this->reader);
 
-  /*  */
-  
-  function getEncoding($src = 'config') {
-    if ($src == 'parser') {
-      return $this->target_encoding;
-    }
-    elseif (($src == 'config') && $this->encoding) {
-      return $this->encoding;
+        return $this->done();
     }
-    return $this->reader->getEncoding();
-    return 'UTF-8';
-  }
-  
-  /*  */
-  
-  function getTriples() {
-    return $this->v('triples', array());
-  }
-  
-  function countTriples() {
-    return $this->t_count;
-  }
-
-  function addT($s = '', $p = '', $o = '', $s_type = '', $o_type = '', $o_dt = '', $o_lang = '', $g = '') {
-    if (!($s && $p && $o)) return 0;
-    //echo "-----\nadding $s / $p / $o\n-----\n";
-    $t = array('s' => $s, 'p' => $p, 'o' => $o, 's_type' => $s_type, 'o_type' => $o_type, 'o_datatype' => $o_dt, 'o_lang' => $o_lang, 'g' => $g);
-    if ($this->skip_dupes) {
-      $h = md5(serialize($t));
-      if (!isset($this->added_triples[$h])) {
-        $this->triples[$this->t_count] = $t;
-        $this->t_count++;
-        $this->added_triples[$h] = true;
-      }
-    }
-    else {
-      $this->triples[$this->t_count] = $t;
-      $this->t_count++;
+
+    public function initXMLParser()
+    {
+        if (!isset($this->xml_parser)) {
+            $enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
+            $parser = xml_parser_create($enc);
+            xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
+            xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
+            xml_set_element_handler($parser, 'open', 'close');
+            xml_set_character_data_handler($parser, 'cdata');
+            xml_set_start_namespace_decl_handler($parser, 'nsDecl');
+            xml_set_object($parser, $this);
+            $this->xml_parser = $parser;
+        }
     }
-  }
-
-  /*  */
-  
-  function open($p, $t, $a) {
-    $this->state = $t;
-    if ($t == 'result') {
-      $this->t = array();
+
+    public function getEncoding($src = 'config')
+    {
+        if ('parser' == $src) {
+            return $this->target_encoding;
+        } elseif (('config' == $src) && $this->encoding) {
+            return $this->encoding;
+        }
+
+        return $this->reader->getEncoding();
+
+        return 'UTF-8';
     }
-    elseif ($t == 'binding') {
-      $this->binding = $a['name'];
-      $this->t[$this->binding] = '';
+
+    public function getTriples()
+    {
+        return $this->v('triples', []);
     }
-    elseif ($t == 'literal') {
-      $this->t[$this->binding . '_dt'] = $this->v('datatype', '', $a);
-      $this->t[$this->binding . '_lang'] = $this->v('xml:lang', '', $a);
-      $this->t[$this->binding . '_type'] = 'literal';
+
+    public function countTriples()
+    {
+        return $this->t_count;
     }
-    elseif ($t == 'uri') {
-      $this->t[$this->binding . '_type'] = 'uri';
+
+    public function addT($s = '', $p = '', $o = '', $s_type = '', $o_type = '', $o_dt = '', $o_lang = '', $g = '')
+    {
+        if (!($s && $p && $o)) {
+            return 0;
+        }
+        //echo "-----\nadding $s / $p / $o\n-----\n";
+        $t = ['s' => $s, 'p' => $p, 'o' => $o, 's_type' => $s_type, 'o_type' => $o_type, 'o_datatype' => $o_dt, 'o_lang' => $o_lang, 'g' => $g];
+        if ($this->skip_dupes) {
+            $h = md5(serialize($t));
+            if (!isset($this->added_triples[$h])) {
+                $this->triples[$this->t_count] = $t;
+                ++$this->t_count;
+                $this->added_triples[$h] = true;
+            }
+        } else {
+            $this->triples[$this->t_count] = $t;
+            ++$this->t_count;
+        }
     }
-    elseif ($t == 'bnode') {
-      $this->t[$this->binding . '_type'] = 'bnode';
-      $this->t[$this->binding] = '_:';
+
+    public function open($p, $t, $a)
+    {
+        $this->state = $t;
+        if ('result' == $t) {
+            $this->t = [];
+        } elseif ('binding' == $t) {
+            $this->binding = $a['name'];
+            $this->t[$this->binding] = '';
+        } elseif ('literal' == $t) {
+            $this->t[$this->binding.'_dt'] = $this->v('datatype', '', $a);
+            $this->t[$this->binding.'_lang'] = $this->v('xml:lang', '', $a);
+            $this->t[$this->binding.'_type'] = 'literal';
+        } elseif ('uri' == $t) {
+            $this->t[$this->binding.'_type'] = 'uri';
+        } elseif ('bnode' == $t) {
+            $this->t[$this->binding.'_type'] = 'bnode';
+            $this->t[$this->binding] = '_:';
+        }
     }
-  }
-  
-  function close($p, $t) {
-    $this->prev_state = $this->state;
-    $this->state = '';
-    if ($t == 'result') {
-      $this->addT(
-        $this->v('s', '', $this->t), 
-        $this->v('p', '', $this->t), 
-        $this->v('o', '', $this->t), 
-        $this->v('s_type', '', $this->t), 
-        $this->v('o_type', '', $this->t), 
-        $this->v('o_dt', '', $this->t), 
-        $this->v('o_lang', '', $this->t), 
+
+    public function close($p, $t)
+    {
+        $this->prev_state = $this->state;
+        $this->state = '';
+        if ('result' == $t) {
+            $this->addT(
+        $this->v('s', '', $this->t),
+        $this->v('p', '', $this->t),
+        $this->v('o', '', $this->t),
+        $this->v('s_type', '', $this->t),
+        $this->v('o_type', '', $this->t),
+        $this->v('o_dt', '', $this->t),
+        $this->v('o_lang', '', $this->t),
         $this->v('g', '', $this->t)
       );
+        }
+    }
+
+    public function cData($p, $d)
+    {
+        if (in_array($this->state, ['uri', 'bnode', 'literal'])) {
+            $this->t[$this->binding] .= $d;
+        }
     }
-  }
 
-  function cData($p, $d) {
-    if (in_array($this->state, array('uri', 'bnode', 'literal'))) {
-      $this->t[$this->binding] .= $d;
+    public function nsDecl($p, $prf, $uri)
+    {
+        $this->nsp[$uri] = isset($this->nsp[$uri]) ? $this->nsp[$uri] : $prf;
     }
-  }
-  
-  function nsDecl($p, $prf, $uri) {
-    $this->nsp[$uri] = isset($this->nsp[$uri]) ? $this->nsp[$uri] : $prf;
-  }
-
-  /*  */
-  
 }
diff --git a/lib/arc2/parsers/ARC2_SemHTMLParser.php b/lib/arc2/parsers/ARC2_SemHTMLParser.php
index 28738c18dc4e57a2cf0252351f7379eb480aaf1f..dccc4476fd49d8cddf1473f6c6a26e2b23e45698 100644
--- a/lib/arc2/parsers/ARC2_SemHTMLParser.php
+++ b/lib/arc2/parsers/ARC2_SemHTMLParser.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 RDF/XML Parser
 author:   Benjamin Nowack
@@ -10,330 +10,349 @@ version:  2010-11-16
 
 ARC2::inc('LegacyXMLParser');
 
-class ARC2_SemHTMLParser extends ARC2_LegacyXMLParser {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* reader */
-    parent::__init();
-    $this->default_sem_html_formats = 'dc openid erdf rdfa posh-rdf microformats';
-    $this->triples = array();
-    $this->target_encoding = '';
-    $this->t_count = 0;
-    $this->added_triples = array();
-    $this->skip_dupes = false;
-    $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
-    $this->bnode_id = 0;
-    $this->auto_extract = $this->v('auto_extract', 1, $this->a);
-    $this->extracted_formats = array();
-    $this->cache = array();
-    $this->detected_formats = array();
-    $this->keep_cdata_ws = $this->v('keep_cdata_whitespace', 0, $this->a);
-  }
-  
-  /*  */
-
-  function x($re, $v, $options = 'si', $keep_ws = 0) {
-    list($ws, $v) = preg_match('/^(\s*)(.*)$/s', $v, $m) ? array($m[1], $m[2]) : array('', $v);
-    if (preg_match("/^" . $re . "(.*)$/" . $options, $v, $m)) {
-      if ($keep_ws) $m[1] = $ws . $m[1];
-      return $m;
+class ARC2_SemHTMLParser extends ARC2_LegacyXMLParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
     }
-    return false;
-  }
-
-  /*  */
-
-  function setReader(&$reader) {
-    $this->reader = $reader;
-  }
-  
-  function createBnodeID(){
-    $this->bnode_id++;
-    return '_:' . $this->bnode_prefix . $this->bnode_id;
-  }
-  
-  function addT($t) {
-    if (function_exists('html_entity_decode')) {
-      $t['o'] = html_entity_decode($t['o']);
+
+    public function __init()
+    {/* reader */
+        parent::__init();
+        $this->default_sem_html_formats = 'dc openid erdf rdfa posh-rdf microformats';
+        $this->triples = [];
+        $this->target_encoding = '';
+        $this->t_count = 0;
+        $this->added_triples = [];
+        $this->skip_dupes = false;
+        $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
+        $this->bnode_id = 0;
+        $this->auto_extract = $this->v('auto_extract', 1, $this->a);
+        $this->extracted_formats = [];
+        $this->cache = [];
+        $this->detected_formats = [];
+        $this->keep_cdata_ws = $this->v('keep_cdata_whitespace', 0, $this->a);
     }
-    if ($this->skip_dupes) {
-      $h = md5(serialize($t));
-      if (!isset($this->added_triples[$h])) {
-        $this->triples[$this->t_count] = $t;
-        $this->t_count++;
-        $this->added_triples[$h] = true;
-      }
+
+    public function x($re, $v, $options = 'si', $keep_ws = 0)
+    {
+        list($ws, $v) = preg_match('/^(\s*)(.*)$/s', $v, $m) ? [$m[1], $m[2]] : ['', $v];
+        if (preg_match('/^'.$re.'(.*)$/'.$options, $v, $m)) {
+            if ($keep_ws) {
+                $m[1] = $ws.$m[1];
+            }
+
+            return $m;
+        }
+
+        return false;
     }
-    else {
-      $this->triples[$this->t_count] = $t;
-      $this->t_count++;
+
+    public function setReader(&$reader)
+    {
+        $this->reader = $reader;
     }
-  }
-
-  function getTriples() {
-    return $this->v('triples', array());
-  }
-
-  function countTriples() {
-    return $this->t_count;
-  }
-  
-  function getSimpleIndex($flatten_objects = 1, $vals = '') {
-    return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
-  }
-
-  /*  */
-
-  function parse($path, $data = '', $iso_fallback = 'ignore') {
-    $this->nodes = array();
-    $this->node_count = 0;
-    $this->level = 0;
-    /* reader */
-    if (!$this->v('reader')) {
-      ARC2::inc('Reader');
-      $this->reader = new ARC2_Reader($this->a, $this);
+
+    public function createBnodeID()
+    {
+        ++$this->bnode_id;
+
+        return '_:'.$this->bnode_prefix.$this->bnode_id;
     }
-    $this->reader->setAcceptHeader('Accept: text/html, application/xhtml, */*; q=0.9');
-    $this->reader->activate($path, $data);
-    $this->target_encoding = $this->reader->getEncoding(false);
-    $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
-    $this->base = $this->x_base;
-    $this->doc_url = $this->reader->base;
-    /* parse */
-    $rest = '';
-    $this->cur_tag = '';
-    while ($d = $this->reader->readStream(1)) {
-      $rest = $this->processData($rest . $d);
+
+    public function addT($t)
+    {
+        if (function_exists('html_entity_decode')) {
+            $t['o'] = html_entity_decode($t['o']);
+        }
+        if ($this->skip_dupes) {
+            $h = md5(serialize($t));
+            if (!isset($this->added_triples[$h])) {
+                $this->triples[$this->t_count] = $t;
+                ++$this->t_count;
+                $this->added_triples[$h] = true;
+            }
+        } else {
+            $this->triples[$this->t_count] = $t;
+            ++$this->t_count;
+        }
     }
-    $this->reader->closeStream();
-    unset($this->reader);
-    return $this->done();
-  }
-  
-  /*  */
-
-  function getEncoding($src = 'ignore') {
-    return $this->target_encoding;
-  }
-
-  /*  */
-  
-  function done() {
-    if ($this->auto_extract) {
-      $this->extractRDF();
+
+    public function getTriples()
+    {
+        return $this->v('triples', []);
     }
-  }
-  
-  /*  */
-
-  function processData($v) {
-    $sub_v = $v;
-    do {
-      $proceed = 1;
-      if ((list($sub_r, $sub_v) = $this->xComment($sub_v)) && $sub_r) {
-        $this->open(0, 'comment', array('value' => $sub_r));
-        $this->close(0, 'comment');
-        continue;
-      }
-      if ((list($sub_r, $sub_v) = $this->xDoctype($sub_v)) && $sub_r) {
-        $this->open(0, 'doctype', array('value' => $sub_r));
-        $this->close(0, 'doctype');
-        /* RDFa detection */
-        if (preg_match('/rdfa /i', $sub_r)) $this->detected_formats['rdfa'] = 1;
-        continue;
-      }
-      if ($this->level && ((list($sub_r, $sub_v) = $this->xWS($sub_v)) && $sub_r)) {
-        $this->cData(0, $sub_r);
-      }
-      elseif ((list($sub_r, $sub_v) = $this->xOpen($sub_v)) && $sub_r) {
-        $this->open(0, $sub_r['tag'], $sub_r['a']);
-        $this->cur_tag = $sub_r['tag'];
-        if ($sub_r['empty']) {
-          $this->close(0, $sub_r['tag'], 1);
-          $this->cur_tag = '';
+
+    public function countTriples()
+    {
+        return $this->t_count;
+    }
+
+    public function getSimpleIndex($flatten_objects = 1, $vals = '')
+    {
+        return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
+    }
+
+    public function parse($path, $data = '', $iso_fallback = 'ignore')
+    {
+        $this->nodes = [];
+        $this->node_count = 0;
+        $this->level = 0;
+        /* reader */
+        if (!$this->v('reader')) {
+            ARC2::inc('Reader');
+            $this->reader = new ARC2_Reader($this->a, $this);
         }
-        /* eRDF detection */
-        if (!isset($this->detected_formats['erdf']) && isset($sub_r['a']['profile m']) && in_array('http://purl.org/NET/erdf/profile', $sub_r['a']['profile m'])) $this->detected_formats['erdf'] = 1;
-        /* poshRDF detection */
-        if (!isset($this->detected_formats['posh-rdf']) && isset($sub_r['a']['class m']) && in_array('rdf-p', $sub_r['a']['class m'])) $this->detected_formats['posh-rdf'] = 1;
-        /* RDFa detection */
-        if (!isset($this->detected_formats['rdfa']) && ($this->cur_tag == 'html') && isset($sub_r['a']['version m']) && in_array('XHTML+RDFa', $sub_r['a']['version m'])) $this->detected_formats['rdfa'] = 1;
-        if (!isset($this->detected_formats['rdfa']) && isset($sub_r['a']['xmlns']) && $sub_r['a']['xmlns'] && $this->isRDFNSDecl($sub_r['a']['xmlns'])) $this->detected_formats['rdfa'] = 1;
-        if (!isset($this->detected_formats['rdfa']) && array_intersect(array('about', 'typeof', 'property'), array_keys($sub_r['a']))) $this->detected_formats['rdfa'] = 1;
-      }
-      elseif ((list($sub_r, $sub_v) = $this->xClose($sub_v)) && $sub_r) {
-        if (preg_match('/^(area|base|br|col|frame|hr|input|img|link|xmeta|param)$/', $sub_r['tag'])) {
-          /* already implicitly closed */
+        $this->reader->setAcceptHeader('Accept: text/html, application/xhtml, */*; q=0.9');
+        $this->reader->activate($path, $data);
+        $this->target_encoding = $this->reader->getEncoding(false);
+        $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
+        $this->base = $this->x_base;
+        $this->doc_url = $this->reader->base;
+        /* parse */
+        $rest = '';
+        $this->cur_tag = '';
+        while ($d = $this->reader->readStream(1)) {
+            $rest = $this->processData($rest.$d);
         }
-        else {
-          $this->close(0, $sub_r['tag']);
-          $this->cur_tag = '';
+        $this->reader->closeStream();
+        unset($this->reader);
+
+        return $this->done();
+    }
+
+    public function getEncoding($src = 'ignore')
+    {
+        return $this->target_encoding;
+    }
+
+    public function done()
+    {
+        if ($this->auto_extract) {
+            $this->extractRDF();
         }
-      }
-      elseif ((list($sub_r, $sub_v) = $this->xCData($sub_v)) && $sub_r) {
-        $this->cData(0, $sub_r);
-      }
-      else {
-        $proceed = 0;
-      }
-    } while ($proceed);
-    return $sub_v;
-  }
-
-  /*  */
-
-  function isRDFNSDecl($ns) {
-    foreach ($ns as $k => $v) {
-      if ($k) return 1;
     }
-    return 0;
-  }
 
-  /*  */
+    public function processData($v)
+    {
+        $sub_v = $v;
+        do {
+            $proceed = 1;
+            if ((list($sub_r, $sub_v) = $this->xComment($sub_v)) && $sub_r) {
+                $this->open(0, 'comment', ['value' => $sub_r]);
+                $this->close(0, 'comment');
+                continue;
+            }
+            if ((list($sub_r, $sub_v) = $this->xDoctype($sub_v)) && $sub_r) {
+                $this->open(0, 'doctype', ['value' => $sub_r]);
+                $this->close(0, 'doctype');
+                /* RDFa detection */
+                if (preg_match('/rdfa /i', $sub_r)) {
+                    $this->detected_formats['rdfa'] = 1;
+                }
+                continue;
+            }
+            if ($this->level && ((list($sub_r, $sub_v) = $this->xWS($sub_v)) && $sub_r)) {
+                $this->cData(0, $sub_r);
+            } elseif ((list($sub_r, $sub_v) = $this->xOpen($sub_v)) && $sub_r) {
+                $this->open(0, $sub_r['tag'], $sub_r['a']);
+                $this->cur_tag = $sub_r['tag'];
+                if ($sub_r['empty']) {
+                    $this->close(0, $sub_r['tag'], 1);
+                    $this->cur_tag = '';
+                }
+                /* eRDF detection */
+                if (!isset($this->detected_formats['erdf']) && isset($sub_r['a']['profile m']) && in_array('http://purl.org/NET/erdf/profile', $sub_r['a']['profile m'])) {
+                    $this->detected_formats['erdf'] = 1;
+                }
+                /* poshRDF detection */
+                if (!isset($this->detected_formats['posh-rdf']) && isset($sub_r['a']['class m']) && in_array('rdf-p', $sub_r['a']['class m'])) {
+                    $this->detected_formats['posh-rdf'] = 1;
+                }
+                /* RDFa detection */
+                if (!isset($this->detected_formats['rdfa']) && ('html' == $this->cur_tag) && isset($sub_r['a']['version m']) && in_array('XHTML+RDFa', $sub_r['a']['version m'])) {
+                    $this->detected_formats['rdfa'] = 1;
+                }
+                if (!isset($this->detected_formats['rdfa']) && isset($sub_r['a']['xmlns']) && $sub_r['a']['xmlns'] && $this->isRDFNSDecl($sub_r['a']['xmlns'])) {
+                    $this->detected_formats['rdfa'] = 1;
+                }
+                if (!isset($this->detected_formats['rdfa']) && array_intersect(['about', 'typeof', 'property'], array_keys($sub_r['a']))) {
+                    $this->detected_formats['rdfa'] = 1;
+                }
+            } elseif ((list($sub_r, $sub_v) = $this->xClose($sub_v)) && $sub_r) {
+                if (preg_match('/^(area|base|br|col|frame|hr|input|img|link|xmeta|param)$/', $sub_r['tag'])) {
+                    /* already implicitly closed */
+                } else {
+                    $this->close(0, $sub_r['tag']);
+                    $this->cur_tag = '';
+                }
+            } elseif ((list($sub_r, $sub_v) = $this->xCData($sub_v)) && $sub_r) {
+                $this->cData(0, $sub_r);
+            } else {
+                $proceed = 0;
+            }
+        } while ($proceed);
 
-  function xComment($v) {
-    if ($r = $this->x('\<\!\-\-', $v)) {
-      if ($sub_r = $this->x('(.*)\-\-\>', $r[1], 'Us')) {
-        return array($sub_r[1], $sub_r[2]);
-      }
+        return $sub_v;
     }
-    return array(0, $v);
-  }
-  
-  function xDoctype($v) {
-    if ($r = $this->x('\<\!DOCTYPE', $v)) {
-      if ($sub_r = $this->x('([^\>]+)\>', $r[1])) {
-        return array($sub_r[1], $sub_r[2]);
-      }
+
+    public function isRDFNSDecl($ns)
+    {
+        foreach ($ns as $k => $v) {
+            if ($k) {
+                return 1;
+            }
+        }
+
+        return 0;
     }
-    return array(0, $v);
-  }
-  
-  function xWS($v) {
-    if ($r = ARC2::x('(\s+)', $v)) {
-      return array($r[1], $r[2]);
+
+    public function xComment($v)
+    {
+        if ($r = $this->x('\<\!\-\-', $v)) {
+            if ($sub_r = $this->x('(.*)\-\-\>', $r[1], 'Us')) {
+                return [$sub_r[1], $sub_r[2]];
+            }
+        }
+
+        return [0, $v];
     }
-    return array(0, $v);
-  }
-  
-  /*  */
-
-  function xOpen($v) {
-    if ($r = $this->x('\<([^\s\/\>]+)([^\>]*)\>', $v)) {
-      list($sub_r, $sub_v) = $this->xAttributes($r[2]);
-      return array(array('tag' => strtolower($r[1]), 'a' => $sub_r, 'empty' => $this->isEmpty($r[1], $r[2])), $r[3]);
+
+    public function xDoctype($v)
+    {
+        if ($r = $this->x('\<\!DOCTYPE', $v)) {
+            if ($sub_r = $this->x('([^\>]+)\>', $r[1])) {
+                return [$sub_r[1], $sub_r[2]];
+            }
+        }
+
+        return [0, $v];
     }
-    return array(0, $v);
-  }
-  
-  /*  */
-
-  function xAttributes($v) {
-    $r = array();
-    while ((list($sub_r, $v) = $this->xAttribute($v)) && $sub_r) {
-      if ($sub_sub_r = $this->x('xmlns\:?(.*)', $sub_r['k'])) {
-        $this->nsDecl(0, $sub_sub_r[1], $sub_r['value']);
-        $r['xmlns'][$sub_sub_r[1]] = $sub_r['value'];
-      }
-      else {
-        $r[$sub_r['k']] = $sub_r['value'];
-        $r[$sub_r['k'] . ' m'] = $sub_r['values'];
-      }
+
+    public function xWS($v)
+    {
+        if ($r = ARC2::x('(\s+)', $v)) {
+            return [$r[1], $r[2]];
+        }
+
+        return [0, $v];
     }
-    return array($r, $v);
-  }
 
-  /*  */
+    public function xOpen($v)
+    {
+        if ($r = $this->x('\<([^\s\/\>]+)([^\>]*)\>', $v)) {
+            list($sub_r, $sub_v) = $this->xAttributes($r[2]);
 
-  function xAttribute($v) {
-    if ($r = $this->x('([^\s\=]+)\s*(\=)?\s*([\'\"]?)', $v)) {
-      if (!$r[2]) {/* no '=' */
-        if ($r[1] == '/') {
-          return array(0, $r[4]);
-        }
-        return array(array('k' => $r[1], 'value' => 1, 'values' => array(1)), $r[4]);
-      }
-      if (!$r[3]) {/* no quots */
-        if ($sub_r = $this->x('([^\s]+)', $r[4])) {
-          return array(array('k' => $r[1], 'value' => $sub_r[1], 'values' => array($sub_r[1])), $sub_r[2]);
+            return [['tag' => strtolower($r[1]), 'a' => $sub_r, 'empty' => $this->isEmpty($r[1], $r[2])], $r[3]];
         }
-        return array(array('k' => $r[1], 'value' => '', 'values' => array()), $r[4]);
-      }
-      $val = '';
-      $multi = 0;
-      $sub_v = $r[4];
-      while ($sub_v && (!$sub_r = $this->x('(\x5c\\' .$r[3]. '|\\' .$r[3]. ')', $sub_v))) {
-        $val .= substr($sub_v, 0, 1);
-        $sub_v = substr($sub_v, 1);
-      }
-      $sub_v = $sub_v ? $sub_r[2] : $sub_v;
-      $vals = preg_split('/ /', $val);
-      return array(array('k' => $r[1], 'value' => $val, 'values' => $vals), $sub_v);
+
+        return [0, $v];
     }
-    return array(0, $v);
-  }
-  
-  /*  */
-
-  function isEmpty($t, $v) {
-    if (preg_match('/^(area|base|br|col|frame|hr|input|img|link|xmeta|param)$/', $t)) {
-      return 1;
+
+    public function xAttributes($v)
+    {
+        $r = [];
+        while ((list($sub_r, $v) = $this->xAttribute($v)) && $sub_r) {
+            if ($sub_sub_r = $this->x('xmlns\:?(.*)', $sub_r['k'])) {
+                $this->nsDecl(0, $sub_sub_r[1], $sub_r['value']);
+                $r['xmlns'][$sub_sub_r[1]] = $sub_r['value'];
+            } else {
+                $r[$sub_r['k']] = $sub_r['value'];
+                $r[$sub_r['k'].' m'] = $sub_r['values'];
+            }
+        }
+
+        return [$r, $v];
     }
-    if (preg_match('/\/$/', $v)) {
-      return 1;
+
+    public function xAttribute($v)
+    {
+        if ($r = $this->x('([^\s\=]+)\s*(\=)?\s*([\'\"]?)', $v)) {
+            if (!$r[2]) {/* no '=' */
+                if ('/' == $r[1]) {
+                    return [0, $r[4]];
+                }
+
+                return [['k' => $r[1], 'value' => 1, 'values' => [1]], $r[4]];
+            }
+            if (!$r[3]) {/* no quots */
+                if ($sub_r = $this->x('([^\s]+)', $r[4])) {
+                    return [['k' => $r[1], 'value' => $sub_r[1], 'values' => [$sub_r[1]]], $sub_r[2]];
+                }
+
+                return [['k' => $r[1], 'value' => '', 'values' => []], $r[4]];
+            }
+            $val = '';
+            $multi = 0;
+            $sub_v = $r[4];
+            while ($sub_v && (!$sub_r = $this->x('(\x5c\\'.$r[3].'|\\'.$r[3].')', $sub_v))) {
+                $val .= substr($sub_v, 0, 1);
+                $sub_v = substr($sub_v, 1);
+            }
+            $sub_v = $sub_v ? $sub_r[2] : $sub_v;
+            $vals = preg_split('/ /', $val);
+
+            return [['k' => $r[1], 'value' => $val, 'values' => $vals], $sub_v];
+        }
+
+        return [0, $v];
     }
-    return 0;
-  }
-  
-  /*  */
-  
-  function xClose($v) {
-    if ($r = $this->x('\<\/([^\s\>]+)\>', $v)) {
-      return array(array('tag' => strtolower($r[1])), $r[2]);
+
+    public function isEmpty($t, $v)
+    {
+        if (preg_match('/^(area|base|br|col|frame|hr|input|img|link|xmeta|param)$/', $t)) {
+            return 1;
+        }
+        if (preg_match('/\/$/', $v)) {
+            return 1;
+        }
+
+        return 0;
     }
-    return array(0, $v);
-  }
-
-  /*  */
-  
-  function xCData($v) {
-    if (preg_match('/(script|style)/i', $this->cur_tag)) {
-      if ($r = $this->x('(.+)(\<\/' . $this->cur_tag . '\>)', $v, 'Uis')) {
-        return array($r[1], $r[2] . $r[3]);
-      }
+
+    public function xClose($v)
+    {
+        if ($r = $this->x('\<\/([^\s\>]+)\>', $v)) {
+            return [['tag' => strtolower($r[1])], $r[2]];
+        }
+
+        return [0, $v];
     }
-    elseif ($r = $this->x('([^\<]+)', $v, 'si', $this->keep_cdata_ws)) {
-      return array($r[1], $r[2]);
+
+    public function xCData($v)
+    {
+        if (preg_match('/(script|style)/i', $this->cur_tag)) {
+            if ($r = $this->x('(.+)(\<\/'.$this->cur_tag.'\>)', $v, 'Uis')) {
+                return [$r[1], $r[2].$r[3]];
+            }
+        } elseif ($r = $this->x('([^\<]+)', $v, 'si', $this->keep_cdata_ws)) {
+            return [$r[1], $r[2]];
+        }
+
+        return [0, $v];
     }
-    return array(0, $v);
-  }
-
-  /*  */
-
-  function extractRDF($formats = '') {
-    $this->node_index = $this->getNodeIndex();
-    $formats = !$formats ? $this->v('sem_html_formats', $this->default_sem_html_formats, $this->a) : $formats;
-    $formats = preg_split('/ /', $formats);
-    foreach ($formats as $format) {
-      if (!in_array($format, $this->extracted_formats)) {
-        $comp = $this->camelCase($format) . 'Extractor';
-        if (ARC2::inc($comp)) {
-          $cls = 'ARC2_' . $comp;
-          $e = new $cls($this->a, $this);
-          $e->extractRDF();
+
+    public function extractRDF($formats = '')
+    {
+        $this->node_index = $this->getNodeIndex();
+        $formats = !$formats ? $this->v('sem_html_formats', $this->default_sem_html_formats, $this->a) : $formats;
+        $formats = preg_split('/ /', $formats);
+        foreach ($formats as $format) {
+            if (!in_array($format, $this->extracted_formats)) {
+                $comp = $this->camelCase($format).'Extractor';
+                if (ARC2::inc($comp)) {
+                    $cls = 'ARC2_'.$comp;
+                    $e = new $cls($this->a, $this);
+                    $e->extractRDF();
+                }
+                $this->extracted_formats[] = $format;
+            }
         }
-        $this->extracted_formats[] = $format;
-      }
     }
-  }
-  
-  function getNode($id) {
-    return isset($this->nodes[$id]) ? $this->nodes[$id] : 0;
-  }
-  
-  /*  */
-  
-}
\ No newline at end of file
+
+    public function getNode($id)
+    {
+        return isset($this->nodes[$id]) ? $this->nodes[$id] : 0;
+    }
+}
diff --git a/lib/arc2/parsers/ARC2_TurtleParser.php b/lib/arc2/parsers/ARC2_TurtleParser.php
index 8ab85f982153059e7396a4bb9d268862f2d41ceb..9e6038fe540d77b969a39975f89dc34030626faa 100644
--- a/lib/arc2/parsers/ARC2_TurtleParser.php
+++ b/lib/arc2/parsers/ARC2_TurtleParser.php
@@ -1,882 +1,947 @@
 <?php
 /**
- * ARC2 SPARQL-enhanced Turtle Parser
+ * ARC2 SPARQL-enhanced Turtle Parser.
  *
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('RDFParser');
 
-class ARC2_TurtleParser extends ARC2_RDFParser {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* reader */
-    parent::__init();
-    $this->state = 0;
-    $this->xml = 'http://www.w3.org/XML/1998/namespace';
-    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
-    $this->xsd = 'http://www.w3.org/2001/XMLSchema#';
-    $this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf', $this->xsd => 'xsd');
-    $this->unparsed_code = '';
-    $this->max_parsing_loops = $this->v('turtle_max_parsing_loops', 500, $this->a);
-  }
-  
-  /*  */
-  
-  function x($re, $v, $options = 'si') {
-    $v = preg_replace('/^[\xA0\xC2]+/', ' ', $v);
-    while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $v, $m)) {/* comment removal */
-      $v = $m[2];
-    }
-    return ARC2::x($re, $v, $options);
-    //$this->unparsed_code = ($sub_r && count($sub_r)) ? $sub_r[count($sub_r) - 1] : '';
-  }
-
-  function createBnodeID(){
-    $this->bnode_id++;
-    return '_:' . $this->bnode_prefix . $this->bnode_id;
-  }
-
-  /*  */
-  
-  function addT($t) {
-    if ($this->skip_dupes) {
-      $h = md5(serialize($t));
-      if (!isset($this->added_triples[$h])) {
-        $this->triples[$this->t_count] = $t;
-        $this->t_count++;
-        $this->added_triples[$h] = true;
-      }
-    }
-    else {
-      $this->triples[$this->t_count] = $t;
-      $this->t_count++;
-    }
-  }
-
-  /*  */
-
-  function getTriples() {
-    return $this->v('triples', array());
-  }
-  
-  function countTriples() {
-    return $this->t_count;
-  }
-  
-  /*  */
-  
-  function getUnparsedCode() {
-    return $this->v('unparsed_code', '');
-  }
-  
-  /*  */
-  
-  function setDefaultPrefixes() {
-    $this->prefixes = array(
-      'rdf:' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
-      'rdfs:' => 'http://www.w3.org/2000/01/rdf-schema#',
-      'owl:' => 'http://www.w3.org/2002/07/owl#',
-      'xsd:' => 'http://www.w3.org/2001/XMLSchema#',
-    );
-    if ($ns = $this->v('ns', array(), $this->a)) {
-      foreach ($ns as $p => $u) $this->prefixes[$p . ':'] = $u;
-    }
-  }
-  
-
-  function parse($path, $data = '', $iso_fallback = false) {
-    $this->setDefaultPrefixes();
-    /* reader */
-    if (!$this->v('reader')) {
-      ARC2::inc('Reader');
-      $this->reader = new ARC2_Reader($this->a, $this);
-    }
-    $this->reader->setAcceptHeader('Accept: application/x-turtle; q=0.9, */*; q=0.1');
-    $this->reader->activate($path, $data);
-    $this->base = $this->v1('base', $this->reader->base, $this->a);
-    $this->r = array('vars' => array());
-    /* parse */
-    $buffer = '';
-    $more_triples = array();
-    $sub_v = '';
-    $sub_v2 = '';
-    $loops = 0;
-    $prologue_done = 0;
-    while ($d = $this->reader->readStream(0)) {
-      $buffer .= $d;
-      $sub_v = $buffer;
-      do {
-        $proceed = 0;
-        if (!$prologue_done) {
-          $proceed = 1;
-          if ((list($sub_r, $sub_v) = $this->xPrologue($sub_v)) && $sub_r) {
-            $loops = 0;
-            $sub_v .= $this->reader->readStream(0, 128);
-            /* we might have missed the final DOT in the previous prologue loop */
-            if ($sub_r = $this->x('\.', $sub_v)) $sub_v = $sub_r[1];
-            if ($this->x("\@?(base|prefix)", $sub_v)) {/* more prologue to come, use outer loop */
-              $proceed = 0;
+class ARC2_TurtleParser extends ARC2_RDFParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
+
+    public function __init()
+    {/* reader */
+        parent::__init();
+        $this->state = 0;
+        $this->xml = 'http://www.w3.org/XML/1998/namespace';
+        $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+        $this->xsd = 'http://www.w3.org/2001/XMLSchema#';
+        $this->nsp = [$this->xml => 'xml', $this->rdf => 'rdf', $this->xsd => 'xsd'];
+        $this->unparsed_code = '';
+        $this->max_parsing_loops = $this->v('turtle_max_parsing_loops', 500, $this->a);
+    }
+
+    public function x($re, $v, $options = 'si')
+    {
+        $v = preg_replace('/^[\xA0\xC2]+/', ' ', $v);
+        while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $v, $m)) {/* comment removal */
+            $v = $m[2];
+        }
+
+        return ARC2::x($re, $v, $options);
+        //$this->unparsed_code = ($sub_r && count($sub_r)) ? $sub_r[count($sub_r) - 1] : '';
+    }
+
+    public function createBnodeID()
+    {
+        ++$this->bnode_id;
+
+        return '_:'.$this->bnode_prefix.$this->bnode_id;
+    }
+
+    public function addT($t)
+    {
+        if ($this->skip_dupes) {
+            $h = md5(serialize($t));
+            if (!isset($this->added_triples[$h])) {
+                $this->triples[$this->t_count] = $t;
+                ++$this->t_count;
+                $this->added_triples[$h] = true;
             }
-          }
-          else {
-            $prologue_done = 1;
-          }
-        }
-        if ($prologue_done && (list($sub_r, $sub_v, $more_triples, $sub_v2) = $this->xTriplesBlock($sub_v)) && is_array($sub_r)) {
-          $proceed = 1;
-          $loops = 0;
-          foreach ($sub_r as $t) {
+        } else {
+            $this->triples[$this->t_count] = $t;
+            ++$this->t_count;
+        }
+    }
+
+    public function getTriples()
+    {
+        return $this->v('triples', []);
+    }
+
+    public function countTriples()
+    {
+        return $this->t_count;
+    }
+
+    public function getUnparsedCode()
+    {
+        return $this->v('unparsed_code', '');
+    }
+
+    public function setDefaultPrefixes()
+    {
+        $this->prefixes = [
+            'rdf:' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
+            'rdfs:' => 'http://www.w3.org/2000/01/rdf-schema#',
+            'owl:' => 'http://www.w3.org/2002/07/owl#',
+            'xsd:' => 'http://www.w3.org/2001/XMLSchema#',
+        ];
+        if ($ns = $this->v('ns', [], $this->a)) {
+            foreach ($ns as $p => $u) {
+                $this->prefixes[$p.':'] = $u;
+            }
+        }
+    }
+
+    public function parse($path, $data = '', $iso_fallback = false)
+    {
+        $this->setDefaultPrefixes();
+        /* reader */
+        if (!$this->v('reader')) {
+            ARC2::inc('Reader');
+            $this->reader = new ARC2_Reader($this->a, $this);
+        }
+        $this->reader->setAcceptHeader('Accept: application/x-turtle; q=0.9, */*; q=0.1');
+        $this->reader->activate($path, $data);
+        $this->base = $this->v1('base', $this->reader->base, $this->a);
+        $this->r = ['vars' => []];
+        /* parse */
+        $buffer = '';
+        $more_triples = [];
+        $sub_v = '';
+        $sub_v2 = '';
+        $loops = 0;
+        $prologue_done = 0;
+        while ($d = $this->reader->readStream(0, 8192)) {
+            $buffer .= $d;
+            $sub_v = $buffer;
+            do {
+                $proceed = 0;
+                if (!$prologue_done) {
+                    $proceed = 1;
+                    if ((list($sub_r, $sub_v) = $this->xPrologue($sub_v)) && $sub_r) {
+                        $loops = 0;
+                        $sub_v .= $this->reader->readStream(0, 128);
+                        /* we might have missed the final DOT in the previous prologue loop */
+                        if ($sub_r = $this->x('\.', $sub_v)) {
+                            $sub_v = $sub_r[1];
+                        }
+                        if ($this->x("\@?(base|prefix)", $sub_v)) {/* more prologue to come, use outer loop */
+                            $proceed = 0;
+                        }
+                    } else {
+                        $prologue_done = 1;
+                    }
+                }
+                if ($prologue_done && (list($sub_r, $sub_v, $more_triples, $sub_v2) = $this->xTriplesBlock($sub_v)) && is_array($sub_r)) {
+                    $proceed = 1;
+                    $loops = 0;
+                    foreach ($sub_r as $t) {
+                        $this->addT($t);
+                    }
+                }
+            } while ($proceed);
+            ++$loops;
+            $buffer = $sub_v;
+            if ($loops > $this->max_parsing_loops) {/* most probably a parser or code bug, might also be a huge object value, though */
+                $this->addError('too many loops: '.$loops.'. Could not parse "'.substr($buffer, 0, 200).'..."');
+                break;
+            }
+        }
+        foreach ($more_triples as $t) {
             $this->addT($t);
-          }
-        }
-      } while ($proceed);
-      $loops++;
-      $buffer = $sub_v;
-      if ($loops > $this->max_parsing_loops) {/* most probably a parser or code bug, might also be a huge object value, though */
-        $this->addError('too many loops: ' . $loops . '. Could not parse "' . substr($buffer, 0, 200) . '..."');
-        break;
-      }
-    }
-    foreach ($more_triples as $t) {
-      $this->addT($t);
-    }
-    $sub_v = count($more_triples) ? $sub_v2 : $sub_v;
-    $buffer = $sub_v;
-    $this->unparsed_code = $buffer;
-    $this->reader->closeStream();
-    unset($this->reader);
-    /* remove trailing comments */
-    while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $this->unparsed_code, $m)) $this->unparsed_code = $m[2];
-    if ($this->unparsed_code && !$this->getErrors()) {
-      $rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($this->unparsed_code, 0, 30));
-      if (trim($rest)) $this->addError('Could not parse "' . $rest . '"');
-    }
-    return $this->done();
-  }
-
-  function xPrologue($v) {
-    $r = 0;
-    if (!$this->t_count) {
-      if ((list($sub_r, $v) = $this->xBaseDecl($v)) && $sub_r) {
-        $this->base = $sub_r;
-        $r = 1;
-      }
-      while ((list($sub_r, $v) = $this->xPrefixDecl($v)) && $sub_r) {
-        $this->prefixes[$sub_r['prefix']] = $sub_r['uri'];
-        $r = 1;
-      }
-    }
-    return array($r, $v);
-  }
-  
-  /* 3 */
-
-  function xBaseDecl($v) {
-    if ($r = $this->x("\@?base\s+", $v)) {
-      if ((list($r, $sub_v) = $this->xIRI_REF($r[1])) && $r) {
-        if ($sub_r = $this->x('\.', $sub_v)) {
-          $sub_v = $sub_r[1];
-        }
-        return array($r, $sub_v);
-      }
-    }
-    return array(0, $v);
-  }
-  
-  /* 4 */
-  
-  function xPrefixDecl($v) {
-    if ($r = $this->x("\@?prefix\s+", $v)) {
-      if ((list($r, $sub_v) = $this->xPNAME_NS($r[1])) && $r) {
-        $prefix = $r;
-        if((list($r, $sub_v) = $this->xIRI_REF($sub_v)) && $r) {
-          $uri = $this->calcURI($r, $this->base);
-          if ($sub_r = $this->x('\.', $sub_v)) {
-            $sub_v = $sub_r[1];
-          }
-          return array(array('prefix' => $prefix, 'uri_ref' => $r, 'uri' => $uri), $sub_v);
-        }
-      }
-    }
-    return array(0, $v);
-  }
-
-  /* 21.., 32.. */
-  
-  function xTriplesBlock($v) {
-    $pre_r = array();
-    $r = array();
-    $state = 1;
-    $sub_v = $v;
-    $buffer = $sub_v;
-    do {
-      $proceed = 0;
-      if ($state == 1) {/* expecting subject */
-        $t = array('type' => 'triple', 's' => '', 'p' => '', 'o' => '', 's_type' => '', 'p_type' => '', 'o_type' => '', 'o_datatype' => '', 'o_lang' => '');
-        if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
-          $t['s'] = $sub_r['value'];
-          $t['s_type'] = $sub_r['type'];
-          $state = 2;
-          $proceed = 1;
-          if ($sub_r = $this->x('(\}|\.)', $sub_v)) {
-            if ($t['s_type'] == 'placeholder') {
-              $state = 4;
+        }
+        $sub_v = count($more_triples) ? $sub_v2 : $sub_v;
+        $buffer = $sub_v;
+        $this->unparsed_code = $buffer;
+        $this->reader->closeStream();
+        unset($this->reader);
+        /* remove trailing comments */
+        while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $this->unparsed_code, $m)) {
+            $this->unparsed_code = $m[2];
+        }
+        if ($this->unparsed_code && !$this->getErrors()) {
+            $rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($this->unparsed_code, 0, 30));
+            if (trim($rest)) {
+                $this->addError('Could not parse "'.$rest.'"');
+            }
+        }
+
+        return $this->done();
+    }
+
+    public function xPrologue($v)
+    {
+        $r = 0;
+        if (!$this->t_count) {
+            if ((list($sub_r, $v) = $this->xBaseDecl($v)) && $sub_r) {
+                $this->base = $sub_r;
+                $r = 1;
             }
-            else {
-              $this->addError('"' . $sub_r[1]. '" after subject found.');
+            while ((list($sub_r, $v) = $this->xPrefixDecl($v)) && $sub_r) {
+                $this->prefixes[$sub_r['prefix']] = $sub_r['uri'];
+                $r = 1;
             }
-          }
-        }
-        elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
-          $t['s'] = $sub_r['id'];
-          $t['s_type'] = $sub_r['type'];
-          $pre_r = array_merge($pre_r, $sub_r['triples']);
-          $state = 2;
-          $proceed = 1;
-          if ($sub_r = $this->x('\.', $sub_v)) {
-            $this->addError('DOT after subject found.');
-          }
-        }
-        elseif ((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
-          $t['s'] = $sub_r['id'];
-          $t['s_type'] = $sub_r['type'];
-          $pre_r = array_merge($pre_r, $sub_r['triples']);
-          $state = 2;
-          $proceed = 1;
-        }
-        elseif ($sub_r = $this->x('\.', $sub_v)) {
-          $this->addError('Subject expected, DOT found.' . $sub_v);
-        }
-      }
-      if ($state == 2) {/* expecting predicate */
-        if ($sub_r = $this->x('a\s+', $sub_v)) {
-          $sub_v = $sub_r[1];
-          $t['p'] = $this->rdf . 'type';
-          $t['p_type'] = 'uri';
-          $state = 3;
-          $proceed = 1;
-        }
-        elseif ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
-          if ($sub_r['type'] == 'bnode') {
-            $this->addError('Blank node used as triple predicate');
-          }
-          $t['p'] = $sub_r['value'];
-          $t['p_type'] = $sub_r['type'];
-          $state = 3;
-          $proceed = 1;
-        }
-        elseif ($sub_r = $this->x('\.', $sub_v)) {
-          $state = 4;          
-        }
-        elseif ($sub_r = $this->x('\}', $sub_v)) {
-          $buffer = $sub_v;
-          $r = array_merge($r, $pre_r);
-          $pre_r = array();
-          $proceed = 0;
-        }
-      }
-      if ($state == 3) {/* expecting object */
-        if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
-          $t['o'] = $sub_r['value'];
-          $t['o_type'] = $sub_r['type'];
-          $t['o_lang'] = $this->v('lang', '', $sub_r);
-          $t['o_datatype'] = $this->v('datatype', '', $sub_r);
-          $pre_r[] = $t;
-          $state = 4;
-          $proceed = 1;
-        }
-        elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
-          $t['o'] = $sub_r['id'];
-          $t['o_type'] = $sub_r['type'];
-          $pre_r = array_merge($pre_r, array($t), $sub_r['triples']);
-          $state = 4;
-          $proceed = 1;
-        }
-        elseif ((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
-          $t['o'] = $sub_r['id'];
-          $t['o_type'] = $sub_r['type'];
-          $pre_r = array_merge($pre_r, array($t), $sub_r['triples']);
-          $state = 4;
-          $proceed = 1;
-        }
-      }
-      if ($state == 4) {/* expecting . or ; or , or } */
-        if ($sub_r = $this->x('\.', $sub_v)) {
-          $sub_v = $sub_r[1];
-          $buffer = $sub_v;
-          $r = array_merge($r, $pre_r);
-          $pre_r = array();
-          $state = 1;
-          $proceed = 1;
-        }
-        elseif ($sub_r = $this->x('\;', $sub_v)) {
-          $sub_v = $sub_r[1];
-          $state = 2;
-          $proceed = 1;
-        }
-        elseif ($sub_r = $this->x('\,', $sub_v)) {
-          $sub_v = $sub_r[1];
-          $state = 3;
-          $proceed = 1;
-          if ($sub_r = $this->x('\}', $sub_v)) {
-            $this->addError('Object expected, } found.');
-          }
-        }
-        if ($sub_r = $this->x('(\}|\{|OPTIONAL|FILTER|GRAPH)', $sub_v)) {
-          $buffer = $sub_v;
-          $r = array_merge($r, $pre_r);
-          $pre_r = array();
-          $proceed = 0;
-        }
-      }
-    } while ($proceed);
-    return count($r) ? array($r, $buffer, $pre_r, $sub_v) : array(0, $buffer, $pre_r, $sub_v);
-  }
-  
-  /* 39.. */
-  
-  function xBlankNodePropertyList($v) {
-    if ($sub_r = $this->x('\[', $v)) {
-      $sub_v = $sub_r[1];
-      $s = $this->createBnodeID();
-      $r = array('id' => $s, 'type' => 'bnode', 'triples' => array());
-      $t = array('type' => 'triple', 's' => $s, 'p' => '', 'o' => '', 's_type' => 'bnode', 'p_type' => '', 'o_type' => '', 'o_datatype' => '', 'o_lang' => '');
-      $state = 2;
-      $closed = 0;
-      do {
-        $proceed = 0;
-        if ($state == 2) {/* expecting predicate */
-          if ($sub_r = $this->x('a\s+', $sub_v)) {
-            $sub_v = $sub_r[1];
-            $t['p'] = $this->rdf . 'type';
-            $t['p_type'] = 'uri';
-            $state = 3;
-            $proceed = 1;
-          }
-          elseif ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
-            $t['p'] = $sub_r['value'];
-            $t['p_type'] = $sub_r['type'];
-            $state = 3;
-            $proceed = 1;
-          }
-        }
-        if ($state == 3) {/* expecting object */
-          if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
-            $t['o'] = $sub_r['value'];
-            $t['o_type'] = $sub_r['type'];
-            $t['o_lang'] = $this->v('lang', '', $sub_r);
-            $t['o_datatype'] = $this->v('datatype', '', $sub_r);
-            $r['triples'][] = $t;
-            $state = 4;
-            $proceed = 1;
-          }
-          elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
-            $t['o'] = $sub_r['id'];
-            $t['o_type'] = $sub_r['type'];
-            $r['triples'] = array_merge($r['triples'], array($t), $sub_r['triples']);
-            $state = 4;
-            $proceed = 1;
-          }
-          elseif((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
-            $t['o'] = $sub_r['id'];
-            $t['o_type'] = $sub_r['type'];
-            $r['triples'] = array_merge($r['triples'], array($t), $sub_r['triples']);
-            $state = 4;
-            $proceed = 1;
-          }
-        }
-        if ($state == 4) {/* expecting . or ; or , or ] */
-          if ($sub_r = $this->x('\.', $sub_v)) {
-            $sub_v = $sub_r[1];
-            $state = 1;
-            $proceed = 1;
-          }
-          if ($sub_r = $this->x('\;', $sub_v)) {
+        }
+
+        return [$r, $v];
+    }
+
+    /* 3 */
+
+    public function xBaseDecl($v)
+    {
+        if ($r = $this->x("\@?base\s+", $v)) {
+            if ((list($r, $sub_v) = $this->xIRI_REF($r[1])) && $r) {
+                if ($sub_r = $this->x('\.', $sub_v)) {
+                    $sub_v = $sub_r[1];
+                }
+
+                return [$r, $sub_v];
+            }
+        }
+
+        return [0, $v];
+    }
+
+    /* 4 */
+
+    public function xPrefixDecl($v)
+    {
+        if ($r = $this->x("\@?prefix\s+", $v)) {
+            if ((list($r, $sub_v) = $this->xPNAME_NS($r[1])) && $r) {
+                $prefix = $r;
+                if ((list($r, $sub_v) = $this->xIRI_REF($sub_v)) && $r) {
+                    $uri = $this->calcURI($r, $this->base);
+                    if ($sub_r = $this->x('\.', $sub_v)) {
+                        $sub_v = $sub_r[1];
+                    }
+
+                    return [['prefix' => $prefix, 'uri_ref' => $r, 'uri' => $uri], $sub_v];
+                }
+            }
+        }
+
+        return [0, $v];
+    }
+
+    /* 21.., 32.. */
+
+    public function xTriplesBlock($v)
+    {
+        $pre_r = [];
+        $r = [];
+        $state = 1;
+        $sub_v = $v;
+        $buffer = $sub_v;
+        do {
+            $proceed = 0;
+            if (1 == $state) {/* expecting subject */
+                $t = ['type' => 'triple', 's' => '', 'p' => '', 'o' => '', 's_type' => '', 'p_type' => '', 'o_type' => '', 'o_datatype' => '', 'o_lang' => ''];
+                if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
+                    $t['s'] = $sub_r['value'];
+                    $t['s_type'] = $sub_r['type'];
+                    $state = 2;
+                    $proceed = 1;
+                    if ($sub_r = $this->x('(\}|\.)', $sub_v)) {
+                        if ('placeholder' == $t['s_type']) {
+                            $state = 4;
+                        } else {
+                            $this->addError('"'.$sub_r[1].'" after subject found.');
+                        }
+                    }
+                } elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
+                    $t['s'] = $sub_r['id'];
+                    $t['s_type'] = $sub_r['type'];
+                    $pre_r = array_merge($pre_r, $sub_r['triples']);
+                    $state = 2;
+                    $proceed = 1;
+                    if ($sub_r = $this->x('\.', $sub_v)) {
+                        $this->addError('DOT after subject found.');
+                    }
+                } elseif ((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
+                    $t['s'] = $sub_r['id'];
+                    $t['s_type'] = $sub_r['type'];
+                    $pre_r = array_merge($pre_r, $sub_r['triples']);
+                    $state = 2;
+                    $proceed = 1;
+                } elseif ($sub_r = $this->x('\.', $sub_v)) {
+                    $this->addError('Subject expected, DOT found.'.$sub_v);
+                }
+            }
+            if (2 == $state) {/* expecting predicate */
+                if ($sub_r = $this->x('a\s+', $sub_v)) {
+                    $sub_v = $sub_r[1];
+                    $t['p'] = $this->rdf.'type';
+                    $t['p_type'] = 'uri';
+                    $state = 3;
+                    $proceed = 1;
+                } elseif ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
+                    if ('bnode' == $sub_r['type']) {
+                        $this->addError('Blank node used as triple predicate');
+                    }
+                    $t['p'] = $sub_r['value'];
+                    $t['p_type'] = $sub_r['type'];
+                    $state = 3;
+                    $proceed = 1;
+                } elseif ($sub_r = $this->x('\.', $sub_v)) {
+                    $state = 4;
+                } elseif ($sub_r = $this->x('\}', $sub_v)) {
+                    $buffer = $sub_v;
+                    $r = array_merge($r, $pre_r);
+                    $pre_r = [];
+                    $proceed = 0;
+                }
+            }
+            if (3 == $state) {/* expecting object */
+                if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
+                    $t['o'] = $sub_r['value'];
+                    $t['o_type'] = $sub_r['type'];
+                    $t['o_lang'] = $this->v('lang', '', $sub_r);
+                    $t['o_datatype'] = $this->v('datatype', '', $sub_r);
+                    $pre_r[] = $t;
+                    $state = 4;
+                    $proceed = 1;
+                } elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
+                    $t['o'] = $sub_r['id'];
+                    $t['o_type'] = $sub_r['type'];
+                    $t['o_datatype'] = '';
+                    $pre_r = array_merge($pre_r, [$t], $sub_r['triples']);
+                    $state = 4;
+                    $proceed = 1;
+                } elseif ((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
+                    $t['o'] = $sub_r['id'];
+                    $t['o_type'] = $sub_r['type'];
+                    $t['o_datatype'] = '';
+                    $pre_r = array_merge($pre_r, [$t], $sub_r['triples']);
+                    $state = 4;
+                    $proceed = 1;
+                }
+            }
+            if (4 == $state) {/* expecting . or ; or , or } */
+                if ($sub_r = $this->x('\.', $sub_v)) {
+                    $sub_v = $sub_r[1];
+                    $buffer = $sub_v;
+                    $r = array_merge($r, $pre_r);
+                    $pre_r = [];
+                    $state = 1;
+                    $proceed = 1;
+                } elseif ($sub_r = $this->x('\;', $sub_v)) {
+                    $sub_v = $sub_r[1];
+                    $state = 2;
+                    $proceed = 1;
+                } elseif ($sub_r = $this->x('\,', $sub_v)) {
+                    $sub_v = $sub_r[1];
+                    $state = 3;
+                    $proceed = 1;
+                    if ($sub_r = $this->x('\}', $sub_v)) {
+                        $this->addError('Object expected, } found.');
+                    }
+                }
+                if ($sub_r = $this->x('(\}|\{|OPTIONAL|FILTER|GRAPH)', $sub_v)) {
+                    $buffer = $sub_v;
+                    $r = array_merge($r, $pre_r);
+                    $pre_r = [];
+                    $proceed = 0;
+                }
+            }
+        } while ($proceed);
+
+        return count($r) ? [$r, $buffer, $pre_r, $sub_v] : [0, $buffer, $pre_r, $sub_v];
+    }
+
+    /* 39.. */
+
+    public function xBlankNodePropertyList($v)
+    {
+        if ($sub_r = $this->x('\[', $v)) {
             $sub_v = $sub_r[1];
+            $s = $this->createBnodeID();
+            $r = ['id' => $s, 'type' => 'bnode', 'triples' => []];
+            $t = ['type' => 'triple', 's' => $s, 'p' => '', 'o' => '', 's_type' => 'bnode', 'p_type' => '', 'o_type' => '', 'o_datatype' => '', 'o_lang' => ''];
             $state = 2;
-            $proceed = 1;
-          }
-          if ($sub_r = $this->x('\,', $sub_v)) {
-            $sub_v = $sub_r[1];
-            $state = 3;
-            $proceed = 1;
-          }
-          if ($sub_r = $this->x('\]', $sub_v)) {
+            $closed = 0;
+            do {
+                $proceed = 0;
+                if (2 == $state) {/* expecting predicate */
+                    if ($sub_r = $this->x('a\s+', $sub_v)) {
+                        $sub_v = $sub_r[1];
+                        $t['p'] = $this->rdf.'type';
+                        $t['p_type'] = 'uri';
+                        $state = 3;
+                        $proceed = 1;
+                    } elseif ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
+                        $t['p'] = $sub_r['value'];
+                        $t['p_type'] = $sub_r['type'];
+                        $state = 3;
+                        $proceed = 1;
+                    }
+                }
+                if (3 == $state) {/* expecting object */
+                    if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
+                        $t['o'] = $sub_r['value'];
+                        $t['o_type'] = $sub_r['type'];
+                        $t['o_lang'] = $this->v('lang', '', $sub_r);
+                        $t['o_datatype'] = $this->v('datatype', '', $sub_r);
+                        $r['triples'][] = $t;
+                        $state = 4;
+                        $proceed = 1;
+                    } elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
+                        $t['o'] = $sub_r['id'];
+                        $t['o_type'] = $sub_r['type'];
+                        $t['o_datatype'] = '';
+                        $r['triples'] = array_merge($r['triples'], [$t], $sub_r['triples']);
+                        $state = 4;
+                        $proceed = 1;
+                    } elseif ((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
+                        $t['o'] = $sub_r['id'];
+                        $t['o_type'] = $sub_r['type'];
+                        $t['o_datatype'] = '';
+                        $r['triples'] = array_merge($r['triples'], [$t], $sub_r['triples']);
+                        $state = 4;
+                        $proceed = 1;
+                    }
+                }
+                if (4 == $state) {/* expecting . or ; or , or ] */
+                    if ($sub_r = $this->x('\.', $sub_v)) {
+                        $sub_v = $sub_r[1];
+                        $state = 1;
+                        $proceed = 1;
+                    }
+                    if ($sub_r = $this->x('\;', $sub_v)) {
+                        $sub_v = $sub_r[1];
+                        $state = 2;
+                        $proceed = 1;
+                    }
+                    if ($sub_r = $this->x('\,', $sub_v)) {
+                        $sub_v = $sub_r[1];
+                        $state = 3;
+                        $proceed = 1;
+                    }
+                    if ($sub_r = $this->x('\]', $sub_v)) {
+                        $sub_v = $sub_r[1];
+                        $proceed = 0;
+                        $closed = 1;
+                    }
+                }
+            } while ($proceed);
+            if ($closed) {
+                return [$r, $sub_v];
+            }
+
+            return [0, $v];
+        }
+
+        return [0, $v];
+    }
+
+    /* 40.. */
+
+    public function xCollection($v)
+    {
+        if ($sub_r = $this->x('\(', $v)) {
             $sub_v = $sub_r[1];
+            $s = $this->createBnodeID();
+            $r = ['id' => $s, 'type' => 'bnode', 'triples' => []];
+            $closed = 0;
+            do {
+                $proceed = 0;
+                if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
+                    $r['triples'][] = ['type' => 'triple', 's' => $s, 'p' => $this->rdf.'first', 'o' => $sub_r['value'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => $this->v('lang', '', $sub_r), 'o_datatype' => $this->v('datatype', '', $sub_r)];
+                    $proceed = 1;
+                } elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
+                    $r['triples'][] = ['type' => 'triple', 's' => $s, 'p' => $this->rdf.'first', 'o' => $sub_r['id'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => '', 'o_datatype' => ''];
+                    $r['triples'] = array_merge($r['triples'], $sub_r['triples']);
+                    $proceed = 1;
+                } elseif ((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
+                    $r['triples'][] = ['type' => 'triple', 's' => $s, 'p' => $this->rdf.'first', 'o' => $sub_r['id'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => '', 'o_datatype' => ''];
+                    $r['triples'] = array_merge($r['triples'], $sub_r['triples']);
+                    $proceed = 1;
+                }
+                if ($proceed) {
+                    if ($sub_r = $this->x('\)', $sub_v)) {
+                        $sub_v = $sub_r[1];
+                        $r['triples'][] = ['type' => 'triple', 's' => $s, 'p' => $this->rdf.'rest', 'o' => $this->rdf.'nil', 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => 'uri', 'o_lang' => '', 'o_datatype' => ''];
+                        $closed = 1;
+                        $proceed = 0;
+                    } else {
+                        $next_s = $this->createBnodeID();
+                        $r['triples'][] = ['type' => 'triple', 's' => $s, 'p' => $this->rdf.'rest', 'o' => $next_s, 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => 'bnode', 'o_lang' => '', 'o_datatype' => ''];
+                        $s = $next_s;
+                    }
+                }
+            } while ($proceed);
+            if ($closed) {
+                return [$r, $sub_v];
+            }
+        }
+
+        return [0, $v];
+    }
+
+    /* 42 */
+
+    public function xVarOrTerm($v)
+    {
+        if ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
+            return [$sub_r, $sub_v];
+        } elseif ((list($sub_r, $sub_v) = $this->xGraphTerm($v)) && $sub_r) {
+            return [$sub_r, $sub_v];
+        }
+
+        return [0, $v];
+    }
+
+    /* 44, 74.., 75.. */
+
+    public function xVar($v)
+    {
+        if ($r = $this->x('(\?|\$)([^\s]+)', $v)) {
+            if ((list($sub_r, $sub_v) = $this->xVARNAME($r[2])) && $sub_r) {
+                if (!in_array($sub_r, $this->r['vars'])) {
+                    $this->r['vars'][] = $sub_r;
+                }
+
+                return [['value' => $sub_r, 'type' => 'var'], $sub_v.$r[3]];
+            }
+        }
+
+        return [0, $v];
+    }
+
+    /* 45 */
+
+    public function xGraphTerm($v)
+    {
+        foreach ([
+            'IRIref' => 'uri',
+            'RDFLiteral' => 'literal',
+            'NumericLiteral' => 'literal',
+            'BooleanLiteral' => 'literal',
+            'BlankNode' => 'bnode',
+            'NIL' => 'uri',
+            'Placeholder' => 'placeholder',
+        ] as $term => $type) {
+            $m = 'x'.$term;
+            if ((list($sub_r, $sub_v) = $this->$m($v)) && $sub_r) {
+                if (!is_array($sub_r)) {
+                    $sub_r = ['value' => $sub_r];
+                }
+                $sub_r['type'] = $this->v1('type', $type, $sub_r);
+
+                return [$sub_r, $sub_v];
+            }
+        }
+
+        return [0, $v];
+    }
+
+    /* 60 */
+
+    public function xRDFLiteral($v)
+    {
+        if ((list($sub_r, $sub_v) = $this->xString($v)) && $sub_r) {
+            $sub_r['value'] = $this->unescapeNtripleUTF($sub_r['value']);
+            $r = $sub_r;
+            if ((list($sub_r, $sub_v) = $this->xLANGTAG($sub_v)) && $sub_r) {
+                $r['lang'] = $sub_r;
+            } elseif (!$this->x('\s', $sub_v) && ($sub_r = $this->x('\^\^', $sub_v)) && (list($sub_r, $sub_v) = $this->xIRIref($sub_r[1])) && $sub_r[1]) {
+                $r['datatype'] = $sub_r;
+            }
+
+            return [$r, $sub_v];
+        }
+
+        return [0, $v];
+    }
+
+    /* 61.., 62.., 63.., 64.. */
+
+    public function xNumericLiteral($v)
+    {
+        $sub_r = $this->x('(\-|\+)?', $v);
+        $prefix = $sub_r[1];
+        $sub_v = $sub_r[2];
+        foreach (['DOUBLE' => 'double', 'DECIMAL' => 'decimal', 'INTEGER' => 'integer'] as $type => $xsd) {
+            $m = 'x'.$type;
+            if ((list($sub_r, $sub_v) = $this->$m($sub_v)) && (false !== $sub_r)) {
+                $r = ['value' => $prefix.$sub_r, 'type' => 'literal', 'datatype' => $this->xsd.$xsd];
+
+                return [$r, $sub_v];
+            }
+        }
+
+        return [0, $v];
+    }
+
+    /* 65.. */
+
+    public function xBooleanLiteral($v)
+    {
+        if ($r = $this->x('(true|false)', $v)) {
+            return [$r[1], $r[2]];
+        }
+
+        return [0, $v];
+    }
+
+    /* 66.., 87.., 88.., 89.., 90.., 91.. */
+
+    public function xString($v)
+    {/* largely simplified, may need some tweaks in following revisions */
+        $sub_v = $v;
+        if (!preg_match('/^\s*([\']{3}|\'|[\"]{3}|\")(.*)$/s', $sub_v, $m)) {
+            return [0, $v];
+        }
+        $delim = $m[1];
+        $rest = $m[2];
+        $sub_types = ["'''" => 'literal_long1', '"""' => 'literal_long2', "'" => 'literal1', '"' => 'literal2'];
+        $sub_type = $sub_types[$delim];
+        $pos = 0;
+        $r = false;
+        do {
             $proceed = 0;
-            $closed = 1;
-          }
-        }
-      } while ($proceed);
-      if ($closed) {
-        return array($r, $sub_v);
-      }
-      return array(0, $v);
-    }
-    return array(0, $v);
-  }
-  
-  /* 40.. */
-  
-  function xCollection($v) {
-    if ($sub_r = $this->x('\(', $v)) {
-      $sub_v = $sub_r[1];
-      $s = $this->createBnodeID();
-      $r = array('id' => $s, 'type' => 'bnode', 'triples' => array());
-      $closed = 0;
-      do {
-        $proceed = 0;
-        if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
-          $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'first', 'o' => $sub_r['value'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => $this->v('lang', '', $sub_r), 'o_datatype' => $this->v('datatype', '', $sub_r));
-          $proceed = 1;
-        }
-        elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
-          $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'first', 'o' => $sub_r['id'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => '', 'o_datatype' => '');
-          $r['triples'] = array_merge($r['triples'], $sub_r['triples']);
-          $proceed = 1;
-        }
-        elseif((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
-          $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'first', 'o' => $sub_r['id'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => '', 'o_datatype' => '');
-          $r['triples'] = array_merge($r['triples'], $sub_r['triples']);
-          $proceed = 1;
-        }
-        if ($proceed) {
-          if ($sub_r = $this->x('\)', $sub_v)) {
-            $sub_v = $sub_r[1];
-            $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'rest', 'o' => $this->rdf . 'nil', 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => 'uri', 'o_lang' => '', 'o_datatype' => '');
-            $closed = 1;
+            $delim_pos = strpos($rest, $delim, $pos);
+            if (false === $delim_pos) {
+                break;
+            }
+            $new_rest = substr($rest, $delim_pos + strlen($delim));
+            $r = substr($rest, 0, $delim_pos);
+            if (!preg_match('/([\x5c]+)$/s', $r, $m) || !(strlen($m[1]) % 2)) {
+                $rest = $new_rest;
+            } else {
+                $r = false;
+                $pos = $delim_pos + 1;
+                $proceed = 1;
+            }
+        } while ($proceed);
+        if (false !== $r) {
+            return [['value' => $this->toUTF8($r), 'type' => 'literal', 'sub_type' => $sub_type], $rest];
+        }
+
+        return [0, $v];
+    }
+
+    /* 67 */
+
+    public function xIRIref($v)
+    {
+        if ((list($r, $v) = $this->xIRI_REF($v)) && $r) {
+            return [$this->calcURI($r, $this->base), $v];
+        } elseif ((list($r, $v) = $this->xPrefixedName($v)) && $r) {
+            return [$r, $v];
+        }
+
+        return [0, $v];
+    }
+
+    /* 68 */
+
+    public function xPrefixedName($v)
+    {
+        if ((list($r, $v) = $this->xPNAME_LN($v)) && $r) {
+            return [$r, $v];
+        } elseif ((list($r, $sub_v) = $this->xPNAME_NS($v)) && $r) {
+            return isset($this->prefixes[$r]) ? [$this->prefixes[$r], $sub_v] : [0, $v];
+        }
+
+        return [0, $v];
+    }
+
+    /* 69.., 73.., 93, 94..  */
+
+    public function xBlankNode($v)
+    {
+        if (($r = $this->x('\_\:', $v)) && (list($r, $sub_v) = $this->xPN_LOCAL($r[1])) && $r) {
+            return [['type' => 'bnode', 'value' => '_:'.$r], $sub_v];
+        }
+        if ($r = $this->x('\[[\x20\x9\xd\xa]*\]', $v)) {
+            return [['type' => 'bnode', 'value' => $this->createBnodeID()], $r[1]];
+        }
+
+        return [0, $v];
+    }
+
+    /* 70.. @@sync with SPARQLParser */
+
+    public function xIRI_REF($v)
+    {
+        //if ($r = $this->x('\<([^\<\>\"\{\}\|\^\'[:space:]]*)\>', $v)) {
+        if (($r = $this->x('\<(\$\{[^\>]*\})\>', $v)) && ($sub_r = $this->xPlaceholder($r[1]))) {
+            return [$r[1], $r[2]];
+        } elseif ($r = $this->x('\<\>', $v)) {
+            return [true, $r[1]];
+        } elseif ($r = $this->x('\<([^\s][^\<\>]*)\>', $v)) {
+            return [$r[1] ? $r[1] : true, $r[2]];
+        }
+
+        return [0, $v];
+    }
+
+    /* 71 */
+
+    public function xPNAME_NS($v)
+    {
+        list($r, $sub_v) = $this->xPN_PREFIX($v);
+        $prefix = $r ? $r : '';
+
+        return ($r = $this->x("\:", $sub_v)) ? [$prefix.':', $r[1]] : [0, $v];
+    }
+
+    /* 72 */
+
+    public function xPNAME_LN($v)
+    {
+        if ((list($r, $sub_v) = $this->xPNAME_NS($v)) && $r) {
+            if (!$this->x('\s', $sub_v) && (list($sub_r, $sub_v) = $this->xPN_LOCAL($sub_v)) && $sub_r) {
+                if (!isset($this->prefixes[$r])) {
+                    return [0, $v];
+                }
+
+                return [$this->prefixes[$r].$sub_r, $sub_v];
+            }
+        }
+
+        return [0, $v];
+    }
+
+    /* 76 */
+
+    public function xLANGTAG($v)
+    {
+        if (!$this->x('\s', $v) && ($r = $this->x('\@([a-z]+(\-[a-z0-9]+)*)', $v))) {
+            return [$r[1], $r[3]];
+        }
+
+        return [0, $v];
+    }
+
+    /* 77.. */
+
+    public function xINTEGER($v)
+    {
+        if ($r = $this->x('([0-9]+)', $v)) {
+            return [$r[1], $r[2]];
+        }
+
+        return [false, $v];
+    }
+
+    /* 78.. */
+
+    public function xDECIMAL($v)
+    {
+        if ($r = $this->x('([0-9]+\.[0-9]*)', $v)) {
+            return [$r[1], $r[2]];
+        }
+        if ($r = $this->x('(\.[0-9]+)', $v)) {
+            return [$r[1], $r[2]];
+        }
+
+        return [false, $v];
+    }
+
+    /* 79.., 86.. */
+
+    public function xDOUBLE($v)
+    {
+        if ($r = $this->x('([0-9]+\.[0-9]*E[\+\-]?[0-9]+)', $v)) {
+            return [$r[1], $r[2]];
+        }
+        if ($r = $this->x('(\.[0-9]+E[\+\-]?[0-9]+)', $v)) {
+            return [$r[1], $r[2]];
+        }
+        if ($r = $this->x('([0-9]+E[\+\-]?[0-9]+)', $v)) {
+            return [$r[1], $r[2]];
+        }
+
+        return [false, $v];
+    }
+
+    /* 92 */
+
+    public function xNIL($v)
+    {
+        if ($r = $this->x('\([\x20\x9\xd\xa]*\)', $v)) {
+            return [['type' => 'uri', 'value' => $this->rdf.'nil'], $r[1]];
+        }
+
+        return [0, $v];
+    }
+
+    /* 95.. */
+
+    public function xPN_CHARS_BASE($v)
+    {
+        if ($r = $this->x("([a-z]+|\\\u[0-9a-f]{1,4})", $v)) {
+            return [$r[1], $r[2]];
+        }
+
+        return [0, $v];
+    }
+
+    /* 96 */
+
+    public function xPN_CHARS_U($v)
+    {
+        if ((list($r, $sub_v) = $this->xPN_CHARS_BASE($v)) && $r) {
+            return [$r, $sub_v];
+        } elseif ($r = $this->x('(_)', $v)) {
+            return [$r[1], $r[2]];
+        }
+
+        return [0, $v];
+    }
+
+    /* 97.. */
+
+    public function xVARNAME($v)
+    {
+        $r = '';
+        do {
             $proceed = 0;
-          }
-          else {
-            $next_s = $this->createBnodeID();
-            $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'rest', 'o' => $next_s, 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => 'bnode', 'o_lang' => '', 'o_datatype' => '');
-            $s = $next_s;
-          }
-        }
-      } while ($proceed);
-      if ($closed) {
-        return array($r, $sub_v);
-      }
-    }
-    return array (0, $v);
-  }
-  
-  /* 42 */
-  
-  function xVarOrTerm($v) {
-    if ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
-      return array($sub_r, $sub_v);
-    }
-    elseif ((list($sub_r, $sub_v) = $this->xGraphTerm($v)) && $sub_r) {
-      return array($sub_r, $sub_v);
-    }
-    return array(0, $v);
-  }
-  
-  /* 44, 74.., 75.. */
-  
-  function xVar($v) {
-    if ($r = $this->x('(\?|\$)([^\s]+)', $v)) {
-      if ((list($sub_r, $sub_v) = $this->xVARNAME($r[2])) && $sub_r) {
-        if (!in_array($sub_r, $this->r['vars'])) {
-          $this->r['vars'][] = $sub_r;
-        }
-        return array(array('value' => $sub_r, 'type' => 'var'), $sub_v . $r[3]);
-      }
-    }
-    return array(0, $v);
-  }
-
-  /* 45 */
-  
-  function xGraphTerm($v) {
-    foreach (array(
-      'IRIref' => 'uri', 
-      'RDFLiteral' => 'literal', 
-      'NumericLiteral' => 'literal', 
-      'BooleanLiteral' => 'literal', 
-      'BlankNode' => 'bnode', 
-      'NIL' => 'uri',
-      'Placeholder' => 'placeholder'
-    ) as $term => $type) {
-      $m = 'x' . $term;
-      if ((list($sub_r, $sub_v) = $this->$m($v)) && $sub_r) {
-        if (!is_array($sub_r)) {
-          $sub_r = array('value' => $sub_r);
-        }
-        $sub_r['type'] = $this->v1('type', $type, $sub_r);
-        return array($sub_r, $sub_v);
-      }
-    }
-    return array(0, $v);
-  }
-
-  /* 60 */
-  
-  function xRDFLiteral($v) {
-    if ((list($sub_r, $sub_v) = $this->xString($v)) && $sub_r) {
-      $sub_r['value'] = $this->unescapeNtripleUTF($sub_r['value']);
-      $r = $sub_r;
-      if ((list($sub_r, $sub_v) = $this->xLANGTAG($sub_v)) && $sub_r) {
-        $r['lang'] = $sub_r;
-      }
-      elseif (!$this->x('\s', $sub_v) && ($sub_r = $this->x('\^\^', $sub_v)) && (list($sub_r, $sub_v) = $this->xIRIref($sub_r[1])) && $sub_r[1]) {
-        $r['datatype'] = $sub_r;
-      }
-      return array($r, $sub_v);
-    }
-    return array(0, $v);
-  }
-
-  /* 61.., 62.., 63.., 64.. */  
-  
-  function xNumericLiteral($v) {
-    $sub_r = $this->x('(\-|\+)?', $v);
-    $prefix = $sub_r[1];
-    $sub_v = $sub_r[2];
-    foreach (array('DOUBLE' => 'double', 'DECIMAL' => 'decimal', 'INTEGER' => 'integer') as $type => $xsd) {
-      $m = 'x' . $type;
-      if ((list($sub_r, $sub_v) = $this->$m($sub_v)) && ($sub_r !== false)) {
-        $r = array('value' => $prefix . $sub_r, 'type' => 'literal', 'datatype' => $this->xsd . $xsd);
-        return array($r, $sub_v);
-      }
-    }
-    return array(0, $v);
-  }
-  
-  /* 65.. */
-  
-  function xBooleanLiteral($v) {
-    if ($r = $this->x('(true|false)', $v)) {
-      return array($r[1], $r[2]);
-    }
-    return array(0, $v);
-  }
-
-  /* 66.., 87.., 88.., 89.., 90.., 91.. */
-  
-  function xString($v) {/* largely simplified, may need some tweaks in following revisions */
-    $sub_v = $v;
-    if (!preg_match('/^\s*([\']{3}|\'|[\"]{3}|\")(.*)$/s', $sub_v, $m)) return array(0, $v);
-    $delim = $m[1];
-    $rest = $m[2];
-    $sub_types = array("'''" => 'literal_long1', '"""' => 'literal_long2', "'" => 'literal1', '"' => 'literal2');
-    $sub_type = $sub_types[$delim];
-    $pos = 0;
-    $r = false;
-    do {
-      $proceed = 0;
-      $delim_pos = strpos($rest, $delim, $pos);
-      if ($delim_pos === false) break;
-      $new_rest = substr($rest, $delim_pos + strlen($delim));
-      $r = substr($rest, 0, $delim_pos);
-      if (!preg_match('/([\x5c]+)$/s', $r, $m) || !(strlen($m[1]) % 2)) {
-        $rest = $new_rest;
-      }
-      else {
-        $r = false;
-        $pos = $delim_pos + 1;
-        $proceed = 1;
-      }
-    } while ($proceed);
-    if ($r !== false) {
-      return array(array('value' => $this->toUTF8($r) , 'type' => 'literal', 'sub_type' => $sub_type), $rest);
-    }
-    return array(0, $v);
-  }
-  
-  /* 67 */
-  
-  function xIRIref($v) {
-    if ((list($r, $v) = $this->xIRI_REF($v)) && $r) {
-      return array($this->calcURI($r, $this->base), $v);
-    }
-    elseif ((list($r, $v) = $this->xPrefixedName($v)) && $r) {
-      return array($r, $v);
-    }
-    return array(0, $v);
-  }
-  
-  /* 68 */
-  
-  function xPrefixedName($v) {
-    if ((list($r, $v) = $this->xPNAME_LN($v)) && $r) {
-      return array($r, $v);
-    }
-    elseif ((list($r, $sub_v) = $this->xPNAME_NS($v)) && $r) {
-      return isset($this->prefixes[$r]) ? array($this->prefixes[$r], $sub_v) : array(0, $v);
-    }
-    return array(0, $v);
-  }
-  
-  /* 69.., 73.., 93, 94..  */
-  
-  function xBlankNode($v) {
-    if (($r = $this->x('\_\:', $v)) && (list($r, $sub_v) = $this->xPN_LOCAL($r[1])) && $r) {
-      return array(array('type' => 'bnode', 'value' => '_:' . $r), $sub_v);
-    }
-    if ($r = $this->x('\[[\x20\x9\xd\xa]*\]', $v)) {
-      return array(array('type' => 'bnode', 'value' => $this->createBnodeID()), $r[1]);
-    }
-    return array(0, $v);
-  }
-
-  /* 70.. @@sync with SPARQLParser */
-  
-  function xIRI_REF($v) {
-    //if ($r = $this->x('\<([^\<\>\"\{\}\|\^\'[:space:]]*)\>', $v)) {
-    if (($r = $this->x('\<(\$\{[^\>]*\})\>', $v)) && ($sub_r = $this->xPlaceholder($r[1]))) {
-      return array($r[1], $r[2]);
-    }
-    elseif ($r = $this->x('\<\>', $v)) {
-      return array(true, $r[1]);
-    }
-    elseif ($r = $this->x('\<([^\s][^\<\>]*)\>', $v)) {
-      return array($r[1] ? $r[1] : true, $r[2]);
-    }
-    return array(0, $v);
-  }
-  
-  /* 71 */
-  
-  function xPNAME_NS($v) {
-    list($r, $sub_v) = $this->xPN_PREFIX($v);
-    $prefix = $r ? $r : '';
-    return ($r = $this->x("\:", $sub_v)) ? array($prefix . ':', $r[1]) : array(0, $v);
-  }
-
-  /* 72 */
-  
-  function xPNAME_LN($v) {
-    if ((list($r, $sub_v) = $this->xPNAME_NS($v)) && $r) {
-      if (!$this->x('\s', $sub_v) && (list($sub_r, $sub_v) = $this->xPN_LOCAL($sub_v)) && $sub_r) {
-        if (!isset($this->prefixes[$r])) {
-          return array(0, $v);
-        }
-        return array($this->prefixes[$r] . $sub_r, $sub_v);
-      }
-    }
-    return array(0, $v);
-  }
-  
-  /* 76 */
-  
-  function xLANGTAG($v) {
-    if (!$this->x('\s', $v) && ($r = $this->x('\@([a-z]+(\-[a-z0-9]+)*)', $v))) {
-      return array($r[1], $r[3]);
-    }
-    return array(0, $v);
-  }
-  
-  /* 77.. */
-  
-  function xINTEGER($v) {
-    if ($r = $this->x('([0-9]+)', $v)) {
-      return array($r[1], $r[2]);
-    }
-    return array(false, $v);
-  }
-
-  /* 78.. */
-
-  function xDECIMAL($v) {
-    if ($r = $this->x('([0-9]+\.[0-9]*)', $v)) {
-      return array($r[1], $r[2]);
-    }
-    if ($r = $this->x('(\.[0-9]+)', $v)) {
-      return array($r[1], $r[2]);
-    }
-    return array(false, $v);
-  }
-
-  /* 79.., 86.. */
-
-  function xDOUBLE($v) {
-    if ($r = $this->x('([0-9]+\.[0-9]*E[\+\-]?[0-9]+)', $v)) {
-      return array($r[1], $r[2]);
-    }
-    if ($r = $this->x('(\.[0-9]+E[\+\-]?[0-9]+)', $v)) {
-      return array($r[1], $r[2]);
-    }
-    if ($r = $this->x('([0-9]+E[\+\-]?[0-9]+)', $v)) {
-      return array($r[1], $r[2]);
-    }
-    return array(false, $v);
-  }
-  
-  /* 92 */
-  
-  function xNIL($v) {
-    if ($r = $this->x('\([\x20\x9\xd\xa]*\)', $v)) {
-      return array(array('type' => 'uri', 'value' => $this->rdf . 'nil'), $r[1]);
-    }
-    return array(0, $v);
-  }
-
-  /* 95.. */
-  
-  function xPN_CHARS_BASE($v) {
-    if ($r = $this->x("([a-z]+|\\\u[0-9a-f]{1,4})", $v)) {
-      return array($r[1], $r[2]);
-    }
-    return array(0, $v);
-  }
-
-  /* 96 */
-  
-  function xPN_CHARS_U($v) {
-    if ((list($r, $sub_v) = $this->xPN_CHARS_BASE($v)) && $r) {
-      return array($r, $sub_v);
-    }
-    elseif ($r = $this->x("(_)", $v)) {
-      return array($r[1], $r[2]);
-    }
-    return array(0, $v);
-  }
-
-  /* 97.. */
-  
-  function xVARNAME($v) {
-    $r = '';
-    do {
-      $proceed = 0;
-      if ($sub_r = $this->x('([0-9]+)', $v)) {
-        $r .= $sub_r[1];
-        $v = $sub_r[2];
-        $proceed = 1;
-      }
-      elseif ((list($sub_r, $sub_v) = $this->xPN_CHARS_U($v)) && $sub_r) {
-        $r .= $sub_r;
-        $v = $sub_v;
-        $proceed = 1;
-      }
-      elseif ($r && ($sub_r = $this->x('([\xb7\x300-\x36f]+)', $v))) {
-        $r .= $sub_r[1];
-        $v = $sub_r[2];
-        $proceed = 1;
-      }
-    } while ($proceed);
-    return array($r, $v);
-  }
-
-  /* 98.. */
-  
-  function xPN_CHARS($v) {
-    if ((list($r, $sub_v) = $this->xPN_CHARS_U($v)) && $r) {
-      return array($r, $sub_v);
-    }
-    elseif ($r = $this->x('([\-0-9\xb7\x300-\x36f])', $v)) {
-      return array($r[1], $r[2]);
-    }
-    return array(false, $v);
-  }
-
-  /* 99 */
-  
-  function xPN_PREFIX($v) {
-    if ($sub_r = $this->x("([^\s\:\(\)\{\}\;\,]+)", $v, 's')) {/* accelerator */
-      return array($sub_r[1], $sub_r[2]);/* @@testing */
-    }
-    if ((list($r, $sub_v) = $this->xPN_CHARS_BASE($v)) && $r) {
-      do {
-        $proceed = 0;
-        list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v);
-        if ($sub_r !== false) {
-          $r .= $sub_r;
-          $proceed = 1;
-        }
-        elseif ($sub_r = $this->x("\.", $sub_v)) {
-          $r .= '.';
-          $sub_v = $sub_r[1];
-          $proceed = 1;
-        }
-      } while ($proceed);
-      list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v);
-      $r .= $sub_r ? $sub_r : '';
-    }
-    return array($r, $sub_v);
-  }
-  
-  /* 100 */
-  
-  function xPN_LOCAL($v) {
-    if (($sub_r = $this->x("([^\s\(\)\{\}\[\]\;\,\.]+)", $v, 's')) && !preg_match('/^\./', $sub_r[2])) {/* accelerator */
-      return array($sub_r[1], $sub_r[2]);/* @@testing */
-    }
-    $r = '';
-    $sub_v = $v;
-    do {
-      $proceed = 0;
-      if ($this->x('\s', $sub_v)) {
-        return array($r, $sub_v);
-      }
-      if ($sub_r = $this->x('([0-9])', $sub_v)) {
-        $r .= $sub_r[1];
-        $sub_v = $sub_r[2];
-        $proceed = 1;
-      }
-      elseif ((list($sub_r, $sub_v) = $this->xPN_CHARS_U($sub_v)) && $sub_r) {
-        $r .= $sub_r;
-        $proceed = 1;
-      }
-      elseif ($r) {
-        if (($sub_r = $this->x('(\.)', $sub_v)) && !preg_match('/^[\s\}]/s', $sub_r[2])) {
-          $r .= $sub_r[1];
-          $sub_v = $sub_r[2];
-        }
-        if ((list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v)) && $sub_r) {
-          $r .= $sub_r;
-          $proceed = 1;
-        }
-      }
-    } while ($proceed);
-    return array($r, $sub_v);
-  }
-  
-  /*  */
-  
-  function unescapeNtripleUTF($v) {
-    if (strpos($v, '\\') === false) return $v;
-    $mappings = array('t' => "\t", 'n' => "\n", 'r' => "\r", '\"' => '"', '\'' => "'");
-    foreach ($mappings as $in => $out) {
-      $v = preg_replace('/\x5c([' . $in . '])/', $out, $v);
-    }
-    if (strpos(strtolower($v), '\u') === false) return $v;
-    while (preg_match('/\\\(U)([0-9A-F]{8})/', $v, $m) || preg_match('/\\\(u)([0-9A-F]{4})/', $v, $m)) {
-      $no = hexdec($m[2]);
-  		if ($no < 128) $char = chr($no);
-      else if ($no < 2048) $char = chr(($no >> 6) + 192) . chr(($no & 63) + 128);
-      else if ($no < 65536) $char = chr(($no >> 12) + 224) . chr((($no >> 6) & 63) + 128) . chr(($no & 63) + 128);
-  		else if ($no < 2097152) $char = chr(($no >> 18) + 240) . chr((($no >> 12) & 63) + 128) . chr((($no >> 6) & 63) + 128) . chr(($no & 63) + 128);
-      else $char= '';
-      $v = str_replace('\\' . $m[1] . $m[2], $char, $v);
-    }
-    return $v;
-  }
-  
-  /*  */
-  
-  function xPlaceholder($v) {
-    //if ($r = $this->x('(\?|\$)\{([^\}]+)\}', $v)) {
-    if ($r = $this->x('(\?|\$)', $v)) {
-      if (preg_match('/(\{(?:[^{}]+|(?R))*\})/', $r[2], $m) && strpos(trim($r[2]), $m[1]) === 0) {
-        $ph = substr($m[1], 1, -1);
-        $rest = substr(trim($r[2]), strlen($m[1]));
-        if (!isset($this->r['placeholders'])) $this->r['placeholders'] = array();
-        if (!in_array($ph, $this->r['placeholders'])) $this->r['placeholders'][] = $ph;
-        return array(array('value' => $ph, 'type' => 'placeholder'), $rest);
-      }
-    }
-    return array(0, $v);
-  }
-  
-  /*  */
+            if ($sub_r = $this->x('([0-9]+)', $v)) {
+                $r .= $sub_r[1];
+                $v = $sub_r[2];
+                $proceed = 1;
+            } elseif ((list($sub_r, $sub_v) = $this->xPN_CHARS_U($v)) && $sub_r) {
+                $r .= $sub_r;
+                $v = $sub_v;
+                $proceed = 1;
+            } elseif ($r && ($sub_r = $this->x('([\xb7\x300-\x36f]+)', $v))) {
+                $r .= $sub_r[1];
+                $v = $sub_r[2];
+                $proceed = 1;
+            }
+        } while ($proceed);
+
+        return [$r, $v];
+    }
+
+    /* 98.. */
+
+    public function xPN_CHARS($v)
+    {
+        if ((list($r, $sub_v) = $this->xPN_CHARS_U($v)) && $r) {
+            return [$r, $sub_v];
+        } elseif ($r = $this->x('([\-0-9\xb7\x300-\x36f])', $v)) {
+            return [$r[1], $r[2]];
+        }
+
+        return [false, $v];
+    }
+
+    /* 99 */
+
+    public function xPN_PREFIX($v)
+    {
+        if ($sub_r = $this->x("([^\s\:\(\)\{\}\;\,]+)", $v, 's')) {/* accelerator */
+            return [$sub_r[1], $sub_r[2]]; /* @@testing */
+        }
+        if ((list($r, $sub_v) = $this->xPN_CHARS_BASE($v)) && $r) {
+            do {
+                $proceed = 0;
+                list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v);
+                if (false !== $sub_r) {
+                    $r .= $sub_r;
+                    $proceed = 1;
+                } elseif ($sub_r = $this->x("\.", $sub_v)) {
+                    $r .= '.';
+                    $sub_v = $sub_r[1];
+                    $proceed = 1;
+                }
+            } while ($proceed);
+            list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v);
+            $r .= $sub_r ? $sub_r : '';
+        }
+
+        return [$r, $sub_v];
+    }
+
+    /* 100 */
+
+    public function xPN_LOCAL($v)
+    {
+        if (($sub_r = $this->x("([^\s\(\)\{\}\[\]\;\,\.]+)", $v, 's')) && !preg_match('/^\./', $sub_r[2])) {/* accelerator */
+            return [$sub_r[1], $sub_r[2]]; /* @@testing */
+        }
+        $r = '';
+        $sub_v = $v;
+        do {
+            $proceed = 0;
+            if ($this->x('\s', $sub_v)) {
+                return [$r, $sub_v];
+            }
+            if ($sub_r = $this->x('([0-9])', $sub_v)) {
+                $r .= $sub_r[1];
+                $sub_v = $sub_r[2];
+                $proceed = 1;
+            } elseif ((list($sub_r, $sub_v) = $this->xPN_CHARS_U($sub_v)) && $sub_r) {
+                $r .= $sub_r;
+                $proceed = 1;
+            } elseif ($r) {
+                if (($sub_r = $this->x('(\.)', $sub_v)) && !preg_match('/^[\s\}]/s', $sub_r[2])) {
+                    $r .= $sub_r[1];
+                    $sub_v = $sub_r[2];
+                }
+                if ((list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v)) && $sub_r) {
+                    $r .= $sub_r;
+                    $proceed = 1;
+                }
+            }
+        } while ($proceed);
+
+        return [$r, $sub_v];
+    }
+
+    public function unescapeNtripleUTF($v)
+    {
+        if (false === strpos($v, '\\')) {
+            return $v;
+        }
+        $mappings = ['t' => "\t", 'n' => "\n", 'r' => "\r", '\"' => '"', '\'' => "'"];
+        foreach ($mappings as $in => $out) {
+            $v = preg_replace('/\x5c(['.$in.'])/', $out, $v);
+        }
+        if (false === strpos(strtolower($v), '\u')) {
+            return $v;
+        }
+        while (preg_match('/\\\(U)([0-9A-F]{8})/', $v, $m) || preg_match('/\\\(u)([0-9A-F]{4})/', $v, $m)) {
+            $no = hexdec($m[2]);
+            if ($no < 128) {
+                $char = chr($no);
+            } elseif ($no < 2048) {
+                $char = chr(($no >> 6) + 192).chr(($no & 63) + 128);
+            } elseif ($no < 65536) {
+                $char = chr(($no >> 12) + 224).chr((($no >> 6) & 63) + 128).chr(($no & 63) + 128);
+            } elseif ($no < 2097152) {
+                $char = chr(($no >> 18) + 240).chr((($no >> 12) & 63) + 128).chr((($no >> 6) & 63) + 128).chr(($no & 63) + 128);
+            } else {
+                $char = '';
+            }
+            $v = str_replace('\\'.$m[1].$m[2], $char, $v);
+        }
+
+        return $v;
+    }
+
+    public function xPlaceholder($v)
+    {
+        //if ($r = $this->x('(\?|\$)\{([^\}]+)\}', $v)) {
+        if ($r = $this->x('(\?|\$)', $v)) {
+            if (preg_match('/(\{(?:[^{}]+|(?R))*\})/', $r[2], $m) && 0 === strpos(trim($r[2]), $m[1])) {
+                $ph = substr($m[1], 1, -1);
+                $rest = substr(trim($r[2]), strlen($m[1]));
+                if (!isset($this->r['placeholders'])) {
+                    $this->r['placeholders'] = [];
+                }
+                if (!in_array($ph, $this->r['placeholders'])) {
+                    $this->r['placeholders'][] = $ph;
+                }
+
+                return [['value' => $ph, 'type' => 'placeholder'], $rest];
+            }
+        }
+
+        return [0, $v];
+    }
 }
diff --git a/lib/arc2/phpunit.xml b/lib/arc2/phpunit.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e3f74ef5e302d86a912f5a9c1e0eb84c2410032c
--- /dev/null
+++ b/lib/arc2/phpunit.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
+    backupGlobals="false"
+    backupStaticAttributes="false"
+    bootstrap="tests/bootstrap.php"
+    colors="true"
+    convertErrorsToExceptions="true"
+    convertNoticesToExceptions="true"
+    convertWarningsToExceptions="true"
+    processIsolation="false"
+    stopOnFailure="false"
+    verbose="true"
+    >
+    <php>
+        <ini name="error_reporting" value="-1" />
+        <ini name="intl.error_level" value="0" />
+        <ini name="display_errors" value="On"/>
+    </php>
+    <testsuites>
+        <testsuite name="db_adapter_depended">
+            <directory suffix="Test.php">./tests/db_adapter_depended</directory>
+        </testsuite>
+        <testsuite name="unit">
+            <directory suffix="Test.php">./tests/unit</directory>
+        </testsuite>
+    </testsuites>
+    <logging>
+        <log type="coverage-html" target="tests/coverage" lowUpperBound="35" highLowerBound="70" />
+    </logging>
+    <filter>
+        <whitelist processUncoveredFilesFromWhitelist="true">
+            <directory suffix=".php">./extractors</directory>
+            <directory suffix=".php">./parsers</directory>
+            <directory suffix=".php">./serializers</directory>
+            <directory suffix=".php">./sparqlscript</directory>
+            <directory suffix=".php">./src</directory>
+            <directory suffix=".php">./store</directory>
+        </whitelist>
+    </filter>
+</phpunit>
diff --git a/lib/arc2/serializers/ARC2_JSONLDSerializer.php b/lib/arc2/serializers/ARC2_JSONLDSerializer.php
new file mode 100644
index 0000000000000000000000000000000000000000..4ecde6e08c075f1b0a1cfd837221dd8b656db53b
--- /dev/null
+++ b/lib/arc2/serializers/ARC2_JSONLDSerializer.php
@@ -0,0 +1,88 @@
+<?php
+/**
+ * ARC2 JSON-LD Serializer.
+ *
+ * @author John Walker <john.walker@semaku.com>
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ */
+ARC2::inc('RDFSerializer');
+
+class ARC2_JSONLDSerializer extends ARC2_RDFSerializer
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
+
+    public function __init()
+    {
+        parent::__init();
+        $this->content_header = 'application/ld+json';
+    }
+
+    public function getTerm($v, $term = 's')
+    {
+        if (!is_array($v)) {
+            if (preg_match('/^\_\:/', $v)) {
+                return ('o' == $term) ? $this->getTerm(['value' => $v, 'type' => 'bnode'], 'o') : '"'.$v.'"';
+            }
+
+            return ('o' == $term) ? $this->getTerm(['value' => $v, 'type' => 'uri'], 'o') : '"'.$v.'"';
+        }
+        if (!isset($v['type']) || ('literal' != $v['type'])) {
+            if ('o' != $term) {
+                return $this->getTerm($v['value'], $term);
+            }
+
+            return '{ "@id" : "'.$this->jsonEscape($v['value']).'" }';
+        }
+        /* literal */
+        $r = '{ "@value" : "'.$this->jsonEscape($v['value']).'"';
+        $suffix = isset($v['datatype']) ? ', "@type" : "'.$v['datatype'].'"' : '';
+        $suffix = isset($v['lang']) ? ', "@language" : "'.$v['lang'].'"' : $suffix;
+        $r .= $suffix.' }';
+
+        return $r;
+    }
+
+    public function jsonEscape($v)
+    {
+        if (function_exists('json_encode')) {
+            return preg_replace('/^"(.*)"$/', '\\1', str_replace("\/", '/', json_encode($v)));
+        }
+        $from = ['\\', "\r", "\t", "\n", '"', "\b", "\f"];
+        $to = ['\\\\', '\r', '\t', '\n', '\"', '\b', '\f'];
+
+        return str_replace($from, $to, $v);
+    }
+
+    public function getSerializedIndex($index, $raw = 0)
+    {
+        $r = '';
+        $nl = "\n";
+        foreach ($index as $s => $ps) {
+            $r .= $r ? ','.$nl.$nl : '';
+            $r .= '  { '.$nl.'    "@id" : '.$this->getTerm($s);
+            //$first_p = 1;
+            foreach ($ps as $p => $os) {
+                $r .= ','.$nl;
+                $r .= '    '.$this->getTerm($p).' : [';
+                $first_o = 1;
+                if (!is_array($os)) {/* single literal o */
+                    $os = [['value' => $os, 'type' => 'literal']];
+                }
+                foreach ($os as $o) {
+                    $r .= $first_o ? $nl : ','.$nl;
+                    $r .= '      '.$this->getTerm($o, 'o');
+                    $first_o = 0;
+                }
+                $r .= $nl.'    ]';
+            }
+            $r .= $nl.'  }';
+        }
+        $r .= $r ? ' ' : '';
+
+        return '['.$nl.$r.$nl.']';
+    }
+}
diff --git a/lib/arc2/serializers/ARC2_LegacyHTMLSerializer.php b/lib/arc2/serializers/ARC2_LegacyHTMLSerializer.php
old mode 100644
new mode 100755
index 81563ba0fb0485727b91fe820e963cea47e31aec..ce2ae2cdfddf906990ab560d0881c2a32b9bff7c
--- a/lib/arc2/serializers/ARC2_LegacyHTMLSerializer.php
+++ b/lib/arc2/serializers/ARC2_LegacyHTMLSerializer.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 Legacy XML Serializer
 author:   Benjamin Nowack
@@ -10,102 +10,104 @@ version:  2010-11-16
 
 ARC2::inc('Class');
 
-class ARC2_LegacyHTMLSerializer extends ARC2_Class {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-    $this->content_header = 'text/html';
-  }
-
-  /*  */
-  
-  function getSerializedArray($struct, $root = 1, $ind = ' ') {
-    $n = "\n";
-    $r = '';
-    $is_flat = $this->isAssociativeArray($struct) ? 0 : 1;
-    foreach ($struct as $k => $v) {
-      if (!$is_flat) $r .= $n . $ind . $ind . '<dt>' . $k . '</dt>';
-      $r .= $n . $ind . $ind . '<dd>' . (is_array($v) ? $this->getSerializedArray($v, 0, $ind . $ind . $ind) . $n . $ind . $ind : htmlspecialchars($v)) . '</dd>';
+class ARC2_LegacyHTMLSerializer extends ARC2_Class
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
     }
-    return $n . $ind . '<dl>' . $r . $n . $ind . '</dl>';
-  }
-  
-  /*  */
 
-  function isAssociativeArray($v) {
-    foreach (array_keys($v) as $k => $val) {
-      if ($k !== $val) return 1;
+    public function __init()
+    {
+        parent::__init();
+        $this->content_header = 'text/html';
     }
-    return 0;
-  }
-  
-  /*  */
 
-  function getSerializedNode($index, $node, $level = 0, $raw = 0) {
-    $r = '';
-    $tag = $this->v('tag', '', $node);
-    if (preg_match('/^(comment|script)$/', $tag)) {
-    }
-    elseif ($tag == 'cdata') {
-      $r .= $this->v('cdata', '', $node);
-      $r .= $this->v('value', '', $node['a']);
-    }
-    else {
-      /* open tag */
-      if (preg_match('/^(div|form|p|section)$/', $tag)) {
-        $r .= str_pad("\n", $level + 1, "  ");
-      }
-      $r .= '<' . $tag;
-      $attrs = $this->v('a', array(), $node);
-      foreach ($attrs as $k => $v) {
-        /* use uri, if detected */
-        if ($k != 'id') {
-          $v = $this->v($k . ' uri', $v, $attrs);
+    public function getSerializedArray($struct, $root = 1, $ind = ' ')
+    {
+        $n = "\n";
+        $r = '';
+        $is_flat = $this->isAssociativeArray($struct) ? 0 : 1;
+        foreach ($struct as $k => $v) {
+            if (!$is_flat) {
+                $r .= $n.$ind.$ind.'<dt>'.$k.'</dt>';
+            }
+            $r .= $n.$ind.$ind.'<dd>'.(is_array($v) ? $this->getSerializedArray($v, 0, $ind.$ind.$ind).$n.$ind.$ind : htmlspecialchars($v)).'</dd>';
         }
-        /* skip arrays and other derived attrs */
-        if (preg_match('/\s/s', $k)) continue;
-        $r .= ' ' . $k . '="' . $v . '"';
-      }
-      if ($node['empty']) {
-        $r .= '/>';
-      }
-      else {
-        $r .= '>';
-        /* cdata */
-        $r .= $this->v('cdata', '', $node);
-        /* sub-nodes */
-        $sub_nodes = $this->v($node['id'], array(), $index);
-        foreach ($sub_nodes as $sub_node) {
-          $r .= $this->getSerializedNode($index, $sub_node, $level + 1, 1);
-        }
-        /* close tag */
-        //$r .= str_pad("\n", $level + 1, "  ") . '</' . $tag . '>';
-        $r .= '</' . $tag . '>';
-        if (preg_match('/^(div|form|p|section)$/', $tag)) {
-          $r .= str_pad("\n", $level + 1, "  ");
+
+        return $n.$ind.'<dl>'.$r.$n.$ind.'</dl>';
+    }
+
+    public function isAssociativeArray($v)
+    {
+        foreach (array_keys($v) as $k => $val) {
+            if ($k !== $val) {
+                return 1;
+            }
         }
-      }
+
+        return 0;
     }
-    /* doc envelope, in case of sub-structure serializing */
-    if (!$raw && ($level == 0) && ($node['level'] > 1)) {
-      $r = '<!DOCTYPE html>
+
+    public function getSerializedNode($index, $node, $level = 0, $raw = 0)
+    {
+        $r = '';
+        $tag = $this->v('tag', '', $node);
+        if (preg_match('/^(comment|script)$/', $tag)) {
+        } elseif ('cdata' == $tag) {
+            $r .= $this->v('cdata', '', $node);
+            $r .= $this->v('value', '', $node['a']);
+        } else {
+            /* open tag */
+            if (preg_match('/^(div|form|p|section)$/', $tag)) {
+                $r .= str_pad("\n", $level + 1, '  ');
+            }
+            $r .= '<'.$tag;
+            $attrs = $this->v('a', [], $node);
+            foreach ($attrs as $k => $v) {
+                /* use uri, if detected */
+                if ('id' != $k) {
+                    $v = $this->v($k.' uri', $v, $attrs);
+                }
+                /* skip arrays and other derived attrs */
+                if (preg_match('/\s/s', $k)) {
+                    continue;
+                }
+                $r .= ' '.$k.'="'.$v.'"';
+            }
+            if ($node['empty']) {
+                $r .= '/>';
+            } else {
+                $r .= '>';
+                /* cdata */
+                $r .= $this->v('cdata', '', $node);
+                /* sub-nodes */
+                $sub_nodes = $this->v($node['id'], [], $index);
+                foreach ($sub_nodes as $sub_node) {
+                    $r .= $this->getSerializedNode($index, $sub_node, $level + 1, 1);
+                }
+                /* close tag */
+                //$r .= str_pad("\n", $level + 1, "  ") . '</' . $tag . '>';
+                $r .= '</'.$tag.'>';
+                if (preg_match('/^(div|form|p|section)$/', $tag)) {
+                    $r .= str_pad("\n", $level + 1, '  ');
+                }
+            }
+        }
+        /* doc envelope, in case of sub-structure serializing */
+        if (!$raw && (0 == $level) && ($node['level'] > 1)) {
+            $r = '<!DOCTYPE html>
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <head>
   <body>
-    ' . $r . '
+    '.$r.'
   </body>
 </html>
      ';
-    }
-    return $r;
-  }
+        }
 
-  /*  */
+        return $r;
+    }
 }
-
diff --git a/lib/arc2/serializers/ARC2_LegacyJSONSerializer.php b/lib/arc2/serializers/ARC2_LegacyJSONSerializer.php
old mode 100644
new mode 100755
index 46449dc27635d8b8b29f234357718b6914a6bd62..6d0a04f34dab2f0f98b02e6b329a38b6e77679c2
--- a/lib/arc2/serializers/ARC2_LegacyJSONSerializer.php
+++ b/lib/arc2/serializers/ARC2_LegacyJSONSerializer.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 Legacy JSON Serializer
 author:   Benjamin Nowack
@@ -10,44 +10,46 @@ version:  2010-11-16
 
 ARC2::inc('Class');
 
-class ARC2_LegacyJSONSerializer extends ARC2_Class {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-    $this->content_header = 'application/json';
-  }
-
-  /*  */
-  
-  function getSerializedArray($struct, $ind = '') {
-    $n = "\n";
-    if (function_exists('json_encode')) return str_replace('","', '",' . $n . '"', json_encode($struct));
-    $r = '';
-    $from = array("\\", "\r", "\t", "\n", '"', "\b", "\f", "/");
-    $to = array('\\\\', '\r', '\t', '\n', '\"', '\b', '\f', '\/');
-    $is_flat = $this->isAssociativeArray($struct) ? 0 : 1;
-    foreach ($struct as $k => $v) {
-      $r .= $r ? ',' . $n . $ind . $ind : $ind . $ind;
-      $r .= $is_flat ? '' : '"' . $k . '": ';
-      $r .= is_array($v) ? $this->getSerializedArray($v, $ind . '  ') : '"' . str_replace($from, $to, $v) . '"';
+class ARC2_LegacyJSONSerializer extends ARC2_Class
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
     }
-    return $is_flat ? $ind . '[' . $n . $r . $n . $ind . ']' : $ind . '{' . $n . $r . $n . $ind . '}';
-  }
-  
-  /*  */
-
-  function isAssociativeArray($v) {
-    foreach (array_keys($v) as $k => $val) {
-      if ($k !== $val) return 1;
+
+    public function __init()
+    {
+        parent::__init();
+        $this->content_header = 'application/json';
     }
-    return 0;
-  }
-  
-  /*  */
 
-}
+    public function getSerializedArray($struct, $ind = '')
+    {
+        $n = "\n";
+        if (function_exists('json_encode')) {
+            return str_replace('","', '",'.$n.'"', str_replace("\/", '/', json_encode($struct)));
+        }
+        $r = '';
+        $from = ['\\', "\r", "\t", "\n", '"', "\b", "\f"];
+        $to = ['\\\\', '\r', '\t', '\n', '\"', '\b', '\f'];
+        $is_flat = $this->isAssociativeArray($struct) ? 0 : 1;
+        foreach ($struct as $k => $v) {
+            $r .= $r ? ','.$n.$ind.$ind : $ind.$ind;
+            $r .= $is_flat ? '' : '"'.$k.'": ';
+            $r .= is_array($v) ? $this->getSerializedArray($v, $ind.'  ') : '"'.str_replace($from, $to, $v).'"';
+        }
+
+        return $is_flat ? $ind.'['.$n.$r.$n.$ind.']' : $ind.'{'.$n.$r.$n.$ind.'}';
+    }
 
+    public function isAssociativeArray($v)
+    {
+        foreach (array_keys($v) as $k => $val) {
+            if ($k !== $val) {
+                return 1;
+            }
+        }
+
+        return 0;
+    }
+}
diff --git a/lib/arc2/serializers/ARC2_LegacyXMLSerializer.php b/lib/arc2/serializers/ARC2_LegacyXMLSerializer.php
old mode 100644
new mode 100755
index a401887c12d06e51dff75fe579f48f10d55be972..ee07ad6364fcdc88260ad2cdb933695da6541386
--- a/lib/arc2/serializers/ARC2_LegacyXMLSerializer.php
+++ b/lib/arc2/serializers/ARC2_LegacyXMLSerializer.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 Legacy XML Serializer
 author:   Benjamin Nowack
@@ -10,57 +10,61 @@ version:  2010-11-16
 
 ARC2::inc('Class');
 
-class ARC2_LegacyXMLSerializer extends ARC2_Class {
+class ARC2_LegacyXMLSerializer extends ARC2_Class
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
+
+    public function __init()
+    {
+        parent::__init();
+        $this->content_header = 'text/xml';
+    }
 
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-    $this->content_header = 'text/xml';
-  }
+    public function getSerializedArray($struct, $root = 1, $ind = '  ')
+    {
+        $n = "\n";
+        $r = '';
+        $is_flat = $this->isAssociativeArray($struct) ? 0 : 1;
+        foreach ($struct as $k => $v) {
+            $tag = $is_flat ? 'item' : preg_replace('/[\s]/s', '_', $k);
+            $tag = preg_replace('/^.*([a-z0-9\-\_]+)$/Uis', '\\1', $tag);
+            $r .= $n.$ind.'<'.$tag.'>'.(is_array($v) ? $this->getSerializedArray($v, 0, $ind.'  ').$n.$ind : htmlspecialchars($v)).'</'.$tag.'>';
+        }
+        if ($root) {
+            $r = $this->getHead().$r.$this->getFooter();
+        }
 
-  /*  */
-  
-  function getSerializedArray($struct, $root = 1, $ind = '  ') {
-    $n = "\n";
-    $r = '';
-    $is_flat = $this->isAssociativeArray($struct) ? 0 : 1;
-    foreach ($struct as $k => $v) {
-      $tag = $is_flat ? 'item' : preg_replace('/[\s]/s', '_', $k);
-      $tag = preg_replace('/^.*([a-z0-9\-\_]+)$/Uis', '\\1', $tag);
-      $r .= $n . $ind . '<' . $tag . '>' . (is_array($v) ? $this->getSerializedArray($v, 0, $ind . '  ') . $n . $ind : htmlspecialchars($v)) . '</' . $tag . '>';
+        return $r;
     }
-    if ($root) $r = $this->getHead() . $r . $this->getFooter();
-    return $r;
-  }
-  
-  /*  */
 
-  function getHead() {
-    $n = "\n";
-    $r = '<?xml version="1.0"?>';
-    $r .= $n . '<items>';
-    return $r;
-  }
-  
-  function getFooter() {
-    $n = "\n";
-    $r = $n . '</items>';
-    return $r;
-  }
-  
-  /*  */
+    public function getHead()
+    {
+        $n = "\n";
+        $r = '<?xml version="1.0"?>';
+        $r .= $n.'<items>';
 
-  function isAssociativeArray($v) {
-    foreach (array_keys($v) as $k => $val) {
-      if ($k !== $val) return 1;
+        return $r;
     }
-    return 0;
-  }
-  
-  /*  */
 
-}
+    public function getFooter()
+    {
+        $n = "\n";
+        $r = $n.'</items>';
 
+        return $r;
+    }
+
+    public function isAssociativeArray($v)
+    {
+        foreach (array_keys($v) as $k => $val) {
+            if ($k !== $val) {
+                return 1;
+            }
+        }
+
+        return 0;
+    }
+}
diff --git a/lib/arc2/serializers/ARC2_MicroRDFSerializer.php b/lib/arc2/serializers/ARC2_MicroRDFSerializer.php
old mode 100644
new mode 100755
index c08a3cea5b72f9c4ab65ec3ac074560b6586d11a..d8afc0ce4873e8eaa93ff9e1dc508e0c728b0738
--- a/lib/arc2/serializers/ARC2_MicroRDFSerializer.php
+++ b/lib/arc2/serializers/ARC2_MicroRDFSerializer.php
@@ -1,142 +1,163 @@
 <?php
 /**
- * ARC2 MicroRDF Serializer
+ * ARC2 MicroRDF Serializer.
  *
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('RDFSerializer');
 
-class ARC2_MicroRDFSerializer extends ARC2_RDFSerializer {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-    $this->content_header = 'text/html';
-    $this->label_store = $this->v('label_store', '', $this->a);
-  }
-
-  /*  */
-  
-  function getLabel($res, $ps = '') {
-    if (!$ps) $ps = array();
-    foreach ($ps as $p => $os) {
-      if (preg_match('/[\/\#](name|label|summary|title|fn)$/i', $p)) {
-        return $os[0]['value'];
-      }
+class ARC2_MicroRDFSerializer extends ARC2_RDFSerializer
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
+
+    public function __init()
+    {
+        parent::__init();
+        $this->content_header = 'text/html';
+        $this->label_store = $this->v('label_store', '', $this->a);
+    }
+
+    public function getLabel($res, $ps = '')
+    {
+        if (!$ps) {
+            $ps = [];
+        }
+        foreach ($ps as $p => $os) {
+            if (preg_match('/[\/\#](name|label|summary|title|fn)$/i', $p)) {
+                return $os[0]['value'];
+            }
+        }
+        if (preg_match('/^\_\:/', $res)) {
+            return 'An unnamed resource';
+        }
+
+        return $this->extractTermLabel($res);
+
+        return preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('_', ' ', $res));
     }
-    if (preg_match('/^\_\:/', $res)) return "An unnamed resource";
-    return $this->extractTermLabel($res);
-    return preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('_', ' ', $res));
-  }
-  
-  function getSerializedIndex($index, $res = '') {
-    $r = '';
-    $n = "\n";
-    if ($res) $index = array($res => $index[$res]);
-    //return Trice::dump($index);
-    $types = $this->v($this->expandPName('rdf:type'), array(), $index);
-    $main_type = $types ? $types[0]['value'] : '';
-    foreach ($index as $s => $ps) {
-      /* node */
-      $r .= '
-        <div class="rdf-item" ' . $this->mdAttrs($s, $main_type) . '>
-          <h3 class="rdf-itemlabel"><a href="' . $s . '">' . ucfirst($this->getLabel($s, $ps))  . '</a></h3>
+
+    public function getSerializedIndex($index, $res = '')
+    {
+        $r = '';
+        $n = "\n";
+        if ($res) {
+            $index = [$res => $index[$res]];
+        }
+        //return Trice::dump($index);
+        $types = $this->v($this->expandPName('rdf:type'), [], $index);
+        $main_type = $types ? $types[0]['value'] : '';
+        foreach ($index as $s => $ps) {
+            /* node */
+            $r .= '
+        <div class="rdf-item" '.$this->mdAttrs($s, $main_type).'>
+          <h3 class="rdf-itemlabel"><a href="'.$s.'">'.ucfirst($this->getLabel($s, $ps)).'</a></h3>
       ';
-      /* arcs */
-      foreach ($ps as $p => $os) {
-        $p_cls = strtolower($this->getPName($p));
-        $p_cls = str_replace(':', '-', $p_cls);
-        $r .= '
-          <div class="rdf-prop ' . $p_cls . '">
-            <a class="rdf-proplabel" href="' . $p . '">' . ucfirst($this->getLabel($p)) . ':</a>
+            /* arcs */
+            foreach ($ps as $p => $os) {
+                $p_cls = strtolower($this->getPName($p));
+                $p_cls = str_replace(':', '-', $p_cls);
+                $r .= '
+          <div class="rdf-prop '.$p_cls.'">
+            <a class="rdf-proplabel" href="'.$p.'">'.ucfirst($this->getLabel($p)).':</a>
             <ul class="rdf-values">
         ';
-        $oc = count($os);
-        foreach ($os as $i => $o) {
-          $val = $this->getObjectValue($o, $p);
-          $cls = '';
-          if ($i == 0) $cls .= ($cls ? ' ' : '') . 'first';
-          if ($i == $oc - 1) $cls .= ($cls ? ' ' : '') . 'last';
-          $r .= $n . '<li' . ($cls ? ' class="' . $cls . '"' : '') . '>' . $val . '</li>';
-        }
-        $r .= '
+                $oc = count($os);
+                foreach ($os as $i => $o) {
+                    $val = $this->getObjectValue($o, $p);
+                    $cls = '';
+                    if (0 == $i) {
+                        $cls .= ($cls ? ' ' : '').'first';
+                    }
+                    if ($i == $oc - 1) {
+                        $cls .= ($cls ? ' ' : '').'last';
+                    }
+                    $r .= $n.'<li'.($cls ? ' class="'.$cls.'"' : '').'>'.$val.'</li>';
+                }
+                $r .= '
             </ul>
             <div class="clb"></div>
           </div>
         ';
-      }
-      /* /node */
-      $r .= '
+            }
+            /* /node */
+            $r .= '
         <div class="clb"></div>
         </div>
       ';
+        }
+
+        return $r;
     }
-    return $r;
-  }
-  
-  function getObjectValue($o, $p) {
-    if ($o['type'] == 'uri') {
-      if (preg_match('/(jpe?g|gif|png)$/i', $o['value'])) {
-        return $this->getImageObjectValue($o, $p);
-      }
-      return $this->getURIObjectValue($o, $p);
-    }
-    if ($o['type'] == "bnode") {
-      return $this->getBNodeObjectValue($o, $p);
+
+    public function getObjectValue($o, $p)
+    {
+        if ('uri' == $o['type']) {
+            if (preg_match('/(jpe?g|gif|png)$/i', $o['value'])) {
+                return $this->getImageObjectValue($o, $p);
+            }
+
+            return $this->getURIObjectValue($o, $p);
+        }
+        if ('bnode' == $o['type']) {
+            return $this->getBNodeObjectValue($o, $p);
+        }
+
+        return $this->getLiteralObjectValue($o, $p);
     }
-    return $this->getLiteralObjectValue($o, $p);
-  }
-  
-  function getImageObjectValue($o, $p) {
-    return '<img class="rdf-value" itemprop="' . $p. '" src="' . htmlspecialchars($o['value']) . '" alt="img" />';
-  }
-  
-  function getURIObjectValue($o, $p) {
-    $id = htmlspecialchars($o['value']);
-    $label = $this->getObjectLabel($o['value']);
-    /* differing href */
-    $href = htmlspecialchars($this->v('href', $o['value'], $o));
-    if ($id != $href) {
-      return '<a class="rdf-value" itemprop="' . $p. '" href="' . $id . '" onclick="location.href=\'' . $href . '\';return false">' . $label . '</a>';
+
+    public function getImageObjectValue($o, $p)
+    {
+        return '<img class="rdf-value" itemprop="'.$p.'" src="'.htmlspecialchars($o['value']).'" alt="img" />';
     }
-    return '<a class="rdf-value" itemprop="' . $p. '" href="' . $id . '">' . $label . '</a>';
-    //$label = $o['value'];
+
+    public function getURIObjectValue($o, $p)
+    {
+        $id = htmlspecialchars($o['value']);
+        $label = $this->getObjectLabel($o['value']);
+        /* differing href */
+        $href = htmlspecialchars($this->v('href', $o['value'], $o));
+        if ($id != $href) {
+            return '<a class="rdf-value" itemprop="'.$p.'" href="'.$id.'" onclick="location.href=\''.$href.'\';return false">'.$label.'</a>';
+        }
+
+        return '<a class="rdf-value" itemprop="'.$p.'" href="'.$id.'">'.$label.'</a>';
+        //$label = $o['value'];
     //$label = preg_replace('/^https?\:\/\/(www\.)?/', '', $label);
-  }
+    }
 
-  function getBNodeObjectValue($o, $p) {
-    return '<div class="rdf-value" itemprop="' . $p. '" itemscope="">' . $o['value'] . '</div>';
-    return '<div class="rdf-value" itemprop="' . $p. '" itemscope="">An unnamed resource</div>';
-  }
+    public function getBNodeObjectValue($o, $p)
+    {
+        return '<div class="rdf-value" itemprop="'.$p.'" itemscope="">'.$o['value'].'</div>';
 
-  function getLiteralObjectValue($o, $p) {
-    return '<div class="rdf-value" itemprop="' . $p. '">' . $o['value'] . '</div>';
-  }
+        return '<div class="rdf-value" itemprop="'.$p.'" itemscope="">An unnamed resource</div>';
+    }
 
-  /*  */
+    public function getLiteralObjectValue($o, $p)
+    {
+        return '<div class="rdf-value" itemprop="'.$p.'">'.$o['value'].'</div>';
+    }
 
-  function getObjectLabel($id) {
-    $r = $this->extractTermLabel($id);
-    if (!$this->label_store) return $r;
-    $q = '
+    public function getObjectLabel($id)
+    {
+        $r = $this->extractTermLabel($id);
+        if (!$this->label_store) {
+            return $r;
+        }
+        $q = '
       SELECT ?val WHERE {
-        <' . $id . '> ?p ?val .
+        <'.$id.'> ?p ?val .
         FILTER(REGEX(str(?p), "(label|title|name|summary)$"))
       } LIMIT 1
     ';
-    $row = $this->label_store->query($q, 'row');
-    return $row ? $row['val'] : $r;
-  }
+        $row = $this->label_store->query($q, 'row');
 
-  /*  */
-  
+        return $row ? $row['val'] : $r;
+    }
 }
-
diff --git a/lib/arc2/serializers/ARC2_NTriplesSerializer.php b/lib/arc2/serializers/ARC2_NTriplesSerializer.php
index 9b51c764ebf2646795ceebfdc4544d3fbb2cc4c2..61e8b6ecf902f561ee3d93e62170b58de5ddc106 100644
--- a/lib/arc2/serializers/ARC2_NTriplesSerializer.php
+++ b/lib/arc2/serializers/ARC2_NTriplesSerializer.php
@@ -1,110 +1,172 @@
 <?php
 /**
- * ARC2 N-Triples Serializer
+ * ARC2 N-Triples Serializer.
  *
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
- * @version 2010-11-16
-*/
-
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ */
 ARC2::inc('RDFSerializer');
 
-class ARC2_NTriplesSerializer extends ARC2_RDFSerializer {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-    $this->esc_chars = array();
-    $this->raw = 0;
-  }
+class ARC2_NTriplesSerializer extends ARC2_RDFSerializer
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
 
-  /*  */
-  
-  function getTerm($v) {
-    if (!is_array($v)) {
-      if (preg_match('/^\_\:/', $v)) {
-        return $v;
-      }
-      if (preg_match('/^[a-z0-9]+\:[^\s\"]*$/is', $v)) {
-        return '<' . $this->escape($v) . '>';
-      }
-      return $this->getTerm(array('type' => 'literal', 'value' => $v));
+    public function __init()
+    {
+        parent::__init();
+        $this->esc_chars = [];
+        $this->raw = 0;
     }
-    if ($v['type'] != 'literal') {
-      return $this->getTerm($v['value']);
+
+    public function getTerm($v, $term = '')
+    {
+        // type detection
+        if (!is_array($v) || empty($v['type'])) {
+            // bnode
+            if (preg_match('/^\_\:/', $v)) {
+                return $this->getTerm(['value' => $v, 'type' => 'bnode']);
+            }
+            // uri
+            if (preg_match('/^[a-z0-9]+\:[^\s\"]*$/is'.($this->has_pcre_unicode ? 'u' : ''), $v)) {
+                return $this->getTerm(['value' => $v, 'type' => 'uri']);
+            }
+            // fallback for non-unicode environments: subjects and predicates can't be literals.
+            if (in_array($term, ['s', 'p'])) {
+                return $this->getTerm(['value' => $v, 'type' => 'uri']);
+            }
+            // assume literal
+            return $this->getTerm(['type' => 'literal', 'value' => $v]);
+        }
+        if ('bnode' == $v['type']) {
+            return $v['value'];
+        } elseif ('uri' == $v['type']) {
+            return '<'.$this->escape($v['value']).'>';
+        }
+        // something went wrong
+        elseif ('literal' != $v['type']) {
+            return $this->getTerm($v['value']);
+        }
+        /* literal */
+        $quot = '"';
+        if ($this->raw && preg_match('/\"/', $v['value'])) {
+            $quot = "'";
+            if (preg_match('/\'/', $v['value'])) {
+                $quot = '"""';
+                if (preg_match('/\"\"\"/', $v['value']) || preg_match('/\"$/', $v['value']) || preg_match('/^\"/', $v['value'])) {
+                    $quot = "'''";
+                    $v['value'] = preg_replace("/'$/", "' ", $v['value']);
+                    $v['value'] = preg_replace("/^'/", " '", $v['value']);
+                    $v['value'] = str_replace("'''", '\\\'\\\'\\\'', $v['value']);
+                }
+            }
+        }
+        if ($this->raw && (1 == strlen($quot)) && preg_match('/[\x0d\x0a]/', $v['value'])) {
+            $quot = $quot.$quot.$quot;
+        }
+        $suffix = isset($v['lang']) && $v['lang'] ? '@'.$v['lang'] : '';
+        $suffix = isset($v['datatype']) && $v['datatype'] ? '^^'.$this->getTerm($v['datatype']) : $suffix;
+        //return $quot . "object" . utf8_encode($v['value']) . $quot . $suffix;
+        return $quot.$this->escape($v['value']).$quot.$suffix;
     }
-    /* literal */
-    $quot = '"';
-    if ($this->raw && preg_match('/\"/', $v['value'])) {
-      $quot = "'";
-      if (preg_match('/\'/', $v['value'])) {
-        $quot = '"""';
-        if (preg_match('/\"\"\"/', $v['value']) || preg_match('/\"$/', $v['value']) || preg_match('/^\"/', $v['value'])) {
-          $quot = "'''";
-          $v['value'] = preg_replace("/'$/", "' ", $v['value']);
-          $v['value'] = preg_replace("/^'/", " '", $v['value']);
-          $v['value'] = str_replace("'''", '\\\'\\\'\\\'', $v['value']);
+
+    public function getSerializedIndex($index, $raw = 0)
+    {
+        $this->raw = $raw;
+        $r = '';
+        $nl = "\n";
+        foreach ($index as $s => $ps) {
+            $s = $this->getTerm($s, 's');
+            foreach ($ps as $p => $os) {
+                $p = $this->getTerm($p, 'p');
+                if (!is_array($os)) {/* single literal o */
+                    $os = [['value' => $os, 'type' => 'literal']];
+                }
+                foreach ($os as $o) {
+                    $o = $this->getTerm($o, 'o‚');
+                    $r .= $r ? $nl : '';
+                    $r .= $s.' '.$p.' '.$o.' .';
+                }
+            }
         }
-      }
+
+        return $r.$nl;
     }
-    if ($this->raw && (strlen($quot) == 1) && preg_match('/[\x0d\x0a]/', $v['value'])) {
-      $quot = $quot . $quot . $quot;
+
+    public function escape($v)
+    {
+        $r = '';
+        // decode, if possible
+        $v = (false === strpos(utf8_decode(str_replace('?', '', $v)), '?')) ? utf8_decode($v) : $v;
+        if ($this->raw) {
+            return $v;
+        } // no further escaping wanted
+        // escape tabs and linefeeds
+        $v = str_replace(["\t", "\r", "\n"], ['\t', '\r', '\n'], $v);
+        // escape non-ascii-chars
+        $v = preg_replace_callback('/([^a-zA-Z0-9 \!\#\$\%\&\(\)\*\+\,\-\.\/\:\;\=\?\@\^\_\{\|\}]+)/', [$this, 'escapeChars'], $v);
+
+        return $v;
     }
-    $suffix = isset($v['lang']) && $v['lang'] ? '@' . $v['lang'] : '';
-    $suffix = isset($v['datatype']) && $v['datatype'] ? '^^' . $this->getTerm($v['datatype']) : $suffix;
-    //return $quot . "object" . utf8_encode($v['value']) . $quot . $suffix;
-    return $quot . $this->escape($v['value']) . $quot . $suffix;
-  }
-  
-  function getSerializedIndex($index, $raw = 0) {
-    $this->raw = $raw;
-    $r = '';
-    $nl = "\n";
-    foreach ($index as $s => $ps) {
-      $s = $this->getTerm($s);
-      foreach ($ps as $p => $os) {
-        $p = $this->getTerm($p);
-        if (!is_array($os)) {/* single literal o */
-          $os = array(array('value' => $os, 'type' => 'literal'));
+
+    public function escapeChars($matches)
+    {
+        $v = $matches[1];
+        $r = '';
+        // loop through mb chars
+        if (function_exists('mb_strlen')) {
+            for ($i = 0, $i_max = mb_strlen($v, 'UTF-8'); $i < $i_max; ++$i) {
+                $c = mb_substr($v, $i, 1, 'UTF-8');
+                if (!isset($this->esc_chars[$c])) {
+                    $this->esc_chars[$c] = $this->getEscapedChar($c, $this->getCharNo($c, 1));
+                }
+                $r .= $this->esc_chars[$c];
+            }
         }
-        foreach ($os as $o) {
-          $o = $this->getTerm($o);
-          $r .= $r ? $nl : '';
-          $r .= $s . ' ' . $p . ' ' . $o . ' .';
+        // fall back to built-in JSON functionality, if available
+        elseif (function_exists('json_encode')) {
+            $r = json_encode($v);
+            if ('null' == $r) {
+                $r = json_encode(utf8_encode($v));
+            }
+            // remove boundary quotes
+            if ('"' == substr($r, 0, 1)) {
+                $r = substr($r, 1);
+            }
+            if ('"' == substr($r, -1)) {
+                $r = substr($r, 0, -1);
+            }
+            // uppercase hex chars
+            $r = preg_replace_callback('/(\\\u)([0-9a-f]{4})', function ($matches) {
+                return $matches[1].strtoupper($matches[2]);
+            }, $r);
+            $r = preg_replace_callback('/(\\\U)([0-9a-f]{8})', function ($matches) {
+                return $matches[1].strtoupper($matches[2]);
+            }, $r);
+        }
+        // escape byte-wise (may be wrong for mb chars and newer php versions)
+        else {
+            for ($i = 0, $i_max = strlen($v); $i < $i_max; ++$i) {
+                $c = $v[$i];
+                if (!isset($this->esc_chars[$c])) {
+                    $this->esc_chars[$c] = $this->getEscapedChar($c, $this->getCharNo($c));
+                }
+                $r .= $this->esc_chars[$c];
+            }
         }
-      }
-    }
-    return $r . $nl;
-  }
-  
-  /*  */
 
-  function escape($v) {
-    $r = '';
-    $v = (strpos(utf8_decode(str_replace('?', '', $v)), '?') === false) ? utf8_decode($v) : $v;
-    if ($this->raw) return $v;
-    for ($i = 0, $i_max = strlen($v); $i < $i_max; $i++) {
-      $c = $v[$i];
-      if (!isset($this->esc_chars[$c])) {
-        $this->esc_chars[$c] = $this->getEscapedChar($c, $this->getCharNo($c));
-      }
-      $r .= $this->esc_chars[$c];
+        return $r;
     }
-    return $r;
-  }
-  
-  /*  */
-  
-  function getCharNo($c) {
-    $c_utf = utf8_encode($c);
-    $bl = strlen($c_utf);/* binary length */
-    $r = 0;
-    switch ($bl) {
+
+    public function getCharNo($c, $is_encoded = false)
+    {
+        $c_utf = $is_encoded ? $c : utf8_encode($c);
+        $bl = strlen($c_utf); /* binary length */
+        $r = 0;
+        switch ($bl) {
       case 1:/* 0####### (0-127) */
         $r = ord($c_utf);
         break;
@@ -118,26 +180,51 @@ class ARC2_NTriplesSerializer extends ARC2_RDFSerializer {
         $r = ((ord($c_utf[0]) - 240) * 262144) + ((ord($c_utf[1]) - 128) * 4096) + ((ord($c_utf[2]) - 128) * 64) + (ord($c_utf[3]) - 128);
         break;
     }
-    return $r;
-  }
 
-  function getEscapedChar($c, $no) {/*see http://www.w3.org/TR/rdf-testcases/#ntrip_strings */
-    if ($no < 9)        return "\\u" . sprintf('%04X', $no);  /* #x0-#x8 (0-8) */
-    if ($no == 9)       return '\t';                          /* #x9 (9) */
-    if ($no == 10)      return '\n';                          /* #xA (10) */
-    if ($no < 13)       return "\\u" . sprintf('%04X', $no);  /* #xB-#xC (11-12) */
-    if ($no == 13)      return '\r';                          /* #xD (13) */
-    if ($no < 32)       return "\\u" . sprintf('%04X', $no);  /* #xE-#x1F (14-31) */
-    if ($no < 34)       return $c;                            /* #x20-#x21 (32-33) */
-    if ($no == 34)      return '\"';                          /* #x22 (34) */
-    if ($no < 92)       return $c;                            /* #x23-#x5B (35-91) */
-    if ($no == 92)      return '\\';                          /* #x5C (92) */
-    if ($no < 127)      return $c;                            /* #x5D-#x7E (93-126) */
-    if ($no < 65536)    return "\\u" . sprintf('%04X', $no);  /* #x7F-#xFFFF (128-65535) */
-    if ($no < 1114112)  return "\\U" . sprintf('%08X', $no);  /* #x10000-#x10FFFF (65536-1114111) */
-    return '';                                                /* not defined => ignore */
-  }
-  
-  /*  */
- 
+        return $r;
+    }
+
+    public function getEscapedChar($c, $no)
+    {/*see http://www.w3.org/TR/rdf-testcases/#ntrip_strings */
+        if ($no < 9) {
+            return '\\u'.sprintf('%04X', $no);
+        }  /* #x0-#x8 (0-8) */
+        if (9 == $no) {
+            return '\t';
+        }                          /* #x9 (9) */
+        if (10 == $no) {
+            return '\n';
+        }                          /* #xA (10) */
+        if ($no < 13) {
+            return '\\u'.sprintf('%04X', $no);
+        }  /* #xB-#xC (11-12) */
+        if (13 == $no) {
+            return '\r';
+        }                          /* #xD (13) */
+        if ($no < 32) {
+            return '\\u'.sprintf('%04X', $no);
+        }  /* #xE-#x1F (14-31) */
+        if ($no < 34) {
+            return $c;
+        }                            /* #x20-#x21 (32-33) */
+        if (34 == $no) {
+            return '\"';
+        }                          /* #x22 (34) */
+        if ($no < 92) {
+            return $c;
+        }                            /* #x23-#x5B (35-91) */
+        if (92 == $no) {
+            return '\\';
+        }                          /* #x5C (92) */
+        if ($no < 127) {
+            return $c;
+        }                            /* #x5D-#x7E (93-126) */
+        if ($no < 65536) {
+            return '\\u'.sprintf('%04X', $no);
+        }  /* #x7F-#xFFFF (128-65535) */
+        if ($no < 1114112) {
+            return '\\U'.sprintf('%08X', $no);
+        }  /* #x10000-#x10FFFF (65536-1114111) */
+        return '';                                                /* not defined => ignore */
+    }
 }
diff --git a/lib/arc2/serializers/ARC2_POSHRDFSerializer.php b/lib/arc2/serializers/ARC2_POSHRDFSerializer.php
old mode 100644
new mode 100755
index 8edd15dfd6ca41ea03724da8da1736964b76a809..d33347a6e7a590cbc8314a1b95960ee5c31f0fb2
--- a/lib/arc2/serializers/ARC2_POSHRDFSerializer.php
+++ b/lib/arc2/serializers/ARC2_POSHRDFSerializer.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 POSH RDF Serializer
 author:   Benjamin Nowack
@@ -10,96 +10,110 @@ version:  2010-11-16
 
 ARC2::inc('RDFSerializer');
 
-class ARC2_POSHRDFSerializer extends ARC2_RDFSerializer {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-    $this->content_header = 'text/html';
-  }
-
-  /*  */
-  
-  function getLabel($res, $ps = '') {
-    if (!$ps) $ps = array();
-    foreach ($ps as $p => $os) {
-      if (preg_match('/[\/\#](name|label|summary|title|fn)$/i', $p)) {
-        return $os[0]['value'];
-      }
+class ARC2_POSHRDFSerializer extends ARC2_RDFSerializer
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
     }
-    if (preg_match('/^\_\:/', $res)) return "An unnamed resource";
-    return preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('_', ' ', $res));
-  }
-  
-  function getSerializedIndex($index, $res = '') {
-    $r = '';
-    $n = "\n";
-    if ($res) $index = array($res => $index[$res]);
-    //return Trice::dump($index);
-    foreach ($index as $s => $ps) {
-      /* node */
-      $r .= '
+
+    public function __init()
+    {
+        parent::__init();
+        $this->content_header = 'text/html';
+    }
+
+    public function getLabel($res, $ps = '')
+    {
+        if (!$ps) {
+            $ps = [];
+        }
+        foreach ($ps as $p => $os) {
+            if (preg_match('/[\/\#](name|label|summary|title|fn)$/i', $p)) {
+                return $os[0]['value'];
+            }
+        }
+        if (preg_match('/^\_\:/', $res)) {
+            return 'An unnamed resource';
+        }
+
+        return preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('_', ' ', $res));
+    }
+
+    public function getSerializedIndex($index, $res = '')
+    {
+        $r = '';
+        $n = "\n";
+        if ($res) {
+            $index = [$res => $index[$res]];
+        }
+        //return Trice::dump($index);
+        foreach ($index as $s => $ps) {
+            /* node */
+            $r .= '
         <div class="rdf-view">
-          <h3><a class="rdf-s" href="' . $s . '">' . $this->getLabel($s, $ps)  . '</a></h3>
+          <h3><a class="rdf-s" href="'.$s.'">'.$this->getLabel($s, $ps).'</a></h3>
       ';
-      /* arcs */
-      foreach ($ps as $p => $os) {
-        $r .= '
+            /* arcs */
+            foreach ($ps as $p => $os) {
+                $r .= '
           <div class="rdf-o-list">
-            <a class="rdf-p" href="' . $p . '">' . ucfirst($this->getLabel($p)) . '</a>
+            <a class="rdf-p" href="'.$p.'">'.ucfirst($this->getLabel($p)).'</a>
         ';
-        foreach ($os as $o) {
-          $r .= $n . $this->getObjectValue($o);
-        }
-        $r .= '    
+                foreach ($os as $o) {
+                    $r .= $n.$this->getObjectValue($o);
+                }
+                $r .= '    
           </div>
         ';
-      }
-      /* node */
-      $r .= '
+            }
+            /* node */
+            $r .= '
         <div class="clb"></div>
         </div>
       ';
+        }
+
+        return $r;
     }
-    return $r;
-  }
-  
-  function getObjectValue($o) {
-    if ($o['type'] == 'uri') {
-      if (preg_match('/(jpe?g|gif|png)$/i', $o['value'])) {
-        return $this->getImageObjectValue($o);
-      }
-      return $this->getURIObjectValue($o);
+
+    public function getObjectValue($o)
+    {
+        if ('uri' == $o['type']) {
+            if (preg_match('/(jpe?g|gif|png)$/i', $o['value'])) {
+                return $this->getImageObjectValue($o);
+            }
+
+            return $this->getURIObjectValue($o);
+        }
+        if ('bnode' == $o['type']) {
+            return $this->getBNodeObjectValue($o);
+        }
+
+        return $this->getLiteralObjectValue($o);
     }
-    if ($o['type'] == "bnode") {
-      return $this->getBNodeObjectValue($o);
+
+    public function getImageObjectValue($o)
+    {
+        return '<img class="rdf-o" src="'.htmlspecialchars($o['value']).'" alt="img" />';
     }
-    return $this->getLiteralObjectValue($o);
-  }
-  
-  function getImageObjectValue($o) {
-    return '<img class="rdf-o" src="' . htmlspecialchars($o['value']) . '" alt="img" />';
-  }
-  
-  function getURIObjectValue($o) {
-    $href = htmlspecialchars($o['value']);
-    $label = $o['value'];
-    $label = preg_replace('/^https?\:\/\/(www\.)?/', '', $label);
-    return '<a class="rdf-o" href="' . $href . '">' . $label . '</a>';
-  }
-
-  function getBNodeObjectValue($o) {
-    return '<div class="rdf-o" title="' . $o['value']. '">An unnamed resource</div>';
-  }
-
-  function getLiteralObjectValue($o) {
-    return '<div class="rdf-o">' . $o['value'] . '</div>';
-  }
-
-  /*  */
 
-}
+    public function getURIObjectValue($o)
+    {
+        $href = htmlspecialchars($o['value']);
+        $label = $o['value'];
+        $label = preg_replace('/^https?\:\/\/(www\.)?/', '', $label);
 
+        return '<a class="rdf-o" href="'.$href.'">'.$label.'</a>';
+    }
+
+    public function getBNodeObjectValue($o)
+    {
+        return '<div class="rdf-o" title="'.$o['value'].'">An unnamed resource</div>';
+    }
+
+    public function getLiteralObjectValue($o)
+    {
+        return '<div class="rdf-o">'.$o['value'].'</div>';
+    }
+}
diff --git a/lib/arc2/serializers/ARC2_RDFJSONSerializer.php b/lib/arc2/serializers/ARC2_RDFJSONSerializer.php
index 76d0d282f9764360f198432be23fc62a630b22f9..3997a55ef1734499a7889da9989bb4c2adefa4ac 100644
--- a/lib/arc2/serializers/ARC2_RDFJSONSerializer.php
+++ b/lib/arc2/serializers/ARC2_RDFJSONSerializer.php
@@ -1,88 +1,92 @@
 <?php
 /**
- * ARC2 RDF/JSON Serializer
+ * ARC2 RDF/JSON Serializer.
  *
  * @author Benjamin Nowack <bnowack@semsol.com>
- * @license http://arc.semsol.org/license
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
- * @version 2010-11-16
-*/
-
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ */
 ARC2::inc('RDFSerializer');
 
-class ARC2_RDFJSONSerializer extends ARC2_RDFSerializer {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-    $this->content_header = 'application/json';
-  }
-
-  /*  */
-  
-  function getTerm($v, $term = 's') {
-    if (!is_array($v)) {
-      if (preg_match('/^\_\:/', $v)) {
-        return ($term == 'o') ? $this->getTerm(array('value' => $v, 'type' => 'bnode'), 'o') : '"' . $v . '"';
-      }
-      return ($term == 'o') ? $this->getTerm(array('value' => $v, 'type' => 'uri'), 'o') : '"' . $v . '"';
+class ARC2_RDFJSONSerializer extends ARC2_RDFSerializer
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
     }
-    if (!isset($v['type']) || ($v['type'] != 'literal')) {
-      if ($term != 'o') {
-        return $this->getTerm($v['value'], $term);
-      }
-      if (preg_match('/^\_\:/', $v['value'])) {
-        return '{ "value" : "' . $this->jsonEscape($v['value']) . '", "type" : "bnode" }';
-      }
-      return '{ "value" : "' . $this->jsonEscape($v['value']) . '", "type" : "uri" }';
+
+    public function __init()
+    {
+        parent::__init();
+        $this->content_header = 'application/json';
     }
-    /* literal */
-    $r = '{ "value" : "' . $this->jsonEscape($v['value']) . '", "type" : "literal"';
-    $suffix = isset($v['datatype']) ? ', "datatype" : "' . $v['datatype'] . '"' : '';
-    $suffix = isset($v['lang']) ? ', "lang" : "' . $v['lang'] . '"' : $suffix;
-    $r .= $suffix . ' }';
-    return $r;
-  }
 
-  function jsonEscape($v) {
-    if (function_exists('json_encode')) return trim(json_encode($v), '"');
-    $from = array("\\", "\r", "\t", "\n", '"', "\b", "\f", "/");
-    $to = array('\\\\', '\r', '\t', '\n', '\"', '\b', '\f', '\/');
-    return str_replace($from, $to, $v);
-  }
-    
-  function getSerializedIndex($index, $raw = 0) {
-    $r = '';
-    $nl = "\n";
-    foreach ($index as $s => $ps) {
-      $r .= $r ? ',' . $nl . $nl : '';
-      $r .= '  ' . $this->getTerm($s). ' : {';
-      $first_p = 1;
-      foreach ($ps as $p => $os) {
-        $r .= $first_p ? $nl : ',' . $nl;
-        $r .= '    ' . $this->getTerm($p). ' : [';
-        $first_o = 1;
-        if (!is_array($os)) {/* single literal o */
-          $os = array(array('value' => $os, 'type' => 'literal'));
+    public function getTerm($v, $term = 's')
+    {
+        if (!is_array($v)) {
+            if (preg_match('/^\_\:/', $v)) {
+                return ('o' == $term) ? $this->getTerm(['value' => $v, 'type' => 'bnode'], 'o') : '"'.$v.'"';
+            }
+
+            return ('o' == $term) ? $this->getTerm(['value' => $v, 'type' => 'uri'], 'o') : '"'.$v.'"';
+        }
+        if (!isset($v['type']) || ('literal' != $v['type'])) {
+            if ('o' != $term) {
+                return $this->getTerm($v['value'], $term);
+            }
+            if (preg_match('/^\_\:/', $v['value'])) {
+                return '{ "value" : "'.$this->jsonEscape($v['value']).'", "type" : "bnode" }';
+            }
+
+            return '{ "value" : "'.$this->jsonEscape($v['value']).'", "type" : "uri" }';
         }
-        foreach ($os as $o) {
-          $r .= $first_o ? $nl : ',' . $nl;
-          $r .= '      ' . $this->getTerm($o, 'o');
-          $first_o = 0;
+        /* literal */
+        $r = '{ "value" : "'.$this->jsonEscape($v['value']).'", "type" : "literal"';
+        $suffix = isset($v['datatype']) ? ', "datatype" : "'.$v['datatype'].'"' : '';
+        $suffix = isset($v['lang']) ? ', "lang" : "'.$v['lang'].'"' : $suffix;
+        $r .= $suffix.' }';
+
+        return $r;
+    }
+
+    public function jsonEscape($v)
+    {
+        if (function_exists('json_encode')) {
+            return preg_replace('/^"(.*)"$/', '\\1', str_replace("\/", '/', json_encode($v)));
         }
-        $first_p = 0;
-        $r .= $nl . '    ]';
-      }
-      $r .= $nl . '  }';
+        $from = ['\\', "\r", "\t", "\n", '"', "\b", "\f"];
+        $to = ['\\\\', '\r', '\t', '\n', '\"', '\b', '\f'];
+
+        return str_replace($from, $to, $v);
     }
-    $r .= $r ? ' ' : '';
-    return '{' . $nl . $r . $nl . '}';
-  }
-  
-  /*  */
 
+    public function getSerializedIndex($index, $raw = 0)
+    {
+        $r = '';
+        $nl = "\n";
+        foreach ($index as $s => $ps) {
+            $r .= $r ? ','.$nl.$nl : '';
+            $r .= '  '.$this->getTerm($s).' : {';
+            $first_p = 1;
+            foreach ($ps as $p => $os) {
+                $r .= $first_p ? $nl : ','.$nl;
+                $r .= '    '.$this->getTerm($p).' : [';
+                $first_o = 1;
+                if (!is_array($os)) {/* single literal o */
+                    $os = [['value' => $os, 'type' => 'literal']];
+                }
+                foreach ($os as $o) {
+                    $r .= $first_o ? $nl : ','.$nl;
+                    $r .= '      '.$this->getTerm($o, 'o');
+                    $first_o = 0;
+                }
+                $first_p = 0;
+                $r .= $nl.'    ]';
+            }
+            $r .= $nl.'  }';
+        }
+        $r .= $r ? ' ' : '';
+
+        return '{'.$nl.$r.$nl.'}';
+    }
 }
diff --git a/lib/arc2/serializers/ARC2_RDFSerializer.php b/lib/arc2/serializers/ARC2_RDFSerializer.php
old mode 100644
new mode 100755
index c9034abe3e0a0e27b90f3ea02476e578ca95a4fd..21aea982cc507b1b44046c2b0a228dd5a001b80e
--- a/lib/arc2/serializers/ARC2_RDFSerializer.php
+++ b/lib/arc2/serializers/ARC2_RDFSerializer.php
@@ -1,53 +1,53 @@
 <?php
 /**
- * ARC2 RDF Serializer
+ * ARC2 RDF Serializer.
  *
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('Class');
 
-class ARC2_RDFSerializer extends ARC2_Class {
+class ARC2_RDFSerializer extends ARC2_Class
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
+
+    public function __init()
+    {
+        parent::__init();
+        foreach ($this->ns as $k => $v) {
+            $this->nsp[$v] = $k;
+        }
+    }
+
+    public function xgetPName($v)
+    {/* moved to merged getPName in ARC2_CLass */
+        if (preg_match('/^([a-z0-9\_\-]+)\:([a-z\_][a-z0-9\_\-]*)$/i', $v, $m) && isset($this->ns[$m[1]])) {
+            $this->used_ns = !in_array($this->ns[$m[1]], $this->used_ns) ? array_merge($this->used_ns, [$this->ns[$m[1]]]) : $this->used_ns;
+
+            return $v;
+        }
+        if (preg_match('/^(.*[\/\#])([a-z\_][a-z0-9\-\_]*)$/i', $v, $m)) {
+            return $this->getPrefix($m[1]).':'.$m[2];
+        }
 
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-    foreach ($this->ns as $k => $v) {
-      $this->nsp[$v] = $k;
+        return 0;
     }
-  }
-
-  /*  */
-  
-  function xgetPName($v) {/* moved to merged getPName in ARC2_CLass */
-    if (preg_match('/^([a-z0-9\_\-]+)\:([a-z\_][a-z0-9\_\-]*)$/i', $v, $m) && isset($this->ns[$m[1]])) {
-      $this->used_ns = !in_array($this->ns[$m[1]], $this->used_ns) ? array_merge($this->used_ns, array($this->ns[$m[1]])) : $this->used_ns;
-      return $v;
+
+    public function getSerializedTriples($triples, $raw = 0)
+    {
+        $index = ARC2::getSimpleIndex($triples, 0);
+
+        return $this->getSerializedIndex($index, $raw);
     }
-    if (preg_match('/^(.*[\/\#])([a-z\_][a-z0-9\-\_]*)$/i', $v, $m)) {
-      return $this->getPrefix($m[1]) . ':' . $m[2];
+
+    public function getSerializedIndex($index, $raw = 0)
+    {
+        return '';
     }
-    return 0;
-  }
-  
-  /*  */
-  
-  function getSerializedTriples($triples, $raw = 0) {
-    $index = ARC2::getSimpleIndex($triples, 0);
-    return $this->getSerializedIndex($index, $raw);
-  }
-  
-  function getSerializedIndex($index, $raw = 0) {
-    return '';
-  }
-  
-  /*  */
-  
 }
diff --git a/lib/arc2/serializers/ARC2_RDFXMLSerializer.php b/lib/arc2/serializers/ARC2_RDFXMLSerializer.php
index d960292b9bce62a9b825ad874095359196d3e4d3..f7ebcabbc3830b211b0f975b1a06bb53b4bc9c6e 100644
--- a/lib/arc2/serializers/ARC2_RDFXMLSerializer.php
+++ b/lib/arc2/serializers/ARC2_RDFXMLSerializer.php
@@ -1,198 +1,233 @@
 <?php
 /**
- * ARC2 RDF/XML Serializer
+ * ARC2 RDF/XML Serializer.
  *
  * @author    Benjamin Nowack
- * @license   <http://arc.semsol.org/license>
- * @homepage  <http://arc.semsol.org/>
- * @package   ARC2
+ * @license   W3C Software License and GPL
+ * @homepage  <https://github.com/semsol/arc2>
+ *
  * @version   2010-11-16
-*/
-
+ */
 ARC2::inc('RDFSerializer');
 
-class ARC2_RDFXMLSerializer extends ARC2_RDFSerializer {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-    $this->content_header = 'application/rdf+xml';
-    $this->pp_containers = $this->v('serializer_prettyprint_containers', 0, $this->a);
-    $this->default_ns = $this->v('serializer_default_ns', '', $this->a);
-    $this->type_nodes = $this->v('serializer_type_nodes', 0, $this->a);
-  }
-
-  /*  */
-  
-  function getTerm($v, $type) {
-    if (!is_array($v)) {/* uri or bnode */
-      if (preg_match('/^\_\:(.*)$/', $v, $m)) {
-        return ' rdf:nodeID="' . $m[1] . '"';
-      }
-      if ($type == 's') {
-        return ' rdf:about="' . htmlspecialchars($v) . '"';
-      }
-      if ($type == 'p') {
-        $pn = $this->getPName($v);
-        return $pn ? $pn : 0;
-      }
-      if ($type == 'o') {
-        $v = $this->expandPName($v);
-        if (!preg_match('/^[a-z0-9]{2,}\:[^\s]+$/is', $v)) return $this->getTerm(array('value' => $v, 'type' => 'literal'), $type);
-        return ' rdf:resource="' . htmlspecialchars($v) . '"';
-      }
-      if ($type == 'datatype') {
-        $v = $this->expandPName($v);
-        return ' rdf:datatype="' . htmlspecialchars($v) . '"';
-      }
-      if ($type == 'lang') {
-        return ' xml:lang="' . htmlspecialchars($v) . '"';
-      }
-    }
-    if ($this->v('type', '', $v) != 'literal') {
-      return $this->getTerm($v['value'], 'o');
+class ARC2_RDFXMLSerializer extends ARC2_RDFSerializer
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
     }
-    /* literal */
-    $dt = isset($v['datatype']) ? $v['datatype'] : '';
-    $lang = isset($v['lang']) ? $v['lang'] : '';
-    if ($dt == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral') {
-      return ' rdf:parseType="Literal">' . $v['value'];
-    }
-    elseif ($dt) {
-      return $this->getTerm($dt, 'datatype') . '>' . htmlspecialchars($v['value']);
+
+    public function __init()
+    {
+        parent::__init();
+        $this->content_header = 'application/rdf+xml';
+        $this->pp_containers = $this->v('serializer_prettyprint_containers', 0, $this->a);
+        $this->default_ns = $this->v('serializer_default_ns', '', $this->a);
+        $this->type_nodes = $this->v('serializer_type_nodes', 0, $this->a);
     }
-    elseif ($lang) {
-      return $this->getTerm($lang, 'lang') . '>' . htmlspecialchars($v['value']);
+
+    public function getTerm($v, $type)
+    {
+        if (!is_array($v)) {/* uri or bnode */
+            if (preg_match('/^\_\:(.*)$/', $v, $m)) {
+                return ' rdf:nodeID="'.$m[1].'"';
+            }
+            if ('s' == $type) {
+                return ' rdf:about="'.htmlspecialchars($v).'"';
+            }
+            if ('p' == $type) {
+                $pn = $this->getPName($v);
+
+                return $pn ? $pn : 0;
+            }
+            if ('o' == $type) {
+                $v = $this->expandPName($v);
+                if (!preg_match('/^[a-z0-9]{2,}\:[^\s]+$/is', $v)) {
+                    return $this->getTerm(['value' => $v, 'type' => 'literal'], $type);
+                }
+
+                return ' rdf:resource="'.htmlspecialchars($v).'"';
+            }
+            if ('datatype' == $type) {
+                $v = $this->expandPName($v);
+
+                return ' rdf:datatype="'.htmlspecialchars($v).'"';
+            }
+            if ('lang' == $type) {
+                return ' xml:lang="'.htmlspecialchars($v).'"';
+            }
+        }
+        if ('literal' != $this->v('type', '', $v)) {
+            return $this->getTerm($v['value'], 'o');
+        }
+        /* literal */
+        $dt = isset($v['datatype']) ? $v['datatype'] : '';
+        $lang = isset($v['lang']) ? $v['lang'] : '';
+        if ('http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral' == $dt) {
+            return ' rdf:parseType="Literal">'.$v['value'];
+        } elseif ($dt) {
+            return $this->getTerm($dt, 'datatype').'>'.htmlspecialchars($v['value']);
+        } elseif ($lang) {
+            return $this->getTerm($lang, 'lang').'>'.htmlspecialchars($v['value']);
+        }
+
+        return '>'.htmlspecialchars($this->v('value', '', $v));
     }
-    return '>' . htmlspecialchars($this->v('value', '', $v));
-  }
 
-  function getPName($v, $connector = ':') {
-    if ($this->default_ns && (strpos($v, $this->default_ns) === 0)) {
-      $pname = substr($v, strlen($this->default_ns));
-      if (!preg_match('/\//', $pname)) return $pname;
+    public function getPName($v, $connector = ':')
+    {
+        if ($this->default_ns && (0 === strpos($v, $this->default_ns))) {
+            $pname = substr($v, strlen($this->default_ns));
+            if (!preg_match('/\//', $pname)) {
+                return $pname;
+            }
+        }
+
+        return parent::getPName($v, $connector);
     }
-    return parent::getPName($v, $connector);
-  }
-  
-  function getHead() {
-    $r = '';
-    $nl = "\n";
-    $r .= '<?xml version="1.0" encoding="UTF-8"?>';
-    $r .= $nl . '<rdf:RDF';
-    $first_ns = 1;
-    foreach ($this->used_ns as $v) {
-      $r .= $first_ns ? ' ' : $nl . '  ';
-      foreach ($this->ns as $prefix => $ns) {
-        if ($ns != $v) continue;
-        $r .= 'xmlns:' . $prefix . '="' .$v. '"';
-        break;
-      }
-      $first_ns = 0;
+
+    public function getHead()
+    {
+        $r = '';
+        $nl = "\n";
+        $r .= '<?xml version="1.0" encoding="UTF-8"?>';
+        $r .= $nl.'<rdf:RDF';
+        $first_ns = 1;
+        foreach ($this->used_ns as $v) {
+            $r .= $first_ns ? ' ' : $nl.'  ';
+            foreach ($this->ns as $prefix => $ns) {
+                if ($ns != $v) {
+                    continue;
+                }
+                $r .= 'xmlns:'.$prefix.'="'.$v.'"';
+                break;
+            }
+            $first_ns = 0;
+        }
+        if ($this->default_ns) {
+            $r .= $first_ns ? ' ' : $nl.'  ';
+            $r .= 'xmlns="'.$this->default_ns.'"';
+        }
+        $r .= '>';
+
+        return $r;
     }
-    if ($this->default_ns) {
-      $r .= $first_ns ? ' ' : $nl . '  ';
-      $r .= 'xmlns="' . $this->default_ns . '"';
+
+    public function getFooter()
+    {
+        $r = '';
+        $nl = "\n";
+        $r .= $nl.$nl.'</rdf:RDF>';
+
+        return $r;
     }
-    $r .= '>';
-    return $r;
-  }
-  
-  function getFooter() {
-    $r = '';
-    $nl = "\n";
-    $r .= $nl . $nl . '</rdf:RDF>';
-    return $r;
-  }
-  
-  function getSerializedIndex($index, $raw = 0) {
-    $r = '';
-    $nl = "\n";
-    foreach ($index as $raw_s => $ps) {
-      $r .= $r ? $nl . $nl : '';
-      $s = $this->getTerm($raw_s, 's');
-      $tag = 'rdf:Description';
-      list($tag, $ps) = $this->getNodeTag($ps);
-      $sub_ps = 0;
-      /* pretty containers */
-      if ($this->pp_containers && ($ctag = $this->getContainerTag($ps))) {
-        $tag = 'rdf:' . $ctag;
-        list($ps, $sub_ps) = $this->splitContainerEntries($ps);
-      }
-      $r .= '  <' . $tag . '' .$s . '>';
-      $first_p = 1;
-      foreach ($ps as $p => $os) {
-        if (!$os) continue;
-        $p = $this->getTerm($p, 'p');
-        if ($p) {
-          $r .= $nl . str_pad('', 4);
-          $first_o = 1;
-          if (!is_array($os)) {/* single literal o */
-            $os = array(array('value' => $os, 'type' => 'literal'));
-          }
-          foreach ($os as $o) {
-            $o = $this->getTerm($o, 'o');
-            $r .= $first_o ? '' : $nl . '    ';
-            $r .= '<' . $p;
-            $r .= $o;
-            $r .= preg_match('/\>/', $o) ? '</' . $p . '>' : '/>'; 
-            $first_o = 0;
-          }
-          $first_p = 0;
+
+    public function getSerializedIndex($index, $raw = 0)
+    {
+        $r = '';
+        $nl = "\n";
+        foreach ($index as $raw_s => $ps) {
+            $r .= $r ? $nl.$nl : '';
+            $s = $this->getTerm($raw_s, 's');
+            $tag = 'rdf:Description';
+            list($tag, $ps) = $this->getNodeTag($ps);
+            $sub_ps = 0;
+            /* pretty containers */
+            if ($this->pp_containers && ($ctag = $this->getContainerTag($ps))) {
+                $tag = 'rdf:'.$ctag;
+                list($ps, $sub_ps) = $this->splitContainerEntries($ps);
+            }
+            $r .= '  <'.$tag.''.$s.'>';
+            $first_p = 1;
+            foreach ($ps as $p => $os) {
+                if (!$os) {
+                    continue;
+                }
+                $p = $this->getTerm($p, 'p');
+                if ($p) {
+                    $r .= $nl.str_pad('', 4);
+                    $first_o = 1;
+                    if (!is_array($os)) {/* single literal o */
+                        $os = [['value' => $os, 'type' => 'literal']];
+                    }
+                    foreach ($os as $o) {
+                        $o = $this->getTerm($o, 'o');
+                        $r .= $first_o ? '' : $nl.'    ';
+                        $r .= '<'.$p;
+                        $r .= $o;
+                        $r .= preg_match('/\>/', $o) ? '</'.$p.'>' : '/>';
+                        $first_o = 0;
+                    }
+                    $first_p = 0;
+                }
+            }
+            $r .= $r ? $nl.'  </'.$tag.'>' : '';
+            if ($sub_ps) {
+                $r .= $nl.$nl.$this->getSerializedIndex([$raw_s => $sub_ps], 1);
+            }
         }
-      }
-      $r .= $r ? $nl . '  </' . $tag . '>' : '';
-      if ($sub_ps) $r .= $nl . $nl . $this->getSerializedIndex(array($raw_s => $sub_ps), 1);
-    }
-    if ($raw) {
-      return $r;
+        if ($raw) {
+            return $r;
+        }
+
+        return $this->getHead().$nl.$nl.$r.$this->getFooter();
     }
-    return $this->getHead() . $nl . $nl . $r . $this->getFooter();
-  }
-
-  function getNodeTag($ps) {
-    if (!$this->type_nodes) return array('rdf:Description', $ps);
-    $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
-    $types = $this->v($rdf . 'type', array(), $ps);
-    if (!$types) return array('rdf:Description', $ps);
-    $type = array_shift($types);
-    $ps[$rdf . 'type'] = $types;
-    if (!is_array($type)) $type = array('value' => $type);
-    return array($this->getPName($type['value']), $ps);
-  }
-
-  /*  */
-
-  function getContainerTag($ps) {
-    $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
-    if (!isset($ps[$rdf . 'type'])) return '';
-    $types = $ps[$rdf . 'type'];
-    foreach ($types as $type) {
-      if (!in_array($type['value'], array($rdf . 'Bag', $rdf . 'Seq', $rdf . 'Alt'))) return '';
-      return str_replace($rdf, '', $type['value']);
+
+    public function getNodeTag($ps)
+    {
+        if (!$this->type_nodes) {
+            return ['rdf:Description', $ps];
+        }
+        $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+        $types = $this->v($rdf.'type', [], $ps);
+        if (!$types) {
+            return ['rdf:Description', $ps];
+        }
+        $type = array_shift($types);
+        $ps[$rdf.'type'] = $types;
+        if (!is_array($type)) {
+            $type = ['value' => $type];
+        }
+
+        return [$this->getPName($type['value']), $ps];
     }
-  }
-
-  function splitContainerEntries($ps) {
-    $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
-    $items = array();
-    $rest = array();
-    foreach ($ps as $p => $os) {
-      $p_short = str_replace($rdf, '', $p);
-      if ($p_short === 'type') continue;
-      if (preg_match('/^\_([0-9]+)$/', $p_short, $m)) {
-        $items = array_merge($items, $os);
-      }
-      else {
-        $rest[$p] = $os;
-      }
+
+    public function getContainerTag($ps)
+    {
+        $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+        if (!isset($ps[$rdf.'type'])) {
+            return '';
+        }
+        $types = $ps[$rdf.'type'];
+        foreach ($types as $type) {
+            if (!in_array($type['value'], [$rdf.'Bag', $rdf.'Seq', $rdf.'Alt'])) {
+                return '';
+            }
+
+            return str_replace($rdf, '', $type['value']);
+        }
     }
-    if ($items) return array(array($rdf . 'li' => $items), $rest);
-    return array($rest, 0);
-  }
 
-  /*  */
+    public function splitContainerEntries($ps)
+    {
+        $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+        $items = [];
+        $rest = [];
+        foreach ($ps as $p => $os) {
+            $p_short = str_replace($rdf, '', $p);
+            if ('type' === $p_short) {
+                continue;
+            }
+            if (preg_match('/^\_([0-9]+)$/', $p_short, $m)) {
+                $items = array_merge($items, $os);
+            } else {
+                $rest[$p] = $os;
+            }
+        }
+        if ($items) {
+            return [[$rdf.'li' => $items], $rest];
+        }
+
+        return [$rest, 0];
+    }
 }
diff --git a/lib/arc2/serializers/ARC2_RSS10Serializer.php b/lib/arc2/serializers/ARC2_RSS10Serializer.php
old mode 100644
new mode 100755
index 6575b4626ee0f98aea728aadb9e488252aef5e93..7a4c61cf7823b41135220b5e99c41b973637e69b
--- a/lib/arc2/serializers/ARC2_RSS10Serializer.php
+++ b/lib/arc2/serializers/ARC2_RSS10Serializer.php
@@ -1,30 +1,28 @@
 <?php
 /**
- * ARC2 RSS 1.0 Serializer
+ * ARC2 RSS 1.0 Serializer.
  *
  * @author Toby Inkster
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('RDFXMLSerializer');
 
-class ARC2_RSS10Serializer extends ARC2_RDFXMLSerializer {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-    $this->content_header = 'application/rss+xml';
-    $this->default_ns = 'http://purl.org/rss/1.0/';
-    $this->type_nodes = true;
-  }
+class ARC2_RSS10Serializer extends ARC2_RDFXMLSerializer
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
 
-  /*  */
-  
+    public function __init()
+    {
+        parent::__init();
+        $this->content_header = 'application/rss+xml';
+        $this->default_ns = 'http://purl.org/rss/1.0/';
+        $this->type_nodes = true;
+    }
 }
diff --git a/lib/arc2/serializers/ARC2_TurtleSerializer.php b/lib/arc2/serializers/ARC2_TurtleSerializer.php
index 041ca0cf5a1f90ec58b16b860b031b48463ce881..84e423215942661e595685517e9f26b350557532 100644
--- a/lib/arc2/serializers/ARC2_TurtleSerializer.php
+++ b/lib/arc2/serializers/ARC2_TurtleSerializer.php
@@ -1,121 +1,128 @@
 <?php
 /**
- * ARC2 Turtle Serializer
+ * ARC2 Turtle Serializer.
  *
  * @author    Benjamin Nowack
- * @license   http://arc.semsol.org/license
- * @homepage <http://arc.semsol.org/>
- * @package   ARC2
+ * @license   W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ *
  * @version   2010-11-16
-*/
-
+ */
 ARC2::inc('RDFSerializer');
 
-class ARC2_TurtleSerializer extends ARC2_RDFSerializer {
+class ARC2_TurtleSerializer extends ARC2_RDFSerializer
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
 
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-    $this->content_header = 'application/x-turtle';
-  }
+    public function __init()
+    {
+        parent::__init();
+        $this->content_header = 'application/x-turtle';
+    }
 
-  /*  */
-  
-  function getTerm($v, $term = '', $qualifier = '') {
-    if (!is_array($v)) {
-      if (preg_match('/^\_\:/', $v)) {
-        return $v;
-      }
-      if (($term === 'p') && ($pn = $this->getPName($v))) {
-        return $pn;
-      }
-      if (
-        ($term === 'o') &&
-        in_array($qualifier, array('rdf:type', 'rdfs:domain', 'rdfs:range', 'rdfs:subClassOf')) &&
+    public function getTerm($v, $term = '', $qualifier = '')
+    {
+        if (!is_array($v)) {
+            if (preg_match('/^\_\:/', $v)) {
+                return $v;
+            }
+            if (('p' === $term) && ($pn = $this->getPName($v))) {
+                return $pn;
+            }
+            if (
+        ('o' === $term) &&
+        in_array($qualifier, ['rdf:type', 'rdfs:domain', 'rdfs:range', 'rdfs:subClassOf']) &&
         ($pn = $this->getPName($v))
       ) {
-        return $pn;
-      }
-      if (preg_match('/^[a-z0-9]+\:[^\s]*$/is', $v)) {
-        return '<' .$v. '>';
-      }
-      return $this->getTerm(array('type' => 'literal', 'value' => $v), $term, $qualifier);
-    }
-    if (!isset($v['type']) || ($v['type'] != 'literal')) {
-      return $this->getTerm($v['value'], $term, $qualifier);
-    }
-    /* literal */
-    $quot = '"';
-    if (preg_match('/\"/', $v['value'])) {
-      $quot = "'";
-      if (preg_match('/\'/', $v['value']) || preg_match('/[\x0d\x0a]/', $v['value'])) {
-        $quot = '"""';
-        if (preg_match('/\"\"\"/', $v['value']) || preg_match('/\"$/', $v['value']) || preg_match('/^\"/', $v['value'])) {
-          $quot = "'''";
-          $v['value'] = preg_replace("/'$/", "' ", $v['value']);
-          $v['value'] = preg_replace("/^'/", " '", $v['value']);
-          $v['value'] = str_replace("'''", '\\\'\\\'\\\'', $v['value']);
+                return $pn;
+            }
+            if (preg_match('/^[a-z0-9]+\:[^\s]*$/is'.($this->has_pcre_unicode ? 'u' : ''), $v)) {
+                return '<'.$v.'>';
+            }
+
+            return $this->getTerm(['type' => 'literal', 'value' => $v], $term, $qualifier);
         }
-      }
-    }
-    if ((strlen($quot) == 1) && preg_match('/[\x0d\x0a]/', $v['value'])) {
-      $quot = $quot . $quot . $quot;
-    }
-    $suffix = isset($v['lang']) && $v['lang'] ? '@' . $v['lang'] : '';
-    $suffix = isset($v['datatype']) && $v['datatype'] ? '^^' . $this->getTerm($v['datatype'], 'dt') : $suffix;
-    return $quot . $v['value'] . $quot . $suffix;
-  }
-  
-  function getHead() {
-    $r = '';
-    $nl = "\n";
-    foreach ($this->used_ns as $v) {
-      $r .= $r ? $nl : '';
-      foreach ($this->ns as $prefix => $ns) {
-        if ($ns != $v) continue;
-        $r .= '@prefix ' . $prefix . ': <' .$v. '> .';
-        break;
-      }
-    }
-    return $r;
-  }
-  
-  function getSerializedIndex($index, $raw = 0) {
-    $r = '';
-    $nl = "\n";
-    foreach ($index as $s => $ps) {
-      $r .= $r ? ' .' . $nl . $nl : '';
-      $s = $this->getTerm($s, 's');
-      $r .= $s;
-      $first_p = 1;
-      foreach ($ps as $p => $os) {
-        if (!$os) continue;
-        $p = $this->getTerm($p, 'p');
-        $r .= $first_p ? ' ' : ' ;' . $nl . str_pad('', strlen($s) + 1);
-        $r .= $p;
-        $first_o = 1;
-        if (!is_array($os)) {/* single literal o */
-          $os = array(array('value' => $os, 'type' => 'literal'));
+        if (!isset($v['type']) || ('literal' != $v['type'])) {
+            return $this->getTerm($v['value'], $term, $qualifier);
         }
-        foreach ($os as $o) {
-          $r .= $first_o ? ' ' : ' ,' . $nl . str_pad('', strlen($s) + strlen($p) + 2);
-          $o = $this->getTerm($o, 'o', $p);
-          $r .= $o;
-          $first_o = 0;
+        /* literal */
+        $quot = '"';
+        if (preg_match('/\"/', $v['value'])) {
+            $quot = "'";
+            if (preg_match('/\'/', $v['value']) || preg_match('/[\x0d\x0a]/', $v['value'])) {
+                $quot = '"""';
+                if (preg_match('/\"\"\"/', $v['value']) || preg_match('/\"$/', $v['value']) || preg_match('/^\"/', $v['value'])) {
+                    $quot = "'''";
+                    $v['value'] = preg_replace("/'$/", "' ", $v['value']);
+                    $v['value'] = preg_replace("/^'/", " '", $v['value']);
+                    $v['value'] = str_replace("'''", '\\\'\\\'\\\'', $v['value']);
+                }
+            }
         }
-        $first_p = 0;
-      }
+        if ((1 == strlen($quot)) && preg_match('/[\x0d\x0a]/', $v['value'])) {
+            $quot = $quot.$quot.$quot;
+        }
+        $suffix = isset($v['lang']) && $v['lang'] ? '@'.$v['lang'] : '';
+        $suffix = isset($v['datatype']) && $v['datatype'] ? '^^'.$this->getTerm($v['datatype'], 'dt') : $suffix;
+
+        return $quot.$v['value'].$quot.$suffix;
     }
-    $r .= $r ? ' .' : '';
-    if ($raw) {
-      return $r;
+
+    public function getHead()
+    {
+        $r = '';
+        $nl = "\n";
+        foreach ($this->used_ns as $v) {
+            $r .= $r ? $nl : '';
+            foreach ($this->ns as $prefix => $ns) {
+                if ($ns != $v) {
+                    continue;
+                }
+                $r .= '@prefix '.$prefix.': <'.$v.'> .';
+                break;
+            }
+        }
+
+        return $r;
     }
-    return $r ? $this->getHead() . $nl . $nl . $r : '';
-  }
-  
-  /*  */
 
+    public function getSerializedIndex($index, $raw = 0)
+    {
+        $r = '';
+        $nl = "\n";
+        foreach ($index as $s => $ps) {
+            $r .= $r ? ' .'.$nl.$nl : '';
+            $s = $this->getTerm($s, 's');
+            $r .= $s;
+            $first_p = 1;
+            foreach ($ps as $p => $os) {
+                if (!$os) {
+                    continue;
+                }
+                $p = $this->getTerm($p, 'p');
+                $r .= $first_p ? ' ' : ' ;'.$nl.str_pad('', strlen($s) + 1);
+                $r .= $p;
+                $first_o = 1;
+                if (!is_array($os)) {/* single literal o */
+                    $os = [['value' => $os, 'type' => 'literal']];
+                }
+                foreach ($os as $o) {
+                    $r .= $first_o ? ' ' : ' ,'.$nl.str_pad('', strlen($s) + strlen($p) + 2);
+                    $o = $this->getTerm($o, 'o', $p);
+                    $r .= $o;
+                    $first_o = 0;
+                }
+                $first_p = 0;
+            }
+        }
+        $r .= $r ? ' .' : '';
+        if ($raw) {
+            return $r;
+        }
+
+        return $r ? $this->getHead().$nl.$nl.$r : '';
+    }
 }
diff --git a/lib/arc2/sparqlscript/ARC2_SPARQLScriptParser.php b/lib/arc2/sparqlscript/ARC2_SPARQLScriptParser.php
old mode 100644
new mode 100755
index 7dc3689eb5b3433b1f0ace45788e10f003aa8fd5..4da4c588899cce0e90a4875eb971d97deecd7ba7
--- a/lib/arc2/sparqlscript/ARC2_SPARQLScriptParser.php
+++ b/lib/arc2/sparqlscript/ARC2_SPARQLScriptParser.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 SPARQLScript Parser (SPARQL+ + functions)
 author:   Benjamin Nowack
diff --git a/lib/arc2/sparqlscript/ARC2_SPARQLScriptProcessor.php b/lib/arc2/sparqlscript/ARC2_SPARQLScriptProcessor.php
old mode 100644
new mode 100755
index e9dcfc40b6325a5364e1591029bc84ec85ab8e55..cfa86c50df34e3cab8bac212588d86b4b9d22a64
--- a/lib/arc2/sparqlscript/ARC2_SPARQLScriptProcessor.php
+++ b/lib/arc2/sparqlscript/ARC2_SPARQLScriptProcessor.php
@@ -3,7 +3,7 @@
  * ARC2 SPARQLScript Processor
  *
  * @author Benjamin Nowack <bnowack@semsol.com>
- * @license http://arc.semsol.org/license
+ * @license W3C Software License and GPL
  * @package ARC2
  * @version 2010-11-16
 */
diff --git a/lib/arc2/src/ARC2/Store/Adapter/AbstractAdapter.php b/lib/arc2/src/ARC2/Store/Adapter/AbstractAdapter.php
new file mode 100644
index 0000000000000000000000000000000000000000..ea9afd559676b51ebe9ae6d5d0c2236ca061ed08
--- /dev/null
+++ b/lib/arc2/src/ARC2/Store/Adapter/AbstractAdapter.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @author Konrad Abicht <konrad.abicht@pier-and-peer.com>
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ */
+
+namespace ARC2\Store\Adapter;
+
+abstract class AbstractAdapter
+{
+    protected $configuration;
+    protected $db;
+
+    /**
+     * Stores errors of failed queries.
+     *
+     * @var array
+     */
+    protected $errors = array();
+
+    /**
+     * Sent queries.
+     *
+     * @var array
+     */
+    protected $queries = array();
+
+    /**
+     * @param array $configuration Default is array(). Only use, if you have your own mysqli connection.
+     */
+    public function __construct(array $configuration = array())
+    {
+        $this->configuration = $configuration;
+
+        $this->checkRequirements();
+    }
+
+    abstract public function checkRequirements();
+
+    abstract public function connect($existingConnection = null);
+
+    abstract public function disconnect();
+
+    abstract public function escape($value);
+
+    abstract public function exec($sql);
+
+    abstract public function fetchList($sql);
+
+    abstract public function fetchRow($sql);
+
+    abstract public function getAdapterName();
+
+    abstract public function getCollation();
+
+    abstract public function getDBSName();
+
+    abstract public function getLastInsertId();
+
+    abstract public function getServerInfo();
+
+    abstract public function getErrorMessage();
+
+    abstract public function getNumberOfRows($sql);
+
+    abstract public function getStoreName();
+
+    abstract public function getTablePrefix();
+
+    abstract public function simpleQuery($sql);
+}
diff --git a/lib/arc2/src/ARC2/Store/Adapter/AdapterFactory.php b/lib/arc2/src/ARC2/Store/Adapter/AdapterFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..9ace7c39f7b4e42a951aa3bbbc75b962a08cb908
--- /dev/null
+++ b/lib/arc2/src/ARC2/Store/Adapter/AdapterFactory.php
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @author Konrad Abicht <konrad.abicht@pier-and-peer.com>
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ */
+
+namespace ARC2\Store\Adapter;
+
+/**
+ * It provides an adapter instance for requested adapter name.
+ */
+class AdapterFactory
+{
+    /**
+     * @param string $adapterName
+     * @param array $configuration Default is array()
+     */
+    public function getInstanceFor($adapterName, $configuration = array())
+    {
+        if (in_array($adapterName, $this->getSupportedAdapters())) {
+            /*
+             * mysqli
+             */
+            if ('mysqli' == $adapterName) {
+                if (false == class_exists('\\ARC2\\Store\\Adapter\\mysqliAdapter')) {
+                    require_once 'mysqliAdapter.php';
+                }
+                return new mysqliAdapter($configuration);
+            /*
+             * PDO
+             */
+            } elseif ('pdo' == $adapterName) {
+                // use cache?
+                if (isset($configuration['cache_enabled']) && true === $configuration['cache_enabled']) {
+                    if (false == class_exists('\\ARC2\\Store\\Adapter\\CachedPDOAdapter')) {
+                        require_once 'CachedPDOAdapter.php';
+                    }
+                    return new CachedPDOAdapter($configuration);
+                // no cache
+                } else {
+                    if (false == class_exists('\\ARC2\\Store\\Adapter\\PDOAdapter')) {
+                        require_once 'PDOAdapter.php';
+                    }
+                    return new PDOAdapter($configuration);
+                }
+            }
+        }
+
+        throw new \Exception(
+            'Unknown adapter name given. Currently supported are: '
+            .implode(', ', $this->getSupportedAdapters())
+        );
+    }
+
+    /**
+     * @return array
+     */
+    public function getSupportedAdapters()
+    {
+        return array('mysqli', 'pdo');
+    }
+}
diff --git a/lib/arc2/src/ARC2/Store/Adapter/CachedPDOAdapter.php b/lib/arc2/src/ARC2/Store/Adapter/CachedPDOAdapter.php
new file mode 100644
index 0000000000000000000000000000000000000000..f4c805e533fe22d65e53049452f92c33b19e4e80
--- /dev/null
+++ b/lib/arc2/src/ARC2/Store/Adapter/CachedPDOAdapter.php
@@ -0,0 +1,145 @@
+<?php
+
+/**
+ * Adapter to enable usage of PDO functions.
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @author Konrad Abicht <konrad.abicht@pier-and-peer.com>
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ */
+
+namespace ARC2\Store\Adapter;
+
+use Psr\SimpleCache\CacheInterface;
+use Symfony\Component\Cache\Simple\FilesystemCache;
+
+/**
+ * PDO Adapter - Handles database operations using PDO.
+ */
+class CachedPDOAdapter extends PDOAdapter
+{
+    protected $cacheEnabled;
+    protected $cache;
+
+    public function __construct(array $configuration = array())
+    {
+        parent::__construct($configuration);
+
+        $this->initCache($configuration);
+    }
+
+    protected function initCache(array $configuration)
+    {
+        $this->cacheEnabled = isset($configuration['cache_enabled'])
+                              && true === $configuration['cache_enabled'];
+
+        if ($this->cacheEnabled) {
+            // reuse existing cache instance, if it implements Psr\SimpleCache\CacheInterface
+            if (isset($configuration['cache_instance'])
+                && $configuration['cache_instance'] instanceof CacheInterface) {
+                $this->cache = $configuration['cache_instance'];
+
+            // create new cache instance
+            } else {
+                // FYI: https://symfony.com/doc/current/components/cache/adapters/filesystem_adapter.html
+                $this->cache = new FilesystemCache('arc2', 0, null);
+            }
+        } else {
+            throw new \Exception('Cache not enabled, therefore CachedPDOAdapter can not be used.');
+        }
+    }
+
+    public function clearCache()
+    {
+        $this->cache->clear();
+    }
+
+    /**
+     * @param string $sql
+     *
+     * @return array
+     */
+    public function fetchList($sql)
+    {
+        $key = hash('sha1', $sql);
+
+        // sql query is known
+        if ($this->cache->has($key)) {
+            return $this->cache->get($key);
+
+        } else {
+            $result = parent::fetchList($sql);
+            $this->cache->set($key, $result);
+            return $result;
+        }
+    }
+
+    /**
+     * @param string $sql
+     *
+     * @return array
+     */
+    public function fetchRow($sql)
+    {
+        $key = hash('sha1', $sql);
+
+        // sql query is known
+        if ($this->cache->has($key)) {
+            return $this->cache->get($key);
+
+        } else {
+            $result = parent::fetchRow($sql);
+            $this->cache->set($key, $result);
+            return $result;
+        }
+    }
+
+    public function getCacheInstance()
+    {
+        return $this->cache;
+    }
+
+    public function getNumberOfRows($sql)
+    {
+        $key = hash('sha1', $sql);
+
+        // sql query is known
+        if ($this->cache->has($key)) {
+            return $this->cache->get($key);
+
+        } else {
+            $result = parent::getNumberOfRows($sql);
+            $this->cache->set($key, $result);
+            return $result;
+        }
+    }
+
+    /**
+     * catches the first part of the query
+     * we need that to determine if its an query which changes the DB in any way
+     */
+    protected function queryChangesDb($sql)
+    {
+        $sqlPart = substr(trim($sql), 0, 4);
+        return true === in_array($sqlPart, ['CREA', 'DROP', 'DELE', 'INSE', 'RENA', 'UPDA',]);
+    }
+
+    public function simpleQuery($sql)
+    {
+        if ($this->queryChangesDb($sql)) {
+            $this->cache->clear();
+        }
+
+        return parent::simpleQuery($sql);
+    }
+
+    public function exec($sql)
+    {
+        if ($this->queryChangesDb($sql)) {
+            $this->cache->clear();
+        }
+
+        return parent::exec($sql);
+    }
+}
diff --git a/lib/arc2/src/ARC2/Store/Adapter/MysqliDbExtended.php b/lib/arc2/src/ARC2/Store/Adapter/MysqliDbExtended.php
new file mode 100644
index 0000000000000000000000000000000000000000..5a74cd51d57a482368aca43389ccc0417a84e1da
--- /dev/null
+++ b/lib/arc2/src/ARC2/Store/Adapter/MysqliDbExtended.php
@@ -0,0 +1,111 @@
+<?php
+
+namespace ARC2\Store\Adapter;
+
+/**
+ * Extends MysqliDb class with some convient functions.
+ */
+class MysqliDbExtended extends \MysqliDb
+{
+    protected $last_result;
+
+    /**
+     * Returns the number of affected rows, if you ran a query using simpleQuery before.
+     *
+     * @return int Affected rows by an UPDATE/DELETE query.
+     */
+    public function getAffectedRows()
+    {
+        return $this->mysqli()->affected_rows;
+    }
+
+    /**
+     * If you ran a query using MysqliDbExtended::simpleQuery and an error occoured, you can
+     * get the error code with this function.
+     *
+     * @return int Error code, if available.
+     */
+    public function getErrorCode()
+    {
+        return $this->mysqli()->errno;
+    }
+
+    /**
+     * If you ran a query using MysqliDbExtended::simpleQuery and an error occoured, you can
+     * get the error message with this function.
+     *
+     * @return string Non-empty string, if an error occoured, empty string otherwise.
+     */
+    public function getErrorMessage()
+    {
+        return $this->mysqli()->error;
+    }
+
+    /**
+     * @return int
+     */
+    public function getLastInsertId()
+    {
+        if (is_object($this->last_result)) {
+            return $this->last_result->insert_id;
+        }
+
+        return null;
+    }
+
+    /**
+     * Executes a SQL statement and returns the number of rows. This function will return 0,
+     * regardless of errors in the query.
+     *
+     * @param string $sql Query to execute.
+     *
+     * @return int Number of rows, if available, 0 otherwise.
+     */
+    public function getNumberOfRows($sql = null)
+    {
+        if (null != $sql) {
+            $result = $this->mysqli()->query($sql);
+            return is_object($result) ? $result->num_rows : 0;
+
+        } elseif (is_object($this->last_result)) {
+            return $this->last_result->num_rows;
+        }
+
+        return 0;
+    }
+
+    /**
+     * Returns the server version.
+     *
+     * @return string
+     */
+    public function getServerInfo()
+    {
+        return $this->mysqli()->server_info;
+    }
+
+    /**
+     * For compatibility reasons. Executes a query using mysqli and returns the result. Dont use
+     * this function directly. It is only used once to make sure, ARC2 keeps its backward compatibility
+     * while in the 2.x branch.
+     *
+     * @param string $sql Query to execute.
+     *
+     * @return mysqli result|false
+     */
+    public function mysqliQuery($sql)
+    {
+        return $this->mysqli()->query($sql);
+    }
+
+    /**
+     * @param string $sql Query to execute.
+     *
+     * @return bool True if query runs without problems, false otherwise.
+     */
+    public function simpleQuery($sql, $num_rows = null)
+    {
+        $this->last_result = $this->mysqli()->query($sql, $num_rows);
+        return $this->last_result ? true : false;
+    }
+}
diff --git a/lib/arc2/src/ARC2/Store/Adapter/PDOAdapter.php b/lib/arc2/src/ARC2/Store/Adapter/PDOAdapter.php
new file mode 100644
index 0000000000000000000000000000000000000000..62e7d2a499c1f1ff123fa45f486dbea0cc7b717f
--- /dev/null
+++ b/lib/arc2/src/ARC2/Store/Adapter/PDOAdapter.php
@@ -0,0 +1,332 @@
+<?php
+
+/**
+ * Adapter to enable usage of PDO functions.
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @author Konrad Abicht <konrad.abicht@pier-and-peer.com>
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ */
+
+namespace ARC2\Store\Adapter;
+
+/**
+ * PDO Adapter - Handles database operations using PDO.
+ */
+class PDOAdapter extends AbstractAdapter
+{
+    public function checkRequirements()
+    {
+        if (false == \extension_loaded('pdo_mysql')) {
+            throw new \Exception('Extension pdo_mysql is not loaded.');
+        }
+    }
+
+    public function getAdapterName()
+    {
+        return 'pdo';
+    }
+
+    /**
+     * Connect to server or storing a given connection.
+     *
+     * @param EasyDB $existingConnection Default is null.
+     */
+    public function connect($existingConnection = null)
+    {
+        // reuse a given existing connection.
+        // it assumes that $existingConnection is a PDO connection object
+        if (null !== $existingConnection) {
+            $this->db = $existingConnection;
+
+        // create your own connection
+        } elseif (false === $this->db instanceof \PDO) {
+            /*
+             * build connection string
+             *
+             * - db_pdo_protocol: Protocol to determine server, e.g. mysql
+             */
+            if (false == isset($this->configuration['db_pdo_protocol'])) {
+                throw new \Exception(
+                    'When using PDO the protocol has to be given (e.g. mysql). Please set db_pdo_protocol in database configuration.'
+                );
+            }
+            $dsn = $this->configuration['db_pdo_protocol'].':host='. $this->configuration['db_host'];
+            if (isset($this->configuration['db_name'])) {
+                $dsn .= ';dbname='.$this->configuration['db_name'];
+            }
+
+            // set charset
+            $dsn .= ';charset=utf8mb4';
+
+            $this->db = new \PDO(
+                $dsn,
+                $this->configuration['db_user'],
+                $this->configuration['db_pwd']
+            );
+
+            $this->db->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
+
+            // errors DONT lead to exceptions
+            // set to false for compatibility reasons with mysqli. ARC2 using mysqli does not throw any
+            // exceptions, instead collects errors in a hidden array.
+            $this->db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
+
+            // default fetch mode is associative
+            $this->db->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
+
+            // from source: http://php.net/manual/de/ref.pdo-mysql.php
+            // If this attribute is set to TRUE on a PDOStatement, the MySQL driver will use
+            // the buffered versions of the MySQL API. But we wont rely on that, setting it false.
+            $this->db->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
+
+            // This is RDF, we may need many JOINs...
+            // TODO find an equivalent in other DBS
+            $stmt = $this->db->prepare('SET SESSION SQL_BIG_SELECTS=1');
+            $stmt->execute();
+            $stmt->closeCursor();
+
+            // with MySQL 5.6 we ran into exceptions like:
+            //      PDOException: SQLSTATE[42000]: Syntax error or access violation:
+            //      1140 In aggregated query without GROUP BY, expression #1 of SELECT list contains
+            //      nonaggregated column 'testdb.T_0_0_0.p'; this is incompatible with sql_mode=only_full_group_by
+            //
+            // the following query makes this right.
+            // FYI: https://stackoverflow.com/questions/23921117/disable-only-full-group-by
+            $stmt = $this->db->prepare("SET sql_mode = ''");
+            $stmt->execute();
+            $stmt->closeCursor();
+        }
+
+        return $this->db;
+    }
+
+    /**
+     * @return void
+     */
+    public function disconnect()
+    {
+        // FYI: https://stackoverflow.com/questions/18277233/pdo-closing-connection
+        $this->db = null;
+    }
+
+    public function escape($value)
+    {
+        $quoted = $this->db->quote($value);
+
+        /*
+         * fixes the case, that we have double quoted strings like:
+         *      ''x1''
+         *
+         * remember, this value will be surrounded by quotes later on!
+         * so we don't send it back with quotes around.
+         */
+        if ("'" == \substr($quoted, 0, 1)) {
+            $quoted = \substr($quoted, 1, \strlen($quoted)-2);
+        }
+
+        return $quoted;
+    }
+
+    /**
+     * @param string $sql
+     *
+     * @return array
+     */
+    public function fetchList($sql)
+    {
+        // save query
+        $this->queries[] = [
+            'query' => $sql,
+            'by_function' => 'fetchList'
+        ];
+
+        if (null == $this->db) {
+            $this->connect();
+        }
+
+        $stmt = $this->db->prepare($sql);
+        $stmt->execute();
+        $rows = $stmt->fetchAll();
+        $stmt->closeCursor();
+
+        return $rows;
+    }
+
+    public function fetchRow($sql)
+    {
+        // save query
+        $this->queries[] = [
+            'query' => $sql,
+            'by_function' => 'fetchRow'
+        ];
+
+        if (null == $this->db) {
+            $this->connect();
+        }
+
+        $row = false;
+        $stmt = $this->db->prepare($sql);
+        $stmt->execute();
+        $rows = $stmt->fetchAll();
+        if (0 < \count($rows)) {
+            $row = \array_values($rows)[0];
+        }
+        $stmt->closeCursor();
+
+        return $row;
+    }
+
+    public function getCollation()
+    {
+        $row = $this->fetchRow('SHOW TABLE STATUS LIKE "'.$this->getTablePrefix().'setting"');
+
+        if (isset($row['Collation'])) {
+            return $row['Collation'];
+        } else {
+            return '';
+        }
+    }
+
+    public function getConnection()
+    {
+        return $this->db;
+    }
+
+    public function getConnectionId()
+    {
+        return $this->db->query('SELECT CONNECTION_ID()')->fetch(\PDO::FETCH_ASSOC);
+    }
+
+    public function getDBSName()
+    {
+        if (null == $this->db) {
+            return;
+        }
+
+        $clientVersion = \strtolower($this->db->getAttribute(\PDO::ATTR_CLIENT_VERSION));
+        $serverVersion = \strtolower($this->db->getAttribute(\PDO::ATTR_SERVER_VERSION));
+        if (false !== \strpos($clientVersion, 'mariadb') || false !== \strpos($serverVersion, 'mariadb')) {
+            $return = 'mariadb';
+        } elseif (false !== \strpos($clientVersion, 'mysql') || false !== \strpos($serverVersion, 'mysql')) {
+            $return = 'mysql';
+        } else {
+            $return = null;
+        }
+
+        return $return;
+    }
+
+    public function getServerInfo()
+    {
+        return $this->db->getAttribute(\constant('PDO::ATTR_CLIENT_VERSION'));
+    }
+
+    /**
+     * Returns the version of the database server like 05-00-12
+     */
+    public function getServerVersion()
+    {
+        $res = \preg_match(
+            "/([0-9]+)\.([0-9]+)\.([0-9]+)/",
+            $this->getServerInfo(),
+            $matches
+        );
+
+        return 1 == $res
+            ? \sprintf('%02d-%02d-%02d', $matches[1], $matches[2], $matches[3])
+            : '00-00-00';
+    }
+
+    public function getErrorCode()
+    {
+        return $this->db->errorCode();
+    }
+
+    public function getErrorMessage()
+    {
+        return $this->db->errorInfo()[2];
+    }
+
+    public function getLastInsertId()
+    {
+        return $this->db->lastInsertId();
+    }
+
+    public function getNumberOfRows($sql)
+    {
+        // save query
+        $this->queries[] = [
+            'query' => $sql,
+            'by_function' => 'getNumberOfRows'
+        ];
+
+        $stmt = $this->db->prepare($sql);
+        $stmt->execute();
+        $rowCount = \count($stmt->fetchAll());
+        $stmt->closeCursor();
+        return $rowCount;
+    }
+
+    public function getStoreName()
+    {
+        if (isset($this->configuration['store_name'])) {
+            return $this->configuration['store_name'];
+        }
+
+        return 'arc';
+    }
+
+    public function getTablePrefix()
+    {
+        $prefix = '';
+        if (isset($this->configuration['db_table_prefix'])) {
+            $prefix = $this->configuration['db_table_prefix'].'_';
+        }
+
+        $prefix .= $this->getStoreName().'_';
+        return $prefix;
+    }
+
+    /**
+     * @param string $sql Query
+     *
+     * @return bool True if query ran fine, false otherwise.
+     */
+    public function simpleQuery($sql)
+    {
+        // save query
+        $this->queries[] = [
+            'query' => $sql,
+            'by_function' => 'simpleQuery'
+        ];
+
+        if (false === $this->db instanceof \PDO) {
+            $this->connect();
+        }
+
+        $stmt = $this->db->prepare($sql);
+        $stmt->execute();
+        $stmt->closeCursor();
+        return true;
+    }
+
+    /**
+     * Encapsulates internal PDO::exec call. This allows us to extend it, e.g. with caching functionality.
+     *
+     * @param string $sql
+     *
+     * @return int Number of affected rows.
+     */
+    public function exec($sql)
+    {
+        // save query
+        $this->queries[] = [
+            'query' => $sql,
+            'by_function' => 'exec'
+        ];
+
+        return $this->db->exec($sql);
+    }
+}
diff --git a/lib/arc2/src/ARC2/Store/Adapter/mysqliAdapter.php b/lib/arc2/src/ARC2/Store/Adapter/mysqliAdapter.php
new file mode 100644
index 0000000000000000000000000000000000000000..adaf0135584e4241ab38225dcf10ecd0fdb6f630
--- /dev/null
+++ b/lib/arc2/src/ARC2/Store/Adapter/mysqliAdapter.php
@@ -0,0 +1,255 @@
+<?php
+
+/**
+ * Adapter to enable usage of mysqli_* functions.
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @author Konrad Abicht <konrad.abicht@pier-and-peer.com>
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ */
+
+namespace ARC2\Store\Adapter;
+
+/**
+ * mysqli Adapter - Handles database operations using mysqli.
+ */
+class mysqliAdapter extends AbstractAdapter
+{
+    protected $last_result;
+
+    public function checkRequirements()
+    {
+        if (false == \extension_loaded('mysqli') || false == \function_exists('mysqli_connect')) {
+            throw new \Exception('Extension mysqli is not loaded or function mysqli_connect is not available.');
+        }
+    }
+
+    public function getAdapterName()
+    {
+        return 'mysqli';
+    }
+
+    /**
+     * Connect to server or storing a given connection.
+     *
+     * @return string|MysqliDbExtended String if an error occoured, instance of MysqliDbExtended otherwise.
+     */
+    public function connect($existingConnection = null)
+    {
+        // reuse a given existing connection.
+        // it assumes that $existingConnection is a mysqli connection object
+        if (null !== $existingConnection) {
+            $this->db = new MysqliDbExtended($existingConnection);
+
+        // create your own connection
+        } elseif (null == $this->db) {
+            // connect
+            try {
+                $this->db = new MysqliDbExtended(
+                    $this->configuration['db_host'],
+                    $this->configuration['db_user'],
+                    $this->configuration['db_pwd']
+                );
+            } catch (\Exception $e) {
+                return $e->getMessage();
+            }
+        }
+
+        if (isset($this->configuration['db_name'])
+            && true !== $this->db->simpleQuery('USE `'.$this->configuration['db_name'].'`')) {
+            $fixed = 0;
+            /* try to create it */
+            if ($this->configuration['db_name']) {
+                $this->db->simpleQuery('
+                  CREATE DATABASE IF NOT EXISTS `'.$this->configuration['db_name'].'`
+                  DEFAULT CHARACTER SET utf8
+                  DEFAULT COLLATE utf8_general_ci
+                  '
+                );
+                if ($this->db->simpleQuery('USE `'.$this->configuration['db_name'].'`')) {
+                    $this->db->simpleQuery("SET NAMES 'utf8'");
+                    $fixed = 1;
+                }
+            }
+            if (!$fixed) {
+                return $this->addError($this->db->getErrorMessage());
+            } else {
+                if (preg_match('/^utf8/', $this->getCollation())) {
+                    $this->db->simpleQuery("SET NAMES 'utf8'");
+                }
+                // This is RDF, we may need many JOINs...
+                $this->db->simpleQuery('SET SESSION SQL_BIG_SELECTS=1');
+            }
+        }
+
+        return $this->db;
+    }
+
+    public function disconnect()
+    {
+        return $this->db->disconnect();
+    }
+
+    public function escape($value)
+    {
+        return $this->db->escape($value);
+    }
+
+    public function fetchList($sql)
+    {
+        return $this->db->rawQuery($sql);
+    }
+
+    public function fetchRow($sql)
+    {
+        $row = $this->db->rawQueryOne($sql);
+
+        return null != $row ? $row : false;
+    }
+
+    public function getCollation()
+    {
+        $row = $this->fetchRow('SHOW TABLE STATUS LIKE "'.$this->getTablePrefix().'setting"');
+
+        if (isset($row['Collation'])) {
+            return $row['Collation'];
+        } else {
+            return '';
+        }
+    }
+
+    public function getConnectionId()
+    {
+        if (null != $this->db) {
+            return $this->db->mysqli()->thread_id;
+        }
+    }
+
+    /**
+     * For backward compatibility reasons. Get mysqli connection object.
+     *
+     * @return mysqli
+     */
+    public function getConnection()
+    {
+        return $this->db->mysqli();
+    }
+
+    public function getDBSName()
+    {
+        if (null == $this->db) {
+            return null;
+        }
+
+        return false !== strpos($this->getServerInfo(), 'MariaDB')
+            ? 'mariadb'
+            : 'mysql';
+    }
+
+    public function getLastInsertId()
+    {
+        if (null != $this->db) {
+            return $this->db->getLastInsertId();
+        }
+
+        return 'No database connection (mysqliAdapter).';
+    }
+
+    public function getServerInfo()
+    {
+        $this->connect();
+
+        return $this->db->mysqli()->server_info;
+    }
+
+    /**
+     * Returns the version of the database server like 05-00-12
+     */
+    public function getServerVersion()
+    {
+        $res = preg_match(
+            "/([0-9]+)\.([0-9]+)\.([0-9]+)/",
+            $this->getServerInfo(),
+            $matches
+        );
+
+        return 1 == $res
+            ? sprintf('%02d-%02d-%02d', $matches[1], $matches[2], $matches[3])
+            : '00-00-00';
+    }
+
+    public function getErrorMessage()
+    {
+        return $this->db->getErrorMessage();
+    }
+
+    public function getErrorCode()
+    {
+        return $this->db->getErrorCode();
+    }
+
+    public function getNumberOfRows($sql)
+    {
+        return $this->db->getNumberOfRows($sql);
+    }
+
+    public function getStoreName()
+    {
+        if (isset($this->configuration['store_name'])) {
+            return $this->configuration['store_name'];
+        }
+
+        return 'arc';
+    }
+
+    public function getTablePrefix()
+    {
+        $prefix = '';
+        if (isset($this->configuration['db_table_prefix'])) {
+            $prefix = $this->configuration['db_table_prefix'].'_';
+        }
+
+        $prefix .= $this->getStoreName().'_';
+        return $prefix;
+    }
+
+    /**
+     * For compatibility reasons. Executes a query using mysqli and returns the result. Dont use
+     * this function directly. It is only used once to make sure, ARC2 keeps its backward compatibility
+     * while in the 2.x branch.
+     *
+     * @param string $sql Query to execute.
+     *
+     * @return mysqli result|false
+     */
+    public function mysqliQuery($sql)
+    {
+        return $this->db->mysqliQuery($sql);
+    }
+
+    /**
+     * @param string $sql Query
+     *
+     * @return bool True if query ran fine, false otherwise.
+     */
+    public function simpleQuery($sql)
+    {
+        if (null == $this->db) {
+            $this->connect();
+        }
+
+        return $this->db->simpleQuery($sql);
+    }
+
+    /**
+     * @param string $sql Query with return of affected rows
+     *
+     * @return bool True if query ran fine, false otherwise.
+     */
+    public function exec($sql)
+    {
+        $this->db->simpleQuery($sql);
+        return $this->db->getAffectedRows();
+    }
+}
diff --git a/lib/arc2/store/ARC2_MemStore.php b/lib/arc2/store/ARC2_MemStore.php
index dc619fd34e7a7db38c76fc8b10273f653a9f6fc2..ad4199427064d1c880a7ea93570bb93b385747c1 100644
--- a/lib/arc2/store/ARC2_MemStore.php
+++ b/lib/arc2/store/ARC2_MemStore.php
@@ -1,194 +1,212 @@
 <?php
 /**
- * ARC2 Memory Store
+ * ARC2 Memory Store.
  *
  * @author Benjamin Nowack <bnowack@semsol.com>
- * @license http://arc.semsol.org/license
- * @package ARC2
+ * @license W3C Software License and GPL
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('Class');
 
-class ARC2_MemStore extends ARC2_Class {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-    $this->is_mem = 1;
-  }
-  
-  function __init() {
-    parent::__init();
-    $this->data = array();
-  }
-
-  /*  */
-
-  function isSetUp() {
-    return 1;
-  }
-  
-  function setUp() {}
-  
-  /*  */
-  
-  function reset() {
-    $this->data = array();
-  }
-  
-  function drop() {
-    $this->reset();
-  }
-
-  /*  */
-
-  function insert($doc, $g = 'http://localhost/') {
-    $index = $this->v($g, array(), $this->data);
-    $this->data[$g] = ARC2::getMergedIndex($index, $this->toIndex($doc));
-  }
-  
-  /*  */
-  /*  */
-
-  
-  function delete($doc, $g = 'http://localhost/') {
-    $index = $this->v($g, array(), $this->data);
-    $this->data[$g] = ARC2::getCleanedIndex($index, $this->toIndex($doc));
-  }
-
-  function replace($doc, $g, $doc_2) {
-    return array($this->delete($doc, $g), $this->insert($doc_2, $g));
-  }
-  
-  /*  */
-  
-  function query($q, $result_format = '', $src = '', $keep_bnode_ids = 0, $log_query = 0) {
-    if ($log_query) $this->logQuery($q);
-    ARC2::inc('SPARQLPlusParser');
-    $p = new ARC2_SPARQLPlusParser($this->a, $this);
-    $p->parse($q, $src);
-    $infos = $p->getQueryInfos();
-    $t1 = ARC2::mtime();
-    if (!$errs = $p->getErrors()) {
-      $qt = $infos['query']['type'];
-      $r = array('query_type' => $qt, 'result' => $this->runQuery($q, $qt));
+class ARC2_MemStore extends ARC2_Class
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+        $this->is_mem = 1;
     }
-    else {
-      $r = array('result' => '');
+
+    public function __init()
+    {
+        parent::__init();
+        $this->data = [];
     }
-    $t2 = ARC2::mtime();
-    $r['query_time'] = $t2 - $t1;
-    /* query result */
-    if ($result_format == 'raw') {
-      return $r['result'];
+
+    public function isSetUp()
+    {
+        return 1;
     }
-    if ($result_format == 'rows') {
-      return $this->v('rows', array(), $r['result']);
+
+    public function setUp(): void
+    {
     }
-    if ($result_format == 'row') {
-      return $r['result']['rows'] ? $r['result']['rows'][0] : array();
+
+    public function reset()
+    {
+        $this->data = [];
     }
-    return $r;
-  }
 
-  function runQuery($q, $qt = '') {
-    /* ep */
-    $ep = $this->v('remote_store_endpoint', 0, $this->a);
-    if (!$ep) return false;
-    /* prefixes */
-    $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
-    $added_prefixes = array();
-    $prologue = '';
-    foreach ($ns as $k => $v) {
-      $k = rtrim($k, ':');
-      if (in_array($k, $added_prefixes)) continue;
-      if (preg_match('/(^|\s)' . $k . ':/s', $q) && !preg_match('/PREFIX\s+' . $k . '\:/is', $q)) {
-        $prologue .=  "\n" . 'PREFIX ' . $k . ': <' . $v . '>';
-      }
-      $added_prefixes[] = $k;
+    public function drop()
+    {
+        $this->reset();
     }
-    $q = $prologue . "\n" . $q;
-    /* http verb */
-    $mthd = in_array($qt, array('load', 'insert', 'delete')) ? 'POST' : 'GET';
-    /* reader */
-    ARC2::inc('Reader');
-    $reader = new ARC2_Reader($this->a, $this);
-    $reader->setAcceptHeader('Accept: application/sparql-results+xml; q=0.9, application/rdf+xml; q=0.9, */*; q=0.1');
-    if ($mthd == 'GET') {
-      $url = $ep;
-      $url .= strpos($ep, '?') ? '&' : '?';
-      $url .= 'query=' . urlencode($q);
-      if ($k = $this->v('store_read_key', '', $this->a)) $url .= '&key=' . urlencode($k);
+
+    public function insert($doc, $g = 'http://localhost/')
+    {
+        $index = $this->v($g, [], $this->data);
+        $this->data[$g] = ARC2::getMergedIndex($index, $this->toIndex($doc));
     }
-    else {
-      $url = $ep;
-      $reader->setHTTPMethod($mthd);
-      $reader->setCustomHeaders("Content-Type: application/x-www-form-urlencoded");
-      $suffix = ($k = $this->v('store_write_key', '', $this->a)) ? '&key=' . rawurlencode($k) : '';
-      $reader->setMessageBody('query=' . rawurlencode($q) . $suffix);
+
+    public function delete($doc, $g = 'http://localhost/')
+    {
+        $index = $this->v($g, [], $this->data);
+        $this->data[$g] = ARC2::getCleanedIndex($index, $this->toIndex($doc));
     }
-    $to = $this->v('remote_store_timeout', 0, $this->a);
-    $reader->activate($url, '', 0, $to);
-    $format = $reader->getFormat();
-    $resp = '';
-    while ($d = $reader->readStream()) {
-      $resp .= $d;
+
+    public function replace($doc, $g, $doc_2)
+    {
+        return [$this->delete($doc, $g), $this->insert($doc_2, $g)];
     }
-    $reader->closeStream();
-    $ers = $reader->getErrors();
-    unset($this->reader);
-    if ($ers) return array('errors' => $ers);
-		$mappings = array('rdfxml' => 'RDFXML', 'sparqlxml' => 'SPARQLXMLResult', 'turtle' => 'Turtle');
-    if (!$format || !isset($mappings[$format])) {
-      return $resp;
-      //return $this->addError('No parser available for "' . $format . '" SPARQL result');
+
+    public function query($q, $result_format = '', $src = '', $keep_bnode_ids = 0, $log_query = 0)
+    {
+        if ($log_query) {
+            $this->logQuery($q);
+        }
+        ARC2::inc('SPARQLPlusParser');
+        $p = new ARC2_SPARQLPlusParser($this->a, $this);
+        $p->parse($q, $src);
+        $infos = $p->getQueryInfos();
+        $t1 = ARC2::mtime();
+        if (!$errs = $p->getErrors()) {
+            $qt = $infos['query']['type'];
+            $r = ['query_type' => $qt, 'result' => $this->runQuery($q, $qt)];
+        } else {
+            $r = ['result' => ''];
+        }
+        $t2 = ARC2::mtime();
+        $r['query_time'] = $t2 - $t1;
+        /* query result */
+        if ('raw' == $result_format) {
+            return $r['result'];
+        }
+        if ('rows' == $result_format) {
+            return $this->v('rows', [], $r['result']);
+        }
+        if ('row' == $result_format) {
+            return $r['result']['rows'] ? $r['result']['rows'][0] : [];
+        }
+
+        return $r;
     }
-    /* format parser */
-    $suffix = $mappings[$format] . 'Parser';
-    ARC2::inc($suffix);
-    $cls = 'ARC2_' . $suffix;
-    $parser = new $cls($this->a, $this);
-    $parser->parse($ep, $resp);
-    /* ask|load|insert|delete */
-    if (in_array($qt, array('ask', 'load', 'insert', 'delete'))) {
-      $bid = $parser->getBooleanInsertedDeleted();
-      switch ($qt) {
+
+    public function runQuery($q, $qt = '')
+    {
+        /* ep */
+        $ep = $this->v('remote_store_endpoint', 0, $this->a);
+        if (!$ep) {
+            return false;
+        }
+        /* prefixes */
+        $ns = isset($this->a['ns']) ? $this->a['ns'] : [];
+        $added_prefixes = [];
+        $prologue = '';
+        foreach ($ns as $k => $v) {
+            $k = rtrim($k, ':');
+            if (in_array($k, $added_prefixes)) {
+                continue;
+            }
+            if (preg_match('/(^|\s)'.$k.':/s', $q) && !preg_match('/PREFIX\s+'.$k.'\:/is', $q)) {
+                $prologue .= "\n".'PREFIX '.$k.': <'.$v.'>';
+            }
+            $added_prefixes[] = $k;
+        }
+        $q = $prologue."\n".$q;
+        /* http verb */
+        $mthd = in_array($qt, ['load', 'insert', 'delete']) ? 'POST' : 'GET';
+        /* reader */
+        ARC2::inc('Reader');
+        $reader = new ARC2_Reader($this->a, $this);
+        $reader->setAcceptHeader('Accept: application/sparql-results+xml; q=0.9, application/rdf+xml; q=0.9, */*; q=0.1');
+        if ('GET' == $mthd) {
+            $url = $ep;
+            $url .= strpos($ep, '?') ? '&' : '?';
+            $url .= 'query='.urlencode($q);
+            if ($k = $this->v('store_read_key', '', $this->a)) {
+                $url .= '&key='.urlencode($k);
+            }
+        } else {
+            $url = $ep;
+            $reader->setHTTPMethod($mthd);
+            $reader->setCustomHeaders('Content-Type: application/x-www-form-urlencoded');
+            $suffix = ($k = $this->v('store_write_key', '', $this->a)) ? '&key='.rawurlencode($k) : '';
+            $reader->setMessageBody('query='.rawurlencode($q).$suffix);
+        }
+        $to = $this->v('remote_store_timeout', 0, $this->a);
+        $reader->activate($url, '', 0, $to);
+        $format = $reader->getFormat();
+        $resp = '';
+        while ($d = $reader->readStream()) {
+            $resp .= $d;
+        }
+        $reader->closeStream();
+        $ers = $reader->getErrors();
+        unset($this->reader);
+        if ($ers) {
+            return ['errors' => $ers];
+        }
+        $mappings = ['rdfxml' => 'RDFXML', 'sparqlxml' => 'SPARQLXMLResult', 'turtle' => 'Turtle'];
+        if (!$format || !isset($mappings[$format])) {
+            return $resp;
+            //return $this->addError('No parser available for "' . $format . '" SPARQL result');
+        }
+        /* format parser */
+        $suffix = $mappings[$format].'Parser';
+        ARC2::inc($suffix);
+        $cls = 'ARC2_'.$suffix;
+        $parser = new $cls($this->a, $this);
+        $parser->parse($ep, $resp);
+        /* ask|load|insert|delete */
+        if (in_array($qt, ['ask', 'load', 'insert', 'delete'])) {
+            $bid = $parser->getBooleanInsertedDeleted();
+            switch ($qt) {
         case 'ask': return $bid['boolean'];
         default: return $bid;
       }
+        }
+        /* select */
+        if (('select' == $qt) && !method_exists($parser, 'getRows')) {
+            return $resp;
+        }
+        if ('select' == $qt) {
+            return ['rows' => $parser->getRows(), 'variables' => $parser->getVariables()];
+        }
+        /* any other */
+        return $parser->getSimpleIndex(0);
     }
-    /* select */
-    if (($qt == 'select') && !method_exists($parser, 'getRows')) return $resp;
-    if ($qt == 'select') return array('rows' => $parser->getRows(), 'variables' => $parser->getVariables());
-    /* any other */
-    return $parser->getSimpleIndex(0);
-  }
-  
-  /*  */
-  
-  function optimizeTables() {}
-  
-  /*  */
 
-  function getResourceLabel($res, $unnamed_label = 'An unnamed resource') {
-    if (!isset($this->resource_labels)) $this->resource_labels = array();
-    if (isset($this->resource_labels[$res])) return $this->resource_labels[$res];
-    if (!preg_match('/^[a-z0-9\_]+\:[^\s]+$/si', $res)) return $res;/* literal */
-    $r = '';
-    if (preg_match('/^\_\:/', $res)) {
-      return $unnamed_label;
-    }
-    $row = $this->query('SELECT ?o WHERE { <' . $res . '> ?p ?o . FILTER(REGEX(str(?p), "(label|name)$", "i"))}', 'row');
-    if ($row) {
-      $r = $row['o'];
+    public function optimizeTables()
+    {
     }
-    else {
-      $r = preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('#self', '', $res));
-      $r = str_replace('_', ' ', $r);
-      $r = preg_replace('/([a-z])([A-Z])/e', '"\\1 " . strtolower("\\2")', $r);
-    }
-    $this->resource_labels[$res] = $r;
-    return $r;
-  }
 
+    public function getResourceLabel($res, $unnamed_label = 'An unnamed resource')
+    {
+        if (!isset($this->resource_labels)) {
+            $this->resource_labels = [];
+        }
+        if (isset($this->resource_labels[$res])) {
+            return $this->resource_labels[$res];
+        }
+        if (!preg_match('/^[a-z0-9\_]+\:[^\s]+$/si', $res)) {
+            return $res;
+        } /* literal */
+        $r = '';
+        if (preg_match('/^\_\:/', $res)) {
+            return $unnamed_label;
+        }
+        $row = $this->query('SELECT ?o WHERE { <'.$res.'> ?p ?o . FILTER(REGEX(str(?p), "(label|name)$", "i"))}', 'row');
+        if ($row) {
+            $r = $row['o'];
+        } else {
+            $r = preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('#self', '', $res));
+            $r = str_replace('_', ' ', $r);
+            $r = preg_replace_callback('/([a-z])([A-Z])/', function ($matches) {
+                return $matches[1].' '.strtolower($matches[2]);
+            }, $r);
+        }
+        $this->resource_labels[$res] = $r;
+
+        return $r;
+    }
 }
diff --git a/lib/arc2/store/ARC2_RemoteStore.php b/lib/arc2/store/ARC2_RemoteStore.php
old mode 100644
new mode 100755
index c1f0f9e22088d6ea60505ae5105f48f2d19d31d2..3377f397bb937f7e804aaec39be98a8fb8047a63
--- a/lib/arc2/store/ARC2_RemoteStore.php
+++ b/lib/arc2/store/ARC2_RemoteStore.php
@@ -1,204 +1,227 @@
 <?php
 /**
- * ARC2 Remote RDF Store
+ * ARC2 Remote RDF Store.
  *
  * @author Benjamin Nowack <bnowack@semsol.com>
- * @license http://arc.semsol.org/license
- * @package ARC2
+ * @license W3C Software License and GPL
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('Class');
 
-class ARC2_RemoteStore extends ARC2_Class {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-    $this->is_remote = 1;
-  }
-  
-  function __init() {
-    parent::__init();
-  }
-
-  /*  */
-
-  function isSetUp() {
-    return 1;
-  }
-  
-  function setUp() {}
-
-  function killDBProcesses() {}
-  
-  /*  */
-  
-  function reset() {}
-  
-  function drop() {}
-  
-  function insert($doc, $g, $keep_bnode_ids = 0) {
-    return $this->query('INSERT INTO <' . $g . '> { ' . $this->toNTriples($doc, '', 1) . ' }');
-  }
-  
-  function delete($doc, $g) {
-    if (!$doc) {
-      return $this->query('DELETE FROM <' . $g . '>');
-    }
-    else {
-      return $this->query('DELETE FROM <' . $g . '> { ' . $this->toNTriples($doc, '', 1) . ' }');
-    }
-  }
-  
-  function replace($doc, $g, $doc_2) {
-    return array($this->delete($doc, $g), $this->insert($doc_2, $g));
-  }
-  
-  /*  */
-  
-  function query($q, $result_format = '', $src = '', $keep_bnode_ids = 0, $log_query = 0) {
-    if ($log_query) $this->logQuery($q);
-    ARC2::inc('SPARQLPlusParser');
-    $p = new ARC2_SPARQLPlusParser($this->a, $this);
-    $p->parse($q, $src);
-    $infos = $p->getQueryInfos();
-    $t1 = ARC2::mtime();
-    if (!$errs = $p->getErrors()) {
-      $qt = $infos['query']['type'];
-      $r = array('query_type' => $qt, 'result' => $this->runQuery($q, $qt, $infos));
-    }
-    else {
-      $r = array('result' => '');
-    }
-    $t2 = ARC2::mtime();
-    $r['query_time'] = $t2 - $t1;
-    /* query result */
-    if ($result_format == 'raw') {
-      return $r['result'];
-    }
-    if ($result_format == 'rows') {
-      return $this->v('rows', array(), $r['result']);
+class ARC2_RemoteStore extends ARC2_Class
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+        $this->is_remote = 1;
     }
-    if ($result_format == 'row') {
-      if (!isset($r['result']['rows'])) return array();
-      return $r['result']['rows'] ? $r['result']['rows'][0] : array();
-    }
-    return $r;
-  }
-
-  function runQuery($q, $qt = '', $infos = '') {
-    /* ep */
-    $ep = $this->v('remote_store_endpoint', 0, $this->a);
-    if (!$ep) return false;
-    /* prefixes */
-    $q = $this->completeQuery($q);
-    /* custom handling */
-    $mthd = 'run' . $this->camelCase($qt) . 'Query';
-    if (method_exists($this, $mthd)) {
-      return $this->$mthd($q, $infos);
+
+    public function __init()
+    {
+        parent::__init();
     }
-    /* http verb */
-    $mthd = in_array($qt, array('load', 'insert', 'delete')) ? 'POST' : 'GET';
-    /* reader */
-    ARC2::inc('Reader');
-    $reader = new ARC2_Reader($this->a, $this);
-    $reader->setAcceptHeader('Accept: application/sparql-results+xml; q=0.9, application/rdf+xml; q=0.9, */*; q=0.1');
-    if ($mthd == 'GET') {
-      $url = $ep;
-      $url .= strpos($ep, '?') ? '&' : '?';
-      $url .= 'query=' . urlencode($q);
-      if ($k = $this->v('store_read_key', '', $this->a)) $url .= '&key=' . urlencode($k);
+
+    public function isSetUp()
+    {
+        return 1;
     }
-    else {
-      $url = $ep;
-      $reader->setHTTPMethod($mthd);
-      $reader->setCustomHeaders("Content-Type: application/x-www-form-urlencoded");
-      $suffix = ($k = $this->v('store_write_key', '', $this->a)) ? '&key=' . rawurlencode($k) : '';
-      $reader->setMessageBody('query=' . rawurlencode($q) . $suffix);
+
+    public function setUp(): void
+    {
     }
-    $to = $this->v('remote_store_timeout', 0, $this->a);
-    $reader->activate($url, '', 0, $to);
-    $format = $reader->getFormat();
-    $resp = '';
-    while ($d = $reader->readStream()) {
-      $resp .= $this->toUTF8($d);
+
+    public function killDBProcesses()
+    {
     }
-    $reader->closeStream();
-    $ers = $reader->getErrors();
-    $this->a['reader_auth_infos'] = $reader->getAuthInfos();
-    unset($this->reader);
-    if ($ers) return array('errors' => $ers);
-    $mappings = array('rdfxml' => 'RDFXML', 'sparqlxml' => 'SPARQLXMLResult', 'turtle' => 'Turtle');
-    if (!$format || !isset($mappings[$format])) {
-      return $resp;
-      //return $this->addError('No parser available for "' . $format . '" SPARQL result');
+
+    public function reset()
+    {
     }
-    /* format parser */
-    $suffix = $mappings[$format] . 'Parser';
-    ARC2::inc($suffix);
-    $cls = 'ARC2_' . $suffix;
-    $parser = new $cls($this->a, $this);
-    $parser->parse($ep, $resp);
-    /* ask|load|insert|delete */
-    if (in_array($qt, array('ask', 'load', 'insert', 'delete'))) {
-      $bid = $parser->getBooleanInsertedDeleted();
-      if ($qt == 'ask') {
-        $r = $bid['boolean'];
-      }
-      else {
-        $r = $bid;
-      }
+
+    public function drop()
+    {
     }
-    /* select */
-    elseif (($qt == 'select') && !method_exists($parser, 'getRows')) {
-      $r = $resp;
+
+    public function insert($doc, $g, $keep_bnode_ids = 0)
+    {
+        return $this->query('INSERT INTO <'.$g.'> { '.$this->toNTriples($doc, '', 1).' }');
     }
-    elseif ($qt == 'select') {
-      $r = array('rows' => $parser->getRows(), 'variables' => $parser->getVariables());
+
+    public function delete($doc, $g)
+    {
+        if (!$doc) {
+            return $this->query('DELETE FROM <'.$g.'>');
+        } else {
+            return $this->query('DELETE FROM <'.$g.'> { '.$this->toNTriples($doc, '', 1).' }');
+        }
     }
-    /* any other */
-    else {
-      $r = $parser->getSimpleIndex(0);
+
+    public function replace($doc, $g, $doc_2)
+    {
+        return [$this->delete($doc, $g), $this->insert($doc_2, $g)];
     }
-    unset($parser);
-    return $r;
-  }
-  
-  /*  */
-  
-  function optimizeTables() {}
-  
-  /*  */
-
-  function getResourceLabel($res, $unnamed_label = 'An unnamed resource') {
-    if (!isset($this->resource_labels)) $this->resource_labels = array();
-    if (isset($this->resource_labels[$res])) return $this->resource_labels[$res];
-    if (!preg_match('/^[a-z0-9\_]+\:[^\s]+$/si', $res)) return $res;/* literal */
-    $r = '';
-    if (preg_match('/^\_\:/', $res)) {
-      return $unnamed_label;
+
+    public function query($q, $result_format = '', $src = '', $keep_bnode_ids = 0, $log_query = 0)
+    {
+        if ($log_query) {
+            $this->logQuery($q);
+        }
+        ARC2::inc('SPARQLPlusParser');
+        $p = new ARC2_SPARQLPlusParser($this->a, $this);
+        $p->parse($q, $src);
+        $infos = $p->getQueryInfos();
+        $t1 = ARC2::mtime();
+        if (!$errs = $p->getErrors()) {
+            $qt = $infos['query']['type'];
+            $r = ['query_type' => $qt, 'result' => $this->runQuery($q, $qt, $infos)];
+        } else {
+            $r = ['result' => ''];
+        }
+        $t2 = ARC2::mtime();
+        $r['query_time'] = $t2 - $t1;
+        /* query result */
+        if ('raw' == $result_format) {
+            return $r['result'];
+        }
+        if ('rows' == $result_format) {
+            return $this->v('rows', [], $r['result']);
+        }
+        if ('row' == $result_format) {
+            if (!isset($r['result']['rows'])) {
+                return [];
+            }
+
+            return $r['result']['rows'] ? $r['result']['rows'][0] : [];
+        }
+
+        return $r;
     }
-    $row = $this->query('SELECT ?o WHERE { <' . $res . '> ?p ?o . FILTER(REGEX(str(?p), "(label|name)$", "i"))}', 'row');
-    if ($row) {
-      $r = $row['o'];
+
+    public function runQuery($q, $qt = '', $infos = '')
+    {
+        /* ep */
+        $ep = $this->v('remote_store_endpoint', 0, $this->a);
+        if (!$ep) {
+            return false;
+        }
+        /* prefixes */
+        $q = $this->completeQuery($q);
+        /* custom handling */
+        $mthd = 'run'.$this->camelCase($qt).'Query';
+        if (method_exists($this, $mthd)) {
+            return $this->$mthd($q, $infos);
+        }
+        /* http verb */
+        $mthd = in_array($qt, ['load', 'insert', 'delete']) ? 'POST' : 'GET';
+        /* reader */
+        ARC2::inc('Reader');
+        $reader = new ARC2_Reader($this->a, $this);
+        $reader->setAcceptHeader('Accept: application/sparql-results+xml; q=0.9, application/rdf+xml; q=0.9, */*; q=0.1');
+        if ('GET' == $mthd) {
+            $url = $ep;
+            $url .= strpos($ep, '?') ? '&' : '?';
+            $url .= 'query='.urlencode($q);
+            if ($k = $this->v('store_read_key', '', $this->a)) {
+                $url .= '&key='.urlencode($k);
+            }
+        } else {
+            $url = $ep;
+            $reader->setHTTPMethod($mthd);
+            $reader->setCustomHeaders('Content-Type: application/x-www-form-urlencoded');
+            $suffix = ($k = $this->v('store_write_key', '', $this->a)) ? '&key='.rawurlencode($k) : '';
+            $reader->setMessageBody('query='.rawurlencode($q).$suffix);
+        }
+        $to = $this->v('remote_store_timeout', 0, $this->a);
+        $reader->activate($url, '', 0, $to);
+        $format = $reader->getFormat();
+        $resp = '';
+        while ($d = $reader->readStream()) {
+            $resp .= $this->toUTF8($d);
+        }
+        $reader->closeStream();
+        $ers = $reader->getErrors();
+        $this->a['reader_auth_infos'] = $reader->getAuthInfos();
+        unset($this->reader);
+        if ($ers) {
+            return ['errors' => $ers];
+        }
+        $mappings = ['rdfxml' => 'RDFXML', 'sparqlxml' => 'SPARQLXMLResult', 'turtle' => 'Turtle'];
+        if (!$format || !isset($mappings[$format])) {
+            return $resp;
+            //return $this->addError('No parser available for "' . $format . '" SPARQL result');
+        }
+        /* format parser */
+        $suffix = $mappings[$format].'Parser';
+        ARC2::inc($suffix);
+        $cls = 'ARC2_'.$suffix;
+        $parser = new $cls($this->a, $this);
+        $parser->parse($ep, $resp);
+        /* ask|load|insert|delete */
+        if (in_array($qt, ['ask', 'load', 'insert', 'delete'])) {
+            $bid = $parser->getBooleanInsertedDeleted();
+            if ('ask' == $qt) {
+                $r = $bid['boolean'];
+            } else {
+                $r = $bid;
+            }
+        }
+        /* select */
+        elseif (('select' == $qt) && !method_exists($parser, 'getRows')) {
+            $r = $resp;
+        } elseif ('select' == $qt) {
+            $r = ['rows' => $parser->getRows(), 'variables' => $parser->getVariables()];
+        }
+        /* any other */
+        else {
+            $r = $parser->getSimpleIndex(0);
+        }
+        unset($parser);
+
+        return $r;
     }
-    else {
-      $r = preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('#self', '', $res));
-      $r = str_replace('_', ' ', $r);
-      $r = preg_replace('/([a-z])([A-Z])/e', '"\\1 " . strtolower("\\2")', $r);
+
+    public function optimizeTables()
+    {
     }
-    $this->resource_labels[$res] = $r;
-    return $r;
-  }
-  
-  function getDomains($p) {
-    $r = array();
-    foreach($this->query('SELECT DISTINCT ?type WHERE {?s <' . $p . '> ?o ; a ?type . }', 'rows') as $row) {
-      $r[] = $row['type'];
+
+    public function getResourceLabel($res, $unnamed_label = 'An unnamed resource')
+    {
+        if (!isset($this->resource_labels)) {
+            $this->resource_labels = [];
+        }
+        if (isset($this->resource_labels[$res])) {
+            return $this->resource_labels[$res];
+        }
+        if (!preg_match('/^[a-z0-9\_]+\:[^\s]+$/si', $res)) {
+            return $res;
+        } /* literal */
+        $r = '';
+        if (preg_match('/^\_\:/', $res)) {
+            return $unnamed_label;
+        }
+        $row = $this->query('SELECT ?o WHERE { <'.$res.'> ?p ?o . FILTER(REGEX(str(?p), "(label|name)$", "i"))}', 'row');
+        if ($row) {
+            $r = $row['o'];
+        } else {
+            $r = preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('#self', '', $res));
+            $r = str_replace('_', ' ', $r);
+            $r = preg_replace_callback('/([a-z])([A-Z])/', function ($matches) {
+                return $matches[1].' '.strtolower($matches[2]);
+            }, $r);
+        }
+        $this->resource_labels[$res] = $r;
+
+        return $r;
     }
-    return $r;
-  }
 
-  /*  */
-  
+    public function getDomains($p)
+    {
+        $r = [];
+        foreach ($this->query('SELECT DISTINCT ?type WHERE {?s <'.$p.'> ?o ; a ?type . }', 'rows') as $row) {
+            $r[] = $row['type'];
+        }
+
+        return $r;
+    }
 }
diff --git a/lib/arc2/store/ARC2_Store.php b/lib/arc2/store/ARC2_Store.php
index 8b91688a25a8ecba240b834ea27d52d085387aeb..b1f52f02b0b1930782d0c297f995db93681b8c09 100644
--- a/lib/arc2/store/ARC2_Store.php
+++ b/lib/arc2/store/ARC2_Store.php
@@ -1,670 +1,951 @@
 <?php
 /**
- * ARC2 RDF Store
+ * ARC2 RDF Store.
  *
  * @author Benjamin Nowack <bnowack@semsol.com>
- * @license http://arc.semsol.org/license
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
- * @version 2010-11-16
-*/
-
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ */
 ARC2::inc('Class');
 
-class ARC2_Store extends ARC2_Class {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* db_con */
-    parent::__init();
-    $this->table_lock = 0;
-    $this->triggers = $this->v('store_triggers', array(), $this->a);
-    $this->queue_queries = $this->v('store_queue_queries', 0, $this->a);
-    $this->is_win = (strtolower(substr(PHP_OS, 0, 3)) == 'win') ? true : false;
-    $this->max_split_tables = $this->v('store_max_split_tables', 10, $this->a);
-    $this->split_predicates = $this->v('store_split_predicates', array(), $this->a);
-  }
-
-  /*  */
-  
-  function getName() {
-    return $this->v('store_name', 'arc', $this->a);
-  }
-
-  function getTablePrefix() {
-    if (!isset($this->tbl_prefix)) {
-      $r = $this->v('db_table_prefix', '', $this->a);
-      $r .= $r ? '_' : '';
-      $r .= $this->getName() . '_';
-      $this->tbl_prefix = $r;
-    }
-    return $this->tbl_prefix;;
-  }
-
-  /*  */
-  
-  function createDBCon() {
-    foreach (array('db_host' => 'localhost', 'db_user' => '', 'db_pwd' => '', 'db_name' => '') as $k => $v) {
-      $this->a[$k] = $this->v($k, $v, $this->a);
-    }
-    if (!$db_con = mysql_connect($this->a['db_host'], $this->a['db_user'], $this->a['db_pwd'])) {
-      return $this->addError(mysql_error());
-    }
-    $this->a['db_con'] = $db_con;
-    if (!mysql_select_db($this->a['db_name'], $db_con)) {
-      return $this->addError(mysql_error($db_con));
-    }
-    if (preg_match('/^utf8/', $this->getCollation())) {
-      $this->queryDB("SET NAMES 'utf8'", $db_con);
-    }
-    return true;
-  }
-  
-  function getDBCon($force = 0) {
-    if ($force || !isset($this->a['db_con'])) {
-      if (!$this->createDBCon()) {
-        return false;
-      }
-    }
-    if (!$force && !@mysql_thread_id($this->a['db_con'])) return $this->getDBCon(1);
-    return $this->a['db_con'];
-  }
-  
-  function closeDBCon() {
-    if ($this->v('db_con', false, $this->a)) {
-      @mysql_close($this->a['db_con']);
-    }
-    unset($this->a['db_con']);
-  }
-  
-  function getDBVersion() {
-    if (!$this->v('db_version')) {
-      $this->db_version = preg_match("/^([0-9]+)\.([0-9]+)\.([0-9]+)/", mysql_get_server_info($this->getDBCon()), $m) ? sprintf("%02d-%02d-%02d", $m[1], $m[2], $m[3])  : '00-00-00';
-    }
-    return $this->db_version;
-  }
-  
-  /*  */
-  
-  function getCollation() {
-    $rs = $this->queryDB('SHOW TABLE STATUS LIKE "' . $this->getTablePrefix(). 'setting"', $this->getDBCon());
-    return ($rs && ($row = mysql_fetch_array($rs)) && isset($row['Collation'])) ? $row['Collation'] : '';
-  }
-
-  function getColumnType() {
-    if (!$this->v('column_type')) {
-      $tbl = $this->getTablePrefix() . 'g2t';
-      $rs = $this->queryDB('SHOW COLUMNS FROM ' . $tbl . ' LIKE "t"', $this->getDBCon());
-      $row = $rs ? mysql_fetch_array($rs) : array('Type' => 'mediumint');
-      $this->column_type = preg_match('/mediumint/', $row['Type']) ? 'mediumint' : 'int';
-    }
-    return $this->column_type;
-  }
-
-  /*  */
-
-  function hasHashColumn($tbl) {
-    $var_name = 'has_hash_column_' . $tbl;
-    if (!isset($this->$var_name)) {
-      $tbl = $this->getTablePrefix() . $tbl;
-      $rs = $this->queryDB('SHOW COLUMNS FROM ' . $tbl . ' LIKE "val_hash"', $this->getDBCon());
-      $this->$var_name = ($rs && mysql_fetch_array($rs));
-    }
-    return $this->$var_name;
-  }
-
-  /*  */
-
-  function hasFulltextIndex() {
-    if (!isset($this->has_fulltext_index)) {
-      $this->has_fulltext_index = 0;
-      $tbl = $this->getTablePrefix() . 'o2val';
-      $rs = $this->queryDB('SHOW INDEX FROM ' . $tbl, $this->getDBCon());
-      while ($row = mysql_fetch_array($rs)) {
-        if ($row['Column_name'] != 'val') continue;
-        if ($row['Index_type'] != 'FULLTEXT') continue;
-        $this->has_fulltext_index = 1;
-        break;
-      }
-    }
-    return $this->has_fulltext_index;
-  }
-
-  function enableFulltextSearch() {
-    if ($this->hasFulltextIndex()) return 1;
-    $tbl = $this->getTablePrefix() . 'o2val';
-    $this->queryDB('CREATE FULLTEXT INDEX vft ON ' . $tbl . '(val(128))', $this->getDBCon(), 1);
-  }
-
-  function disableFulltextSearch() {
-    if (!$this->hasFulltextIndex()) return 1;
-    $tbl = $this->getTablePrefix() . 'o2val';
-    $this->queryDB('DROP INDEX vft ON ' . $tbl, $this->getDBCon());
-  }
-
-  /*  */
-
-  function countDBProcesses() {
-    return ($rs = $this->queryDB('SHOW PROCESSLIST', $this->getDBCon())) ? mysql_num_rows($rs) : 0;
-  }
-
-  function killDBProcesses($needle = '', $runtime = 30) {
-    $dbcon = $this->getDBCon();
-    /* make sure needle is sql */
-    if (preg_match('/\?.+ WHERE/i', $needle, $m)) {
-      $needle = $this->query($needle, 'sql');
-    }
-    $rs = $this->queryDB('SHOW FULL PROCESSLIST', $dbcon);
-    $ref_tbl = $this->getTablePrefix() . 'triple';
-    while ($row = mysql_fetch_array($rs)) {
-      if ($row['Time'] < $runtime) continue;
-      if (!preg_match('/^\s*(INSERT|SELECT) /s', $row['Info'])) continue; /* only basic queries */
-      if (!strpos($row['Info'], $ref_tbl . ' ')) continue; /* only from this store */
-      $kill = 0;
-      if ($needle && (strpos($row['Info'], $needle) !== false)) $kill = 1;
-      if (!$needle) $kill = 1;
-      if (!$kill) continue;
-      $this->queryDB('KILL ' . $row['Id'], $dbcon);
-    }
-  }
-  
-  /*  */
-
-  function getTables() {
-    return array('triple', 'g2t', 'id2val', 's2val', 'o2val', 'setting');
-  }  
-  
-  /*  */
-
-  function isSetUp() {
-    if (($con = $this->getDBCon())) {
-      $tbl = $this->getTablePrefix() . 'setting';
-      return $this->queryDB("SELECT 1 FROM " . $tbl . " LIMIT 0", $con) ? 1 : 0;
-    }
-  }
-  
-  function setUp($force = 0) {
-    if (($force || !$this->isSetUp()) && ($con = $this->getDBCon())) {
-      if ($this->getDBVersion() < '04-00-04') {
-        /* UPDATE + JOINs */
-        return $this->addError('MySQL version not supported. ARC requires version 4.0.4 or higher.');
-      }
-      ARC2::inc('StoreTableManager');
-      $mgr = new ARC2_StoreTableManager($this->a, $this);
-      $mgr->createTables();
-    }
-  }
-
-  function extendColumns() {
-    ARC2::inc('StoreTableManager');
-    $mgr = new ARC2_StoreTableManager($this->a, $this);
-    $mgr->extendColumns();
-    $this->column_type = 'int';
-  }
-
-  function splitTables() {
-    ARC2::inc('StoreTableManager');
-    $mgr = new ARC2_StoreTableManager($this->a, $this);
-    $mgr->splitTables();
-  }
-  
-  /*  */
-  
-  function hasSetting($k) {
-    $tbl = $this->getTablePrefix() . 'setting';
-    $sql = "SELECT val FROM " . $tbl . " WHERE k = '" .md5($k). "'";
-    $rs = $this->queryDB($sql, $this->getDBCon());
-    return ($rs && ($row = mysql_fetch_array($rs))) ? 1 : 0;
-  }
-  
-  function getSetting($k, $default = 0) {
-    $tbl = $this->getTablePrefix() . 'setting';
-    $sql = "SELECT val FROM " . $tbl . " WHERE k = '" .md5($k). "'";
-    $rs = $this->queryDB($sql, $this->getDBCon());
-    if ($rs && ($row = mysql_fetch_array($rs))) {
-      return unserialize($row['val']);
-    }
-    return $default;
-  }
-  
-  function setSetting($k, $v) {
-    $con = $this->getDBCon();
-    $tbl = $this->getTablePrefix() . 'setting';
-    if ($this->hasSetting($k)) {
-      $sql = "UPDATE " .$tbl . " SET val = '" . mysql_real_escape_string(serialize($v), $con) . "' WHERE k = '" . md5($k) . "'";
-    }
-    else {
-      $sql = "INSERT INTO " . $tbl . " (k, val) VALUES ('" . md5($k) . "', '" . mysql_real_escape_string(serialize($v), $con) . "')";
-    }
-    return $this->queryDB($sql, $con);
-  }
-  
-  function removeSetting($k) {
-    $tbl = $this->getTablePrefix() . 'setting';
-    return $this->queryDB("DELETE FROM " . $tbl . " WHERE k = '" . md5($k) . "'", $this->getDBCon());
-  }
-  
-  function getQueueTicket() {
-    if (!$this->queue_queries) return 1;
-    $t = 'ticket_' . substr(md5(uniqid(rand())), 0, 10);
-    $con = $this->getDBCon();
-    /* lock */
-    $rs = $this->queryDB('LOCK TABLES ' . $this->getTablePrefix() . 'setting WRITE', $con);
-    /* queue */
-    $queue = $this->getSetting('query_queue', array());
-    $queue[] = $t;
-    $this->setSetting('query_queue', $queue);
-    $this->queryDB('UNLOCK TABLES', $con);
-    /* loop */
-    $lc = 0;
-    $queue = $this->getSetting('query_queue', array());
-    while ($queue && ($queue[0] != $t) && ($lc < 30)) {
-      if ($this->is_win) {
-        sleep(1);
-        $lc++;
-      }
-      else {
-         usleep(100000);
-         $lc += 0.1;
-      }
-      $queue = $this->getSetting('query_queue', array());
-    }
-    return ($lc < 30) ? $t : 0;
-  }
-  
-  function removeQueueTicket($t) {
-    if (!$this->queue_queries) return 1;
-    $con = $this->getDBCon();
-    /* lock */
-    $this->queryDB('LOCK TABLES ' . $this->getTablePrefix() . 'setting WRITE', $con);
-    /* queue */
-    $vals = $this->getSetting('query_queue', array());
-    $pos = array_search($t, $vals);
-    $queue = ($pos < (count($vals) - 1)) ? array_slice($vals, $pos + 1) : array();
-    $this->setSetting('query_queue', $queue);
-    $this->queryDB('UNLOCK TABLES', $con);
-  }
-  
-  /*  */
-
-  function reset($keep_settings = 0) {
-    $con = $this->getDBCon();
-    $tbls = $this->getTables();
-    $prefix = $this->getTablePrefix();
-    /* remove split tables */
-    $ps = $this->getSetting('split_predicates', array());
-    foreach ($ps as $p) {
-      $tbl = 'triple_' . abs(crc32($p));
-      $this->queryDB('DROP TABLE ' . $prefix . $tbl, $con);
-    }
-    $this->removeSetting('split_predicates');
-    /* truncate tables */
-    foreach ($tbls as $tbl) {
-      if ($keep_settings && ($tbl == 'setting')) {
-        continue;
-      }
-      $this->queryDB('TRUNCATE ' . $prefix . $tbl, $con);
-    }
-  }
-  
-  function drop() {
-    $con = $this->getDBCon();
-    $tbls = $this->getTables();
-    $prefix = $this->getTablePrefix();
-    foreach ($tbls as $tbl) {
-      $this->queryDB('DROP TABLE ' . $prefix . $tbl, $con);
-    }
-  }
-  
-  function insert($doc, $g, $keep_bnode_ids = 0) {
-    $doc = is_array($doc) ? $this->toTurtle($doc) : $doc;
-    $infos = array('query' => array('url' => $g, 'target_graph' => $g));
-    ARC2::inc('StoreLoadQueryHandler');
-    $h = new ARC2_StoreLoadQueryHandler($this->a, $this);
-    $r = $h->runQuery($infos, $doc, $keep_bnode_ids);
-    $this->processTriggers('insert', $infos);
-    return $r;
-  }
-  
-  function delete($doc, $g) {
-    if (!$doc) {
-      $infos = array('query' => array('target_graphs' => array($g)));
-      ARC2::inc('StoreDeleteQueryHandler');
-      $h = new ARC2_StoreDeleteQueryHandler($this->a, $this);
-      $r = $h->runQuery($infos);
-      $this->processTriggers('delete', $infos);
-      return $r;
-    }
-  }
-  
-  function replace($doc, $g, $doc_2) {
-    return array($this->delete($doc, $g), $this->insert($doc_2, $g));
-  }
-  
-  function dump() {
-    ARC2::inc('StoreDumper');
-    $d = new ARC2_StoreDumper($this->a, $this);
-    $d->dumpSPOG();
-  }
-  
-  function createBackup($path, $q = '') {
-    ARC2::inc('StoreDumper');
-    $d = new ARC2_StoreDumper($this->a, $this);
-    $d->saveSPOG($path, $q);
-  }
-  
-  function renameTo($name) {
-    $con = $this->getDBCon();
-    $tbls = $this->getTables();
-    $old_prefix = $this->getTablePrefix();
-    $new_prefix = $this->v('db_table_prefix', '', $this->a);
-    $new_prefix .= $new_prefix ? '_' : '';
-    $new_prefix .= $name . '_';
-    foreach ($tbls as $tbl) {
-      $rs = $this->queryDB('RENAME TABLE ' . $old_prefix . $tbl .' TO ' . $new_prefix . $tbl, $con);
-      if ($er = mysql_error($con)) {
-        return $this->addError($er);
-      }
-    }
-    $this->a['store_name'] = $name;
-    unset($this->tbl_prefix);
-  }
-  
-  function replicateTo($name) {
-    $conf = array_merge($this->a, array('store_name' => $name));
-    $new_store = ARC2::getStore($conf);
-    $new_store->setUp();
-    $new_store->reset();
-    $con = $this->getDBCon();
-    $tbls = $this->getTables();
-    $old_prefix = $this->getTablePrefix();
-    $new_prefix = $new_store->getTablePrefix();
-    foreach ($tbls as $tbl) {
-      $rs = $this->queryDB('INSERT IGNORE INTO ' . $new_prefix . $tbl .' SELECT * FROM ' . $old_prefix . $tbl, $con);
-      if ($er = mysql_error($con)) {
-        return $this->addError($er);
-      }
-    }
-    return $new_store->query('SELECT COUNT(*) AS t_count WHERE { ?s ?p ?o}', 'row');
-  }
-  
-  /*  */
-  
-  function query($q, $result_format = '', $src = '', $keep_bnode_ids = 0, $log_query = 0) {
-    if ($log_query) $this->logQuery($q);
-    $con = $this->getDBCon();
-    if (preg_match('/^dump/i', $q)) {
-      $infos = array('query' => array('type' => 'dump'));
-    }
-    else {
-      ARC2::inc('SPARQLPlusParser');
-      $p = new ARC2_SPARQLPlusParser($this->a, $this);
-      $p->parse($q, $src);
-      $infos = $p->getQueryInfos();
-    }
-    if ($result_format == 'infos') return $infos;
-    $infos['result_format'] = $result_format;
-    if (!isset($p) || !$p->getErrors()) {
-      $qt = $infos['query']['type'];
-      if (!in_array($qt, array('select', 'ask', 'describe', 'construct', 'load', 'insert', 'delete', 'dump'))) {
-        return $this->addError('Unsupported query type "'.$qt.'"');
-      }
-      $t1 = ARC2::mtime();
-      $r = array('query_type' => $qt, 'result' => $this->runQuery($infos, $qt, $keep_bnode_ids, $q));
-      $t2 = ARC2::mtime();
-      $r['query_time'] = $t2 - $t1;
-      /* query result */
-      if ($result_format == 'raw') {
-        return $r['result'];
-      }
-      if ($result_format == 'rows') {
-        return $r['result']['rows'] ? $r['result']['rows'] : array();
-      }
-      if ($result_format == 'row') {
-        return $r['result']['rows'] ? $r['result']['rows'][0] : array();
-      }
-      return $r;
-    }
-    return 0;
-  }
-
-  function runQuery($infos, $type, $keep_bnode_ids = 0, $q = '') {
-    ARC2::inc('Store' . ucfirst($type) . 'QueryHandler');
-    $cls = 'ARC2_Store' . ucfirst($type) . 'QueryHandler';
-    $h = new $cls($this->a, $this);
-    $ticket = 1;
-    $r = array();
-    if ($q && ($type == 'select')) $ticket = $this->getQueueTicket($q);
-    if ($ticket) {
-      if ($type == 'load') {/* the LoadQH supports raw data as 2nd parameter */
-        $r = $h->runQuery($infos, '', $keep_bnode_ids);
-      }
-      else {
-        $r = $h->runQuery($infos, $keep_bnode_ids);
-      }
-    }
-    if ($q && ($type == 'select')) $this->removeQueueTicket($ticket);
-    $trigger_r = $this->processTriggers($type, $infos);
-    return $r;
-  }
-  
-  function processTriggers($type, $infos) {
-    $r = array();
-    $trigger_defs = $this->triggers;
-    $this->triggers = array();
-    if ($triggers = $this->v($type, array(), $trigger_defs)) {
-      $r['trigger_results'] = array();
-      $triggers = is_array($triggers) ? $triggers : array($triggers);
-      $trigger_inc_path = $this->v('store_triggers_path', '', $this->a);
-      foreach ($triggers as $trigger) {
-        $trigger .= !preg_match('/Trigger$/', $trigger) ? 'Trigger' : '';
-        if (ARC2::inc(ucfirst($trigger), $trigger_inc_path)) {
-          $cls = 'ARC2_' . ucfirst($trigger);
-          $config = array_merge($this->a, array('query_infos' => $infos));
-          $trigger_obj = new $cls($config, $this);
-          if (method_exists($trigger_obj, 'go')) {
-            $r['trigger_results'][] = $trigger_obj->go();
-          }
-        }
-      }
-    }
-    $this->triggers = $trigger_defs;
-    return $r;
-  }
-  
-  /*  */
-
-  function getValueHash($val) {
-    return abs(crc32($val));
-  }
-
-  function getTermID($val, $term = '') {
-    $tbl = preg_match('/^(s|o)$/', $term) ? $term . '2val' : 'id2val';
-    $con = $this->getDBCon();
-    /* via hash */
-    if (preg_match('/^(s2val|o2val)$/', $tbl) && $this->hasHashColumn($tbl)) {
-      $sql = "SELECT id, val FROM " . $this->getTablePrefix() . $tbl . " WHERE val_hash = '" . $this->getValueHash($val) . "'";
-      if (($rs = $this->queryDB($sql, $con)) && mysql_num_rows($rs)) {
-        while ($row = mysql_fetch_array($rs)) {
-          if ($row['val'] == $val) {
-            return $row['id'];
-          }
-        }
-      }
-    }
-    /* exact match */
-    else {
-      $sql = "SELECT id FROM " . $this->getTablePrefix() . $tbl . " WHERE val = BINARY '" . mysql_real_escape_string($val, $con) . "' LIMIT 1";
-      if (($rs = $this->queryDB($sql, $con)) && mysql_num_rows($rs) && ($row = mysql_fetch_array($rs))) {
-        return $row['id'];
-      }
-    }
-    return 0;
-  }
-
-  function getIDValue($id, $term = '') {
-    $tbl = preg_match('/^(s|o)$/', $term) ? $term . '2val' : 'id2val';
-    $con = $this->getDBCon();
-    $sql = "SELECT val FROM " . $this->getTablePrefix() . $tbl . " WHERE id = " . mysql_real_escape_string($id, $con) . " LIMIT 1";
-    if (($rs = $this->queryDB($sql, $con)) && mysql_num_rows($rs) && ($row = mysql_fetch_array($rs))) {
-      return $row['val'];
-    }
-    return 0;
-  }
-
-  /*  */
-  
-  function getLock($t_out = 10, $t_out_init = '') {
-    if (!$t_out_init) $t_out_init = $t_out;
-    $con = $this->getDBCon();
-    $l_name = $this->a['db_name'] . '.' . $this->getTablePrefix() . '.write_lock';
-    if ($rs = $this->queryDB('SELECT IS_FREE_LOCK("' . $l_name. '") AS success', $con)) {
-      $row = mysql_fetch_array($rs);
-      if (!$row['success']) {
-        if ($t_out) {
-          sleep(1);
-          return $this->getLock($t_out - 1, $t_out_init);
-        }
-      }
-      elseif ($rs = $this->queryDB('SELECT GET_LOCK("' . $l_name. '", ' . $t_out_init. ') AS success', $con)) {
-        $row = mysql_fetch_array($rs);
-        return $row['success'];
-      }
-    }
-    return 0;   
-  }
-  
-  function releaseLock() {
-    $con = $this->getDBCon();
-    return $this->queryDB('DO RELEASE_LOCK("' . $this->a['db_name'] . '.' . $this->getTablePrefix() . '.write_lock")', $con);
-  }
-
-  /*  */
-
-  function processTables($level = 2, $operation = 'optimize') {/* 1: triple + g2t, 2: triple + *2val, 3: all tables */
-    $con = $this->getDBCon();
-    $pre = $this->getTablePrefix();
-    $tbls = $this->getTables();
-    $sql = '';
-    foreach ($tbls as $tbl) {
-      if (($level < 3) && preg_match('/(backup|setting)$/', $tbl)) continue;
-      if (($level < 2) && preg_match('/(val)$/', $tbl)) continue;
-      $sql .= $sql ? ', ' : strtoupper($operation) . ' TABLE ';
-      $sql .= $pre . $tbl;
-    }
-    $this->queryDB($sql, $con);
-    if ($err = mysql_error($con)) $this->addError($err . ' in ' . $sql);
-  }
-
-  function optimizeTables($level = 2) {
-    if ($this->v('ignore_optimization')) return 1;
-    return $this->processTables($level, 'optimize');
-  }
-
-  function checkTables($level = 2) {
-    return $this->processTables($level, 'check');
-  }
-
-  function repairTables($level = 2) {
-    return $this->processTables($level, 'repair');
-  }
-
-  /*  */
-
-  function changeNamespaceURI($old_uri, $new_uri) {
-    ARC2::inc('StoreHelper');
-    $c = new ARC2_StoreHelper($this->a, $this);
-    return $c->changeNamespaceURI($old_uri, $new_uri);
-  }
-  
-  /*  */
-  
-  function getResourceLabel($res, $unnamed_label = 'An unnamed resource') {
-    if (!isset($this->resource_labels)) $this->resource_labels = array();
-    if (isset($this->resource_labels[$res])) return $this->resource_labels[$res];
-    if (!preg_match('/^[a-z0-9\_]+\:[^\s]+$/si', $res)) return $res;/* literal */
-    $ps = $this->getLabelProps();
-    if ($this->getSetting('store_label_properties', '-') != md5(serialize($ps))) {
-      $this->inferLabelProps($ps);
-    }
-    //$sub_q .= $sub_q ? ' || ' : '';
-    //$sub_q .= 'REGEX(str(?p), "(last_name|name|fn|title|label)$", "i")';
-    $q = 'SELECT ?label WHERE { <' . $res . '> ?p ?label . ?p a <http://semsol.org/ns/arc#LabelProperty> } LIMIT 3';
-    $r = '';
-    if ($rows = $this->query($q, 'rows')) {
-      foreach ($rows as $row) {
-        $r = strlen($row['label']) > strlen($r) ? $row['label'] : $r;
-      }
-    }
-    if (!$r && preg_match('/^\_\:/', $res)) {
-      return $unnamed_label;
-    }
-    $r = $r ? $r : preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('#self', '', $res));
-    $r = str_replace('_', ' ', $r);
-    $r = preg_replace('/([a-z])([A-Z])/e', '"\\1 " . strtolower("\\2")', $r);
-    $this->resource_labels[$res] = $r;
-    return $r;
-  }
-  
-  function getLabelProps() {
-    return array_merge(
-      $this->v('rdf_label_properties' , array(), $this->a),
-      array(
-        'http://www.w3.org/2000/01/rdf-schema#label',
-        'http://xmlns.com/foaf/0.1/name',
-        'http://purl.org/dc/elements/1.1/title',
-        'http://purl.org/rss/1.0/title',
-        'http://www.w3.org/2004/02/skos/core#prefLabel',
-        'http://xmlns.com/foaf/0.1/nick',
-      )
-    );
-  }
-  
-  function inferLabelProps($ps) {
-    $this->query('DELETE FROM <label-properties>');
-    $sub_q = '';
-    foreach ($ps as $p) {
-      $sub_q .= ' <' . $p . '> a <http://semsol.org/ns/arc#LabelProperty> . ';
-    }
-    $this->query('INSERT INTO <label-properties> { ' . $sub_q. ' }');
-    $this->setSetting('store_label_properties', md5(serialize($ps)));
-  }
-  
-  /*  */
-
-  function getResourcePredicates($res) {
-    $r = array();
-    if ($rows = $this->query('SELECT DISTINCT ?p WHERE { <' . $res . '> ?p ?o . }', 'rows')) {
-      foreach ($rows as $row) {
-        $r[$row['p']] = array();
-      }
-    }
-    return $r;
-  }
-  
-  function getDomains($p) {
-    $r = array();
-    foreach($this->query('SELECT DISTINCT ?type WHERE {?s <' . $p . '> ?o ; a ?type . }', 'rows') as $row) {
-      $r[] = $row['type'];
-    }
-    return $r;
-  }
-
-  function getPredicateRange($p) {
-    $row = $this->query('SELECT ?val WHERE {<' . $p . '> rdfs:range ?val . } LIMIT 1', 'row');
-    return $row ? $row['val'] : '';
-  }
-
-  /*  */
-  
-  function logQuery($q) {
-    $fp = @fopen("arc_query_log.txt", "a");
-    @fwrite($fp, date('Y-m-d\TH:i:s\Z', time()) . ' : ' . $q . '' . "\n\n");
-    @fclose($fp);
-  }
-
-  /*  */
+class ARC2_Store extends ARC2_Class
+{
+    protected $cache;
+    protected $db;
+
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
+
+    public function __init()
+    {
+        parent::__init();
+        $this->table_lock = 0;
+        $this->triggers = $this->v('store_triggers', [], $this->a);
+        $this->queue_queries = $this->v('store_queue_queries', 0, $this->a);
+        $this->is_win = ('win' == strtolower(substr(PHP_OS, 0, 3))) ? true : false;
+        $this->max_split_tables = $this->v('store_max_split_tables', 10, $this->a);
+        $this->split_predicates = $this->v('store_split_predicates', [], $this->a);
+
+        /*
+         * setup cache instance, if required by the user.
+         */
+        if ($this->cacheEnabled()) {
+            // reuse existing cache instance, if it implements Psr\SimpleCache\CacheInterface
+            if (isset($this->a['cache_instance'])
+                && $this->a['cache_instance'] instanceof \Psr\SimpleCache\CacheInterface) {
+                $this->cache = $this->a['cache_instance'];
+
+            // create new cache instance
+            } else {
+                // FYI: https://symfony.com/doc/current/components/cache/adapters/filesystem_adapter.html
+                $this->cache = new \Symfony\Component\Cache\Simple\FilesystemCache('arc2', 0, null);
+            }
+        }
+    }
+
+    public function cacheEnabled()
+    {
+        return isset($this->a['cache_enabled'])
+            && true === $this->a['cache_enabled']
+            && 'pdo' == $this->a['db_adapter'];
+    }
+
+    public function getName()
+    {
+        return $this->v('store_name', 'arc', $this->a);
+    }
+
+    public function getTablePrefix()
+    {
+        if (!isset($this->tbl_prefix)) {
+            $r = $this->v('db_table_prefix', '', $this->a);
+            $r .= $r ? '_' : '';
+            $r .= $this->getName().'_';
+            $this->tbl_prefix = $r;
+        }
+
+        return $this->tbl_prefix;
+    }
+
+    public function createDBCon()
+    {
+        // build connection credential array
+        foreach (['db_host' => 'localhost', 'db_user' => '', 'db_pwd' => '', 'db_name' => ''] as $k => $v) {
+            $this->a[$k] = $this->v($k, $v, $this->a);
+        }
+
+        // connect
+        try {
+            if (false === class_exists('\\ARC2\\Store\\Adapter\\AdapterFactory')) {
+                require __DIR__.'/../src/ARC2/Store/Adapter/AdapterFactory.php';
+            }
+            if (false == isset($this->a['db_adapter'])) {
+                $this->a['db_adapter'] = 'mysqli';
+            }
+            $factory = new \ARC2\Store\Adapter\AdapterFactory();
+            $this->db = $factory->getInstanceFor($this->a['db_adapter'], $this->a);
+            $err = $this->db->connect();
+            // stop here, if an error occoured
+            if (is_string($err) && false !== empty($err)) {
+                throw new \Exception($err);
+            }
+        } catch (\Exception $e) {
+            return $this->addError($e->getMessage());
+        }
+
+        if ('mysqli' == $this->db->getAdapterName()) {
+            $this->a['db_con'] = $this->db->getConnection();
+        }
+
+        $this->a['db_object'] = $this->db;
+
+        return true;
+    }
+
+    public function getDBObject()
+    {
+        return $this->db;
+    }
+
+    /**
+     * @param int $force 1 if you want to force a connection.
+     *
+     * @return mysqli mysqli-connection, only if mysqli adapter was selected. null otherwise,
+     *                because direct access to DB connection is not recommended.
+     */
+    public function getDBCon($force = 0)
+    {
+        if ($force || !isset($this->a['db_object'])) {
+            if (!$this->createDBCon()) {
+                return false;
+            }
+        }
+
+        if ('mysqli' == $this->a['db_adapter']) {
+            // for backward compatibility reasons only.
+            // TODO remove that in 3.x
+            return $this->a['db_con'];
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * @todo make property $a private, but provide access via a getter
+     */
+    public function closeDBCon()
+    {
+        if (isset($this->a['db_object'])) {
+            $this->db->disconnect();
+        }
+        unset($this->a['db_con']);
+        unset($this->a['db_object']);
+    }
+
+    public function getDBVersion()
+    {
+        if (!$this->v('db_version')) {
+            // connect, if no connection available
+            if (null == $this->db) {
+                $this->createDBCon();
+            }
+
+            $this->db_version = $this->db->getServerVersion();
+        }
+
+        return $this->db_version;
+    }
+
+    /**
+     * @return string Returns DBS name. Possible values: mysql, mariadb
+     */
+    public function getDBSName()
+    {
+        return $this->db->getDBSName();
+    }
+
+    public function getCollation()
+    {
+        $row = $this->db->fetchRow('SHOW TABLE STATUS LIKE "'.$this->getTablePrefix().'setting"');
+        return isset($row['Collation']) ? $row['Collation'] : '';
+    }
+
+    public function getColumnType()
+    {
+        if (!$this->v('column_type')) {
+            $tbl = $this->getTablePrefix().'g2t';
+
+            $row = $this->db->fetchRow('SHOW COLUMNS FROM '.$tbl.' LIKE "t"');
+            if (null == $row) {
+                $row = ['Type' => 'mediumint'];
+            }
+
+            $this->column_type = preg_match('/mediumint/', $row['Type']) ? 'mediumint' : 'int';
+        }
+
+        return $this->column_type;
+    }
+
+    public function hasHashColumn($tbl)
+    {
+        $var_name = 'has_hash_column_'.$tbl;
+        if (!isset($this->$var_name)) {
+            $tbl = $this->getTablePrefix().$tbl;
+
+            $row = $this->db->fetchRow('SHOW COLUMNS FROM '.$tbl.' LIKE "val_hash"');
+            $this->$var_name = null !== $row;
+        }
+
+        return $this->$var_name;
+    }
+
+    public function hasFulltextIndex()
+    {
+        if (!isset($this->has_fulltext_index)) {
+            $this->has_fulltext_index = 0;
+            $tbl = $this->getTablePrefix().'o2val';
+
+            $rows = $this->db->fetchList('SHOW INDEX FROM '.$tbl);
+            foreach($rows as $row) {
+                if ('val' != $row['Column_name']) {
+                    continue;
+                }
+                if ('FULLTEXT' != $row['Index_type']) {
+                    continue;
+                }
+                $this->has_fulltext_index = 1;
+                break;
+            }
+        }
+
+        return $this->has_fulltext_index;
+    }
+
+    public function enableFulltextSearch()
+    {
+        if ($this->hasFulltextIndex()) {
+            return 1;
+        }
+        $tbl = $this->getTablePrefix().'o2val';
+        $this->db->simpleQuery('CREATE FULLTEXT INDEX vft ON '.$tbl.'(val(128))');
+    }
+
+    public function disableFulltextSearch()
+    {
+        if (!$this->hasFulltextIndex()) {
+            return 1;
+        }
+        $tbl = $this->getTablePrefix().'o2val';
+        $this->db->simpleQuery('DROP INDEX vft ON '.$tbl);
+    }
+
+    public function countDBProcesses()
+    {
+        return $this->db->getNumberOfRows('SHOW PROCESSLIST');
+    }
+
+    /**
+     * Manipulating database processes using ARC2 is discouraged.
+     *
+     * @deprecated
+     */
+    public function killDBProcesses($needle = '', $runtime = 30)
+    {
+        /* make sure needle is sql */
+        if (preg_match('/\?.+ WHERE/i', $needle, $m)) {
+            $needle = $this->query($needle, 'sql');
+        }
+        $ref_tbl = $this->getTablePrefix().'triple';
+
+        $rows = $this->db->fetchList('SHOW FULL PROCESSLIST');
+        foreach ($rows as $row) {
+            if ($row['Time'] < $runtime) {
+                continue;
+            }
+            if (!preg_match('/^\s*(INSERT|SELECT) /s', $row['Info'])) {
+                continue;
+            } /* only basic queries */
+            if (!strpos($row['Info'], $ref_tbl.' ')) {
+                continue;
+            } /* only from this store */
+            $kill = 0;
+            if ($needle && (false !== strpos($row['Info'], $needle))) {
+                $kill = 1;
+            }
+            if (!$needle) {
+                $kill = 1;
+            }
+            if (!$kill) {
+                continue;
+            }
+            $this->db->simpleQuery('KILL '.$row['Id']);
+        }
+    }
+
+    public function getTables()
+    {
+        return ['triple', 'g2t', 'id2val', 's2val', 'o2val', 'setting'];
+    }
+
+    public function isSetUp()
+    {
+        if (null !== $this->db) {
+            $tbl = $this->getTablePrefix().'setting';
+
+            try {
+                // mysqli way
+                return $this->db->simpleQuery('SELECT 1 FROM '.$tbl.' LIMIT 0') ? 1 : 0;
+            } catch (\Exception $e) {
+                // when using PDO, an exception gets thrown if $tbl does not exist.
+                $this->errors[] = $e->getMessage();
+                return 0;
+            }
+        }
+
+        return 0;
+    }
+
+    public function setUp($force = 0)
+    {
+        if (($force || !$this->isSetUp()) && false !== $this->getDBCon()) {
+            ARC2::inc('StoreTableManager');
+            $mgr = new ARC2_StoreTableManager($this->a, $this);
+            $mgr->createTables();
+        }
+    }
+
+    public function extendColumns()
+    {
+        ARC2::inc('StoreTableManager');
+        $mgr = new ARC2_StoreTableManager($this->a, $this);
+        $mgr->extendColumns();
+        $this->column_type = 'int';
+    }
+
+    public function splitTables()
+    {
+        ARC2::inc('StoreTableManager');
+        $mgr = new ARC2_StoreTableManager($this->a, $this);
+        $mgr->splitTables();
+    }
+
+    public function hasSetting($k)
+    {
+        if (null == $this->db) {
+            $this->createDBCon();
+        }
+
+        $tbl = $this->getTablePrefix().'setting';
+
+        return $this->db->fetchRow('SELECT val FROM '.$tbl." WHERE k = '".md5($k)."'")
+            ? 1
+            : 0;
+    }
+
+    public function getSetting($k, $default = 0)
+    {
+        if (null == $this->db) {
+            $this->createDBCon();
+        }
+
+        $tbl = $this->getTablePrefix().'setting';
+        $row = $this->db->fetchRow('SELECT val FROM '.$tbl." WHERE k = '".md5($k)."'");
+        if (isset($row['val'])) {
+            return unserialize($row['val']);
+        }
+
+        return $default;
+    }
+
+    public function setSetting($k, $v)
+    {
+        $tbl = $this->getTablePrefix().'setting';
+        if ($this->hasSetting($k)) {
+            $sql = 'UPDATE '.$tbl." SET val = '".$this->db->escape(serialize($v))."' WHERE k = '".md5($k)."'";
+        } else {
+            $sql = 'INSERT INTO '.$tbl." (k, val) VALUES ('".md5($k)."', '".$this->db->escape(serialize($v))."')";
+        }
+
+        return $this->db->simpleQuery($sql);
+    }
+
+    public function removeSetting($k)
+    {
+        $tbl = $this->getTablePrefix().'setting';
+
+        return $this->db->simpleQuery('DELETE FROM '.$tbl." WHERE k = '".md5($k)."'");
+    }
+
+    public function getQueueTicket()
+    {
+        if (!$this->queue_queries) {
+            return 1;
+        }
+        $t = 'ticket_'.substr(md5(uniqid(rand())), 0, 10);
+        /* lock */
+        $this->db->simpleQuery('LOCK TABLES '.$this->getTablePrefix().'setting WRITE');
+        /* queue */
+        $queue = $this->getSetting('query_queue', []);
+        $queue[] = $t;
+        $this->setSetting('query_queue', $queue);
+        $this->db->simpleQuery('UNLOCK TABLES');
+        /* loop */
+        $lc = 0;
+        $queue = $this->getSetting('query_queue', []);
+        while ($queue && ($queue[0] != $t) && ($lc < 30)) {
+            if ($this->is_win) {
+                sleep(1);
+                ++$lc;
+            } else {
+                usleep(100000);
+                $lc += 0.1;
+            }
+            $queue = $this->getSetting('query_queue', []);
+        }
+
+        return ($lc < 30) ? $t : 0;
+    }
+
+    public function removeQueueTicket($t)
+    {
+        if (!$this->queue_queries) {
+            return 1;
+        }
+        /* lock */
+        $this->db->simpleQuery('LOCK TABLES '.$this->getTablePrefix().'setting WRITE');
+        /* queue */
+        $vals = $this->getSetting('query_queue', []);
+        $pos = array_search($t, $vals);
+        $queue = ($pos < (count($vals) - 1)) ? array_slice($vals, $pos + 1) : [];
+        $this->setSetting('query_queue', $queue);
+        $this->db->simpleQuery('UNLOCK TABLES');
+    }
+
+    public function reset($keep_settings = 0)
+    {
+        $tbls = $this->getTables();
+        $prefix = $this->getTablePrefix();
+        /* remove split tables */
+        $ps = $this->getSetting('split_predicates', []);
+        foreach ($ps as $p) {
+            $tbl = 'triple_'.abs(crc32($p));
+            $this->db->simpleQuery('DROP TABLE '.$prefix.$tbl);
+        }
+        $this->removeSetting('split_predicates');
+        /* truncate tables */
+        foreach ($tbls as $tbl) {
+            if ($keep_settings && ('setting' == $tbl)) {
+                continue;
+            }
+            $this->db->simpleQuery('TRUNCATE '.$prefix.$tbl);
+        }
+    }
+
+    public function drop()
+    {
+        if (null == $this->db) {
+            $this->createDBCon();
+        }
+
+        $prefix = $this->getTablePrefix();
+        $tbls = $this->getTables();
+        foreach ($tbls as $tbl) {
+            $this->db->simpleQuery('DROP TABLE IF EXISTS '.$prefix.$tbl);
+        }
+    }
+
+    public function insert($doc, $g, $keep_bnode_ids = 0)
+    {
+        $doc = is_array($doc) ? $this->toTurtle($doc) : $doc;
+        $infos = ['query' => ['url' => $g, 'target_graph' => $g]];
+        ARC2::inc('StoreLoadQueryHandler');
+        $h = new ARC2_StoreLoadQueryHandler($this->a, $this);
+        $r = $h->runQuery($infos, $doc, $keep_bnode_ids);
+        $this->processTriggers('insert', $infos);
+
+        return $r;
+    }
+
+    public function delete($doc, $g)
+    {
+        if (!$doc) {
+            $infos = ['query' => ['target_graphs' => [$g]]];
+            ARC2::inc('StoreDeleteQueryHandler');
+            $h = new ARC2_StoreDeleteQueryHandler($this->a, $this);
+            $r = $h->runQuery($infos);
+            $this->processTriggers('delete', $infos);
+
+            return $r;
+        }
+    }
+
+    public function replace($doc, $g, $doc_2)
+    {
+        return [$this->delete($doc, $g), $this->insert($doc_2, $g)];
+    }
+
+    public function dump()
+    {
+        ARC2::inc('StoreDumper');
+        $d = new ARC2_StoreDumper($this->a, $this);
+        $d->dumpSPOG();
+    }
+
+    public function createBackup($path, $q = '')
+    {
+        ARC2::inc('StoreDumper');
+        $d = new ARC2_StoreDumper($this->a, $this);
+        $d->saveSPOG($path, $q);
+    }
+
+    public function renameTo($name)
+    {
+        $tbls = $this->getTables();
+        $old_prefix = $this->getTablePrefix();
+        $new_prefix = $this->v('db_table_prefix', '', $this->a);
+        $new_prefix .= $new_prefix ? '_' : '';
+        $new_prefix .= $name.'_';
+        foreach ($tbls as $tbl) {
+            $this->db->simpleQuery('RENAME TABLE '.$old_prefix.$tbl.' TO '.$new_prefix.$tbl);
+            if (!empty($this->db->getErrorMessage())) {
+                return $this->addError($this->db->getErrorMessage());
+            }
+        }
+        $this->a['store_name'] = $name;
+        unset($this->tbl_prefix);
+    }
+
+    public function replicateTo($name)
+    {
+        $conf = array_merge($this->a, ['store_name' => $name]);
+        $new_store = ARC2::getStore($conf);
+        $new_store->setUp();
+        $new_store->reset();
+        $tbls = $this->getTables();
+        $old_prefix = $this->getTablePrefix();
+        $new_prefix = $new_store->getTablePrefix();
+        foreach ($tbls as $tbl) {
+            $this->db->simpleQuery('INSERT IGNORE INTO '.$new_prefix.$tbl.' SELECT * FROM '.$old_prefix.$tbl);
+            if (!empty($this->db->getErrorMessage())) {
+                return $this->addError($this->db->getErrorMessage());
+            }
+        }
+
+        return $new_store->query('SELECT COUNT(*) AS t_count WHERE { ?s ?p ?o}', 'row');
+    }
+
+    /**
+     * Executes a SPARQL query.
+     *
+     * @param string $q             SPARQL query
+     * @param string $result_format Possible values: infos, raw, rows, row
+     * @param string $src
+     * @param int $keep_bnode_ids   Keep blank node IDs? Default is 0
+     * @param int $log_query        Log executed queries? Default is 0
+     *
+     * @return array|int Array if query returned a result, 0 otherwise.
+     */
+    public function query($q, $result_format = '', $src = '', $keep_bnode_ids = 0, $log_query = 0)
+    {
+        if ($log_query) {
+            $this->logQuery($q);
+        }
+        if (preg_match('/^dump/i', $q)) {
+            $infos = ['query' => ['type' => 'dump']];
+        } else {
+            // check cache
+            $key = \hash('sha1', $q);
+            if ($this->cacheEnabled() && $this->cache->has($key.'_infos')) {
+                $infos = $this->cache->get($key.'_infos');
+                $errors = $this->cache->get($key.'_errors');
+            // no entry found
+            } else {
+                ARC2::inc('SPARQLPlusParser');
+                $p = new ARC2_SPARQLPlusParser($this->a, $this);
+                $p->parse($q, $src);
+                $infos = $p->getQueryInfos();
+                $errors = $p->getErrors();
+
+                // store result in cache
+                if ($this->cacheEnabled()) {
+                    $this->cache->set($key.'_infos', $infos);
+                    $this->cache->set($key.'_errors', $errors);
+                }
+            }
+        }
+
+        if ('infos' == $result_format) {
+            return $infos;
+        }
+
+        $infos['result_format'] = $result_format;
+
+        if (!isset($p) || 0 == count($errors)) {
+            $qt = $infos['query']['type'];
+            if (!in_array($qt, ['select', 'ask', 'describe', 'construct', 'load', 'insert', 'delete', 'dump'])) {
+                return $this->addError('Unsupported query type "'.$qt.'"');
+            }
+            $t1 = ARC2::mtime();
+
+            // if cache is enabled, get/store result
+            $key = \hash('sha1', $q);
+            if ($this->cacheEnabled() && $this->cache->has($key)) {
+                $result = $this->cache->get($key);
+
+            } else {
+                $result = $this->runQuery($infos, $qt, $keep_bnode_ids, $q);
+
+                // store in cache, if enabled
+                if ($this->cacheEnabled()) {
+                    $this->cache->set($key, $result);
+                }
+            }
+
+            $r = ['query_type' => $qt, 'result' => $result];
+            $r['query_time'] = ARC2::mtime() - $t1;
+
+            /* query result */
+            if ('raw' == $result_format) {
+                return $r['result'];
+            }
+            if ('rows' == $result_format) {
+                return $r['result']['rows'] ? $r['result']['rows'] : [];
+            }
+            if ('row' == $result_format) {
+                return $r['result']['rows'] ? $r['result']['rows'][0] : [];
+            }
+
+            return $r;
+        }
+
+        return 0;
+    }
+
+    /**
+     * Runs a SPARQL query. Dont use this function directly, use query instead.
+     */
+    public function runQuery($infos, $type, $keep_bnode_ids = 0, $q = '')
+    {
+        // invalidate cache, if enabled and a query is executed, which changes the store
+        if ($this->cacheEnabled() && in_array($type, ['load', 'insert', 'delete'])) {
+            $this->cache->clear();
+        }
+
+        ARC2::inc('Store'.ucfirst($type).'QueryHandler');
+        $cls = 'ARC2_Store'.ucfirst($type).'QueryHandler';
+        $h = new $cls($this->a, $this);
+        $ticket = 1;
+        $r = [];
+        if ($q && ('select' == $type)) {
+            $ticket = $this->getQueueTicket($q);
+        }
+        if ($ticket) {
+            if ('load' == $type) {/* the LoadQH supports raw data as 2nd parameter */
+                $r = $h->runQuery($infos, '', $keep_bnode_ids);
+            } else {
+                $r = $h->runQuery($infos, $keep_bnode_ids);
+            }
+        }
+        if ($q && ('select' == $type)) {
+            $this->removeQueueTicket($ticket);
+        }
+        $trigger_r = $this->processTriggers($type, $infos);
+
+        return $r;
+    }
+
+    public function processTriggers($type, $infos)
+    {
+        $r = [];
+        $trigger_defs = $this->triggers;
+        $this->triggers = [];
+        $triggers = $this->v($type, [], $trigger_defs);
+        if ($triggers) {
+            $r['trigger_results'] = [];
+            $triggers = is_array($triggers) ? $triggers : [$triggers];
+            $trigger_inc_path = $this->v('store_triggers_path', '', $this->a);
+            foreach ($triggers as $trigger) {
+                $trigger .= !preg_match('/Trigger$/', $trigger) ? 'Trigger' : '';
+                if (ARC2::inc(ucfirst($trigger), $trigger_inc_path)) {
+                    $cls = 'ARC2_'.ucfirst($trigger);
+                    $config = array_merge($this->a, ['query_infos' => $infos]);
+                    $trigger_obj = new $cls($config, $this);
+                    if (method_exists($trigger_obj, 'go')) {
+                        $r['trigger_results'][] = $trigger_obj->go();
+                    }
+                }
+            }
+        }
+        $this->triggers = $trigger_defs;
+
+        return $r;
+    }
+
+    public function getValueHash($val, $_32bit = false)
+    {
+        $hash = crc32($val);
+        if ($_32bit && ($hash & 0x80000000)) {
+            $hash = sprintf('%u', $hash);
+        }
+        $hash = abs($hash);
+
+        return $hash;
+    }
+
+    public function getTermID($val, $term = '')
+    {
+        /* mem cache */
+        if (!isset($this->term_id_cache) || (count(array_keys($this->term_id_cache)) > 100)) {
+            $this->term_id_cache = [];
+        }
+        if (!isset($this->term_id_cache[$term])) {
+            $this->term_id_cache[$term] = [];
+        }
+        $tbl = preg_match('/^(s|o)$/', $term) ? $term.'2val' : 'id2val';
+        /* cached? */
+        if ((strlen($val) < 100) && isset($this->term_id_cache[$term][$val])) {
+            return $this->term_id_cache[$term][$val];
+        }
+        $r = 0;
+        /* via hash */
+        if (preg_match('/^(s2val|o2val)$/', $tbl) && $this->hasHashColumn($tbl)) {
+
+            $rows = $this->db->fetchList(
+                'SELECT id, val FROM '.$this->getTablePrefix().$tbl." WHERE val_hash = '".$this->getValueHash($val)."' ORDER BY id"
+            );
+            if (is_array($rows) && 0 < count($rows)) {
+                foreach($rows as $row) {
+                    if ($row['val'] == $val) {
+                        $r = $row['id'];
+                        break;
+                    }
+                }
+            }
+        }
+        /* exact match */
+        else {
+            $sql = 'SELECT id FROM '.$this->getTablePrefix().$tbl." WHERE val = BINARY '".$this->db->escape($val)."' LIMIT 1";
+            $row = $this->db->fetchRow($sql);
+
+            if (null !== $row && isset($row['id'])) {
+                $r = $row['id'];
+            }
+        }
+        if ($r && (strlen($val) < 100)) {
+            $this->term_id_cache[$term][$val] = $r;
+        }
+
+        return $r;
+    }
+
+    public function getIDValue($id, $term = '')
+    {
+        $tbl = preg_match('/^(s|o)$/', $term) ? $term.'2val' : 'id2val';
+        $row = $this->db->fetchRow(
+            'SELECT val FROM '.$this->getTablePrefix().$tbl.' WHERE id = '.$this->db->escape($id).' LIMIT 1'
+        );
+        if (isset($row['val'])) {
+            return $row['val'];
+        }
+
+        return 0;
+    }
+
+    public function getLock($t_out = 10, $t_out_init = '')
+    {
+        if (!$t_out_init) {
+            $t_out_init = $t_out;
+        }
+
+        $l_name = $this->a['db_name'].'.'.$this->getTablePrefix().'.write_lock';
+        $row = $this->db->fetchRow('SELECT IS_FREE_LOCK("'.$l_name.'") AS success');
+
+        if (is_array($row)) {
+            if (!$row['success']) {
+                if ($t_out) {
+                    sleep(1);
+
+                    return $this->getLock($t_out - 1, $t_out_init);
+                }
+            } else {
+                $row = $this->db->fetchRow('SELECT GET_LOCK("'.$l_name.'", '.$t_out_init.') AS success');
+                if (isset($row['success'])) {
+                    return $row['success'];
+                }
+            }
+        }
+
+        return 0;
+    }
+
+    public function releaseLock()
+    {
+        return $this->db->simpleQuery('DO RELEASE_LOCK("'.$this->a['db_name'].'.'.$this->getTablePrefix().'.write_lock")');
+    }
+
+    public function processTables($level = 2, $operation = 'optimize')
+    {
+        /*
+         * level:
+         *      1. triple + g2t
+         *      2. triple + *2val
+         *      3. all tables
+         */
+        $pre = $this->getTablePrefix();
+        $tbls = $this->getTables();
+        $sql = '';
+        foreach ($tbls as $tbl) {
+            if (($level < 3) && preg_match('/(backup|setting)$/', $tbl)) {
+                continue;
+            }
+            if (($level < 2) && preg_match('/(val)$/', $tbl)) {
+                continue;
+            }
+            $sql .= $sql ? ', ' : strtoupper($operation).' TABLE ';
+            $sql .= $pre.$tbl;
+        }
+        $this->db->simpleQuery($sql);
+        if (false == empty($this->db->getErrorMessage())) {
+            $this->addError($this->db->getErrorMessage().' in '.$sql);
+        }
+    }
+
+    public function optimizeTables($level = 2)
+    {
+        if ($this->v('ignore_optimization')) {
+            return 1;
+        }
+
+        return $this->processTables($level, 'optimize');
+    }
+
+    public function checkTables($level = 2)
+    {
+        return $this->processTables($level, 'check');
+    }
+
+    public function repairTables($level = 2)
+    {
+        return $this->processTables($level, 'repair');
+    }
+
+    public function changeNamespaceURI($old_uri, $new_uri)
+    {
+        ARC2::inc('StoreHelper');
+        $c = new ARC2_StoreHelper($this->a, $this);
 
+        return $c->changeNamespaceURI($old_uri, $new_uri);
+    }
+
+    /**
+     * @param string $res URI
+     * @param string $unnamed_label How to label a resource without a name?
+     *
+     * @return string
+     */
+    public function getResourceLabel($res, $unnamed_label = 'An unnamed resource')
+    {
+        // init local label cache, if not set
+        if (!isset($this->resource_labels)) {
+            $this->resource_labels = [];
+        }
+        // if we already know the label for the given resource
+        if (isset($this->resource_labels[$res])) {
+            return $this->resource_labels[$res];
+        }
+        // if no URI was given, assume its a literal and return it
+        if (!preg_match('/^[a-z0-9\_]+\:[^\s]+$/si', $res)) {
+            return $res;
+        }
+
+        $ps = $this->getLabelProps();
+        if ($this->getSetting('store_label_properties', '-') != md5(serialize($ps))) {
+            $this->inferLabelProps($ps);
+        }
+
+        foreach ($ps as $labelProperty) {
+            // send a query for each label property
+            $result = $this->query('SELECT ?label WHERE { <'.$res.'> <'.$labelProperty.'> ?label }');
+            if (isset($result['result']['rows'][0])) {
+                $this->resource_labels[$res] = $result['result']['rows'][0]['label'];
+                return $result['result']['rows'][0]['label'];
+            }
+        }
+
+        $r = preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('#self', '', $res));
+        $r = str_replace('_', ' ', $r);
+        $r = preg_replace_callback('/([a-z])([A-Z])/', function ($matches) {
+            return $matches[1].' '.strtolower($matches[2]);
+        }, $r);
+        return $r;
+    }
+
+    public function getLabelProps()
+    {
+        return array_merge(
+            $this->v('rdf_label_properties', [], $this->a),
+            [
+                'http://www.w3.org/2000/01/rdf-schema#label',
+                'http://xmlns.com/foaf/0.1/name',
+                'http://purl.org/dc/elements/1.1/title',
+                'http://purl.org/rss/1.0/title',
+                'http://www.w3.org/2004/02/skos/core#prefLabel',
+                'http://xmlns.com/foaf/0.1/nick',
+            ]
+        );
+    }
+
+    public function inferLabelProps($ps)
+    {
+        $this->query('DELETE FROM <label-properties>');
+        $sub_q = '';
+        foreach ($ps as $p) {
+            $sub_q .= ' <'.$p.'> a <http://semsol.org/ns/arc#LabelProperty> . ';
+        }
+        $this->query('INSERT INTO <label-properties> { '.$sub_q.' }');
+        $this->setSetting('store_label_properties', md5(serialize($ps)));
+    }
+
+    public function getResourcePredicates($res)
+    {
+        $r = [];
+        $rows = $this->query('SELECT DISTINCT ?p WHERE { <'.$res.'> ?p ?o . }', 'rows');
+        foreach ($rows as $row) {
+            $r[$row['p']] = [];
+        }
+
+        return $r;
+    }
+
+    public function getDomains($p)
+    {
+        $r = [];
+        foreach ($this->query('SELECT DISTINCT ?type WHERE {?s <'.$p.'> ?o ; a ?type . }', 'rows') as $row) {
+            $r[] = $row['type'];
+        }
+
+        return $r;
+    }
+
+    public function getPredicateRange($p)
+    {
+        $row = $this->query('SELECT ?val WHERE {<'.$p.'> rdfs:range ?val . } LIMIT 1', 'row');
+
+        return $row ? $row['val'] : '';
+    }
+
+    /**
+     * @param string $q
+     *
+     * @todo make file path configurable
+     * @todo add try/catch in case file creation/writing fails
+     */
+    public function logQuery($q)
+    {
+        $fp = fopen('arc_query_log.txt', 'a');
+        fwrite($fp, date('Y-m-d\TH:i:s\Z', time()).' : '.$q.''."\n\n");
+        fclose($fp);
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreAskQueryHandler.php b/lib/arc2/store/ARC2_StoreAskQueryHandler.php
old mode 100644
new mode 100755
index 3515536873fd81cc4478d4c1ce77f92ae9ee264f..9458c8d3df75e36342a63a90f5c4bb1d29dd053e
--- a/lib/arc2/store/ARC2_StoreAskQueryHandler.php
+++ b/lib/arc2/store/ARC2_StoreAskQueryHandler.php
@@ -1,53 +1,46 @@
 <?php
 /**
- * ARC2 SPARQL ASK query handler
+ * ARC2 SPARQL ASK query handler.
  *
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('StoreSelectQueryHandler');
 
-class ARC2_StoreAskQueryHandler extends ARC2_StoreSelectQueryHandler {
-
-  function __construct($a, &$caller) {/* caller has to be a store */
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* db_con */
-    parent::__init();
-    $this->store = $this->caller;
-  }
-
-  /*  */
-  
-  function runQuery($infos) {
-    $infos['query']['limit'] = 1;
-    $this->infos = $infos;
-    $this->buildResultVars();
-    return parent::runQuery($this->infos);
-  }
-  
-  /*  */
-  
-  function buildResultVars() {
-    $this->infos['query']['result_vars'][] = array('var' => '1', 'aggregate' => '', 'alias' => 'success');
-  }
-
-  /*  */
-  
-  function getFinalQueryResult($q_sql, $tmp_tbl) {
-    $con = $this->store->getDBCon();
-    $rs = mysql_query('SELECT success FROM ' . $tmp_tbl, $con);
-    $r = ($row = mysql_fetch_array($rs)) ? $row['success'] : 0;
-    return $r ? true : false;
-  }
-
-  /*  */
-  
+class ARC2_StoreAskQueryHandler extends ARC2_StoreSelectQueryHandler
+{
+    public function __construct($a, &$caller)
+    {/* caller has to be a store */
+        parent::__construct($a, $caller);
+    }
+
+    public function __init()
+    {
+        parent::__init();
+        $this->store = $this->caller;
+    }
+
+    public function runQuery($infos)
+    {
+        $infos['query']['limit'] = 1;
+        $this->infos = $infos;
+        $this->buildResultVars();
+
+        return parent::runQuery($this->infos);
+    }
+
+    public function buildResultVars()
+    {
+        $this->infos['query']['result_vars'][] = ['var' => '1', 'aggregate' => '', 'alias' => 'success'];
+    }
+
+    public function getFinalQueryResult($q_sql, $tmp_tbl)
+    {
+        $row = $this->store->a['db_object']->fetchRow('SELECT success FROM '.$tmp_tbl);
+        $r = isset($row['success']) ? $row['success'] : 0;
+        return $r ? true : false;
+    }
 }
-
-
diff --git a/lib/arc2/store/ARC2_StoreAtomLoader.php b/lib/arc2/store/ARC2_StoreAtomLoader.php
old mode 100644
new mode 100755
index 2070df003b14e855b97d547322effb527c7d0662..650fe5f8b37005e4705900b0acfc863ab7492cc7
--- a/lib/arc2/store/ARC2_StoreAtomLoader.php
+++ b/lib/arc2/store/ARC2_StoreAtomLoader.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 Store Atom(2) Loader
 author:   Benjamin Nowack
@@ -10,23 +10,21 @@ version:  2010-11-16
 
 ARC2::inc('AtomParser');
 
-class ARC2_StoreAtomLoader extends ARC2_AtomParser {
+class ARC2_StoreAtomLoader extends ARC2_AtomParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
 
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-  }
-
-  /*  */
-  
-  function addT($t) {
-    $this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
-    $this->t_count++;
-  }
-
-  /*  */
+    public function __init()
+    {
+        parent::__init();
+    }
 
+    public function addT($t)
+    {
+        $this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
+        ++$this->t_count;
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreCBJSONLoader.php b/lib/arc2/store/ARC2_StoreCBJSONLoader.php
old mode 100644
new mode 100755
index ae262b5090b987c925d61a5b3d4306097ddfd028..40f7c6d338dbfb460c5c0aec26844a990349a157
--- a/lib/arc2/store/ARC2_StoreCBJSONLoader.php
+++ b/lib/arc2/store/ARC2_StoreCBJSONLoader.php
@@ -1,38 +1,36 @@
 <?php
 /**
- * ARC2 Store CrunchBase API JSON Loader
+ * ARC2 Store CrunchBase API JSON Loader.
  *
  * @author Benjamin Nowack <bnowack@semsol.com>
- * @license http://arc.semsol.org/license
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('CBJSONParser');
 
-class ARC2_StoreCBJSONLoader extends ARC2_CBJSONParser {
+class ARC2_StoreCBJSONLoader extends ARC2_CBJSONParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
 
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-  }
+    public function __init()
+    {
+        parent::__init();
+    }
 
-  /*  */
-  
-  function done() {
-    $this->extractRDF();
-  }
-  
-  function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
-    $o = $this->toUTF8($o);
-    $this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
-    $this->t_count++;
-  }
-  
-  /*  */
+    public function done()
+    {
+        $this->extractRDF();
+    }
 
+    public function addT($s = '', $p = '', $o = '', $s_type = '', $o_type = '', $o_dt = '', $o_lang = '')
+    {
+        $o = $this->toUTF8($o);
+        $this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
+        ++$this->t_count;
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreConstructQueryHandler.php b/lib/arc2/store/ARC2_StoreConstructQueryHandler.php
old mode 100644
new mode 100755
index 150e5981d1eb4d8fb1944ffc9a615967e7a141a0..8c7ca92f62f23224a4dddbefea5e5877e9cebc50
--- a/lib/arc2/store/ARC2_StoreConstructQueryHandler.php
+++ b/lib/arc2/store/ARC2_StoreConstructQueryHandler.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 RDF Store CONSTRUCT Query Handler
 author:   Benjamin Nowack
@@ -10,106 +10,102 @@ version:  2010-11-16
 
 ARC2::inc('StoreSelectQueryHandler');
 
-class ARC2_StoreConstructQueryHandler extends ARC2_StoreSelectQueryHandler {
-
-  function __construct($a, &$caller) {/* caller has to be a store */
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* db_con */
-    parent::__init();
-    $this->store = $this->caller;
-  }
+class ARC2_StoreConstructQueryHandler extends ARC2_StoreSelectQueryHandler
+{
+    public function __construct($a, &$caller)
+    {/* caller has to be a store */
+        parent::__construct($a, $caller);
+    }
 
-  /*  */
-  
-  function runQuery($infos) {
-    $this->infos = $infos;
-    $this->buildResultVars();
-    $this->infos['query']['distinct'] = 1;
-    $sub_r = parent::runQuery($this->infos);
-    $rf = $this->v('result_format', '', $infos);
-    if (in_array($rf, array('sql', 'structure', 'index'))) {
-      return $sub_r;
+    public function __init()
+    {
+        parent::__init();
+        $this->store = $this->caller;
     }
-    return $this->getResultIndex($sub_r);
-  }
-  
-  /*  */
-  
-  function buildResultVars() {
-    $r = array();
-    foreach ($this->infos['query']['construct_triples'] as $t) {
-      foreach (array('s', 'p', 'o') as $term) {
-        if ($t[$term . '_type'] == 'var') {
-          if (!in_array($t[$term], $r)) {
-            $r[] = array('var' => $t[$term], 'aggregate' => '', 'alias' => '');
-          }
+
+    public function runQuery($infos)
+    {
+        $this->infos = $infos;
+        $this->buildResultVars();
+        $this->infos['query']['distinct'] = 1;
+        $sub_r = parent::runQuery($this->infos);
+        $rf = $this->v('result_format', '', $infos);
+        if (in_array($rf, ['sql', 'structure', 'index'])) {
+            return $sub_r;
         }
-      }
-    }
-    $this->infos['query']['result_vars'] = $r;
-  }
 
-  /*  */
+        return $this->getResultIndex($sub_r);
+    }
 
-  function getResultIndex($qr) {
-    $r = array();
-    $added = array();
-    $rows = $this->v('rows', array(), $qr);
-    $cts = $this->infos['query']['construct_triples'];
-    $bnc = 0;
-    foreach ($rows as $row) {
-      $bnc++;
-      foreach ($cts as $ct) {
-        $skip_t = 0;
-        $t = array();
-        foreach (array('s', 'p', 'o') as $term) {
-          $val = $ct[$term];
-          $type = $ct[$term . '_type'];
-          $val = ($type == 'bnode') ? $val . $bnc : $val;
-          if ($type == 'var') {
-            $skip_t = !isset($row[$val]) ? 1 : $skip_t;
-            $type = !$skip_t ? $row[$val . ' type'] : '';
-            $val = (!$skip_t) ? $row[$val] : '';
-          }
-          $t[$term] = $val;
-          $t[$term . '_type'] = $type;
-          if (isset($row[$term . ' lang'])) {
-            $t[$term . '_lang'] = $row[$term . ' lang'];
-          }
-          if (isset($row[$term . ' datatype'])) {
-            $t[$term . '_datatype'] = $row[$term . ' datatype'];
-          }
-        }
-        if (!$skip_t) {
-          $s = $t['s'];
-          $p = $t['p'];
-          $o = $t['o'];
-          if (!isset($r[$s])) {
-            $r[$s] = array();
-          }
-          if (!isset($r[$s][$p])) {
-            $r[$s][$p] = array();
-          }
-          $o = array('value' => $o);
-          foreach (array('lang', 'type', 'datatype') as $suffix) {
-            if (isset($t['o_' . $suffix]) && $t['o_' . $suffix]) {
-              $o[$suffix] = $t['o_' . $suffix];
+    public function buildResultVars()
+    {
+        $r = [];
+        foreach ($this->infos['query']['construct_triples'] as $t) {
+            foreach (['s', 'p', 'o'] as $term) {
+                if ('var' == $t[$term.'_type']) {
+                    if (!in_array($t[$term], $r)) {
+                        $r[] = ['var' => $t[$term], 'aggregate' => '', 'alias' => ''];
+                    }
+                }
             }
-          }
-          if (!isset($added[md5($s . ' ' . $p . ' ' . serialize($o))])) {
-            $r[$s][$p][] = $o;
-            $added[md5($s . ' ' . $p . ' ' . serialize($o))] = 1;
-          }
         }
-      }
+        $this->infos['query']['result_vars'] = $r;
     }
-    return $r;
-  }
-  
-  /*  */
-
-}
 
+    public function getResultIndex($qr)
+    {
+        $r = [];
+        $added = [];
+        $rows = $this->v('rows', [], $qr);
+        $cts = $this->infos['query']['construct_triples'];
+        $bnc = 0;
+        foreach ($rows as $row) {
+            ++$bnc;
+            foreach ($cts as $ct) {
+                $skip_t = 0;
+                $t = [];
+                foreach (['s', 'p', 'o'] as $term) {
+                    $val = $ct[$term];
+                    $type = $ct[$term.'_type'];
+                    $val = ('bnode' == $type) ? $val.$bnc : $val;
+                    if ('var' == $type) {
+                        $skip_t = !isset($row[$val]) ? 1 : $skip_t;
+                        $type = !$skip_t ? $row[$val.' type'] : '';
+                        $val = (!$skip_t) ? $row[$val] : '';
+                    }
+                    $t[$term] = $val;
+                    $t[$term.'_type'] = $type;
+                    if (isset($row[$ct[$term].' lang'])) {
+                        $t[$term.'_lang'] = $row[$ct[$term].' lang'];
+                    }
+                    if (isset($row[$ct[$term].' datatype'])) {
+                        $t[$term.'_datatype'] = $row[$ct[$term].' datatype'];
+                    }
+                }
+                if (!$skip_t) {
+                    $s = $t['s'];
+                    $p = $t['p'];
+                    $o = $t['o'];
+                    if (!isset($r[$s])) {
+                        $r[$s] = [];
+                    }
+                    if (!isset($r[$s][$p])) {
+                        $r[$s][$p] = [];
+                    }
+                    $o = ['value' => $o];
+                    foreach (['lang', 'type', 'datatype'] as $suffix) {
+                        if (isset($t['o_'.$suffix]) && $t['o_'.$suffix]) {
+                            $o[$suffix] = $t['o_'.$suffix];
+                        }
+                    }
+                    if (!isset($added[md5($s.' '.$p.' '.serialize($o))])) {
+                        $r[$s][$p][] = $o;
+                        $added[md5($s.' '.$p.' '.serialize($o))] = 1;
+                    }
+                }
+            }
+        }
 
+        return $r;
+    }
+}
diff --git a/lib/arc2/store/ARC2_StoreDeleteQueryHandler.php b/lib/arc2/store/ARC2_StoreDeleteQueryHandler.php
index 9351dbd670f59f5421b1d8f00b5385dc48a843c7..b8889809fa593e8941201e5472f099ff75f41ad6 100644
--- a/lib/arc2/store/ARC2_StoreDeleteQueryHandler.php
+++ b/lib/arc2/store/ARC2_StoreDeleteQueryHandler.php
@@ -1,233 +1,240 @@
 <?php
 /**
- * ARC2 RDF Store DELETE Query Handler
+ * ARC2 RDF Store DELETE Query Handler.
  *
  * @author Benjamin Nowack <bnowack@semsol.com>
- * @license http://arc.semsol.org/license
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
- * @version 2010-11-16
-*/
-
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ */
 ARC2::inc('StoreQueryHandler');
 
-class ARC2_StoreDeleteQueryHandler extends ARC2_StoreQueryHandler {
-
-  function __construct($a, &$caller) {/* caller has to be a store */
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* db_con */
-    parent::__init();
-    $this->store = $this->caller;
-    $this->handler_type = 'delete';
-  }
-
-  /*  */
-  
-  function runQuery($infos) {
-    $this->infos = $infos;
-    $con = $this->store->getDBCon();
-    $t1 = ARC2::mtime();
-    /* delete */
-    $this->refs_deleted = false;
-    /* graph(s) only */
-    if (!$this->v('construct_triples', array(), $this->infos['query'])) {
-      $tc = $this->deleteTargetGraphs();
-    }
-    /* graph(s) + explicit triples */
-    elseif (!$this->v('pattern', array(), $this->infos['query'])) {
-      $tc = $this->deleteTriples();
-    }
-    /* graph(s) + constructed triples */
-    else {
-      $tc = $this->deleteConstructedGraph();
+class ARC2_StoreDeleteQueryHandler extends ARC2_StoreQueryHandler
+{
+    public function __construct($a, &$caller)
+    {/* caller has to be a store */
+        parent::__construct($a, $caller);
     }
-    $t2 = ARC2::mtime();
-    /* clean up */
-    if ($tc && ($this->refs_deleted || (rand(1, 100) == 1))) $this->cleanTableReferences();
-    if ($tc && (rand(1, 100) == 1)) $this->store->optimizeTables();
-    if ($tc && (rand(1, 500) == 1)) $this->cleanValueTables();
-    $t3 = ARC2::mtime();
-    $index_dur = round($t3 - $t2, 4);
-    $dur = round($t3 - $t1, 4);
-    return array(
-      't_count' => $tc,
-      'delete_time' => $dur,
-      'index_update_time' => $index_dur,
-    );
-  }
-  
-  /*  */
-
-  function deleteTargetGraphs() {
-    $tbl_prefix = $this->store->getTablePrefix();
-    $r = 0;
-    $con = $this->store->getDBCon();
-    foreach ($this->infos['query']['target_graphs'] as $g) {
-      if ($g_id = $this->getTermID($g, 'g')) {
-        $rs = mysql_query('DELETE FROM ' . $tbl_prefix . 'g2t WHERE g = ' .$g_id, $con);
-        $r += mysql_affected_rows($con);
-      }
-    }
-    $this->refs_deleted = $r ? 1 : 0;
-    return $r;
-  }
-  
-  /*  */
-  
-  function deleteTriples() {
-    $r = 0;
-    $dbv = $this->store->getDBVersion();
-    $tbl_prefix = $this->store->getTablePrefix();
-    $con = $this->store->getDBCon();
-    /* graph restriction */
-    $tgs = $this->infos['query']['target_graphs'];
-    $gq = '';
-    foreach ($tgs as $g) {
-      if ($g_id = $this->getTermID($g, 'g')) {
-        $gq .= $gq ? ', ' . $g_id : $g_id;
-      }
+
+    public function __init()
+    {
+        parent::__init();
+        $this->store = $this->caller;
+        $this->handler_type = 'delete';
     }
-    $gq = $gq ? ' AND G.g IN (' . $gq . ')' : '';
-    /* triples */
-    foreach ($this->infos['query']['construct_triples'] as $t) {
-      $q = '';
-      $skip = 0;
-      foreach (array('s', 'p', 'o') as $term) {
-        if (isset($t[$term . '_type']) && preg_match('/(var)/', $t[$term . '_type'])) {
-          //$skip = 1;
+
+    public function runQuery($infos)
+    {
+        $this->infos = $infos;
+        $t1 = ARC2::mtime();
+        /* delete */
+        $this->refs_deleted = false;
+        /* graph(s) only */
+        if (!$this->v('construct_triples', [], $this->infos['query'])) {
+            $tc = $this->deleteTargetGraphs();
         }
+        /* graph(s) + explicit triples */
+        elseif (!$this->v('pattern', [], $this->infos['query'])) {
+            $tc = $this->deleteTriples();
+        }
+        /* graph(s) + constructed triples */
         else {
-          $term_id = $this->getTermID($t[$term], $term);
-          $q .= ($q ? ' AND ' : '') . 'T.' . $term . '=' . $term_id;
-          /* explicit lang/dt restricts the matching */
-          if ($term == 'o') {
-            $o_lang = $this->v1('o_lang', '', $t);
-            $o_lang_dt = $this->v1('o_datatype', $o_lang, $t);
-            if ($o_lang_dt) {
-              $q .= ($q ? ' AND ' : '') . 'T.o_lang_dt=' . $this->getTermID($o_lang_dt, 'lang_dt');
+            $tc = $this->deleteConstructedGraph();
+        }
+        $t2 = ARC2::mtime();
+        /* clean up */
+        if ($tc && ($this->refs_deleted || (1 == rand(1, 100)))) {
+            $this->cleanTableReferences();
+        }
+        // TODO What does this rand() call here? remove it and think about a cleaner way
+        //      when to trigger optimizeTables
+        if ($tc && (1 == rand(1, 100))) {
+            $this->store->optimizeTables();
+        }
+        // TODO What does this rand() call here? remove it and think about a cleaner way
+        //      when to trigger cleanValueTables
+        if ($tc && (1 == rand(1, 500))) {
+            $this->cleanValueTables();
+        }
+        $t3 = ARC2::mtime();
+        $index_dur = round($t3 - $t2, 4);
+        $dur = round($t3 - $t1, 4);
+
+        return [
+            't_count' => $tc,
+            'delete_time' => $dur,
+            'index_update_time' => $index_dur,
+        ];
+    }
+
+    public function deleteTargetGraphs()
+    {
+        $tbl_prefix = $this->store->getTablePrefix();
+        $r = 0;
+        foreach ($this->infos['query']['target_graphs'] as $g) {
+            if ($g_id = $this->getTermID($g, 'g')) {
+                $r += $this->store->a['db_object']->exec('DELETE FROM '.$tbl_prefix.'g2t WHERE g = '.$g_id);
             }
-          }
         }
-      }
-      if ($skip) {
-        continue;
-      }
-      if ($gq) {
-        $sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 'g2t' : 'DELETE G';
-        $sql .= '
-          FROM ' . $tbl_prefix . 'g2t G 
-          JOIN ' . $this->getTripleTable() . ' T ON (T.t = G.t' . $gq . ')
-          WHERE ' . $q . '
+        $this->refs_deleted = $r ? 1 : 0;
+
+        return $r;
+    }
+
+    public function deleteTriples()
+    {
+        $r = 0;
+        $dbv = $this->store->getDBVersion();
+        $tbl_prefix = $this->store->getTablePrefix();
+        /* graph restriction */
+        $tgs = $this->infos['query']['target_graphs'];
+        $gq = '';
+        foreach ($tgs as $g) {
+            if ($g_id = $this->getTermID($g, 'g')) {
+                $gq .= $gq ? ', '.$g_id : $g_id;
+            }
+        }
+        $gq = $gq ? ' AND G.g IN ('.$gq.')' : '';
+        /* triples */
+        foreach ($this->infos['query']['construct_triples'] as $t) {
+            $q = '';
+            $skip = 0;
+            foreach (['s', 'p', 'o'] as $term) {
+                if (isset($t[$term.'_type']) && preg_match('/(var)/', $t[$term.'_type'])) {
+                    //$skip = 1;
+                } else {
+                    $term_id = $this->getTermID($t[$term], $term);
+                    $q .= ($q ? ' AND ' : '').'T.'.$term.'='.$term_id;
+                    /* explicit lang/dt restricts the matching */
+                    if ('o' == $term) {
+                        $o_lang = $this->v1('o_lang', '', $t);
+                        $o_lang_dt = $this->v1('o_datatype', $o_lang, $t);
+                        if ($o_lang_dt) {
+                            $q .= ($q ? ' AND ' : '').'T.o_lang_dt='.$this->getTermID($o_lang_dt, 'lang_dt');
+                        }
+                    }
+                }
+            }
+            if ($skip) {
+                continue;
+            }
+            if ($gq) {
+                $sql = ($dbv < '04-01') ? 'DELETE '.$tbl_prefix.'g2t' : 'DELETE G';
+                $sql .= '
+          FROM '.$tbl_prefix.'g2t G
+          JOIN '.$this->getTripleTable().' T ON (T.t = G.t'.$gq.')
+          WHERE '.$q.'
         ';
-        $this->refs_deleted = 1;
-      }
-      else {/* triples only */
-        $sql = ($dbv < '04-01') ? 'DELETE ' . $this->getTripleTable() : 'DELETE T';
-        $sql .= ' FROM ' . $this->getTripleTable() . ' T WHERE ' . $q;
-      }
-      $rs = mysql_query($sql, $con);
-      if ($er = mysql_error($con)) {
-        $this->addError($er .' in ' . $sql);
-      }
-      $r += mysql_affected_rows($con);
+                $this->refs_deleted = 1;
+            } else {/* triples only */
+                $sql = ($dbv < '04-01') ? 'DELETE '.$this->getTripleTable() : 'DELETE T';
+                $sql .= ' FROM '.$this->getTripleTable().' T WHERE '.$q;
+            }
+            $r += $this->store->a['db_object']->exec($sql);
+            if (!empty($this->store->a['db_object']->getErrorMessage())) {
+                $this->addError($this->store->a['db_object']->getErrorMessage().' in '.$sql);
+            }
+        }
+
+        return $r;
     }
-    return $r;
-  }
-  
-  /*  */
-  
-  function deleteConstructedGraph() {
-    ARC2::inc('StoreConstructQueryHandler');
-    $h = new ARC2_StoreConstructQueryHandler($this->a, $this->store);
-    $sub_r = $h->runQuery($this->infos);
-    $triples = ARC2::getTriplesFromIndex($sub_r);
-    $tgs = $this->infos['query']['target_graphs'];
-    $this->infos = array('query' => array('construct_triples' => $triples, 'target_graphs' => $tgs));
-    return $this->deleteTriples();
-  }
-  
-  /*  */
-  
-  function cleanTableReferences() {
-    /* lock */
-    if (!$this->store->getLock()) return $this->addError('Could not get lock in "cleanTableReferences"');
-    $con = $this->store->getDBCon();
-    $tbl_prefix = $this->store->getTablePrefix();
-    $dbv = $this->store->getDBVersion();
-    /* check for unconnected triples */
-    $sql = '
-      SELECT T.t FROM '. $tbl_prefix . 'triple T LEFT JOIN '. $tbl_prefix . 'g2t G ON ( G.t = T.t )
+
+    public function deleteConstructedGraph()
+    {
+        ARC2::inc('StoreConstructQueryHandler');
+        $h = new ARC2_StoreConstructQueryHandler($this->a, $this->store);
+        $sub_r = $h->runQuery($this->infos);
+        $triples = ARC2::getTriplesFromIndex($sub_r);
+        $tgs = $this->infos['query']['target_graphs'];
+        $this->infos = ['query' => ['construct_triples' => $triples, 'target_graphs' => $tgs]];
+
+        return $this->deleteTriples();
+    }
+
+    public function cleanTableReferences()
+    {
+        /* lock */
+        if (!$this->store->getLock()) {
+            return $this->addError('Could not get lock in "cleanTableReferences"');
+        }
+        $tbl_prefix = $this->store->getTablePrefix();
+        $dbv = $this->store->getDBVersion();
+        /* check for unconnected triples */
+        $sql = '
+      SELECT T.t FROM '.$tbl_prefix.'triple T LEFT JOIN '.$tbl_prefix.'g2t G ON ( G.t = T.t )
       WHERE G.t IS NULL LIMIT 1
     ';
-    if (($rs = mysql_query($sql, $con)) && mysql_num_rows($rs)) {
-      /* delete unconnected triples */
-      $sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 'triple' : 'DELETE T';
-      $sql .= '
-        FROM ' . $tbl_prefix . 'triple T 
-        LEFT JOIN ' . $tbl_prefix . 'g2t G ON (G.t = T.t)
+        $numRows = $this->store->a['db_object']->getNumberOfRows($sql);
+        if (0 < $numRows) {
+            /* delete unconnected triples */
+            $sql = ($dbv < '04-01') ? 'DELETE '.$tbl_prefix.'triple' : 'DELETE T';
+            $sql .= '
+        FROM '.$tbl_prefix.'triple T
+        LEFT JOIN '.$tbl_prefix.'g2t G ON (G.t = T.t)
         WHERE G.t IS NULL
       ';
-      mysql_query($sql, $con);
+            $this->store->a['db_object']->simpleQuery($sql);
+        }
+        /* check for unconnected graph refs */
+        if ((1 == rand(1, 10))) {
+            $sql = '
+                SELECT G.g FROM '.$tbl_prefix.'g2t G LEFT JOIN '.$tbl_prefix.'triple T ON ( T.t = G.t )
+                WHERE T.t IS NULL LIMIT 1
+            ';
+            if (0 < $this->store->a['db_object']->getNumberOfRows($sql)) {
+                /* delete unconnected graph refs */
+                $sql = ($dbv < '04-01') ? 'DELETE '.$tbl_prefix.'g2t' : 'DELETE G';
+                $sql .= '
+                    FROM '.$tbl_prefix.'g2t G
+                    LEFT JOIN '.$tbl_prefix.'triple T ON (T.t = G.t)
+                    WHERE T.t IS NULL
+                ';
+                $this->store->a['db_object']->simpleQuery($sql);
+             }
+        }
+        /* release lock */
+        $this->store->releaseLock();
     }
-    /* check for unconnected graph refs */
-    if ((rand(1, 10) == 1)) {
-      $sql = '
-        SELECT G.g FROM '. $tbl_prefix . 'g2t G LEFT JOIN '. $tbl_prefix . 'triple T ON ( T.t = G.t )
-        WHERE T.t IS NULL LIMIT 1
-      ';
-      if (($rs = mysql_query($sql, $con)) && mysql_num_rows($rs)) {
-        /* delete unconnected graph refs */
-        $sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 'g2t' : 'DELETE G';
+
+    public function cleanValueTables()
+    {
+        /* lock */
+        if (!$this->store->getLock()) {
+            return $this->addError('Could not get lock in "cleanValueTables"');
+        }
+        $tbl_prefix = $this->store->getTablePrefix();
+        $dbv = $this->store->getDBVersion();
+
+        /* o2val */
+        $sql = ($dbv < '04-01') ? 'DELETE '.$tbl_prefix.'o2val' : 'DELETE V';
         $sql .= '
-          FROM ' . $tbl_prefix . 'g2t G 
-          LEFT JOIN ' . $tbl_prefix . 'triple T ON (T.t = G.t)
-          WHERE T.t IS NULL
-        ';
-        mysql_query($sql, $con);
-      }
-    }
-    /* release lock */
-    $this->store->releaseLock();
-  }
-  
-  /*  */
-
-  function cleanValueTables() {
-    /* lock */
-    if (!$this->store->getLock()) return $this->addError('Could not get lock in "cleanValueTables"');
-    $con = $this->store->getDBCon();
-    $tbl_prefix = $this->store->getTablePrefix();
-    $dbv = $this->store->getDBVersion();
-    /* o2val */
-    $sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 'o2val' : 'DELETE V';
-    $sql .= '
-      FROM ' . $tbl_prefix . 'o2val V 
-      LEFT JOIN ' . $tbl_prefix . 'triple T ON (T.o = V.id)
+      FROM '.$tbl_prefix.'o2val V
+      LEFT JOIN '.$tbl_prefix.'triple T ON (T.o = V.id)
       WHERE T.t IS NULL
     ';
-    mysql_query($sql, $con);
-    /* s2val */
-    $sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 's2val' : 'DELETE V';
-    $sql .= '
-      FROM ' . $tbl_prefix . 's2val V 
-      LEFT JOIN ' . $tbl_prefix . 'triple T ON (T.s = V.id)
+        $this->store->a['db_object']->simpleQuery($sql);
+
+        /* s2val */
+        $sql = ($dbv < '04-01') ? 'DELETE '.$tbl_prefix.'s2val' : 'DELETE V';
+        $sql .= '
+      FROM '.$tbl_prefix.'s2val V
+      LEFT JOIN '.$tbl_prefix.'triple T ON (T.s = V.id)
       WHERE T.t IS NULL
     ';
-    mysql_query($sql, $con);
-    /* id2val */
-    $sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 'id2val' : 'DELETE V';
-    $sql .= '
-      FROM ' . $tbl_prefix . 'id2val V 
-      LEFT JOIN ' . $tbl_prefix . 'g2t G ON (G.g = V.id)
-      LEFT JOIN ' . $tbl_prefix . 'triple T1 ON (T1.p = V.id)
-      LEFT JOIN ' . $tbl_prefix . 'triple T2 ON (T2.o_lang_dt = V.id)
+        $this->store->a['db_object']->simpleQuery($sql);
+
+        /* id2val */
+        $sql = ($dbv < '04-01') ? 'DELETE '.$tbl_prefix.'id2val' : 'DELETE V';
+        $sql .= '
+      FROM '.$tbl_prefix.'id2val V
+      LEFT JOIN '.$tbl_prefix.'g2t G ON (G.g = V.id)
+      LEFT JOIN '.$tbl_prefix.'triple T1 ON (T1.p = V.id)
+      LEFT JOIN '.$tbl_prefix.'triple T2 ON (T2.o_lang_dt = V.id)
       WHERE G.g IS NULL AND T1.t IS NULL AND T2.t IS NULL
     ';
-    //mysql_query($sql, $con);
-  }
-  
-  /*  */
+        // TODO was commented out before. could this be a problem?
+        $this->store->a['db_object']->simpleQuery($sql);
 
+        /* release lock */
+        $this->store->releaseLock();
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreDescribeQueryHandler.php b/lib/arc2/store/ARC2_StoreDescribeQueryHandler.php
index eb71b0813929b2746f10ea2640b0789ef6ec5dd1..00dcb5ce094908e8ff67fe6448acd834ecf8701d 100644
--- a/lib/arc2/store/ARC2_StoreDescribeQueryHandler.php
+++ b/lib/arc2/store/ARC2_StoreDescribeQueryHandler.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 Store DESCRIBE Query Handler
 author:   Benjamin Nowack
@@ -10,110 +10,112 @@ version:  2010-11-16
 
 ARC2::inc('StoreSelectQueryHandler');
 
-class ARC2_StoreDescribeQueryHandler extends ARC2_StoreSelectQueryHandler {
+class ARC2_StoreDescribeQueryHandler extends ARC2_StoreSelectQueryHandler
+{
+    public function __construct($a, &$caller)
+    {/* caller has to be a store */
+        parent::__construct($a, $caller);
+    }
 
-  function __construct($a, &$caller) {/* caller has to be a store */
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* db_con */
-    parent::__init();
-    $this->store = $this->caller;
-    $this->detect_labels = $this->v('detect_describe_query_labels', 0, $this->a);
-  }
+    public function __init()
+    {
+        parent::__init();
+        $this->store = $this->caller;
+        $this->detect_labels = $this->v('detect_describe_query_labels', 0, $this->a);
+    }
 
-  /*  */
-  
-  function runQuery($infos) {
-    $ids = $infos['query']['result_uris'];
-    if ($vars = $infos['query']['result_vars']) {
-      $sub_r = parent::runQuery($infos);
-      $rf = $this->v('result_format', '', $infos);
-      if (in_array($rf, array('sql', 'structure', 'index'))) {
-        return $sub_r;
-      }
-      $rows = $this->v('rows', array(), $sub_r);
-      foreach ($rows as $row) {
-        foreach ($vars as $info) {
-          $val = isset($row[$info['var']]) ? $row[$info['var']] : '';
-          if ($val && ($row[$info['var'] . ' type'] != 'literal') && !in_array($val, $ids)) {
-            $ids[] = $val;
-          }
+    public function runQuery($infos)
+    {
+        $ids = $infos['query']['result_uris'];
+        if ($vars = $infos['query']['result_vars']) {
+            $sub_r = parent::runQuery($infos);
+            $rf = $this->v('result_format', '', $infos);
+            if (in_array($rf, ['sql', 'structure', 'index'])) {
+                return $sub_r;
+            }
+            $rows = $this->v('rows', [], $sub_r);
+            foreach ($rows as $row) {
+                foreach ($vars as $info) {
+                    $val = isset($row[$info['var']]) ? $row[$info['var']] : '';
+                    if ($val && ('literal' != $row[$info['var'].' type']) && !in_array($val, $ids)) {
+                        $ids[] = $val;
+                    }
+                }
+            }
         }
-      }
-    }
-    $this->r = array();
-    $this->described_ids = array();
-    $this->ids = $ids;
-    $this->added_triples = array();
-    $is_sub_describe = 0;
-    while ($this->ids) {
-      $id = $this->ids[0];
-      $this->described_ids[] = $id;
-      if ($this->detect_labels) {
-        $q = '
+        $this->r = [];
+        $this->described_ids = [];
+        $this->ids = $ids;
+        $this->added_triples = [];
+        $is_sub_describe = 0;
+        while ($this->ids) {
+            $id = $this->ids[0];
+            $this->described_ids[] = $id;
+            if ($this->detect_labels) {
+                $q = '
           CONSTRUCT { 
-            <' . $id . '> ?p ?o . 
+            <'.$id.'> ?p ?o . 
             ?o ?label_p ?o_label . 
             ?o <http://arc.semsol.org/ns/arc#label> ?o_label .
           } WHERE { 
-            <' . $id . '> ?p ?o .
+            <'.$id.'> ?p ?o .
             OPTIONAL {
               ?o ?label_p ?o_label .
               FILTER REGEX(str(?label_p), "(name|label|title|summary|nick|fn)$", "i") 
             }
           }
         ';
-      }
-      else {
-        $q = '
+            } else {
+                $q = '
           CONSTRUCT { 
-            <' . $id . '> ?p ?o . 
+            <'.$id.'> ?p ?o . 
           } WHERE { 
-            <' . $id . '> ?p ?o .
+            <'.$id.'> ?p ?o .
           }
         ';
-      }
-      $sub_r = $this->store->query($q);
-      $sub_index = is_array($sub_r['result']) ? $sub_r['result'] : array();
-      $this->mergeSubResults($sub_index, $is_sub_describe);
-      $is_sub_describe = 1;
+            }
+            $sub_r = $this->store->query($q);
+            $sub_index = is_array($sub_r['result']) ? $sub_r['result'] : [];
+            $this->mergeSubResults($sub_index, $is_sub_describe);
+            $is_sub_describe = 1;
+        }
+
+        return $this->r;
     }
-    return $this->r;
-  }
-  
-  /*  */
-  
-  function mergeSubResults($index, $is_sub_describe = 1) {
-    foreach ($index as $s => $ps) {
-      if (!isset($this->r[$s])) $this->r[$s] = array();
-      foreach ($ps as $p => $os) {
-        if (!isset($this->r[$s][$p])) $this->r[$s][$p] = array();
-        foreach ($os as $o) {
-          $id = md5($s . ' ' . $p . ' ' . serialize($o));
-          if (!isset($this->added_triples[$id])) {
-            if (1 || !$is_sub_describe) {
-              $this->r[$s][$p][] = $o;
-              if (is_array($o) && ($o['type'] == 'bnode') && !in_array($o['value'], $this->ids)) $this->ids[] = $o['value'];
+
+    public function mergeSubResults($index, $is_sub_describe = 1)
+    {
+        foreach ($index as $s => $ps) {
+            if (!isset($this->r[$s])) {
+                $this->r[$s] = [];
             }
-            elseif (!is_array($o) || ($o['type'] != 'bnode')) {
-              $this->r[$s][$p][] = $o;
+            foreach ($ps as $p => $os) {
+                if (!isset($this->r[$s][$p])) {
+                    $this->r[$s][$p] = [];
+                }
+                foreach ($os as $o) {
+                    $id = md5($s.' '.$p.' '.serialize($o));
+                    if (!isset($this->added_triples[$id])) {
+                        if (1 || !$is_sub_describe) {
+                            $this->r[$s][$p][] = $o;
+                            if (is_array($o) && ('bnode' == $o['type']) && !in_array($o['value'], $this->ids)) {
+                                $this->ids[] = $o['value'];
+                            }
+                        } elseif (!is_array($o) || ('bnode' != $o['type'])) {
+                            $this->r[$s][$p][] = $o;
+                        }
+                        $this->added_triples[$id] = 1;
+                    }
+                }
+            }
+        }
+        /* adjust ids */
+        $ids = $this->ids;
+        $this->ids = [];
+        foreach ($ids as $id) {
+            if (!in_array($id, $this->described_ids)) {
+                $this->ids[] = $id;
             }
-            $this->added_triples[$id] = 1;
-          }
         }
-      }
-    }
-    /* adjust ids */
-    $ids = $this->ids;
-    $this->ids = array();
-    foreach ($ids as $id) {
-      if (!in_array($id, $this->described_ids)) $this->ids[] = $id;
     }
-  }
-  
-  /*  */
-
 }
-
-
diff --git a/lib/arc2/store/ARC2_StoreDumpQueryHandler.php b/lib/arc2/store/ARC2_StoreDumpQueryHandler.php
old mode 100644
new mode 100755
index cbcdaa06b72674d0ce0a4efa3e3c3c835e353a6b..f00025f02ebba72be3f64366c9ce9cb71c893d78
--- a/lib/arc2/store/ARC2_StoreDumpQueryHandler.php
+++ b/lib/arc2/store/ARC2_StoreDumpQueryHandler.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 RDF Store DUMP Query Handler
 author:   Benjamin Nowack
@@ -10,28 +10,26 @@ version:  2010-11-16
 
 ARC2::inc('StoreQueryHandler');
 
-class ARC2_StoreDumpQueryHandler extends ARC2_StoreQueryHandler {
+class ARC2_StoreDumpQueryHandler extends ARC2_StoreQueryHandler
+{
+    public function __construct($a, &$caller)
+    {/* caller has to be a store */
+        parent::__construct($a, $caller);
+    }
 
-  function __construct($a, &$caller) {/* caller has to be a store */
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* db_con */
-    parent::__init();
-    $this->store = $this->caller;
-  }
+    public function __init()
+    {
+        parent::__init();
+        $this->store = $this->caller;
+    }
 
-  /*  */
-  
-  function runQuery($infos, $keep_bnode_ids = 0) {
-    $this->infos = $infos;
-    $con = $this->store->getDBCon();
-    ARC2::inc('StoreDumper');
-    $d = new ARC2_StoreDumper($this->a, $this->store);
-    $d->dumpSPOG();
-    return 1;
-  }
-  
-  /*  */
+    public function runQuery($infos, $keep_bnode_ids = 0)
+    {
+        $this->infos = $infos;
+        ARC2::inc('StoreDumper');
+        $d = new ARC2_StoreDumper($this->a, $this->store);
+        $d->dumpSPOG();
 
+        return 1;
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreDumper.php b/lib/arc2/store/ARC2_StoreDumper.php
old mode 100644
new mode 100755
index 931fa92e6919baa5cd85e566c95ec885874ddc1f..471e174da5d7001ce0babe7f88b7c886795f0a97
--- a/lib/arc2/store/ARC2_StoreDumper.php
+++ b/lib/arc2/store/ARC2_StoreDumper.php
@@ -1,101 +1,108 @@
 <?php
 /**
- * ARC2 Store Dumper
+ * ARC2 Store Dumper.
  *
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('Class');
 
-class ARC2_StoreDumper extends ARC2_Class {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-    $this->store = $this->caller;
-    $this->keep_time_limit = $this->v('keep_time_limit', 0, $this->a);
-    $this->limit = 100000;
-  }
-
-  /*  */
-  
-  function dumpSPOG() {
-    header('Content-Type: application/sparql-results+xml');
-    if ($this->v('store_use_dump_dir', 0, $this->a)) {
-      $path = $this->v('store_dump_dir', 'dumps', $this->a);
-      /* default: monthly dumps */
-      $path_suffix = $this->v('store_dump_suffix', date('Y_m'), $this->a);
-      $path .= '/dump_' . $path_suffix . '.spog';
-      if (!file_exists($path)) {
-        $this->saveSPOG($path);
-      }
-      readfile($path);
-      exit;
+class ARC2_StoreDumper extends ARC2_Class
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
+
+    public function __init()
+    {
+        parent::__init();
+        $this->store = $this->caller;
+        $this->keep_time_limit = $this->v('keep_time_limit', 0, $this->a);
+        $this->limit = 100000;
+    }
+
+    public function dumpSPOG()
+    {
+        header('Content-Type: application/sparql-results+xml');
+        if ($this->v('store_use_dump_dir', 0, $this->a)) {
+            $path = $this->v('store_dump_dir', 'dumps', $this->a);
+            /* default: monthly dumps */
+            $path_suffix = $this->v('store_dump_suffix', date('Y_m'), $this->a);
+            $path .= '/dump_'.$path_suffix.'.spog';
+            if (!file_exists($path)) {
+                $this->saveSPOG($path);
+            }
+            readfile($path);
+            exit;
+        }
+        echo $this->getHeader();
+        $offset = 0;
+        do {
+            $proceed = 0;
+            $rows = $this->getRecordset($offset);
+            if (false == is_array($rows)) {
+                break;
+            }
+            foreach($rows as $row) {
+                echo $this->getEntry($row);
+                $proceed = 1;
+            }
+            $offset += $this->limit;
+        } while ($proceed);
+        echo $this->getFooter();
+    }
+
+    public function saveSPOG($path, $q = '')
+    {
+        if ($q) {
+            return $this->saveCustomSPOG($path, $q);
+        }
+        if (!$fp = fopen($path, 'w')) {
+            return $this->addError('Could not create backup file at '.realpath($path));
+        }
+        fwrite($fp, $this->getHeader());
+        $offset = 0;
+        do {
+            $proceed = 0;
+            $rows = $this->getRecordset($offset);
+            if (false == is_array($rows)) {
+                break;
+            }
+            foreach($rows as $row) {
+                fwrite($fp, $this->getEntry($row));
+                $proceed = 1;
+            }
+            $offset += $this->limit;
+        } while ($proceed);
+        fwrite($fp, $this->getFooter());
+        fclose($fp);
+
+        return 1;
     }
-    echo $this->getHeader();
-    $offset = 0;
-    do {
-      $proceed = 0;
-      $rs = $this->getRecordset($offset);
-      if (!$rs) break;
-      while ($row = mysql_fetch_array($rs)) {
-        echo $this->getEntry($row);
-        $proceed = 1;
-      }
-      $offset += $this->limit;
-    } while ($proceed);
-    echo $this->getFooter();
-  }
-
-  /*  */
-
-  function saveSPOG($path, $q = '') {
-    if ($q) return $this->saveCustomSPOG($path, $q);
-    if (!$fp = @fopen($path, 'w')) return $this->addError('Could not create backup file at ' . realpath($path));
-    fwrite($fp, $this->getHeader());
-    $offset = 0;
-    do {
-      $proceed = 0;
-      $rs = $this->getRecordset($offset);
-      if (!$rs) break;
-      while ($row = mysql_fetch_array($rs)) {
-        fwrite($fp, $this->getEntry($row));
-        $proceed = 1;
-      }
-      $offset += $this->limit;
-    } while ($proceed);
-    fwrite($fp, $this->getFooter());
-    @fclose($fp);
-    return 1;
-  }
-
-  /*  */
-
-  function saveCustomSPOG($path, $q) {
-    if (!$fp = @fopen($path, 'w')) return $this->addError('Could not create backup file at ' . realpath($path));
-    fwrite($fp, $this->getHeader());
-    $rows = $this->store->query($q, 'rows');
-    foreach ($rows as $row) {
-      fwrite($fp, $this->getEntry($row));
+
+    public function saveCustomSPOG($path, $q)
+    {
+        if (!$fp = fopen($path, 'w')) {
+            return $this->addError('Could not create backup file at '.realpath($path));
+        }
+        fwrite($fp, $this->getHeader());
+        $rows = $this->store->query($q, 'rows');
+        foreach ($rows as $row) {
+            fwrite($fp, $this->getEntry($row));
+        }
+        fwrite($fp, $this->getFooter());
+        fclose($fp);
     }
-    fwrite($fp, $this->getFooter());
-    @fclose($fp);
-  }
-  
-  /*  */
-
-  function getRecordset($offset) {
-    $prefix = $this->store->getTablePrefix();
-    $con = $this->store->getDBCon();
-    $sql = '
-      SELECT 
+
+    public function getRecordset($offset)
+    {
+        $prefix = $this->store->getTablePrefix();
+        $sql = '
+      SELECT
         VS.val AS s,
         T.s_type AS `s type`,
         VP.val AS p,
@@ -106,117 +113,129 @@ class ARC2_StoreDumper extends ARC2_Class {
         VG.val as g,
         0 AS `g type`
       FROM
-        ' . $prefix . 'triple T
-        JOIN ' . $prefix . 's2val VS ON (T.s = VS.id)
-        JOIN ' . $prefix . 'id2val VP ON (T.p = VP.id)
-        JOIN ' . $prefix . 'o2val VO ON (T.o = VO.id)
-        JOIN ' . $prefix . 'id2val VLDT ON (T.o_lang_dt = VLDT.id)
-        JOIN ' . $prefix . 'g2t G2T ON (T.t = G2T.t)
-        JOIN ' . $prefix . 'id2val VG ON (G2T.g = VG.id)
+        '.$prefix.'triple T
+        JOIN '.$prefix.'s2val VS ON (T.s = VS.id)
+        JOIN '.$prefix.'id2val VP ON (T.p = VP.id)
+        JOIN '.$prefix.'o2val VO ON (T.o = VO.id)
+        JOIN '.$prefix.'id2val VLDT ON (T.o_lang_dt = VLDT.id)
+        JOIN '.$prefix.'g2t G2T ON (T.t = G2T.t)
+        JOIN '.$prefix.'id2val VG ON (G2T.g = VG.id)
     ';
-    if ($this->limit) $sql .= ' LIMIT ' . $this->limit;
-    if ($offset) $sql .= ' OFFSET ' . $offset;
-    $rs = mysql_unbuffered_query($sql, $con);
-    if (($err = mysql_error($con))) {
-      return $this->addError($err);
-    }
-    return $rs;
-  }
-
-  /*  */
-  
-  function getHeader() {
-    $n = "\n";
-    return '' .
-      '<?xml version="1.0"?>' . 
-      $n . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
-      $n . '  <head>' .
-      $n . '    <variable name="s"/>' .
-      $n . '    <variable name="p"/>' .
-      $n . '    <variable name="o"/>' .
-      $n . '    <variable name="g"/>' .
-      $n . '  </head>' .
-      $n . '  <results>' .
-    '';
-  }
-
-  function getEntry($row) {
-    if (!$this->keep_time_limit) @set_time_limit($this->v('time_limit', 1200, $this->a));
-    $n = "\n";
-    $r = '';
-    $r .= $n . '    <result>';
-    foreach (array('s', 'p', 'o', 'g') as $var) {
-      if (isset($row[$var])) {
-        $type = (string) $row[$var . ' type'];
-        $r .= $n . '      <binding name="' . $var . '">';
-        $val = $this->toUTF8($row[$var]);
-        if (($type == '0') || ($type == 'uri')) {
-          $r .= $n . '        <uri>' . $this->getSafeValue($val) . '</uri>';
+        if ($this->limit) {
+            $sql .= ' LIMIT '.$this->limit;
         }
-        elseif (($type == '1') || ($type == 'bnode')) {
-          $r .= $n . '        <bnode>' . substr($val, 2) . '</bnode>';
+        if ($offset) {
+            $sql .= ' OFFSET '.$offset;
         }
-        else {
-          $lang_dt = '';
-          foreach (array('o lang_dt', 'o lang', 'o datatype') as $k) {
-            if (($var == 'o') && isset($row[$k]) && $row[$k]) $lang_dt = $row[$k];
-          }
-          $is_lang = preg_match('/^([a-z]+(\-[a-z0-9]+)*)$/i', $lang_dt);
-          list($lang, $dt) = $is_lang ? array($lang_dt, '') : array('', $lang_dt);
-          $lang = $lang ? ' xml:lang="' . $lang . '"' : '';
-          $dt = $dt ? ' datatype="' . htmlspecialchars($dt) . '"' : '';
-          $r .= $n . '        <literal' . $dt . $lang . '>' . $this->getSafeValue($val) . '</literal>';
+
+        $rows = $this->store->a['db_object']->fetchList($sql);
+        if (false == empty($this->store->a['db_object']->getErrorMessage())) {
+            return $this->addError($this->store->a['db_object']->getErrorMessage());
         }
-        $r .= $n . '      </binding>';
-      }
+
+        return $rows;
     }
-    $r .= $n . '    </result>';
-    return $r;
-  }
-
-  function getSafeValue($val) {/* mainly for fixing json_decode bugs */
-    $mappings = array(
-      '%00' => '',
-      '%01' => '',
-      '%02' => '',
-      '%03' => '',
-      '%04' => '',
-      '%05' => '',
-      '%06' => '',
-      '%07' => '',
-      '%08' => '',
-      '%09' => '',
-      '%0B' => '',
-      '%0C' => '',
-      '%0E' => '',
-      '%0F' => '',
-      '%15' => '',
-      '%17' => 'Ä—',
-      '%1A' => ',',
-      '%1F' => '',
-    );
-    $froms = array_keys($mappings);
-    $tos = array_values($mappings);
-    foreach ($froms as $i => $from) $froms[$i] = urldecode($from);
-    $val = str_replace($froms, $tos, $val);
-    if (strpos($val, '</') !== false) {
-      $val = "\n<![CDATA[\n" . $val . "\n]]>\n";
+
+    public function getHeader()
+    {
+        $n = "\n";
+
+        return ''.
+      '<?xml version="1.0"?>'.
+      $n.'<sparql xmlns="http://www.w3.org/2005/sparql-results#">'.
+      $n.'  <head>'.
+      $n.'    <variable name="s"/>'.
+      $n.'    <variable name="p"/>'.
+      $n.'    <variable name="o"/>'.
+      $n.'    <variable name="g"/>'.
+      $n.'  </head>'.
+      $n.'  <results>'.
+    '';
     }
-    else {
-      $val = htmlspecialchars($val);
+
+    public function getEntry($row)
+    {
+        if (!$this->keep_time_limit) {
+            set_time_limit($this->v('time_limit', 1200, $this->a));
+        }
+        $n = "\n";
+        $r = '';
+        $r .= $n.'    <result>';
+        foreach (['s', 'p', 'o', 'g'] as $var) {
+            if (isset($row[$var])) {
+                $type = (string) $row[$var.' type'];
+                $r .= $n.'      <binding name="'.$var.'">';
+                $val = $this->toUTF8($row[$var]);
+                if (('0' == $type) || ('uri' == $type)) {
+                    $r .= $n.'        <uri>'.$this->getSafeValue($val).'</uri>';
+                } elseif (('1' == $type) || ('bnode' == $type)) {
+                    $r .= $n.'        <bnode>'.substr($val, 2).'</bnode>';
+                } else {
+                    $lang_dt = '';
+                    foreach (['o lang_dt', 'o lang', 'o datatype'] as $k) {
+                        if (('o' == $var) && isset($row[$k]) && $row[$k]) {
+                            $lang_dt = $row[$k];
+                        }
+                    }
+                    $is_lang = preg_match('/^([a-z]+(\-[a-z0-9]+)*)$/i', $lang_dt);
+                    list($lang, $dt) = $is_lang ? [$lang_dt, ''] : ['', $lang_dt];
+                    $lang = $lang ? ' xml:lang="'.$lang.'"' : '';
+                    $dt = $dt ? ' datatype="'.htmlspecialchars($dt).'"' : '';
+                    $r .= $n.'        <literal'.$dt.$lang.'>'.$this->getSafeValue($val).'</literal>';
+                }
+                $r .= $n.'      </binding>';
+            }
+        }
+        $r .= $n.'    </result>';
+
+        return $r;
     }
-    return $val;
-  }
-
-  function getFooter() {
-    $n = "\n";
-    return '' .
-      $n . '  </results>' .
-      $n . '</sparql>' . 
-      $n .
-    '';
-  }
 
-  /*  */
+    public function getSafeValue($val)
+    {/* mainly for fixing json_decode bugs */
+        $mappings = [
+            '%00' => '',
+            '%01' => '',
+            '%02' => '',
+            '%03' => '',
+            '%04' => '',
+            '%05' => '',
+            '%06' => '',
+            '%07' => '',
+            '%08' => '',
+            '%09' => '',
+            '%0B' => '',
+            '%0C' => '',
+            '%0E' => '',
+            '%0F' => '',
+            '%15' => '',
+            '%17' => 'Ä—',
+            '%1A' => ',',
+            '%1F' => '',
+        ];
+        $froms = array_keys($mappings);
+        $tos = array_values($mappings);
+        foreach ($froms as $i => $from) {
+            $froms[$i] = urldecode($from);
+        }
+        $val = str_replace($froms, $tos, $val);
+        if (false !== strpos($val, '</')) {
+            $val = "\n<![CDATA[\n".$val."\n]]>\n";
+        } else {
+            $val = htmlspecialchars($val);
+        }
+
+        return $val;
+    }
+
+    public function getFooter()
+    {
+        $n = "\n";
 
+        return ''.
+      $n.'  </results>'.
+      $n.'</sparql>'.
+      $n.
+    '';
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreEndpoint.php b/lib/arc2/store/ARC2_StoreEndpoint.php
old mode 100644
new mode 100755
index d762485174532f47fa04decb099daf16a1d158d4..0dea29338dbd270afaaf5b586d7ece0446f8979a
--- a/lib/arc2/store/ARC2_StoreEndpoint.php
+++ b/lib/arc2/store/ARC2_StoreEndpoint.php
@@ -1,157 +1,157 @@
 <?php
 /**
- * ARC2 SPARQL Endpoint
+ * ARC2 SPARQL Endpoint.
  *
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('Store');
 
-class ARC2_StoreEndpoint extends ARC2_Store {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-    $this->headers = array('http' => 'HTTP/1.1 200 OK', 'vary' => 'Vary: Accept');
-    $this->read_key = $this->v('endpoint_read_key', '', $this->a);
-    $this->write_key = $this->v('endpoint_write_key', '', $this->a);
-    $this->timeout = $this->v('endpoint_timeout', 0, $this->a);
-    $this->a['store_allow_extension_functions'] = $this->v('store_allow_extension_functions', 0, $this->a);    
-    $this->allow_sql = $this->v('endpoint_enable_sql_output', 0, $this->a);
-    $this->result = '';
-  }
-
-  /*  */
-  
-  function getQueryString($mthd = '') {
-    $r = '';
-    if (!$mthd || ($mthd == 'post')) {
-      $r = @file_get_contents('php://input');
-    }
-    $r = !$r ?$this->v1('QUERY_STRING', '', $_SERVER) : $r;
-    return $r;
-  }
-
-  function p($name='', $mthd = '', $multi = '', $default = '') {
-    $mthd = strtolower($mthd);
-    if($multi){
-      $qs = $this->getQueryString($mthd);
-      if (preg_match_all('/\&' . $name . '=([^\&]+)/', $qs, $m)){
-        foreach ($m[1] as $i => $val) {
-          $m[1][$i] = stripslashes($val);
+class ARC2_StoreEndpoint extends ARC2_Store
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
+
+    public function __init()
+    {
+        parent::__init();
+        $this->headers = ['http' => 'HTTP/1.1 200 OK', 'vary' => 'Vary: Accept'];
+        $this->read_key = $this->v('endpoint_read_key', '', $this->a);
+        $this->write_key = $this->v('endpoint_write_key', '', $this->a);
+        $this->timeout = $this->v('endpoint_timeout', 0, $this->a);
+        $this->a['store_allow_extension_functions'] = $this->v('store_allow_extension_functions', 0, $this->a);
+        $this->allow_sql = $this->v('endpoint_enable_sql_output', 0, $this->a);
+        $this->result = '';
+    }
+
+    public function getQueryString($mthd = '')
+    {
+        $r = '';
+        if (!$mthd || ('post' == $mthd)) {
+            $r = file_get_contents('php://input');
         }
-        return $m[1];
-      }
-      return $default ? $default : array();
-    }
-    $args = array_merge($_GET, $_POST);
-    $r = isset($args[$name]) ? $args[$name] : $default;
-    return is_array($r) ? $r : stripslashes($r);
-  }
-  
-  /*  */
-
-  function getFeatures() {
-    return $this->v1('endpoint_features', array(), $this->a);
-  }
-
-  function setHeader($k, $v) {
-    $this->headers[$k] = $v;
-  }
-  
-  function sendHeaders() {
-    if (!isset($this->is_dump) || !$this->is_dump) {
-      $this->setHeader('content-length', 'Content-Length: ' . strlen($this->getResult()));
-      foreach ($this->headers as $k => $v) {
-        header($v);
-      }
+        $r = !$r ? $this->v1('QUERY_STRING', '', $_SERVER) : $r;
+
+        return $r;
     }
-  }
-  
-  function getResult() {
-    return $this->result;
-  }
-  
-  /*  */
-  
-  function handleRequest($auto_setup = 0) {
-    if (!$this->isSetUp()) {
-      if ($auto_setup) {
-        $this->setUp();
-        return $this->handleRequest(0);
-      }
-      else {
-        $this->setHeader('http', 'HTTP/1.1 400 Bad Request');
-        $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
-        $this->result = 'Missing configuration or the endpoint store was not set up yet.';
-      }
+
+    public function p($name = '', $mthd = '', $multi = '', $default = '')
+    {
+        $mthd = strtolower($mthd);
+        if ($multi) {
+            $qs = $this->getQueryString($mthd);
+            if (preg_match_all('/\&'.$name.'=([^\&]+)/', $qs, $m)) {
+                foreach ($m[1] as $i => $val) {
+                    $m[1][$i] = stripslashes($val);
+                }
+
+                return $m[1];
+            }
+
+            return $default ? $default : [];
+        }
+        $args = array_merge($_GET, $_POST);
+        $r = isset($args[$name]) ? $args[$name] : $default;
+
+        return is_array($r) ? $r : stripslashes($r);
     }
-    elseif (($img = $this->p('img'))) {
-      $this->handleImgRequest($img);
+
+    public function getFeatures()
+    {
+        return $this->v1('endpoint_features', [], $this->a);
     }
-    elseif (($q = $this->p('query'))) {
-      $this->checkProcesses();
-      $this->handleQueryRequest($q);
-      if ($this->p('show_inline')) {
-        $this->query_result = '
+
+    public function setHeader($k, $v)
+    {
+        $this->headers[$k] = $v;
+    }
+
+    public function sendHeaders()
+    {
+        if (!isset($this->is_dump) || !$this->is_dump) {
+            $this->setHeader('content-length', 'Content-Length: '.strlen($this->getResult()));
+            foreach ($this->headers as $k => $v) {
+                header($v);
+            }
+        }
+    }
+
+    public function getResult()
+    {
+        return $this->result;
+    }
+
+    public function handleRequest($auto_setup = 0)
+    {
+        if (!$this->isSetUp()) {
+            if ($auto_setup) {
+                $this->setUp();
+
+                return $this->handleRequest(0);
+            } else {
+                $this->setHeader('http', 'HTTP/1.1 400 Bad Request');
+                $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+                $this->result = 'Missing configuration or the endpoint store was not set up yet.';
+            }
+        } elseif (($img = $this->p('img'))) {
+            $this->handleImgRequest($img);
+        } elseif (($q = $this->p('query'))) {
+            $this->checkProcesses();
+            $this->handleQueryRequest($q);
+            if ($this->p('show_inline')) {
+                $this->query_result = '
           <div class="results">
-            ' . ($this->p('output') != 'htmltab' ? '<pre>' . htmlspecialchars($this->getResult()) . '</pre>' : $this->getResult()) . '
+            '.('htmltab' != $this->p('output') ? '<pre>'.htmlspecialchars($this->getResult()).'</pre>' : $this->getResult()).'
           </div>
         ';
-        $this->handleEmptyRequest(1);
-      }
+                $this->handleEmptyRequest(1);
+            }
+        } else {
+            $this->handleEmptyRequest();
+        }
+    }
+
+    public function go($auto_setup = 0)
+    {
+        $this->handleRequest($auto_setup);
+        $this->sendHeaders();
+        echo $this->getResult();
+    }
+
+    public function handleImgRequest($img)
+    {
+        $this->setHeader('content-type', 'Content-type: image/gif');
+        $imgs = [
+            'bg_body' => base64_decode('R0lGODlhAQBkAMQAAPf39/Hx8erq6vPz8/Ly8u/v7+np6fT09Ovr6/b29u3t7ejo6Pz8/Pv7+/39/fr6+vj4+P7+/vn5+f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAGQAAAUp4GIIiFIExHAkAAC9cAxJdG3TT67vTe//jKBQ6Cgaj5GkcpmcOJ/QZwgAOw=='),
+        ];
+        $this->result = isset($imgs[$img]) ? $imgs[$img] : '';
+        $this->sendHeaders();
+        echo $this->getResult();
+        exit;
     }
-    else {
-      $this->handleEmptyRequest();
-    }
-  }
-  
-  function go($auto_setup = 0) {
-    $this->handleRequest($auto_setup);
-    $this->sendHeaders();
-    echo $this->getResult();
-  }
-  
-  /*  */
-  
-  function handleImgRequest($img) {
-    $this->setHeader('content-type', 'Content-type: image/gif');
-    $imgs = array(
-      'bg_body' => base64_decode('R0lGODlhAQBkAMQAAPf39/Hx8erq6vPz8/Ly8u/v7+np6fT09Ovr6/b29u3t7ejo6Pz8/Pv7+/39/fr6+vj4+P7+/vn5+f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAGQAAAUp4GIIiFIExHAkAAC9cAxJdG3TT67vTe//jKBQ6Cgaj5GkcpmcOJ/QZwgAOw=='),
-    );
-    $this->result = isset($imgs[$img]) ? $imgs[$img] : '';
-    $this->sendHeaders();
-    echo $this->getResult();
-    exit;
-  }
-  
-  /*  */
-  
-  function handleEmptyRequest($force = 0) {
-    /* service description */
-    $formats = array(
-      'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML', 'html' => 'HTML'
-    );
-    if (!$force && $this->getResultFormat($formats, 'html') != 'HTML') {
-      $this->handleServiceDescriptionRequest();
-    }
-    else {
-      $this->setHeader('content-type', 'Content-type: text/html; charset=utf-8');
-      $this->result = $this->getHTMLFormDoc();
-    }
-  }
-
-  /*  */
-
-  function handleServiceDescriptionRequest() {
-    $q = '
+
+    public function handleEmptyRequest($force = 0)
+    {
+        /* service description */
+        $formats = [
+            'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML', 'html' => 'HTML',
+        ];
+        if (!$force && 'HTML' != $this->getResultFormat($formats, 'html')) {
+            $this->handleServiceDescriptionRequest();
+        } else {
+            $this->setHeader('content-type', 'Content-type: text/html; charset=utf-8');
+            $this->result = $this->getHTMLFormDoc();
+        }
+    }
+
+    public function handleServiceDescriptionRequest()
+    {
+        $q = '
       PREFIX void: <http://rdfs.org/ns/void#>
       CONSTRUCT {
         <> void:sparqlEndpoint <> .
@@ -160,774 +160,868 @@ class ARC2_StoreEndpoint extends ARC2_Store {
         ?s ?p ?o .
       } LIMIT 1
     ';
-    $this->handleQueryRequest($q);
-  }
-
-  /*  */
-
-  function checkProcesses() {
-    if (method_exists($this->caller, 'checkSPARQLEndpointProcesses')) {
-      $sub_r = $this->caller->checkSPARQLEndpointProcesses();
-    }
-    elseif ($this->timeout) {
-      $this->killDBProcesses('', $this->timeout);
-    }
-  }
-  
-  /*  */
-
-  function handleQueryRequest($q) {
-    if (preg_match('/^dump/i', $q)) {
-      $infos = array('query' => array('type' => 'dump'));
-      $this->is_dump = 1;
-    }
-    else {
-      ARC2::inc('SPARQLPlusParser');
-      $p = new ARC2_SPARQLPlusParser($this->a, $this);
-      $p->parse($q);
-      $infos = $p->getQueryInfos();
-    }
-    /* errors? */
-    if ($errors = $this->getErrors()) {
-      $this->setHeader('http', 'HTTP/1.1 400 Bad Request');
-      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
-      $this->result = join("\n", $errors);
-      return true;
-    }
-    $qt = $infos['query']['type'];
-    /* wrong read key? */
-    if ($this->read_key && ($this->p('key') != $this->read_key) && preg_match('/^(select|ask|construct|describe|dump)$/', $qt)) {
-      $this->setHeader('http', 'HTTP/1.1 401 Access denied');
-      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
-      $this->result = 'Access denied. Missing or wrong "key" parameter.';
-      return true;
-    }
-    /* wrong write key? */
-    if ($this->write_key && ($this->p('key') != $this->write_key) && preg_match('/^(load|insert|delete|update)$/', $qt)) {
-      $this->setHeader('http', 'HTTP/1.1 401 Access denied');
-      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
-      $this->result = 'Access denied. Missing or wrong "key" parameter.';
-      return true;
-    }
-    /* non-allowed query type? */
-    if (!in_array($qt, $this->getFeatures())) {
-      $this->setHeader('http', 'HTTP/1.1 401 Access denied');
-      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
-      $this->result = 'Access denied for "' .$qt. '" query';
-      return true;
-    }
-    /* load/insert/delete via GET */
-    if (in_array($qt, array('load', 'insert', 'delete')) && isset($_GET['query'])) {
-      $this->setHeader('http', 'HTTP/1.1 501 Not Implemented');
-      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
-      $this->result = 'Query type "' .$qt. '" not supported via GET';
-      return true;
-    }
-    /* unsupported query type */
-    if (!in_array($qt, array('select', 'ask', 'describe', 'construct', 'load', 'insert', 'delete', 'dump'))) {
-      $this->setHeader('http', 'HTTP/1.1 501 Not Implemented');
-      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
-      $this->result = 'Unsupported query type "' .$qt. '"';
-      return true;
-    }
-    /* adjust infos */
-    $infos = $this->adjustQueryInfos($infos);
-    $t1 = ARC2::mtime();
-    $r = array('result' => $this->runQuery($infos, $qt));
-    $t2 = ARC2::mtime();
-    $r['query_time'] = $t2 - $t1;
-    /* query errors? */
-    if ($errors = $this->getErrors()) {
-      $this->setHeader('http', 'HTTP/1.1 400 Bad Request');
-      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
-      $this->result = 'Error: ' . join("\n", $errors);
-      return true;
-    }
-    /* result */
-    $m = 'get' . ucfirst($qt) . 'ResultDoc';
-    if (method_exists($this, $m)) {
-      $this->result = $this->$m($r);
-    }
-    else {
-      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
-      $this->result = 'Result serializer not available, dumping raw data:' . "\n" . print_r($r, 1);
-    }
-  }
-  
-  /*  */
-
-  function adjustQueryInfos($infos) {
-    /* limit */
-    if ($max_l = $this->v('endpoint_max_limit', 0, $this->a)) {
-      if ($this->v('limit', $max_l + 1, $infos['query']) > $max_l) {
-        $infos['query']['limit'] = $max_l;
-      }
+        $this->handleQueryRequest($q);
     }
-    /* default-graph-uri / named-graph-uri */
-    $dgs = $this->p('default-graph-uri', '', 1);
-    $ngs = $this->p('named-graph-uri', '', 1);
-    if (count(array_merge($dgs, $ngs))) {
-      $ds = array();
-      foreach ($dgs as $g) {
-        $ds[] = array('graph' => $this->calcURI($g), 'named' => 0);
-      }
-      foreach ($ngs as $g) {
-        $ds[] = array('graph' => $this->calcURI($g), 'named' => 1);
-      }
-      $infos['query']['dataset'] = $ds;
-    }
-    /* infos result format */
-    if (($this->p('format') == 'infos') || ($this->p('output') == 'infos')) {
-      $infos['result_format'] = 'structure';
-    }
-    /* sql result format */
-    if (($this->p('format') == 'sql') || ($this->p('output') == 'sql')) {
-      $infos['result_format'] = 'sql';
-    }
-    return $infos;
-  }
-  
-  /*  */
-
-  function getResultFormat($formats, $default) {
-    $prefs = array();
-    /* arg */
-    if (($v = $this->p('format')) || ($v = $this->p('output'))) {
-      $prefs[] = $v;
-    }
-    /* accept header */
-    $vals = explode(',', $_SERVER['HTTP_ACCEPT']);
-    if ($vals) {
-      $o_vals = array();
-      foreach ($vals as $val) {
-        if (preg_match('/(rdf\+n3|x\-turtle|rdf\+xml|sparql\-results\+xml|sparql\-results\+json|json)/', $val, $m)) {
-          $o_vals[$m[1]] = 1;
-          if (preg_match('/\;q\=([0-9\.]+)/', $val, $sub_m)) {
-            $o_vals[$m[1]] = 1 * $sub_m[1];
-          }
+
+    public function checkProcesses()
+    {
+        if (method_exists($this->caller, 'checkSPARQLEndpointProcesses')) {
+            $sub_r = $this->caller->checkSPARQLEndpointProcesses();
+        } elseif ($this->timeout) {
+            $this->killDBProcesses('', $this->timeout);
         }
-      }
-      arsort($o_vals);
-      foreach ($o_vals as $val => $prio) {
-        $prefs[] = $val;
-      }
     }
-    /* default */
-    $prefs[] = $default;
-    foreach ($prefs as $pref) {
-      if (isset($formats[$pref])) {
-        return $formats[$pref];
-      }
+
+    public function handleQueryRequest($q)
+    {
+        if (preg_match('/^dump/i', $q)) {
+            $infos = ['query' => ['type' => 'dump']];
+            $this->is_dump = 1;
+        } else {
+            ARC2::inc('SPARQLPlusParser');
+            $p = new ARC2_SPARQLPlusParser($this->a, $this);
+            $p->parse($q);
+            $infos = $p->getQueryInfos();
+        }
+        /* errors? */
+        if ($errors = $this->getErrors()) {
+            $this->setHeader('http', 'HTTP/1.1 400 Bad Request');
+            $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+            $this->result = htmlspecialchars(implode("\n", $errors));
+
+            return true;
+        }
+        $qt = $infos['query']['type'];
+        /* wrong read key? */
+        if ($this->read_key && ($this->p('key') != $this->read_key) && preg_match('/^(select|ask|construct|describe|dump)$/', $qt)) {
+            $this->setHeader('http', 'HTTP/1.1 401 Access denied');
+            $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+            $this->result = 'Access denied. Missing or wrong "key" parameter.';
+
+            return true;
+        }
+        /* wrong write key? */
+        if ($this->write_key && ($this->p('key') != $this->write_key) && preg_match('/^(load|insert|delete|update)$/', $qt)) {
+            $this->setHeader('http', 'HTTP/1.1 401 Access denied');
+            $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+            $this->result = 'Access denied. Missing or wrong "key" parameter.';
+
+            return true;
+        }
+        /* non-allowed query type? */
+        if (!in_array($qt, $this->getFeatures())) {
+            $this->setHeader('http', 'HTTP/1.1 401 Access denied');
+            $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+            $this->result = 'Access denied for "'.$qt.'" query';
+
+            return true;
+        }
+        /* load/insert/delete via GET */
+        if (in_array($qt, ['load', 'insert', 'delete']) && isset($_GET['query'])) {
+            $this->setHeader('http', 'HTTP/1.1 501 Not Implemented');
+            $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+            $this->result = 'Query type "'.$qt.'" not supported via GET';
+
+            return true;
+        }
+        /* unsupported query type */
+        if (!in_array($qt, ['select', 'ask', 'describe', 'construct', 'load', 'insert', 'delete', 'dump'])) {
+            $this->setHeader('http', 'HTTP/1.1 501 Not Implemented');
+            $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+            $this->result = 'Unsupported query type "'.$qt.'"';
+
+            return true;
+        }
+        /* adjust infos */
+        $infos = $this->adjustQueryInfos($infos);
+        $t1 = ARC2::mtime();
+        $r = ['result' => $this->runQuery($infos, $qt)];
+        $t2 = ARC2::mtime();
+        $r['query_time'] = $t2 - $t1;
+        /* query errors? */
+        if ($errors = $this->getErrors()) {
+            $this->setHeader('http', 'HTTP/1.1 400 Bad Request');
+            $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+            $this->result = 'Error: '.implode("\n", $errors);
+
+            return true;
+        }
+        /* result */
+        $m = 'get'.ucfirst($qt).'ResultDoc';
+        if (method_exists($this, $m)) {
+            $this->result = $this->$m($r);
+        } else {
+            $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+            $this->result = 'Result serializer not available, dumping raw data:'."\n".print_r($r, 1);
+        }
     }
-  }
-
-  /* SELECT */
-
-  function getSelectResultDoc($r) {
-    $formats = array(
-      'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML', 
-      'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
-      'php_ser' => 'PHPSER', 'plain' => 'Plain', 
-      'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
-      'infos' => 'Plain',
-      'htmltab' => 'HTMLTable',
-      'tsv' => 'TSV',
-    );
-    if ($f = $this->getResultFormat($formats, 'xml')) {
-      $m = 'get' . $f . 'SelectResultDoc';
-      return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
-    }
-    return '';
-  }
-  
-  function getSPARQLXMLSelectResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
-    $vars = $r['result']['variables'];
-    $rows = $r['result']['rows'];
-    $dur = $r['query_time'];
-    $nl = "\n";
-    /* doc */
-    $r = '' .
-      '<?xml version="1.0"?>' . 
-      $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
-    '';
-    /* head */
-    $r .= $nl . '  <head>';
-    $r .= $nl . '    <!-- query time: '. round($dur, 4) .' sec -->';
-    if (is_array($vars)) {
-      foreach ($vars as $var) {
-        $r .= $nl . '    <variable name="' .$var. '"/>';
-      }
+
+    public function adjustQueryInfos($infos)
+    {
+        /* limit */
+        if ($max_l = $this->v('endpoint_max_limit', 0, $this->a)) {
+            if ($this->v('limit', $max_l + 1, $infos['query']) > $max_l) {
+                $infos['query']['limit'] = $max_l;
+            }
+        }
+        /* default-graph-uri / named-graph-uri */
+        $dgs = $this->p('default-graph-uri', '', 1);
+        $ngs = $this->p('named-graph-uri', '', 1);
+        if (count(array_merge($dgs, $ngs))) {
+            $ds = [];
+            foreach ($dgs as $g) {
+                $ds[] = ['graph' => $this->calcURI($g), 'named' => 0];
+            }
+            foreach ($ngs as $g) {
+                $ds[] = ['graph' => $this->calcURI($g), 'named' => 1];
+            }
+            $infos['query']['dataset'] = $ds;
+        }
+        /* infos result format */
+        if (('infos' == $this->p('format')) || ('infos' == $this->p('output'))) {
+            $infos['result_format'] = 'structure';
+        }
+        /* sql result format */
+        if (('sql' == $this->p('format')) || ('sql' == $this->p('output'))) {
+            $infos['result_format'] = 'sql';
+        }
+
+        return $infos;
     }
-    $r .= $nl . '  </head>';
-    /* results */
-    $r .= $nl . '  <results>';
-    if (is_array($rows)) {
-      foreach ($rows as $row) {
-        $r .= $nl . '    <result>';
-        foreach ($vars as $var) {
-          if (isset($row[$var])) {
-            $r .= $nl . '      <binding name="' .$var. '">';
-            if ($row[$var . ' type'] == 'uri') {
-              $r .= $nl . '        <uri>' .htmlspecialchars($row[$var]). '</uri>';
+
+    public function getResultFormat($formats, $default)
+    {
+        $prefs = [];
+        /* arg */
+        if (($v = $this->p('format')) || ($v = $this->p('output'))) {
+            $prefs[] = $v;
+        }
+        /* accept header */
+        $vals = explode(',', $_SERVER['HTTP_ACCEPT']);
+        if ($vals) {
+            $o_vals = [];
+            foreach ($vals as $val) {
+                if (preg_match('/(rdf\+n3|x\-turtle|rdf\+xml|sparql\-results\+xml|sparql\-results\+json|json)/', $val, $m)) {
+                    $o_vals[$m[1]] = 1;
+                    if (preg_match('/\;q\=([0-9\.]+)/', $val, $sub_m)) {
+                        $o_vals[$m[1]] = 1 * $sub_m[1];
+                    }
+                }
             }
-            elseif ($row[$var . ' type'] == 'bnode') {
-              $r .= $nl . '        <bnode>' .substr($row[$var], 2). '</bnode>';
+            arsort($o_vals);
+            foreach ($o_vals as $val => $prio) {
+                $prefs[] = $val;
             }
-            else {
-              $dt = isset($row[$var . ' datatype']) ? ' datatype="' .htmlspecialchars($row[$var . ' datatype']). '"' : '';
-              $lang = isset($row[$var . ' lang']) ? ' xml:lang="' .htmlspecialchars($row[$var . ' lang']). '"' : '';
-              $r .= $nl . '        <literal' . $dt . $lang . '>' .htmlspecialchars($row[$var]). '</literal>';
+        }
+        /* default */
+        $prefs[] = $default;
+        foreach ($prefs as $pref) {
+            if (isset($formats[$pref])) {
+                return $formats[$pref];
             }
-            $r .= $nl . '      </binding>';
-          }
         }
-        $r .= $nl . '    </result>';
-      }
     }
-    $r .= $nl . '  </results>';
-    /* /doc */
-    $r .= $nl . '</sparql>';
-    return $r;
-  }
-  
-  function getSPARQLJSONSelectResultDoc($r) {
-    $con = $this->getDBCon();
-    $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
-    $vars = $r['result']['variables'];
-    $rows = $r['result']['rows'];
-    $dur = $r['query_time'];
-    $nl = "\n";
-    /* doc */
-    $r = '{';
-    /* head */
-    $r .= $nl . '  "head": {';
-    $r .= $nl . '    "vars": [';
-    $first_var = 1;
-    foreach ($vars as $var) {
-      $r .= $first_var ? $nl : ',' . $nl;
-      $r .= '      "' .$var. '"';
-      $first_var = 0;
-    }
-    $r .= $nl . '    ]';
-    $r .= $nl . '  },';
-    /* results */
-    $r .= $nl . '  "results": {';
-    $r .= $nl . '    "bindings": [';
-    $first_row = 1;
-    foreach ($rows as $row) {
-      $r .= $first_row ? $nl : ',' . $nl;
-      $r .= '      {';
-      $first_var = 1;
-      foreach ($vars as $var) {
-        if (isset($row[$var])) {
-          $r .= $first_var ? $nl : ',' . $nl . $nl;
-          $r .= '        "' .$var. '": {';
-          if ($row[$var . ' type'] == 'uri') {
-            $r .= $nl . '          "type": "uri",';
-            $r .= $nl . '          "value": "' .mysql_real_escape_string($row[$var], $con). '"';
-          }
-          elseif ($row[$var . ' type'] == 'bnode') {
-            $r .= $nl . '          "type": "bnode",';
-            $r .= $nl . '          "value": "' . substr($row[$var], 2) . '"';
-          }
-          else {
-            $dt = isset($row[$var . ' datatype']) ? ',' . $nl .'          "datatype": "' .mysql_real_escape_string($row[$var . ' datatype'], $con). '"' : '';
-            $lang = isset($row[$var . ' lang']) ? ',' . $nl .'          "xml:lang": "' .mysql_real_escape_string($row[$var . ' lang'], $con). '"' : '';
-            $type = $dt ? 'typed-literal' : 'literal';
-            $r .= $nl . '          "type": "' . $type . '",';
-            $r .= $nl . '          "value": "' . $this->jsonEscape($row[$var]) . '"';
-            $r .= $dt . $lang;
-          }
-          $r .= $nl . '        }';
-          $first_var = 0;
+
+    /* SELECT */
+
+    public function getSelectResultDoc($r)
+    {
+        $formats = [
+            'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML',
+            'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
+            'php_ser' => 'PHPSER', 'plain' => 'Plain',
+            'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
+            'infos' => 'Plain',
+            'htmltab' => 'HTMLTable',
+            'tsv' => 'TSV',
+        ];
+        if ($f = $this->getResultFormat($formats, 'xml')) {
+            $m = 'get'.$f.'SelectResultDoc';
+
+            return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
         }
-      }
-      $r .= $nl . '      }';
-      $first_row = 0;
-    }
-    $r .= $nl . '    ]';
-    $r .= $nl . '  }';
-    /* /doc */
-    $r .= $nl . '}';
-    if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
-      $r = $v . '(' . $r . ')';
-    }
-    return $r;
-  }
-  
-  function getPHPSERSelectResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/plain');
-    return serialize($r);
-  }
-
-  function getPlainSelectResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/plain');
-    return print_r($r['result'], 1);
-  }
-
-  function getHTMLTableSelectResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/html; charset=utf-8');
-    $vars = $r['result']['variables'];
-    $rows = $r['result']['rows'];
-    $dur = $r['query_time'];
-    if ($this->p('show_inline')) return '<table>' . $this->getHTMLTableRows($rows, $vars) . '</table>';
-    return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+        return '';
+    }
+
+    public function getSPARQLXMLSelectResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
+        $vars = $r['result']['variables'];
+        $rows = $r['result']['rows'];
+        $dur = $r['query_time'];
+        $nl = "\n";
+        /* doc */
+        $r = ''.
+      '<?xml version="1.0"?>'.
+      $nl.'<sparql xmlns="http://www.w3.org/2005/sparql-results#">'.
+    '';
+        /* head */
+        $r .= $nl.'  <head>';
+        $r .= $nl.'    <!-- query time: '.round($dur, 4).' sec -->';
+        if (is_array($vars)) {
+            foreach ($vars as $var) {
+                $r .= $nl.'    <variable name="'.$var.'"/>';
+            }
+        }
+        $r .= $nl.'  </head>';
+        /* results */
+        $r .= $nl.'  <results>';
+        if (is_array($rows)) {
+            foreach ($rows as $row) {
+                $r .= $nl.'    <result>';
+                foreach ($vars as $var) {
+                    if (isset($row[$var])) {
+                        $r .= $nl.'      <binding name="'.$var.'">';
+                        if ('uri' == $row[$var.' type']) {
+                            $r .= $nl.'        <uri>'.htmlspecialchars($row[$var]).'</uri>';
+                        } elseif ('bnode' == $row[$var.' type']) {
+                            $r .= $nl.'        <bnode>'.substr($row[$var], 2).'</bnode>';
+                        } else {
+                            $dt = isset($row[$var.' datatype']) ? ' datatype="'.htmlspecialchars($row[$var.' datatype']).'"' : '';
+                            $lang = isset($row[$var.' lang']) ? ' xml:lang="'.htmlspecialchars($row[$var.' lang']).'"' : '';
+                            $r .= $nl.'        <literal'.$dt.$lang.'>'.htmlspecialchars($row[$var]).'</literal>';
+                        }
+                        $r .= $nl.'      </binding>';
+                    }
+                }
+                $r .= $nl.'    </result>';
+            }
+        }
+        $r .= $nl.'  </results>';
+        /* /doc */
+        $r .= $nl.'</sparql>';
+
+        return $r;
+    }
+
+    public function getSPARQLJSONSelectResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
+        $vars = $r['result']['variables'];
+        $rows = $r['result']['rows'];
+        $dur = $r['query_time'];
+        $nl = "\n";
+        /* doc */
+        $r = '{';
+        /* head */
+        $r .= $nl.'  "head": {';
+        $r .= $nl.'    "vars": [';
+        $first_var = 1;
+        foreach ($vars as $var) {
+            $r .= $first_var ? $nl : ','.$nl;
+            $r .= '      "'.$var.'"';
+            $first_var = 0;
+        }
+        $r .= $nl.'    ]';
+        $r .= $nl.'  },';
+        /* results */
+        $r .= $nl.'  "results": {';
+        $r .= $nl.'    "bindings": [';
+        $first_row = 1;
+        foreach ($rows as $row) {
+            $r .= $first_row ? $nl : ','.$nl;
+            $r .= '      {';
+            $first_var = 1;
+            foreach ($vars as $var) {
+                if (isset($row[$var])) {
+                    $r .= $first_var ? $nl : ','.$nl.$nl;
+                    $r .= '        "'.$var.'": {';
+                    if ('uri' == $row[$var.' type']) {
+                        $r .= $nl.'          "type": "uri",';
+                        $r .= $nl.'          "value": "'.$this->a['db_object']->escape($row[$var]).'"';
+                    } elseif ('bnode' == $row[$var.' type']) {
+                        $r .= $nl.'          "type": "bnode",';
+                        $r .= $nl.'          "value": "'.substr($row[$var], 2).'"';
+                    } else {
+                        $dt = isset($row[$var.' datatype']) ? ','.$nl.'          "datatype": "'.$this->a['db_object']->escape($row[$var.' datatype']).'"' : '';
+                        $lang = isset($row[$var.' lang']) ? ','.$nl.'          "xml:lang": "'.$this->a['db_object']->escape($row[$var.' lang']).'"' : '';
+                        $type = $dt ? 'typed-literal' : 'literal';
+                        $r .= $nl.'          "type": "'.$type.'",';
+                        $r .= $nl.'          "value": "'.$this->jsonEscape($row[$var]).'"';
+                        $r .= $dt.$lang;
+                    }
+                    $r .= $nl.'        }';
+                    $first_var = 0;
+                }
+            }
+            $r .= $nl.'      }';
+            $first_row = 0;
+        }
+        $r .= $nl.'    ]';
+        $r .= $nl.'  }';
+        /* /doc */
+        $r .= $nl.'}';
+        if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
+            $r = $v.'('.$r.')';
+        }
+
+        return $r;
+    }
+
+    public function getPHPSERSelectResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/plain');
+
+        return serialize($r);
+    }
+
+    public function getPlainSelectResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/plain');
+
+        return print_r($r['result'], 1);
+    }
+
+    public function getHTMLTableSelectResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/html; charset=utf-8');
+        $vars = $r['result']['variables'];
+        $rows = $r['result']['rows'];
+        $dur = $r['query_time'];
+        if ($this->p('show_inline')) {
+            return '<table>'.$this->getHTMLTableRows($rows, $vars).'</table>';
+        }
+
+        return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-      ' .$this->getHTMLDocHead() . '
+      '.$this->getHTMLDocHead().'
       <body>
         <table>
-          ' . $this->getHTMLTableRows($rows, $vars) . '
+          '.$this->getHTMLTableRows($rows, $vars).'
         </table>
       </body>
       </html>
     ';
-  }
-
-  function getHTMLTableRows($rows, $vars) {
-    $r = '';
-    foreach ($rows as $row) {
-      $hr = '';
-      $rr = '';
-      foreach ($vars as $var) {
-        $hr .= $r ? '' : '<th>' . htmlspecialchars($var) . '</th>';
-        $rr .= '<td>' . @htmlspecialchars($row[$var]) . '</td>';
-      }
-      $r .= $hr ? '<tr>' . $hr . '</tr>' : '';
-      $r .= '<tr>' . $rr . '</tr>';
-    }
-    return $r ? $r : '<em>No results found</em>';
-  }
-
-  function getTSVSelectResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/plain; charset=utf-8');
-    $vars = $r['result']['variables'];
-    $rows = $r['result']['rows'];
-    $dur = $r['query_time'];
-    return $this->getTSVRows($rows, $vars);
-  }
-
-  function getTSVRows($rows, $vars) {
-    $r = '';
-    $delim = "\t";
-    $esc_delim = "\\t";
-    foreach ($rows as $row) {
-      $hr = '';
-      $rr = '';
-      foreach ($vars as $var) {
-        $hr .= $r ? '' : ($hr ? $delim . $var : $var);
-        $val = isset($row[$var]) ? str_replace($delim, $esc_delim, $row[$var]) : '';
-        $rr .= $rr ? $delim . $val : $val;
-      }
-      $r .= $hr . "\n" . $rr;
-    }
-    return $r ? $r : 'No results found';
-  }
-
-  /* ASK */
-  
-  function getAskResultDoc($r) {
-    $formats = array(
-      'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML', 
-      'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
-      'plain' => 'Plain',
-      'php_ser' => 'PHPSER',
-      'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
-      'infos' => 'Plain',
-    );
-    if ($f = $this->getResultFormat($formats, 'xml')) {
-      $m = 'get' . $f . 'AskResultDoc';
-      return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
-    }
-    return '';
-  }
-
-  function getSPARQLXMLAskResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
-    $r_val = $r['result'] ? 'true' : 'false';
-    $dur = $r['query_time'];
-    $nl = "\n";
-    return '' .
-      '<?xml version="1.0"?>' .
-      $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
-      $nl . '  <head>' .
-      $nl . '    <!-- query time: '. round($dur, 4) .' sec -->' .
-      $nl . '  </head>' .
-      $nl . '  <boolean>' .$r_val. '</boolean>' .
-      $nl . '</sparql>' .
+    }
+
+    public function getHTMLTableRows($rows, $vars)
+    {
+        $r = '';
+        foreach ($rows as $row) {
+            $hr = '';
+            $rr = '';
+            foreach ($vars as $var) {
+                $hr .= $r ? '' : '<th>'.htmlspecialchars($var).'</th>';
+                $rr .= '<td>'.htmlspecialchars($row[$var]).'</td>';
+            }
+            $r .= $hr ? '<tr>'.$hr.'</tr>' : '';
+            $r .= '<tr>'.$rr.'</tr>';
+        }
+
+        return $r ? $r : '<em>No results found</em>';
+    }
+
+    public function getTSVSelectResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/plain; charset=utf-8');
+        $vars = $r['result']['variables'];
+        $rows = $r['result']['rows'];
+        $dur = $r['query_time'];
+
+        return $this->getTSVRows($rows, $vars);
+    }
+
+    public function getTSVRows($rows, $vars)
+    {
+        $r = '';
+        $delim = "\t";
+        $esc_delim = '\\t';
+        foreach ($rows as $row) {
+            $hr = '';
+            $rr = '';
+            foreach ($vars as $var) {
+                $hr .= $r ? '' : ($hr ? $delim.$var : $var);
+                $val = isset($row[$var]) ? str_replace($delim, $esc_delim, $row[$var]) : '';
+                $rr .= $rr ? $delim.$val : $val;
+            }
+            $r .= $hr."\n".$rr;
+        }
+
+        return $r ? $r : 'No results found';
+    }
+
+    /* ASK */
+
+    public function getAskResultDoc($r)
+    {
+        $formats = [
+            'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML',
+            'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
+            'plain' => 'Plain',
+            'php_ser' => 'PHPSER',
+            'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
+            'infos' => 'Plain',
+        ];
+        if ($f = $this->getResultFormat($formats, 'xml')) {
+            $m = 'get'.$f.'AskResultDoc';
+
+            return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
+        }
+
+        return '';
+    }
+
+    public function getSPARQLXMLAskResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
+        $r_val = $r['result'] ? 'true' : 'false';
+        $dur = $r['query_time'];
+        $nl = "\n";
+
+        return ''.
+      '<?xml version="1.0"?>'.
+      $nl.'<sparql xmlns="http://www.w3.org/2005/sparql-results#">'.
+      $nl.'  <head>'.
+      $nl.'    <!-- query time: '.round($dur, 4).' sec -->'.
+      $nl.'  </head>'.
+      $nl.'  <boolean>'.$r_val.'</boolean>'.
+      $nl.'</sparql>'.
     '';
-  }
-  
-  function getSPARQLJSONAskResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
-    $r_val = $r['result'] ? 'true' : 'false';
-    $dur = $r['query_time'];
-    $nl = "\n";
-    $r = '' .
-      $nl . '{' .
-      $nl . '  "head": {' .
-      $nl . '  },' .
-      $nl . '  "boolean" : ' . $r_val . 
-      $nl . '}' . 
+    }
+
+    public function getSPARQLJSONAskResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
+        $r_val = $r['result'] ? 'true' : 'false';
+        $dur = $r['query_time'];
+        $nl = "\n";
+        $r = ''.
+      $nl.'{'.
+      $nl.'  "head": {'.
+      $nl.'  },'.
+      $nl.'  "boolean" : '.$r_val.
+      $nl.'}'.
     '';
-    if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
-      $r = $v . '(' . $r . ')';
-    }
-    return $r;
-  }    
-  
-  function getPHPSERAskResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/plain');
-    return serialize($r);
-  }
-
-  function getPlainAskResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/plain');
-    return $r['result'] ? 'true' : 'false';
-  }
-
-  /* CONSTRUCT */
-
-  function getConstructResultDoc($r) {
-    $formats = array(
-      'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML', 
-      'json' => 'RDFJSON', 'rdf+json' => 'RDFJSON',
-      'turtle' => 'Turtle', 'x-turtle' => 'Turtle', 'rdf+n3' => 'Turtle',
-      'php_ser' => 'PHPSER',
-      'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
-      'infos' => 'Plain',
-    );
-    if ($f = $this->getResultFormat($formats, 'rdfxml')) {
-      $m = 'get' . $f . 'ConstructResultDoc';
-      return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
-    }
-    return '';
-  }
-  
-  function getRDFXMLConstructResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: application/rdf+xml');
-    $index = $r['result'];
-    $ser = ARC2::getRDFXMLSerializer($this->a);
-    $dur = $r['query_time'];
-    return $ser->getSerializedIndex($index) . "\n" . '<!-- query time: ' . $dur . ' -->';
-  }
-  
-  function getTurtleConstructResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: application/x-turtle');
-    $index = $r['result'];
-    $ser = ARC2::getTurtleSerializer($this->a);
-    $dur = $r['query_time'];
-    return '# query time: ' . $dur . "\n" . $ser->getSerializedIndex($index);
-  }
-  
-  function getRDFJSONConstructResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: application/json');
-    $index = $r['result'];
-    $ser = ARC2::getRDFJSONSerializer($this->a);
-    $dur = $r['query_time'];
-    $r = $ser->getSerializedIndex($index);
-    if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
-      $r = $v . '(' . $r . ')';
-    }
-    return $r;
-  }
-
-  function getPHPSERConstructResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/plain');
-    return serialize($r);
-  }
-
-  function getPlainConstructResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/plain');
-    return print_r($r['result'], 1);
-  }
-
-  /* DESCRIBE */
-  
-  function getDescribeResultDoc($r) {
-    $formats = array(
-      'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML', 
-      'json' => 'RDFJSON', 'rdf+json' => 'RDFJSON',
-      'turtle' => 'Turtle', 'x-turtle' => 'Turtle', 'rdf+n3' => 'Turtle',
-      'php_ser' => 'PHPSER',
-      'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
-      'infos' => 'Plain'
-    );
-    if ($f = $this->getResultFormat($formats, 'rdfxml')) {
-      $m = 'get' . $f . 'DescribeResultDoc';
-      return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
-    }
-    return '';
-  }
-  
-  function getRDFXMLDescribeResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: application/rdf+xml');
-    $index = $r['result'];
-    $ser = ARC2::getRDFXMLSerializer($this->a);
-    $dur = $r['query_time'];
-    return $ser->getSerializedIndex($index) . "\n" . '<!-- query time: ' . $dur . ' -->';
-  }
-  
-  function getTurtleDescribeResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: application/x-turtle');
-    $index = $r['result'];
-    $ser = ARC2::getTurtleSerializer($this->a);
-    $dur = $r['query_time'];
-    return '# query time: ' . $dur . "\n" . $ser->getSerializedIndex($index);
-  }
-  
-  function getRDFJSONDescribeResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: application/json');
-    $index = $r['result'];
-    $ser = ARC2::getRDFJSONSerializer($this->a);
-    $dur = $r['query_time'];
-    $r = $ser->getSerializedIndex($index);
-    if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
-      $r = $v . '(' . $r . ')';
-    }
-    return $r;
-  }
-
-  function getPHPSERDescribeResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/plain');
-    return serialize($r);
-  }
-  
-  function getPlainDescribeResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/plain');
-    return print_r($r['result'], 1);
-  }
-
-  /* DUMP */
-  
-  function getDumpResultDoc() {
-    $this->headers = array();
-    return '';
-  }
-  
-  /* LOAD */
-  
-  function getLoadResultDoc($r) {
-    $formats = array(
-      'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML', 
-      'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
-      'plain' => 'Plain',
-      'php_ser' => 'PHPSER',
-      'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
-      'infos' => 'Plain',
-    );
-    if ($f = $this->getResultFormat($formats, 'xml')) {
-      $m = 'get' . $f . 'LoadResultDoc';
-      return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
-    }
-    return '';
-  }
-
-  function getSPARQLXMLLoadResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
-    $r_val = $r['result']['t_count'];
-    $dur = $r['query_time'];
-    $nl = "\n";
-    return '' .
-      '<?xml version="1.0"?>' .
-      $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
-      $nl . '  <head>' .
-      $nl . '    <!-- query time: '. round($dur, 4) .' sec -->' .
-      $nl . '  </head>' .
-      $nl . '  <inserted>' .$r_val. '</inserted>' .
-      $nl . '</sparql>' .
+        if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
+            $r = $v.'('.$r.')';
+        }
+
+        return $r;
+    }
+
+    public function getPHPSERAskResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/plain');
+
+        return serialize($r);
+    }
+
+    public function getPlainAskResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/plain');
+
+        return $r['result'] ? 'true' : 'false';
+    }
+
+    /* CONSTRUCT */
+
+    public function getConstructResultDoc($r)
+    {
+        $formats = [
+            'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML',
+            'json' => 'RDFJSON', 'rdf+json' => 'RDFJSON',
+            'turtle' => 'Turtle', 'x-turtle' => 'Turtle', 'rdf+n3' => 'Turtle',
+            'php_ser' => 'PHPSER',
+            'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
+            'infos' => 'Plain',
+        ];
+        if ($f = $this->getResultFormat($formats, 'rdfxml')) {
+            $m = 'get'.$f.'ConstructResultDoc';
+
+            return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
+        }
+
+        return '';
+    }
+
+    public function getRDFXMLConstructResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/rdf+xml');
+        $index = $r['result'];
+        $ser = ARC2::getRDFXMLSerializer($this->a);
+        $dur = $r['query_time'];
+
+        return $ser->getSerializedIndex($index)."\n".'<!-- query time: '.$dur.' -->';
+    }
+
+    public function getTurtleConstructResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/x-turtle');
+        $index = $r['result'];
+        $ser = ARC2::getTurtleSerializer($this->a);
+        $dur = $r['query_time'];
+
+        return '# query time: '.$dur."\n".$ser->getSerializedIndex($index);
+    }
+
+    public function getRDFJSONConstructResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/json');
+        $index = $r['result'];
+        $ser = ARC2::getRDFJSONSerializer($this->a);
+        $dur = $r['query_time'];
+        $r = $ser->getSerializedIndex($index);
+        if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
+            $r = $v.'('.$r.')';
+        }
+
+        return $r;
+    }
+
+    public function getPHPSERConstructResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/plain');
+
+        return serialize($r);
+    }
+
+    public function getPlainConstructResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/plain');
+
+        return print_r($r['result'], 1);
+    }
+
+    /* DESCRIBE */
+
+    public function getDescribeResultDoc($r)
+    {
+        $formats = [
+            'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML',
+            'json' => 'RDFJSON', 'rdf+json' => 'RDFJSON',
+            'turtle' => 'Turtle', 'x-turtle' => 'Turtle', 'rdf+n3' => 'Turtle',
+            'php_ser' => 'PHPSER',
+            'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
+            'infos' => 'Plain',
+        ];
+        if ($f = $this->getResultFormat($formats, 'rdfxml')) {
+            $m = 'get'.$f.'DescribeResultDoc';
+
+            return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
+        }
+
+        return '';
+    }
+
+    public function getRDFXMLDescribeResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/rdf+xml');
+        $index = $r['result'];
+        $ser = ARC2::getRDFXMLSerializer($this->a);
+        $dur = $r['query_time'];
+
+        return $ser->getSerializedIndex($index)."\n".'<!-- query time: '.$dur.' -->';
+    }
+
+    public function getTurtleDescribeResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/x-turtle');
+        $index = $r['result'];
+        $ser = ARC2::getTurtleSerializer($this->a);
+        $dur = $r['query_time'];
+
+        return '# query time: '.$dur."\n".$ser->getSerializedIndex($index);
+    }
+
+    public function getRDFJSONDescribeResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/json');
+        $index = $r['result'];
+        $ser = ARC2::getRDFJSONSerializer($this->a);
+        $dur = $r['query_time'];
+        $r = $ser->getSerializedIndex($index);
+        if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
+            $r = $v.'('.$r.')';
+        }
+
+        return $r;
+    }
+
+    public function getPHPSERDescribeResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/plain');
+
+        return serialize($r);
+    }
+
+    public function getPlainDescribeResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/plain');
+
+        return print_r($r['result'], 1);
+    }
+
+    /* DUMP */
+
+    public function getDumpResultDoc()
+    {
+        $this->headers = [];
+
+        return '';
+    }
+
+    /* LOAD */
+
+    public function getLoadResultDoc($r)
+    {
+        $formats = [
+            'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML',
+            'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
+            'plain' => 'Plain',
+            'php_ser' => 'PHPSER',
+            'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
+            'infos' => 'Plain',
+        ];
+        if ($f = $this->getResultFormat($formats, 'xml')) {
+            $m = 'get'.$f.'LoadResultDoc';
+
+            return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
+        }
+
+        return '';
+    }
+
+    public function getSPARQLXMLLoadResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
+        $r_val = $r['result']['t_count'];
+        $dur = $r['query_time'];
+        $nl = "\n";
+
+        return ''.
+      '<?xml version="1.0"?>'.
+      $nl.'<sparql xmlns="http://www.w3.org/2005/sparql-results#">'.
+      $nl.'  <head>'.
+      $nl.'    <!-- query time: '.round($dur, 4).' sec -->'.
+      $nl.'  </head>'.
+      $nl.'  <inserted>'.$r_val.'</inserted>'.
+      $nl.'</sparql>'.
     '';
-  }
-  
-  function getSPARQLJSONLoadResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
-    $r_val = $r['result']['t_count'];
-    $dur = $r['query_time'];
-    $nl = "\n";
-    $r = '' .
-      $nl . '{' .
-      $nl . '  "head": {' .
-      $nl . '  },' .
-      $nl . '  "inserted" : ' . $r_val . 
-      $nl . '}' . 
+    }
+
+    public function getSPARQLJSONLoadResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
+        $r_val = $r['result']['t_count'];
+        $dur = $r['query_time'];
+        $nl = "\n";
+        $r = ''.
+      $nl.'{'.
+      $nl.'  "head": {'.
+      $nl.'  },'.
+      $nl.'  "inserted" : '.$r_val.
+      $nl.'}'.
     '';
-    if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
-      $r = $v . '(' . $r . ')';
-    }
-    return $r;
-  }    
-  
-  function getPHPSERLoadResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/plain');
-    return serialize($r);
-  }
-
-  function getPlainLoadResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/plain');
-    return print_r($r['result'], 1);
-  }
-
-  /* DELETE */
-  
-  function getDeleteResultDoc($r) {
-    $formats = array(
-      'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML', 
-      'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
-      'plain' => 'Plain',
-      'php_ser' => 'PHPSER'
-    );
-    if ($f = $this->getResultFormat($formats, 'xml')) {
-      $m = 'get' . $f . 'DeleteResultDoc';
-      return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
-    }
-    return '';
-  }
-
-  function getSPARQLXMLDeleteResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
-    $r_val = $r['result']['t_count'];
-    $dur = $r['query_time'];
-    $nl = "\n";
-    return '' .
-      '<?xml version="1.0"?>' .
-      $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
-      $nl . '  <head>' .
-      $nl . '    <!-- query time: '. round($dur, 4) .' sec -->' .
-      $nl . '  </head>' .
-      $nl . '  <deleted>' .$r_val. '</deleted>' .
-      $nl . '</sparql>' .
+        if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
+            $r = $v.'('.$r.')';
+        }
+
+        return $r;
+    }
+
+    public function getPHPSERLoadResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/plain');
+
+        return serialize($r);
+    }
+
+    public function getPlainLoadResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/plain');
+
+        return print_r($r['result'], 1);
+    }
+
+    /* DELETE */
+
+    public function getDeleteResultDoc($r)
+    {
+        $formats = [
+            'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML',
+            'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
+            'plain' => 'Plain',
+            'php_ser' => 'PHPSER',
+        ];
+        if ($f = $this->getResultFormat($formats, 'xml')) {
+            $m = 'get'.$f.'DeleteResultDoc';
+
+            return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
+        }
+
+        return '';
+    }
+
+    public function getSPARQLXMLDeleteResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
+        $r_val = $r['result']['t_count'];
+        $dur = $r['query_time'];
+        $nl = "\n";
+
+        return ''.
+      '<?xml version="1.0"?>'.
+      $nl.'<sparql xmlns="http://www.w3.org/2005/sparql-results#">'.
+      $nl.'  <head>'.
+      $nl.'    <!-- query time: '.round($dur, 4).' sec -->'.
+      $nl.'  </head>'.
+      $nl.'  <deleted>'.$r_val.'</deleted>'.
+      $nl.'</sparql>'.
     '';
-  }
-  
-  function getSPARQLJSONDeleteResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
-    $r_val = $r['result']['t_count'];
-    $dur = $r['query_time'];
-    $nl = "\n";
-    $r = '' .
-      $nl . '{' .
-      $nl . '  "head": {' .
-      $nl . '  },' .
-      $nl . '  "deleted" : ' . $r_val . 
-      $nl . '}' . 
+    }
+
+    public function getSPARQLJSONDeleteResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
+        $r_val = $r['result']['t_count'];
+        $dur = $r['query_time'];
+        $nl = "\n";
+        $r = ''.
+      $nl.'{'.
+      $nl.'  "head": {'.
+      $nl.'  },'.
+      $nl.'  "deleted" : '.$r_val.
+      $nl.'}'.
     '';
-    if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
-      $r = $v . '(' . $r . ')';
-    }
-    return $r;
-  }    
-  
-  function getPHPSERDeleteResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/plain');
-    return serialize($r);
-  }
-
-  function getPlainDeleteResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/plain');
-    return print_r($r['result'], 1);
-  }
-
-  /* INSERT */
-  
-  function getInsertResultDoc($r) {
-    $formats = array(
-      'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML', 
-      'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
-      'plain' => 'Plain',
-      'php_ser' => 'PHPSER'
-    );
-    if ($f = $this->getResultFormat($formats, 'xml')) {
-      $m = 'get' . $f . 'InsertResultDoc';
-      return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
-    }
-    return '';
-  }
-
-  function getSPARQLXMLInsertResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
-    $r_val = $r['result']['t_count'];
-    $dur = $r['query_time'];
-    $nl = "\n";
-    return '' .
-      '<?xml version="1.0"?>' .
-      $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
-      $nl . '  <head>' .
-      $nl . '    <!-- query time: '. round($dur, 4) .' sec -->' .
-      $nl . '  </head>' .
-      $nl . '  <inserted>' .$r_val. '</inserted>' .
-      $nl . '</sparql>' .
+        if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
+            $r = $v.'('.$r.')';
+        }
+
+        return $r;
+    }
+
+    public function getPHPSERDeleteResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/plain');
+
+        return serialize($r);
+    }
+
+    public function getPlainDeleteResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/plain');
+
+        return print_r($r['result'], 1);
+    }
+
+    /* INSERT */
+
+    public function getInsertResultDoc($r)
+    {
+        $formats = [
+            'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML',
+            'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
+            'plain' => 'Plain',
+            'php_ser' => 'PHPSER',
+        ];
+        if ($f = $this->getResultFormat($formats, 'xml')) {
+            $m = 'get'.$f.'InsertResultDoc';
+
+            return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
+        }
+
+        return '';
+    }
+
+    public function getSPARQLXMLInsertResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
+        $r_val = $r['result']['t_count'];
+        $dur = $r['query_time'];
+        $nl = "\n";
+
+        return ''.
+      '<?xml version="1.0"?>'.
+      $nl.'<sparql xmlns="http://www.w3.org/2005/sparql-results#">'.
+      $nl.'  <head>'.
+      $nl.'    <!-- query time: '.round($dur, 4).' sec -->'.
+      $nl.'  </head>'.
+      $nl.'  <inserted>'.$r_val.'</inserted>'.
+      $nl.'</sparql>'.
     '';
-  }
-  
-  function getSPARQLJSONInsertResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
-    $r_val = $r['result']['t_count'];
-    $dur = $r['query_time'];
-    $nl = "\n";
-    $r = '' .
-      $nl . '{' .
-      $nl . '  "head": {' .
-      $nl . '  },' .
-      $nl . '  "inserted" : ' . $r_val . 
-      $nl . '}' . 
+    }
+
+    public function getSPARQLJSONInsertResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
+        $r_val = $r['result']['t_count'];
+        $dur = $r['query_time'];
+        $nl = "\n";
+        $r = ''.
+      $nl.'{'.
+      $nl.'  "head": {'.
+      $nl.'  },'.
+      $nl.'  "inserted" : '.$r_val.
+      $nl.'}'.
     '';
-    if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
-      $r = $v . '(' . $r . ')';
-    }
-    return $r;
-  }    
-  
-  function getPHPSERInsertResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/plain');
-    return serialize($r);
-  }
-
-  function getPlainInsertResultDoc($r) {
-    $this->setHeader('content-type', 'Content-Type: text/plain');
-    return print_r($r['result'], 1);
-  }
-
-  /*  */  
-  
-  function jsonEscape($v) {
-    if (function_exists('json_encode')) return trim(json_encode($v), '"');
-    $from = array("\\", "\r", "\t", "\n", '"', "\b", "\f", "/");
-    $to = array('\\\\', '\r', '\t', '\n', '\"', '\b', '\f', '\/');
-    return str_replace($from, $to, $v);
-  }
-    
-  /*  */
-
-  function getHTMLFormDoc() {
-    return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+        if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
+            $r = $v.'('.$r.')';
+        }
+
+        return $r;
+    }
+
+    public function getPHPSERInsertResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/plain');
+
+        return serialize($r);
+    }
+
+    public function getPlainInsertResultDoc($r)
+    {
+        $this->setHeader('content-type', 'Content-Type: text/plain');
+
+        return print_r($r['result'], 1);
+    }
+
+    public function jsonEscape($v)
+    {
+        if (function_exists('json_encode')) {
+            return trim(json_encode($v), '"');
+        }
+        $from = ['\\', "\r", "\t", "\n", '"', "\b", "\f", '/'];
+        $to = ['\\\\', '\r', '\t', '\n', '\"', '\b', '\f', '\/'];
+
+        return str_replace($from, $to, $v);
+    }
+
+    public function getHTMLFormDoc()
+    {
+        return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-      ' . $this->getHTMLDocHead() . '
-      ' . $this->getHTMLDocBody() . '
+      '.$this->getHTMLDocHead().'
+      '.$this->getHTMLDocBody().'
       </html>
     ';
-  }
+    }
 
-  function getHTMLDocHead() {
-    return '
+    public function getHTMLDocHead()
+    {
+        return '
     	<head>
-    		<title>' . $this->getHTMLDocTitle() . '</title>
+    		<title>'.$this->getHTMLDocTitle().'</title>
     		<style type="text/css">
-        ' . $this->getHTMLDocCSS() . '
+        '.$this->getHTMLDocCSS().'
     		</style>
     	</head>
     ';
-  }
-  
-  function getHTMLDocTitle() {
-    return $this->v('endpoint_title', 'ARC SPARQL+ Endpoint', $this->a);
-  }
-  
-  function getHTMLDocHeading() {
-    return $this->v('endpoint_heading', 'ARC SPARQL+ Endpoint (v' . ARC2::getVersion() . ')', $this->a);
-  }
-  
-  function getHTMLDocCSS() {
-    $default = '
+    }
+
+    public function getHTMLDocTitle()
+    {
+        return $this->v('endpoint_title', 'ARC SPARQL+ Endpoint', $this->a);
+    }
+
+    public function getHTMLDocHeading()
+    {
+        return $this->v('endpoint_heading', 'ARC SPARQL+ Endpoint (v'.ARC2::getVersion().')', $this->a);
+    }
+
+    public function getHTMLDocCSS()
+    {
+        $default = '
       body {
         font-size: 14px;
       	font-family: Trebuchet MS, Verdana, Geneva, sans-serif;
@@ -939,16 +1033,16 @@ class ARC2_StoreEndpoint extends ARC2_Store {
       a { color: #c00000; }
       th, td {
         border: 1px dotted #eee;
-        padding: 2px 4px; 
+        padding: 2px 4px;
       }
       #sparql-form {
         margin-bottom: 30px;
       }
-      #query { 
+      #query {
         float: left;
         width: 60%;
-        display: block; 
-        height: 265px; 
+        display: block;
+        height: 265px;
         margin-bottom: 10px;
       }
       .options {
@@ -986,95 +1080,98 @@ class ARC2_StoreEndpoint extends ARC2_Store {
         background-color: #fcfcfc;
       }
     ';
-    return $this->v('endpoint_css', $default, $this->a);
-  }
-  
-  function getHTMLDocBody() {
-    return '
+
+        return $this->v('endpoint_css', $default, $this->a);
+    }
+
+    public function getHTMLDocBody()
+    {
+        return '
     	<body>
-        <h1>' . $this->getHTMLDocHeading() . '</h1>
+        <h1>'.$this->getHTMLDocHeading().'</h1>
         <div class="intro">
           <p>
-            <a href="?">This interface</a> implements 
+            <a href="?">This interface</a> implements
             <a href="http://www.w3.org/TR/rdf-sparql-query/">SPARQL</a> and
-            <a href="http://arc.semsol.org/docs/v2/sparql+">SPARQL+</a> via <a href="http://www.w3.org/TR/rdf-sparql-protocol/#query-bindings-http">HTTP Bindings</a>. 
+            <a href="https://github.com/semsol/arc2/wiki/SPARQL%2B">SPARQL+</a> via <a href="http://www.w3.org/TR/rdf-sparql-protocol/#query-bindings-http">HTTP Bindings</a>.
           </p>
           <p>
-            Enabled operations: ' . join(', ', $this->getFeatures()) . '
+            Enabled operations: '.implode(', ', $this->getFeatures()).'
           </p>
           <p>
-            Max. number of results : ' . $this->v('endpoint_max_limit', '<em>unrestricted</em>', $this->a) . '
+            Max. number of results : '.$this->v('endpoint_max_limit', '<em>unrestricted</em>', $this->a).'
           </p>
         </div>
-        ' . $this->getHTMLDocForm() .'
-        ' . ($this->p('show_inline') ? $this->query_result : '') . '
+        '.$this->getHTMLDocForm().'
+        '.($this->p('show_inline') ? $this->query_result : '').'
     	</body>
     ';
-  }
-  
-  function getHTMLDocForm() {
-    $q = $this->p('query') ? htmlspecialchars($this->p('query')) : "SELECT * WHERE {\n  GRAPH ?g { ?s ?p ?o . }\n}\nLIMIT 10";
-    return '
-      <form id="sparql-form" action="?" enctype="application/x-www-form-urlencoded" method="' . ($_SERVER['REQUEST_METHOD'] == 'GET' ? 'get' : 'post' ) . '">
-        <textarea id="query" name="query" rows="20" cols="80">' . $q . '</textarea>
-        ' . $this->getHTMLDocOptions() . '
+    }
+
+    public function getHTMLDocForm()
+    {
+        $q = $this->p('query') ? htmlspecialchars($this->p('query')) : "SELECT * WHERE {\n  GRAPH ?g { ?s ?p ?o . }\n}\nLIMIT 10";
+
+        return '
+      <form id="sparql-form" action="?" enctype="application/x-www-form-urlencoded" method="'.('GET' == $_SERVER['REQUEST_METHOD'] ? 'get' : 'post').'">
+        <textarea id="query" name="query" rows="20" cols="80">'.$q.'</textarea>
+        '.$this->getHTMLDocOptions().'
         <div class="form-buttons">
           <input type="submit" value="Send Query" />
           <input type="reset" value="Reset" />
         </div>
       </form>
     ';
-  }
-  
-  function getHTMLDocOptions() {
-    $sel = $this->p('output');
-    $sel_code = ' selected="selected"';
-    return '
+    }
+
+    public function getHTMLDocOptions()
+    {
+        $sel = $this->p('output');
+        $sel_code = ' selected="selected"';
+
+        return '
       <div class="options">
         <h3>Options</h3>
         <dl>
           <dt class="first">Output format (if supported by query type):</dt>
           <dd>
             <select id="output" name="output">
-              <option value="" ' . (!$sel ? $sel_code : '') . '>default</option>
-              <option value="xml" ' . ($sel == 'xml' ? $sel_code : '') . '>XML</option>
-              <option value="json" ' . ($sel == 'json' ? $sel_code : '') . '>JSON</option>
-              <option value="plain" ' . ($sel == 'plain' ? $sel_code : '') . '>Plain</option>
-              <option value="php_ser" ' . ($sel == 'php_ser' ? $sel_code : '') . '>Serialized PHP</option>
-              <option value="turtle" ' . ($sel == 'turtle' ? $sel_code : '') . '>Turtle</option>
-              <option value="rdfxml" ' . ($sel == 'rdfxml' ? $sel_code : '') . '>RDF/XML</option>
-              <option value="infos" ' . ($sel == 'infos' ? $sel_code : '') . '>Query Structure</option>
-              ' . ($this->allow_sql ? '<option value="sql" ' . ($sel == 'sql' ? $sel_code : '') . '>SQL</option>' : '') . '
-              <option value="htmltab" ' . ($sel == 'htmltab' ? $sel_code : '') . '>HTML Table</option>
-              <option value="tsv" ' . ($sel == 'tsv' ? $sel_code : '') . '>TSV</option>
+              <option value="" '.(!$sel ? $sel_code : '').'>default</option>
+              <option value="xml" '.('xml' == $sel ? $sel_code : '').'>XML</option>
+              <option value="json" '.('json' == $sel ? $sel_code : '').'>JSON</option>
+              <option value="plain" '.('plain' == $sel ? $sel_code : '').'>Plain</option>
+              <option value="php_ser" '.('php_ser' == $sel ? $sel_code : '').'>Serialized PHP</option>
+              <option value="turtle" '.('turtle' == $sel ? $sel_code : '').'>Turtle</option>
+              <option value="rdfxml" '.('rdfxml' == $sel ? $sel_code : '').'>RDF/XML</option>
+              <option value="infos" '.('infos' == $sel ? $sel_code : '').'>Query Structure</option>
+              '.($this->allow_sql ? '<option value="sql" '.('sql' == $sel ? $sel_code : '').'>SQL</option>' : '').'
+              <option value="htmltab" '.('htmltab' == $sel ? $sel_code : '').'>HTML Table</option>
+              <option value="tsv" '.('tsv' == $sel ? $sel_code : '').'>TSV</option>
             </select>
           </dd>
-          
+
           <dt>jsonp/callback (for JSON results)</dt>
           <dd>
-            <input type="text" id="jsonp" name="jsonp" value="' . htmlspecialchars($this->p('jsonp')) . '" />
+            <input type="text" id="jsonp" name="jsonp" value="'.htmlspecialchars($this->p('jsonp')).'" />
           </dd>
-          
+
           <dt>API key (if required)</dt>
           <dd>
-            <input type="text" id="key" name="key" value="' . htmlspecialchars($this->p('key')) . '" />
+            <input type="text" id="key" name="key" value="'.htmlspecialchars($this->p('key')).'" />
           </dd>
-          
+
           <dt>Show results inline: </dt>
           <dd>
-            <input type="checkbox" name="show_inline" value="1" ' . ($this->p('show_inline') ? ' checked="checked"' : '') . ' />
+            <input type="checkbox" name="show_inline" value="1" '.($this->p('show_inline') ? ' checked="checked"' : '').' />
           </dd>
-          
+
         </dl>
       </div>
       <div class="options-2">
-        Change HTTP method: 
-            <a href="javascript:;" onclick="javascript:document.getElementById(\'sparql-form\').method=\'get\'">GET</a> 
-            <a href="javascript:;" onclick="javascript:document.getElementById(\'sparql-form\').method=\'post\'">POST</a> 
+        Change HTTP method:
+            <a href="javascript:;" onclick="javascript:document.getElementById(\'sparql-form\').method=\'get\'">GET</a>
+            <a href="javascript:;" onclick="javascript:document.getElementById(\'sparql-form\').method=\'post\'">POST</a>
        </div>
     ';
-  }
-  
-  /*  */
-  
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreHelper.php b/lib/arc2/store/ARC2_StoreHelper.php
old mode 100644
new mode 100755
index 9ce9c580acc9f421d063d0d68cd823e91d897103..60b6de0279036691327f8ecac9bc0409163e11f8
--- a/lib/arc2/store/ARC2_StoreHelper.php
+++ b/lib/arc2/store/ARC2_StoreHelper.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 RDF Store Helper
 author:   Benjamin Nowack
@@ -10,57 +10,57 @@ version:  2010-11-16
 
 ARC2::inc('Class');
 
-class ARC2_StoreHelper extends ARC2_Class {
+class ARC2_StoreHelper extends ARC2_Class
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
 
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* db_con */
-    parent::__init();
-    $this->store = $this->caller;
-  }
+    public function __init()
+    {
+        parent::__init();
+        $this->store = $this->caller;
+    }
 
-  /*  */
+    public function changeNamespaceURI($old_uri, $new_uri)
+    {
+        $id_changes = 0;
+        $t_changes = 0;
+        /* table lock */
+        if ($this->store->getLock()) {
+            foreach (['id', 's', 'o'] as $id_col) {
+                $tbl = $this->store->getTablePrefix().$id_col.'2val';
+                $sql = 'SELECT id, val FROM '.$tbl.' WHERE val LIKE "'.$this->store->a['db_object']->escape($old_uri).'%"';
+                $rows = $this->store->a['db_object']->fetchList($sql);
 
-  function changeNamespaceURI($old_uri, $new_uri) {
-    $id_changes = 0;
-    $t_changes = 0;
-    /* table lock */
-    if ($this->store->getLock()) {
-      $con = $this->store->getDBCon();
-      foreach (array('id', 's', 'o') as $id_col) {
-        $tbl = $this->store->getTablePrefix() . $id_col . '2val';
-        $sql = 'SELECT id, val FROM ' . $tbl . ' WHERE val LIKE "' . mysql_real_escape_string($old_uri, $con). '%"';
-        $rs = mysql_query($sql, $con);
-        if (!$rs) continue;
-        while ($row = mysql_fetch_array($rs)) {
-          $new_val = str_replace($old_uri, $new_uri, $row['val']);
-          $new_id = $this->store->getTermID($new_val, $id_col);
-          if (!$new_id) {/* unknown ns uri, overwrite current id value */
-            $sub_sql = "UPDATE " . $tbl . " SET val = '" . mysql_real_escape_string($new_val, $con) . "' WHERE id = " . $row['id'];
-            $sub_r = mysql_query($sub_sql, $con);
-            $id_changes++;
-          }
-          else {/* replace ids */
-            $t_tbls = $this->store->getTables();
-            foreach ($t_tbls as $t_tbl) {
-              if (preg_match('/^triple/', $t_tbl)) {
-                foreach (array('s', 'p', 'o', 'o_lang_dt') as $t_col) {
-                  $sub_sql = "UPDATE " . $this->store->getTablePrefix() . $t_tbl . " SET " . $t_col . " = " . $new_id . " WHERE " . $t_col . " = " . $row['id'];
-                  $sub_r = mysql_query($sub_sql, $con);
-                  $t_changes += mysql_affected_rows($con);
+                if (false == is_array($rows)) {
+                    continue;
+                }
+                foreach($rows as $row) {
+                    $new_val = str_replace($old_uri, $new_uri, $row['val']);
+                    $new_id = $this->store->getTermID($new_val, $id_col);
+                    if (!$new_id) {/* unknown ns uri, overwrite current id value */
+                        $sub_sql = 'UPDATE '.$tbl." SET val = '".$this->store->a['db_object']->escape($new_val)."' WHERE id = ".$row['id'];
+                        $sub_r = $this->store->a['db_object']->simpleQuery($sub_sql);
+                        ++$id_changes;
+                    } else {/* replace ids */
+                        $t_tbls = $this->store->getTables();
+                        foreach ($t_tbls as $t_tbl) {
+                            if (preg_match('/^triple/', $t_tbl)) {
+                                foreach (['s', 'p', 'o', 'o_lang_dt'] as $t_col) {
+                                    $sub_sql = 'UPDATE '.$this->store->getTablePrefix().$t_tbl.' SET '.$t_col.' = '.$new_id.' WHERE '.$t_col.' = '.$row['id'];
+                                    $sub_r = $this->store->a['db_object']->simpleQuery($sub_sql);
+                                    $t_changes += $this->store->a['db_object']->getAffectedRows();
+                                }
+                            }
+                        }
+                    }
                 }
-              }
             }
-          }
+            $this->store->releaseLock();
         }
-      }
-      $this->store->releaseLock();
-    }
-    return array('id_replacements' => $id_changes, 'triple_updates' => $t_changes);
-  }
-  
-  /*  */
 
+        return ['id_replacements' => $id_changes, 'triple_updates' => $t_changes];
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreInsertQueryHandler.php b/lib/arc2/store/ARC2_StoreInsertQueryHandler.php
index 122d9be7fd6c995e0c6351ee567a3f0c909f6877..8f0bd729ec8b814b4f6ce5c71f74447612a99873 100644
--- a/lib/arc2/store/ARC2_StoreInsertQueryHandler.php
+++ b/lib/arc2/store/ARC2_StoreInsertQueryHandler.php
@@ -1,46 +1,48 @@
 <?php
-/*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
-
-class:    ARC2 RDF Store INSERT Query Handler
-author:   Benjamin Nowack
-version:  2010-11-16
-*/
-
+/**
+ * ARC2 RDF Store INSERT Query Handler.
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ */
 ARC2::inc('StoreQueryHandler');
 
-class ARC2_StoreInsertQueryHandler extends ARC2_StoreQueryHandler {
-
-  function __construct($a, &$caller) {/* caller has to be a store */
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* db_con */
-    parent::__init();
-    $this->store = $this->caller;
-  }
-
-  /*  */
-  
-  function runQuery($infos, $keep_bnode_ids = 0) {
-    $this->infos = $infos;
-    $con = $this->store->getDBCon();
-    /* insert */
-    if (!$this->v('pattern', array(), $this->infos['query'])) {
-      return $this->store->insert($this->infos['query']['construct_triples'], $this->infos['query']['target_graph'], $keep_bnode_ids);
+class ARC2_StoreInsertQueryHandler extends ARC2_StoreQueryHandler
+{
+    public function __construct($a, &$caller)
+    {/* caller has to be a store */
+        parent::__construct($a, $caller);
     }
-    else {
-      $keep_bnode_ids = 1;
-      ARC2::inc('StoreConstructQueryHandler');
-      $h = new ARC2_StoreConstructQueryHandler($this->a, $this->store);
-      if ($sub_r = $h->runQuery($this->infos)) {
-        return $this->store->insert($sub_r, $this->infos['query']['target_graph'], $keep_bnode_ids);
-      }
-      return array('t_count' => 0, 'load_time' => 0);
+
+    public function __init()
+    {
+        parent::__init();
+        $this->store = $this->caller;
     }
-  }
-  
-  /*  */
 
+    public function runQuery($infos, $keep_bnode_ids = 0)
+    {
+        $this->infos = $infos;
+        /* insert */
+        if (!$this->v('pattern', [], $this->infos['query'])) {
+            $triples = $this->infos['query']['construct_triples'];
+            /* don't execute empty INSERTs as they trigger a LOAD on the graph URI */
+            if ($triples) {
+                return $this->store->insert($triples, $this->infos['query']['target_graph'], $keep_bnode_ids);
+            } else {
+                return ['t_count' => 0, 'load_time' => 0];
+            }
+        } else {
+            $keep_bnode_ids = 1;
+            ARC2::inc('StoreConstructQueryHandler');
+            $h = new ARC2_StoreConstructQueryHandler($this->a, $this->store);
+            $sub_r = $h->runQuery($this->infos);
+            if ($sub_r) {
+                return $this->store->insert($sub_r, $this->infos['query']['target_graph'], $keep_bnode_ids);
+            }
+
+            return ['t_count' => 0, 'load_time' => 0];
+        }
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreLoadQueryHandler.php b/lib/arc2/store/ARC2_StoreLoadQueryHandler.php
index c9e809f7122b598a592bd2451925dcdf221a1d93..a62c3b8535f5113a7ecef591a9ee127c7859342a 100644
--- a/lib/arc2/store/ARC2_StoreLoadQueryHandler.php
+++ b/lib/arc2/store/ARC2_StoreLoadQueryHandler.php
@@ -1,459 +1,484 @@
 <?php
 /**
- * ARC2 RDF Store LOAD Query Handler
+ * ARC2 RDF Store LOAD Query Handler.
  *
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
- * @version 2010-11-16
-*/
-
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ */
 ARC2::inc('StoreQueryHandler');
 
-class ARC2_StoreLoadQueryHandler extends ARC2_StoreQueryHandler {
-
-  function __construct($a, &$caller) {/* caller has to be a store */
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* db_con, store_log_inserts */
-    parent::__init();
-    $this->store = $this->caller;
-    $this->write_buffer_size = $this->v('store_write_buffer', 2500, $this->a);
-    $this->split_threshold = $this->v('store_split_threshold', 0, $this->a);
-    $this->has_pcre_unicode = @preg_match('/\pL/u', 'test');
-    $this->strip_mb_comp_str = $this->v('store_strip_mb_comp_str', 0, $this->a);
-  }
-
-  /*  */
-  
-  function runQuery($infos, $data = '', $keep_bnode_ids = 0) {
-    $url = $infos['query']['url'];
-    $graph = $infos['query']['target_graph'];
-    $this->target_graph = $graph ? $this->calcURI($graph) : $this->calcURI($url);
-    $this->fixed_target_graph = $graph ? $this->target_graph : '';
-    $this->keep_bnode_ids = $keep_bnode_ids;
-    /* reader */
-    ARC2::inc('Reader');
-    $reader = new ARC2_Reader($this->a, $this);
-    $reader->activate($url, $data);
-    /* format detection */
-    $mappings = array(
-      'rdfxml' => 'RDFXML', 
-      'sparqlxml' => 'SPOG', 
-      'turtle' => 'Turtle', 
-      'ntriples' => 'Turtle', 
-      'rss' => 'RSS',
-      'atom' => 'Atom',
-      'n3' => 'Turtle', 
-      'html' => 'SemHTML',
-      'sgajson' => 'SGAJSON',
-      'cbjson' => 'CBJSON'
-    );
-    $format = $reader->getFormat();
-    if (!$format || !isset($mappings[$format])) {
-      return $this->addError('No loader available for "' .$url. '": ' . $format);
-    }
-    /* format loader */
-    $suffix = 'Store' . $mappings[$format] . 'Loader';
-    ARC2::inc($suffix);
-    $cls = 'ARC2_' . $suffix;
-    $loader = new $cls($this->a, $this);
-    $loader->setReader($reader);
-    /* lock */
-    if (!$this->store->getLock()) {
-      $l_name = $this->a['db_name'] . '.' . $this->store->getTablePrefix() . '.write_lock';
-      return $this->addError('Could not get lock in "runQuery" (' . $l_name . ')');
-    }
-    $this->has_lock = 1;
-    /* logging */
-    $this->t_count = 0;
-    $this->t_start = ARC2::mtime();
-    $this->log_inserts = $this->v('store_log_inserts', 0, $this->a);
-    if ($this->log_inserts) {
-      @unlink("arc_insert_log.txt");
-      $this->inserts = array();
-      $this->insert_times = array();
-      $this->t_prev = $this->t_start;
-      $this->t_count_prev = 0 ;
-    }
-    /* load and parse */
-    $this->max_term_id = $this->getMaxTermID();
-    $this->max_triple_id = $this->getMaxTripleID();
-    $this->column_type = $this->store->getColumnType();
-    //$this->createMergeTable();
-    $this->term_ids = array();
-    $this->triple_ids = array();
-    $this->sql_buffers = array();
-    $r = $loader->parse($url, $data);
-    /* done */
-    $this->checkSQLBuffers(1);
-    if ($this->log_inserts) {
-      $this->logInserts();
-    }
-    $this->store->releaseLock();
-    //$this->dropMergeTable();
-    if ((rand(1, 100) == 1)) $this->store->optimizeTables();
-    $t2 = ARC2::mtime();
-    $dur = round($t2 - $this->t_start, 4);
-    $r = array(
-      't_count' => $this->t_count,
-      'load_time' => $dur,
-    );
-    if ($this->log_inserts) {
-      $r['inserts'] = $this->inserts;
-      $r['insert_times'] = $this->insert_times;
-    }
-    return $r;
-  }
-  
-  /*  */
-
-  function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
-    if (!$this->has_lock) return 0;
-    $type_ids = array ('uri' => '0', 'bnode' => '1' , 'literal' => '2');
-    $g = $this->getStoredTermID($this->target_graph, '0', 'id');
-    $s = (($s_type == 'bnode') && !$this->keep_bnode_ids) ? '_:b' . abs(crc32($g . $s)) . '_' . (strlen($s) > 12 ? substr(substr($s, 2) , -10) : substr($s, 2)) : $s;
-    $o = (($o_type == 'bnode') && !$this->keep_bnode_ids) ? '_:b' . abs(crc32($g . $o)) . '_' . (strlen($o) > 12 ? substr(substr($o, 2), -10) : substr($o, 2)) : $o;
-    /* triple */
-    $t = array(
-      's' => $this->getStoredTermID($s, $type_ids[$s_type], 's'),
-      'p' => $this->getStoredTermID($p, '0', 'id'),
-      'o' => $this->getStoredTermID($o, $type_ids[$o_type], 'o'),
-      'o_lang_dt' => $this->getStoredTermID($o_dt . $o_lang, $o_dt ? '0' : '2', 'id'),
-      'o_comp' => $this->getOComp($o),
-      's_type' => $type_ids[$s_type], 
-      'o_type' => $type_ids[$o_type],
-    );
-    $t['t'] = $this->getTripleID($t);
-    if (is_array($t['t'])) {/* t exists already */
-      $t['t'] = $t['t'][0];
+class ARC2_StoreLoadQueryHandler extends ARC2_StoreQueryHandler
+{
+    public function __construct($a, &$caller)
+    {/* caller has to be a store */
+        parent::__construct($a, $caller);
     }
-    else {
-      $this->bufferTripleSQL($t);
-    }
-    /* g2t */
-    $g2t = array('g' => $g, 't' => $t['t']);
-    $this->bufferGraphSQL($g2t);
-    $this->t_count++;
-    /* check buffers */
-    if (($this->t_count % $this->write_buffer_size) == 0) {
-      $force_write = 1;
-      $reset_buffers = (($this->t_count % ($this->write_buffer_size * 2)) == 0);
-      $refresh_lock = (($this->t_count % 25000) == 0);
-      $split_tables = (($this->t_count % ($this->write_buffer_size * 10)) == 0);
-      if ($this->log_inserts) $this->logInserts();
-      $this->checkSQLBuffers($force_write, $reset_buffers, $refresh_lock, $split_tables);
-    }
-  }
-
-  /*  */
-  
-  function getMaxTermID() {
-    $con = $this->store->getDBCon();
-    $sql = '';
-    foreach (array('id2val', 's2val', 'o2val') as $tbl) {
-      $sql .= $sql ? ' UNION ' : '';
-      $sql .= "(SELECT MAX(id) as `id` FROM " . $this->store->getTablePrefix() . $tbl . ')';
-    }
-    $r = 0;
-    if (($rs = $this->queryDB($sql, $con)) && mysql_num_rows($rs)) {
-      while ($row = mysql_fetch_array($rs)) {
-        $r = ($r < $row['id']) ? $row['id'] : $r;
-      }
-    }
-    return $r + 1;
-  }
-  
-  function getMaxTripleID() {
-    $con = $this->store->getDBCon();
-    $sql = "SELECT MAX(t) AS `id` FROM " . $this->store->getTablePrefix() . "triple";
-    if (($rs = $this->queryDB($sql, $con)) && mysql_num_rows($rs) && ($row = mysql_fetch_array($rs))) {
-      return $row['id'] + 1;
+
+    public function __init()
+    {/* db_con, store_log_inserts */
+        parent::__init();
+        $this->store = $this->caller;
+        $this->write_buffer_size = $this->v('store_write_buffer', 2500, $this->a);
+        $this->split_threshold = $this->v('store_split_threshold', 0, $this->a);
+        $this->strip_mb_comp_str = $this->v('store_strip_mb_comp_str', 0, $this->a);
     }
-    return 1;
-  }
-
-  function getStoredTermID($val, $type_id, $tbl) {
-    $con = $this->store->getDBCon();
-    /* buffered */
-    if (isset($this->term_ids[$val])) {
-      if (!isset($this->term_ids[$val][$tbl])) {
-        foreach (array('id', 's', 'o') as $other_tbl) {
-          if (isset($this->term_ids[$val][$other_tbl])) {
-            $this->term_ids[$val][$tbl] = $this->term_ids[$val][$other_tbl];
-            $this->bufferIDSQL($tbl, $this->term_ids[$val][$tbl], $val, $type_id);
-            break;
-          }
+
+    public function runQuery($infos, $data = '', $keep_bnode_ids = 0)
+    {
+        $url = $infos['query']['url'];
+        $graph = $infos['query']['target_graph'];
+        $this->target_graph = $graph ? $this->calcURI($graph) : $this->calcURI($url);
+        $this->fixed_target_graph = $graph ? $this->target_graph : '';
+        $this->keep_bnode_ids = $keep_bnode_ids;
+        /* reader */
+        ARC2::inc('Reader');
+        $reader = new ARC2_Reader($this->a, $this);
+        $reader->activate($url, $data);
+        /* format detection */
+        $mappings = [
+            'rdfxml' => 'RDFXML',
+            'sparqlxml' => 'SPOG',
+            'turtle' => 'Turtle',
+            'ntriples' => 'Turtle',
+            'rss' => 'RSS',
+            'atom' => 'Atom',
+            'n3' => 'Turtle',
+            'html' => 'SemHTML',
+            'sgajson' => 'SGAJSON',
+            'cbjson' => 'CBJSON',
+        ];
+        $format = $reader->getFormat();
+        if (!$format || !isset($mappings[$format])) {
+            return $this->addError('No loader available for "'.$url.'": '.$format);
         }
-      }
-      return $this->term_ids[$val][$tbl];
-    }
-    /* db */
-    $tbl_prefix = $this->store->getTablePrefix();
-    $sub_tbls = ($tbl == 'id') ? array('id2val', 's2val', 'o2val') : ($tbl == 's' ? array('s2val', 'id2val', 'o2val') : array('o2val', 'id2val', 's2val'));
-    foreach ($sub_tbls as $sub_tbl) {
-      $id = 0;
-      //$sql = "SELECT id AS `id`, '" . $sub_tbl . "' AS `tbl` FROM " . $tbl_prefix . $sub_tbl . " WHERE val = BINARY '" . mysql_real_escape_string($val, $con) . "'";
-      /* via hash */
-      if (preg_match('/^(s2val|o2val)$/', $sub_tbl) && $this->hasHashColumn($sub_tbl)) {
-        $sql = "SELECT id AS `id`, val AS `val` FROM " . $tbl_prefix . $sub_tbl . " WHERE val_hash = BINARY '" . $this->getValueHash($val) . "'";
-        if (($rs = $this->queryDB($sql, $con)) && mysql_num_rows($rs)) {
-          while ($row = mysql_fetch_array($rs)) {
-            if ($row['val'] == $val) {
-              $id = $row['id'];
-              break;
+        /* format loader */
+        $suffix = 'Store'.$mappings[$format].'Loader';
+        ARC2::inc($suffix);
+        $cls = 'ARC2_'.$suffix;
+        $loader = new $cls($this->a, $this);
+        $loader->setReader($reader);
+        /* lock */
+        if (!$this->store->getLock()) {
+            $l_name = $this->a['db_name'].'.'.$this->store->getTablePrefix().'.write_lock';
+
+            return $this->addError('Could not get lock in "runQuery" ('.$l_name.')');
+        }
+        $this->has_lock = 1;
+        /* logging */
+        $this->t_count = 0;
+        $this->t_start = ARC2::mtime();
+        $this->log_inserts = $this->v('store_log_inserts', 0, $this->a);
+        if ($this->log_inserts) {
+            if (file_exists('arc_insert_log.txt')) {
+                unlink('arc_insert_log.txt');
             }
-          }
+            $this->inserts = [];
+            $this->insert_times = [];
+            $this->t_prev = $this->t_start;
+            $this->t_count_prev = 0;
         }
-      }
-      else {
-        $sql = "SELECT id AS `id` FROM " . $tbl_prefix . $sub_tbl . " WHERE val = BINARY '" . mysql_real_escape_string($val, $con) . "'";
-        if (($rs = $this->queryDB($sql . ' LIMIT 1', $con)) && mysql_num_rows($rs)) {
-          $row = mysql_fetch_array($rs);
-          $id = $row['id'];
+        /* load and parse */
+        $this->max_term_id = $this->getMaxTermID();
+        $this->max_triple_id = $this->getMaxTripleID();
+        $this->column_type = $this->store->getColumnType();
+        //$this->createMergeTable();
+        $this->term_ids = [];
+        $this->triple_ids = [];
+        $this->sql_buffers = [];
+        $r = $loader->parse($url, $data);
+        /* done */
+        $this->checkSQLBuffers(1);
+        if ($this->log_inserts) {
+            $this->logInserts();
         }
-      }
-      if ($id) {
-        $this->term_ids[$val] = array($tbl => $id);
-        if ($sub_tbl != $tbl . '2val') {
-          $this->bufferIDSQL($tbl, $id, $val, $type_id);
+        $this->store->releaseLock();
+        //$this->dropMergeTable();
+        if ((1 == rand(1, 100))) {
+            $this->store->optimizeTables();
         }
-        break;
-      }
-    }
-    /* new */
-    if (!isset($this->term_ids[$val])) {
-      $this->term_ids[$val] = array($tbl => $this->max_term_id);
-      $this->bufferIDSQL($tbl, $this->max_term_id, $val, $type_id);
-      $this->max_term_id++;
-      /* upgrade tables ? */
-      if (($this->column_type == 'mediumint') && ($this->max_term_id >= 16750000)) {
-        $this->store->extendColumns();
-        $this->column_type = 'int';
-      }
-    }
-    return $this->term_ids[$val][$tbl];
-  }
-
-  function getTripleID($t) {
-    $con = $this->store->getDBCon();
-    $val = serialize($t);
-    /* buffered */
-    if (isset($this->triple_ids[$val])) {
-      return array($this->triple_ids[$val]);/* hack for "don't insert this triple" */
-    }
-    /* db */
-    $sql = "SELECT t FROM " . $this->store->getTablePrefix() . "triple WHERE 
-      s = " . $t['s'] . " AND p = " . $t['p'] . " AND o = " . $t['o'] . " AND o_lang_dt = " . $t['o_lang_dt'] . " AND s_type = " . $t['s_type'] . " AND o_type = " . $t['o_type'] . "
-      LIMIT 1
-    ";
-    if (($rs = $this->queryDB($sql, $con)) && mysql_num_rows($rs) && ($row = mysql_fetch_array($rs))) {
-      $this->triple_ids[$val] = $row['t'];/* hack for "don't insert this triple" */
-      return array($row['t']);/* hack for "don't insert this triple" */
-    }
-    /* new */
-    else {
-      $this->triple_ids[$val] = $this->max_triple_id;
-      $this->max_triple_id++;
-      /* split tables ? */
-      if ($this->split_threshold && !($this->max_triple_id % $this->split_threshold)) {
-        $this->store->splitTables();
-        $this->dropMergeTable();
-        $this->createMergeTable();
-      }
-      return $this->triple_ids[$val];
-    }
-  }
-  
-  function getOComp($val) {
-    /* try date (e.g. 21 August 2007) */
-    if (preg_match('/^[0-9]{1,2}\s+[a-z]+\s+[0-9]{4}/i', $val) && ($uts = strtotime($val)) && ($uts !== -1)) {
-      return date("Y-m-d\TH:i:s", $uts);
+        $t2 = ARC2::mtime();
+        $dur = round($t2 - $this->t_start, 4);
+        $r = [
+            't_count' => $this->t_count,
+            'load_time' => $dur,
+        ];
+        if ($this->log_inserts) {
+            $r['inserts'] = $this->inserts;
+            $r['insert_times'] = $this->insert_times;
+        }
+
+        return $r;
     }
-    /* xsd date (e.g. 2009-05-28T18:03:38+09:00 2009-05-28T18:03:38GMT) */
-    if (preg_match('/^([0-9]{4}\-[0-9]{2}\-[0-9]{2}\T)([0-9\:]+)?([0-9\+\-\:\Z]+)?(\s*[a-z]{2,3})?$/si', $val, $m)) {
-      /* yyyy-mm-dd */
-      $val = $m[1];
-      /* hh:ss */
-      if ($m[2]) {
-        $val .= $m[2];
-        /* timezone offset */
-        if (isset($m[3]) && ($m[3] != 'Z')) {
-          $uts = strtotime(str_replace('T', ' ', $val));
-          if (preg_match('/([\+\-])([0-9]{2})\:?([0-9]{2})$/', $m[3], $sub_m)) {
-            $diff_mins = (3600 * ltrim($sub_m[2], '0')) + ltrim($sub_m[3], '0');
-            $uts = ($sub_m[1] == '-') ? $uts + $diff_mins : $uts - $diff_mins;
-            $val = date('Y-m-d\TH:i:s\Z', $uts);
-          }
+
+    public function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '')
+    {
+        if (!$this->has_lock) {
+            return 0;
         }
-        else {
-          $val .= 'Z';
+        $type_ids = ['uri' => '0', 'bnode' => '1', 'literal' => '2'];
+        $g = $this->getStoredTermID($this->target_graph, '0', 'id');
+        $s = (('bnode' == $s_type) && !$this->keep_bnode_ids) ? '_:b'.abs(crc32($g.$s)).'_'.(strlen($s) > 12 ? substr(substr($s, 2), -10) : substr($s, 2)) : $s;
+        $o = (('bnode' == $o_type) && !$this->keep_bnode_ids) ? '_:b'.abs(crc32($g.$o)).'_'.(strlen($o) > 12 ? substr(substr($o, 2), -10) : substr($o, 2)) : $o;
+        /* triple */
+        $t = [
+            's' => $this->getStoredTermID($s, $type_ids[$s_type], 's'),
+            'p' => $this->getStoredTermID($p, '0', 'id'),
+            'o' => $this->getStoredTermID($o, $type_ids[$o_type], 'o'),
+            'o_lang_dt' => $this->getStoredTermID($o_dt.$o_lang, $o_dt ? '0' : '2', 'id'),
+            'o_comp' => $this->getOComp($o),
+            's_type' => $type_ids[$s_type],
+            'o_type' => $type_ids[$o_type],
+        ];
+        $t['t'] = $this->getTripleID($t);
+        if (is_array($t['t'])) {/* t exists already */
+            $t['t'] = $t['t'][0];
+        } else {
+            $this->bufferTripleSQL($t);
+        }
+        /* g2t */
+        $g2t = ['g' => $g, 't' => $t['t']];
+        $this->bufferGraphSQL($g2t);
+        ++$this->t_count;
+        /* check buffers */
+        if (0 == ($this->t_count % $this->write_buffer_size)) {
+            $force_write = 1;
+            $reset_buffers = (0 == ($this->t_count % ($this->write_buffer_size * 2)));
+            $refresh_lock = (0 == ($this->t_count % 25000));
+            $split_tables = (0 == ($this->t_count % ($this->write_buffer_size * 10)));
+            if ($this->log_inserts) {
+                $this->logInserts();
+            }
+            $this->checkSQLBuffers($force_write, $reset_buffers, $refresh_lock, $split_tables);
         }
-      }
-      return $val;
-    }
-    /* fallback & backup w/o UTC calculation, to be removed in later revision */
-    if (preg_match('/^[0-9]{4}[0-9\-\:\T\Z\+]+([a-z]{2,3})?$/i', $val)) {
-      return $val;
-    }
-    if (is_numeric($val)) {
-      $val = sprintf("%f", $val);
-      if (preg_match("/([\-\+])([0-9]*)\.([0-9]*)/", $val, $m)) {
-        return $m[1] . sprintf("%018s", $m[2]) . "." . sprintf("%-015s", $m[3]);
-      }
-      if (preg_match("/([0-9]*)\.([0-9]*)/", $val, $m)) {
-        return "+" . sprintf("%018s", $m[1]) . "." . sprintf("%-015s", $m[2]);
-      }
-      return $val;
-    }
-    /* any other string: remove tags, linebreaks etc., but keep MB-chars  */
-    //$val = substr(trim(preg_replace('/[\W\s]+/is', '-', strip_tags($val))), 0, 35);
-    $re = $this->has_pcre_unicode ? '/[\PL\s]+/isu' : '/[\s\'\"\´\`]+/is';
-    $val = trim(preg_replace($re, '-', strip_tags($val)));
-    if (strlen($val) > 35) {
-      $fnc = function_exists("mb_substr") ? 'mb_substr' : 'substr';
-      $val = $fnc($val, 0, 17) . '-' . $fnc($val, -17);
-    }
-    if ($this->strip_mb_comp_str) {
-      $val = urldecode(preg_replace('/\%[0-9A-F]{2}/', '', urlencode($val)));
     }
-    return $this->toUTF8($val);
-  }
-
-  /*  */
-  
-  function bufferTripleSQL($t) {
-    $con = $this->store->getDBCon();
-    $tbl = 'triple';
-    $sql = ", ";
-    if (!isset($this->sql_buffers[$tbl])) {
-      $this->sql_buffers[$tbl] = "INSERT IGNORE INTO " . $this->store->getTablePrefix() . $tbl . " (t, s, p, o, o_lang_dt, o_comp, s_type, o_type) VALUES";
-      $sql = " ";
+
+    public function getMaxTermID()
+    {
+        $sql = '';
+        foreach (['id2val', 's2val', 'o2val'] as $tbl) {
+            $sql .= $sql ? ' UNION ' : '';
+            $sql .= '(SELECT MAX(id) as `id` FROM '.$this->store->getTablePrefix().$tbl.')';
+        }
+        $r = 0;
+
+        $rows = $this->store->a['db_object']->fetchList($sql);
+
+        if (is_array($rows)) {
+            foreach($rows as $row) {
+                $r = ($r < $row['id']) ? $row['id'] : $r;
+            }
+        }
+
+        return $r + 1;
     }
-    $this->sql_buffers[$tbl] .= $sql . "(" . $t['t'] . ", " . $t['s'] . ", " . $t['p'] . ", " . $t['o'] . ", " . $t['o_lang_dt'] . ", '" . mysql_real_escape_string($t['o_comp'], $con) . "', " . $t['s_type'] . ", " . $t['o_type'] . ")";
-  }
-  
-  function bufferGraphSQL($g2t) {
-    $tbl = 'g2t';
-    $sql = ", ";
-    if (!isset($this->sql_buffers[$tbl])) {
-      $this->sql_buffers[$tbl] = "INSERT IGNORE INTO " . $this->store->getTablePrefix() . $tbl . " (g, t) VALUES";
-      $sql = " ";
+
+    /**
+     * @todo change DB schema and avoid using this function because it does not protect against race conditions
+     *
+     * @return int
+     */
+    public function getMaxTripleID()
+    {
+        $sql = 'SELECT MAX(t) AS `id` FROM '.$this->store->getTablePrefix().'triple';
+
+        $row = $this->store->a['db_object']->fetchRow($sql);
+        if (isset($row['id'])) {
+            return $row['id']+1;
+        }
+
+        return 1;
     }
-    $this->sql_buffers[$tbl] .= $sql . "(" . $g2t['g'] . ", " . $g2t['t'] . ")";
-  }
-  
-  function bufferIDSQL($tbl, $id, $val, $val_type) {
-    $con = $this->store->getDBCon();
-    $tbl = $tbl . '2val';
-    if ($tbl == 'id2val') {
-      $cols = "id, val, val_type";
-      $vals = "(" . $id . ", '" . mysql_real_escape_string($val, $con) . "', " . $val_type . ")";
+
+    public function getStoredTermID($val, $type_id, $tbl)
+    {
+        /* buffered */
+        if (isset($this->term_ids[$val])) {
+            if (!isset($this->term_ids[$val][$tbl])) {
+                foreach (['id', 's', 'o'] as $other_tbl) {
+                    if (isset($this->term_ids[$val][$other_tbl])) {
+                        $this->term_ids[$val][$tbl] = $this->term_ids[$val][$other_tbl];
+                        $this->bufferIDSQL($tbl, $this->term_ids[$val][$tbl], $val, $type_id);
+                        break;
+                    }
+                }
+            }
+
+            return $this->term_ids[$val][$tbl];
+        }
+        /* db */
+        $tbl_prefix = $this->store->getTablePrefix();
+        $sub_tbls = ('id' == $tbl) ? ['id2val', 's2val', 'o2val'] : ('s' == $tbl ? ['s2val', 'id2val', 'o2val'] : ['o2val', 'id2val', 's2val']);
+        foreach ($sub_tbls as $sub_tbl) {
+            $id = 0;
+            /* via hash */
+            if (preg_match('/^(s2val|o2val)$/', $sub_tbl) && $this->hasHashColumn($sub_tbl)) {
+                $sql = 'SELECT id AS `id`, val AS `val` FROM '.$tbl_prefix.$sub_tbl." WHERE val_hash = BINARY '".$this->getValueHash($val)."'";
+                $rows = $this->store->a['db_object']->fetchList($sql);
+                if (is_array($rows)) {
+                    foreach($rows as $row) {
+                        if ($row['val'] == $val) {
+                            $id = $row['id'];
+                            break;
+                        }
+                    }
+                }
+            } else {
+                $binaryValue = $this->store->a['db_object']->escape($val);
+                if (false !== empty($binaryValue)) {
+                    $sql = 'SELECT id AS `id` FROM '.$tbl_prefix.$sub_tbl." WHERE val = BINARY '".$binaryValue."'";
+                    $row = $this->store->a['db_object']->fetchRow($sql);
+                    if (is_array($row) && isset($row['id'])) {
+                        $id = $row['id'];
+                    }
+                }
+            }
+            if ($id) {
+                $this->term_ids[$val] = [$tbl => $id];
+                if ($sub_tbl != $tbl.'2val') {
+                    $this->bufferIDSQL($tbl, $id, $val, $type_id);
+                }
+                break;
+            }
+        }
+        /* new */
+        if (!isset($this->term_ids[$val])) {
+            $this->term_ids[$val] = [$tbl => $this->max_term_id];
+            $this->bufferIDSQL($tbl, $this->max_term_id, $val, $type_id);
+            ++$this->max_term_id;
+            /* upgrade tables ? */
+            if (('mediumint' == $this->column_type) && ($this->max_term_id >= 16750000)) {
+                $this->store->extendColumns();
+                $this->column_type = 'int';
+            }
+        }
+
+        return $this->term_ids[$val][$tbl];
     }
-    elseif (preg_match('/^(s2val|o2val)$/', $tbl) && $this->hasHashColumn($tbl)) {
-      $cols = "id, val_hash, val";
-      $vals = "(" . $id . ", '" . $this->getValueHash($val). "', '" . mysql_real_escape_string($val, $con) . "')";
+
+    public function getTripleID($t)
+    {
+        $val = serialize($t);
+        /* buffered */
+        if (isset($this->triple_ids[$val])) {
+            return [$this->triple_ids[$val]]; /* hack for "don't insert this triple" */
+        }
+        /* db */
+        $sql = 'SELECT t
+                  FROM '.$this->store->getTablePrefix().'triple
+                 WHERE s = '.$t['s'].' AND p = '.$t['p'].' AND o = '.$t['o'].'
+                        AND o_lang_dt = '.$t['o_lang_dt'].' AND s_type = '.$t['s_type'].'
+                        AND o_type = '.$t['o_type'].'
+                 LIMIT 1';
+        $row = $this->store->a['db_object']->fetchRow($sql);
+        if (isset($row['t'])) {
+            $this->triple_ids[$val] = $row['t']; /* hack for "don't insert this triple" */
+            return [$row['t']]; /* hack for "don't insert this triple" */
+
+        /* new */
+        } else {
+            $this->triple_ids[$val] = $this->max_triple_id;
+            ++$this->max_triple_id;
+            /* split tables ? */
+            if (0 && $this->split_threshold && !($this->max_triple_id % $this->split_threshold)) {
+                $this->store->splitTables();
+                $this->dropMergeTable();
+                $this->createMergeTable();
+            }
+            /* upgrade tables ? // Thanks to patch by Mark Fichtner (https://github.com/Knurg) */
+            if (('mediumint' == $this->column_type) && ($this->max_triple_id >= 16750000)) {
+                $this->store->extendColumns();
+                $this->column_type = 'int';
+            }
+
+            return $this->triple_ids[$val];
+        }
     }
-    else {
-      $cols = "id, val";
-      $vals = "(" . $id . ", '" . mysql_real_escape_string($val, $con) . "')";
+
+    public function getOComp($val)
+    {
+        /* try date (e.g. 21 August 2007) */
+        if (preg_match('/^[0-9]{1,2}\s+[a-z]+\s+[0-9]{4}/i', $val) && ($uts = strtotime($val)) && ($uts !== -1)) {
+            return date("Y-m-d\TH:i:s", $uts);
+        }
+
+        /* xsd date (e.g. 2009-05-28T18:03:38+09:00 2009-05-28T18:03:38GMT) */
+        if (true === (bool) \strtotime($val)) {
+            return \date('Y-m-d\TH:i:s\Z', \strtotime($val));
+        }
+
+        if (is_numeric($val)) {
+            $val = sprintf('%f', $val);
+            if (preg_match("/([\-\+])([0-9]*)\.([0-9]*)/", $val, $m)) {
+                return $m[1].sprintf('%018s', $m[2]).'.'.sprintf('%-015s', $m[3]);
+            }
+            if (preg_match("/([0-9]*)\.([0-9]*)/", $val, $m)) {
+                return '+'.sprintf('%018s', $m[1]).'.'.sprintf('%-015s', $m[2]);
+            }
+
+            return $val;
+        }
+
+        /* any other string: remove tags, linebreaks etc., but keep MB-chars  */
+        //$val = substr(trim(preg_replace('/[\W\s]+/is', '-', strip_tags($val))), 0, 35);
+        // [\PL\s]+ ( = non-Letters) kills digits
+        $re = $this->has_pcre_unicode ? '/[\PL\s]+/isu' : '/[\s\'\"\´\`]+/is';
+        $re = '/[\s\'\"\´\`]+/is';
+        $val = trim(preg_replace($re, '-', strip_tags($val)));
+        if (strlen($val) > 35) {
+            $fnc = function_exists('mb_substr') ? 'mb_substr' : 'substr';
+            $val = $fnc($val, 0, 17).'-'.$fnc($val, -17);
+        }
+        if ($this->strip_mb_comp_str) {
+            $val = urldecode(preg_replace('/\%[0-9A-F]{2}/', '', urlencode($val)));
+        }
+
+        return $this->toUTF8($val);
     }
-    if (!isset($this->sql_buffers[$tbl])) {
-      $this->sql_buffers[$tbl] = '';
-      $sql = "INSERT IGNORE INTO " . $this->store->getTablePrefix() . $tbl . "(" . $cols . ") VALUES ";
+
+    public function bufferTripleSQL($t)
+    {
+        $tbl = 'triple';
+        $sql = ', ';
+        if (!isset($this->sql_buffers[$tbl])) {
+            $this->sql_buffers[$tbl] = 'INSERT IGNORE INTO '.$this->store->getTablePrefix().$tbl.' (t, s, p, o, o_lang_dt, o_comp, s_type, o_type) VALUES';
+            $sql = ' ';
+        }
+        $this->sql_buffers[$tbl] .= $sql.'('.$t['t'].', '.$t['s'].', '.$t['p'].', '.$t['o'].', '.$t['o_lang_dt'].", '".$this->store->a['db_object']->escape($t['o_comp'])."', ".$t['s_type'].', '.$t['o_type'].')';
     }
-    else {
-      $sql = ", ";
+
+    public function bufferGraphSQL($g2t)
+    {
+        $tbl = 'g2t';
+        $sql = ', ';
+        if (!isset($this->sql_buffers[$tbl])) {
+            $this->sql_buffers[$tbl] = 'INSERT IGNORE INTO '.$this->store->getTablePrefix().$tbl.' (g, t) VALUES';
+            $sql = ' ';
+        }
+        $this->sql_buffers[$tbl] .= $sql.'('.$g2t['g'].', '.$g2t['t'].')';
     }
-    $sql .= $vals;
-    $this->sql_buffers[$tbl] .= $sql;
-  }
-  
-  /*  */
-
-  function checkSQLBuffers($force_write = 0, $reset_id_buffers = 0, $refresh_lock = 0, $split_tables = 0) {
-    $con = $this->store->getDBCon();
-    if (!$this->keep_time_limit) @set_time_limit($this->v('time_limit', 60, $this->a));
-    foreach (array('triple', 'g2t', 'id2val', 's2val', 'o2val') as $tbl) {
-      $buffer_size = isset($this->sql_buffers[$tbl]) ? 1 : 0;
-      if ($buffer_size && $force_write) {
-        $t1 = ARC2::mtime();
-        $this->queryDB($this->sql_buffers[$tbl], $con);
-        /* table error */
-        if ($er = mysql_error($con)) {
-          $this->autoRepairTable($er, $con, $this->sql_buffers[$tbl]);
+
+    public function bufferIDSQL($tbl, $id, $val, $val_type)
+    {
+        $tbl = $tbl.'2val';
+        if ('id2val' == $tbl) {
+            $cols = 'id, val, val_type';
+            $vals = '('.$id.", '".$this->store->a['db_object']->escape($val)."', ".$val_type.')';
+        } elseif (preg_match('/^(s2val|o2val)$/', $tbl) && $this->hasHashColumn($tbl)) {
+            $cols = 'id, val_hash, val';
+            $vals = '('.$id.", '".$this->getValueHash($val)."', '".$this->store->a['db_object']->escape($val)."')";
+        } else {
+            $cols = 'id, val';
+            $vals = '('.$id.", '".$this->store->a['db_object']->escape($val)."')";
         }
-        unset($this->sql_buffers[$tbl]);
-        if ($this->log_inserts) {
-          $t2 = ARC2::mtime();
-          $this->inserts[$tbl] = $this->v($tbl, 0, $this->inserts) + max(0, mysql_affected_rows($con));
-          $dur = round($t2 - $t1, 4);
-          $this->insert_times[$tbl] = isset($this->insert_times[$tbl]) ? $this->insert_times[$tbl] : array('min' => $dur, 'max' => $dur, 'sum' => $dur);
-          $this->insert_times[$tbl] = array('min' => min($dur, $this->insert_times[$tbl]['min']), 'max' => max($dur, $this->insert_times[$tbl]['max']), 'sum' => $dur + $this->insert_times[$tbl]['sum']);
+        if (!isset($this->sql_buffers[$tbl])) {
+            $this->sql_buffers[$tbl] = '';
+            $sql = 'INSERT IGNORE INTO '.$this->store->getTablePrefix().$tbl.'('.$cols.') VALUES ';
+        } else {
+            $sql = ', ';
         }
-        /* reset term id buffers */
-        if ($reset_id_buffers) {
-          $this->term_ids = array();
-          $this->triple_ids = array();
+        $sql .= $vals;
+        $this->sql_buffers[$tbl] .= $sql;
+    }
+
+    public function checkSQLBuffers($force_write = 0, $reset_id_buffers = 0, $refresh_lock = 0, $split_tables = 0)
+    {
+        if (!$this->keep_time_limit) {
+            set_time_limit($this->v('time_limit', 60, $this->a));
         }
-        /* refresh lock */
-        if ($refresh_lock) {
-          $this->store->releaseLock();
-          $this->has_lock = 0;
-          sleep(1);
-          if (!$this->store->getLock(5)) return $this->addError('Could not re-obtain lock in "checkSQLBuffers"');
-          $this->has_lock = 1;
+        foreach (['triple', 'g2t', 'id2val', 's2val', 'o2val'] as $tbl) {
+            $buffer_size = isset($this->sql_buffers[$tbl]) ? 1 : 0;
+            if ($buffer_size && $force_write) {
+                $t1 = ARC2::mtime();
+                $this->store->a['db_object']->simpleQuery($this->sql_buffers[$tbl]);
+                /* table error */
+                $error = $this->store->a['db_object']->getErrorMessage();
+                if (!empty($error)) {
+                    $this->autoRepairTable($error, $this->sql_buffers[$tbl]);
+                }
+                unset($this->sql_buffers[$tbl]);
+                if ($this->log_inserts) {
+                    $t2 = ARC2::mtime();
+                    $this->inserts[$tbl] = $this->v(
+                        $tbl,
+                        0,
+                        $this->inserts
+                    ) + max(0, $this->store->a['db_object']->getAffectedRows());
+
+                    $dur = round($t2 - $t1, 4);
+                    $this->insert_times[$tbl] = isset($this->insert_times[$tbl])
+                        ? $this->insert_times[$tbl]
+                        : ['min' => $dur, 'max' => $dur, 'sum' => $dur];
+                    $this->insert_times[$tbl] = [
+                        'min' => min($dur, $this->insert_times[$tbl]['min']),
+                        'max' => max($dur, $this->insert_times[$tbl]['max']),
+                        'sum' => $dur + $this->insert_times[$tbl]['sum']
+                    ];
+                }
+                /* reset term id buffers */
+                if ($reset_id_buffers) {
+                    $this->term_ids = [];
+                    $this->triple_ids = [];
+                }
+                /* refresh lock */
+                if ($refresh_lock) {
+                    $this->store->releaseLock();
+                    $this->has_lock = 0;
+                    sleep(1);
+                    if (!$this->store->getLock(5)) {
+                        return $this->addError('Could not re-obtain lock in "checkSQLBuffers"');
+                    }
+                    $this->has_lock = 1;
+                }
+            }
         }
-      }
+
+        return 1;
     }
-    return 1;
-  }
-
-  function autoRepairTable($er, $con, $sql = '') {
-    $this->addError('MySQL error: ' . $er . ' (' . $sql . ')');
-    if (preg_match('/Table \'[^\']+\/([a-z0-9\_\-]+)\' .*(crashed|repair)/i', $er, $m)) {
-      $rs = $this->queryDB('REPAIR TABLE ' . rawurlencode($m[1]), $con);
-      $msg = $rs ? mysql_fetch_array($rs) : array();
-      if ($this->v('Msg_type', 'error', $msg) == 'error') {
-        /* auto-reset */
-        if ($this->v('store_reset_on_table_crash', 0, $this->a)) {
-          $this->store->drop();
-          $this->store->setUp();
-        }
-        else {
-          $er = $this->v('Msg_text', 'unknown error', $msg);
-          $this->addError('Auto-repair failed on ' . rawurlencode($m[1]) . ': ' . $er);
+
+    public function autoRepairTable($er, $sql = '')
+    {
+        $this->addError('MySQL error: '.$er.' ('.$sql.')');
+        if (preg_match('/Table \'[^\']+\/([a-z0-9\_\-]+)\' .*(crashed|repair)/i', $er, $m)) {
+            $row = $this->store->a['db_object']->fetchRow('REPAIR TABLE '.rawurlencode($m[1]));
+            $msg = is_array($row) ? $row : [];
+
+            if ('error' == $this->v('Msg_type', 'error', $msg)) {
+                /* auto-reset */
+                if ($this->v('store_reset_on_table_crash', 0, $this->a)) {
+                    $this->store->drop();
+                    $this->store->setUp();
+                } else {
+                    $er = $this->v('Msg_text', 'unknown error', $msg);
+                    $this->addError('Auto-repair failed on '.rawurlencode($m[1]).': '.$er);
+                }
+            }
         }
-        //die("Fatal errors: \n" . print_r($this->getErrors(), 1));
-      }
     }
-  }
-
-  /* speed log */
-  
-  function logInserts() {
-    $t_start = $this->t_start;
-    $t_prev = $this->t_prev;
-    $t_now = ARC2::mtime();
-    $tc_prev = $this->t_count_prev;
-    $tc_now = $this->t_count;
-    $tc_diff = $tc_now - $tc_prev;
-    
-    $dur_full = $t_now - $t_start;
-    $dur_diff = $t_now - $t_prev;
-
-    $speed_full = round($tc_now / $dur_full);
-    $speed_now = round($tc_diff / $dur_diff);
-
-    $r = $tc_diff . ' in ' . round($dur_diff, 5) . ' = ' . $speed_now . ' t/s  (' .$tc_now. ' in ' . round($dur_full, 5). ' = ' . $speed_full . ' t/s )'; 
-    $fp = @fopen("arc_insert_log.txt", "a");
-    @fwrite($fp, $r . "\r\n");
-    @fclose($fp);
-    
-    $this->t_prev = $t_now;
-    $this->t_count_prev = $tc_now;
-  }
 
+    /* speed log */
+
+    public function logInserts()
+    {
+        $t_start = $this->t_start;
+        $t_prev = $this->t_prev;
+        $t_now = ARC2::mtime();
+        $tc_prev = $this->t_count_prev;
+        $tc_now = $this->t_count;
+        $tc_diff = $tc_now - $tc_prev;
+
+        $dur_full = $t_now - $t_start;
+        $dur_diff = $t_now - $t_prev;
+
+        $speed_full = round($tc_now / $dur_full);
+        $speed_now = round($tc_diff / $dur_diff);
+
+        $r = $tc_diff.' in '.round($dur_diff, 5).' = '.$speed_now.' t/s  ('.$tc_now.' in '.round($dur_full, 5).' = '.$speed_full.' t/s )';
+        $fp = fopen('arc_insert_log.txt', 'a');
+        fwrite($fp, $r."\r\n");
+        fclose($fp);
+
+        $this->t_prev = $t_now;
+        $this->t_count_prev = $tc_now;
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreQueryHandler.php b/lib/arc2/store/ARC2_StoreQueryHandler.php
old mode 100644
new mode 100755
index 282be77efbd7d7534aa2ae3aa1134d850291d844..98f93d3220e5983c45c15c72a256f1caadc5df28
--- a/lib/arc2/store/ARC2_StoreQueryHandler.php
+++ b/lib/arc2/store/ARC2_StoreQueryHandler.php
@@ -1,64 +1,66 @@
 <?php
 /**
- * ARC2 RDF Store Query Handler
+ * ARC2 RDF Store Query Handler.
  *
  * @author Benjamin Nowack
- * @license <http://arc.semsol.org/license>
- * @homepage <http://arc.semsol.org/>
- * @package ARC2
+ * @license W3C Software License and GPL
+ * @homepage <https://github.com/semsol/arc2>
+ *
  * @version 2010-11-16
-*/
-
+ */
 ARC2::inc('Class');
 
-class ARC2_StoreQueryHandler extends ARC2_Class {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* db_con */
-    parent::__init();
-    $this->xsd = 'http://www.w3.org/2001/XMLSchema#';
-    $this->allow_extension_functions = $this->v('store_allow_extension_functions', 1, $this->a);    
-    $this->keep_time_limit = $this->v('keep_time_limit', 0, $this->a);
-    $this->handler_type = '';
-  }
+class ARC2_StoreQueryHandler extends ARC2_Class
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
 
-  /*  */
+    public function __init()
+    {
+        parent::__init();
+        $this->xsd = 'http://www.w3.org/2001/XMLSchema#';
+        $this->allow_extension_functions = $this->v('store_allow_extension_functions', 1, $this->a);
+        $this->keep_time_limit = $this->v('keep_time_limit', 0, $this->a);
+        $this->handler_type = '';
+    }
 
-  function getTermID($val, $term = '') {
-    return $this->store->getTermID($val, $term);
-  }
+    public function getTermID($val, $term = '')
+    {
+        return $this->store->getTermID($val, $term);
+    }
 
-  function hasHashColumn($tbl) {
-    return $this->store->hasHashColumn($tbl);
-  }
+    public function hasHashColumn($tbl)
+    {
+        return $this->store->hasHashColumn($tbl);
+    }
 
-  function getValueHash($val) {
-    return $this->store->getValueHash($val);
-  }
-  
-  /*  */
+    public function getValueHash($val)
+    {
+        return $this->store->getValueHash($val);
+    }
 
-  function getTripleTable() {
-    $r = $this->store->getTablePrefix() . 'triple';
-    return $r;
-  }
+    public function getTripleTable()
+    {
+        $r = $this->store->getTablePrefix().'triple';
 
-  /*  */
+        return $r;
+    }
 
-  function createMergeTable() {
-    $split_ps = $this->store->getSetting('split_predicates', array());
-    if (!$split_ps) return 1;
-    $this->mrg_table_id = 'MRG_' . $this->store->getTablePrefix() . crc32(uniqid(rand()));
-    $con = $this->store->getDBCon();
-    $this->queryDB("FLUSH TABLES", $con);
-    $indexes = $this->v('store_indexes', array('sp (s,p)', 'os (o,s)', 'po (p,o)'), $this->a);
-    $index_code = $indexes ? 'KEY ' . join(', KEY ',  $indexes) . ', ' : '';
-    $prefix = $this->store->getTablePrefix();
-    $sql = "
-      CREATE TEMPORARY TABLE IF NOT EXISTS " . $prefix . "triple_all (
+    public function createMergeTable()
+    {
+        $split_ps = $this->store->getSetting('split_predicates', []);
+        if (!$split_ps) {
+            return 1;
+        }
+        $this->mrg_table_id = 'MRG_'.$this->store->getTablePrefix().crc32(uniqid(rand()));
+        $this->getDBObject()->query('FLUSH TABLES');
+        $indexes = $this->v('store_indexes', ['sp (s,p)', 'os (o,s)', 'po (p,o)'], $this->a);
+        $index_code = $indexes ? 'KEY '.implode(', KEY ', $indexes).', ' : '';
+        $prefix = $this->store->getTablePrefix();
+        $sql = '
+      CREATE TEMPORARY TABLE IF NOT EXISTS '.$prefix.'triple_all (
         t mediumint UNSIGNED NOT NULL,
         s mediumint UNSIGNED NOT NULL,
         p mediumint UNSIGNED NOT NULL,
@@ -68,27 +70,29 @@ class ARC2_StoreQueryHandler extends ARC2_Class {
         s_type tinyint(1) NOT NULL default 0,       /* uri/bnode => 0/1 */
         o_type tinyint(1) NOT NULL default 0,       /* uri/bnode/literal => 0/1/2 */
         misc tinyint(1) NOT NULL default 0,         /* temporary flags */
-        UNIQUE KEY (t), " . $index_code . " KEY (misc)
-      ) 
-    ";
-    $v = $this->store->getDBVersion();
-    $sql .= (($v < '04-01-00') && ($v >= '04-00-18')) ? 'ENGINE' : (($v >= '04-01-02') ? 'ENGINE' : 'TYPE');
-    $sql .= "=MERGE UNION=(" . $prefix . "triple" ;
-    foreach ($split_ps as $pos => $p) {
-      $sql .= ',' . $prefix . 'triple_' . abs(crc32($p));
+        UNIQUE KEY (t), '.$index_code.' KEY (misc)
+      )
+    ';
+        $v = $this->store->getDBVersion();
+        $sql .= (($v < '04-01-00') && ($v >= '04-00-18')) ? 'ENGINE' : (($v >= '04-01-02') ? 'ENGINE' : 'TYPE');
+        $sql .= '=MERGE UNION=('.$prefix.'triple';
+        foreach ($split_ps as $pos => $p) {
+            $sql .= ','.$prefix.'triple_'.abs(crc32($p));
+        }
+        $sql .= ')';
+        // TODO whats about that?
+        //$sql .= ($v >= '04-00-00') ? " CHARACTER SET utf8" : "";
+        //$sql .= ($v >= '04-01-00') ? " COLLATE utf8_unicode_ci" : "";
+        //echo $sql;
+        return $this->getDBObject()->query($sql);
     }
-    $sql .= ")";
-    //$sql .= ($v >= '04-00-00') ? " CHARACTER SET utf8" : "";
-    //$sql .= ($v >= '04-01-00') ? " COLLATE utf8_unicode_ci" : "";
-    //echo $sql;
-    return $this->queryDB($sql, $con);
-  }
 
-  function dropMergeTable() {
-    return 1;
-    $sql = "DROP TABLE IF EXISTS " . $this->store->getTablePrefix() . "triple_all";
-    //echo $sql;
-    return $this->queryDB($sql, $this->store->getDBCon());
-  }
-  
+    public function dropMergeTable()
+    {
+        return 1;
+        // TODO triple_all table seems not used anymore, therefore this function can be removed?
+        $sql = 'DROP TABLE IF EXISTS '.$this->store->getTablePrefix().'triple_all';
+        //echo $sql;
+        //return $this->queryDB($sql, $this->store->getDBCon());
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreRDFXMLLoader.php b/lib/arc2/store/ARC2_StoreRDFXMLLoader.php
old mode 100644
new mode 100755
index 1a7b5096f25420adb27203343a736a7610a56e6e..069c445ed016ce50218a5f8826fc5a9bb60140d1
--- a/lib/arc2/store/ARC2_StoreRDFXMLLoader.php
+++ b/lib/arc2/store/ARC2_StoreRDFXMLLoader.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 Store RDF/XML Loader
 author:   Benjamin Nowack
@@ -10,23 +10,21 @@ version:  2010-11-16
 
 ARC2::inc('RDFXMLParser');
 
-class ARC2_StoreRDFXMLLoader extends ARC2_RDFXMLParser {
+class ARC2_StoreRDFXMLLoader extends ARC2_RDFXMLParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
 
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-  }
-
-  /*  */
-  
-  function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
-    $this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
-    $this->t_count++;
-  }
-  
-  /*  */
+    public function __init()
+    {
+        parent::__init();
+    }
 
+    public function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '')
+    {
+        $this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
+        ++$this->t_count;
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreRSSLoader.php b/lib/arc2/store/ARC2_StoreRSSLoader.php
index 7deb6ebd3ee8fb40a9b5e8d29775c50bf911c593..d21ac86ebc6fb8df34d9da690414be012113df51 100644
--- a/lib/arc2/store/ARC2_StoreRSSLoader.php
+++ b/lib/arc2/store/ARC2_StoreRSSLoader.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 Store RSS(2) Loader
 author:   Benjamin Nowack
@@ -10,23 +10,21 @@ version:  2010-11-16
 
 ARC2::inc('RSSParser');
 
-class ARC2_StoreRSSLoader extends ARC2_RSSParser {
+class ARC2_StoreRSSLoader extends ARC2_RSSParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
 
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-  }
-
-  /*  */
-  
-  function addT($t) {
-    $this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
-    $this->t_count++;
-  }
-
-  /*  */
+    public function __init()
+    {
+        parent::__init();
+    }
 
+    public function addT($t)
+    {
+        $this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
+        ++$this->t_count;
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreSGAJSONLoader.php b/lib/arc2/store/ARC2_StoreSGAJSONLoader.php
old mode 100644
new mode 100755
index c95c8a2ff1ae16a5e13ced837bc69d376511a123..410cc51654bd7dcb1d57a0db449e1e1697156553
--- a/lib/arc2/store/ARC2_StoreSGAJSONLoader.php
+++ b/lib/arc2/store/ARC2_StoreSGAJSONLoader.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 Store SG API JSON Loader
 author:   Benjamin Nowack
@@ -10,27 +10,26 @@ version:  2010-11-16
 
 ARC2::inc('SGAJSONParser');
 
-class ARC2_StoreSGAJSONLoader extends ARC2_SGAJSONParser {
+class ARC2_StoreSGAJSONLoader extends ARC2_SGAJSONParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
 
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-  }
+    public function __init()
+    {
+        parent::__init();
+    }
 
-  /*  */
-  
-  function done() {
-    $this->extractRDF();
-  }
-  
-  function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
-    $this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
-    $this->t_count++;
-  }
-  
-  /*  */
+    public function done()
+    {
+        $this->extractRDF();
+    }
 
+    public function addT($s = '', $p = '', $o = '', $s_type = '', $o_type = '', $o_dt = '', $o_lang = '')
+    {
+        $this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
+        ++$this->t_count;
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreSPOGLoader.php b/lib/arc2/store/ARC2_StoreSPOGLoader.php
old mode 100644
new mode 100755
index 1d1886e10ca3a7059864969c90a1d4c373c77d86..080c689648597dd4860c46ba605ceee5338f20a6
--- a/lib/arc2/store/ARC2_StoreSPOGLoader.php
+++ b/lib/arc2/store/ARC2_StoreSPOGLoader.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 Store SPOG Loader
 author:   Morten H�ybye Frederiksen / Benjamin Nowack
@@ -10,29 +10,33 @@ version:  2010-11-16
 
 ARC2::inc('SPOGParser');
 
-class ARC2_StoreSPOGLoader extends ARC2_SPOGParser {
+class ARC2_StoreSPOGLoader extends ARC2_SPOGParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
 
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-  }
-
-  /*  */
-  
-  function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '', $g) {
-    if (!($s && $p && $o)) return 0;
-    if (!$g) $g = $this->caller->target_graph;
-    if ($this->caller->fixed_target_graph) $g = $this->caller->fixed_target_graph;
-    $prev_g = $this->caller->target_graph;
-    $this->caller->target_graph = $g;
-    $this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
-    $this->caller->target_graph = $prev_g;
-    $this->t_count++;
-  }
-  
-  /*  */
+    public function __init()
+    {
+        parent::__init();
+    }
 
+    public function addT($s = '', $p = '', $o = '', $s_type = '', $o_type = '', $o_dt = '', $o_lang = '', $g = '')
+    {
+        if (!($s && $p && $o)) {
+            return 0;
+        }
+        if (!$g) {
+            $g = $this->caller->target_graph;
+        }
+        if ($this->caller->fixed_target_graph) {
+            $g = $this->caller->fixed_target_graph;
+        }
+        $prev_g = $this->caller->target_graph;
+        $this->caller->target_graph = $g;
+        $this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
+        $this->caller->target_graph = $prev_g;
+        ++$this->t_count;
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreSelectQueryHandler.php b/lib/arc2/store/ARC2_StoreSelectQueryHandler.php
index 192fcad7fc8f12fd6480cb46b1a899531fe09ece..af5464bf74c722fc8b3b85ac290da4e882308985 100644
--- a/lib/arc2/store/ARC2_StoreSelectQueryHandler.php
+++ b/lib/arc2/store/ARC2_StoreSelectQueryHandler.php
@@ -1,1786 +1,1911 @@
 <?php
 /**
- * ARC2 RDF Store SELECT Query Handler
+ * ARC2 RDF Store SELECT Query Handler.
  *
  * @author    Benjamin Nowack
- * @license   http://arc.semsol.org/license
- * @homepage  <http://arc.semsol.org/>
- * @package   ARC2
- * @version   2010-11-16
+ * @license   W3C Software License and GPL
+ * @homepage  <https://github.com/semsol/arc2>
  *
-*/
-
+ * @version   2010-11-16
+ */
 ARC2::inc('StoreQueryHandler');
 
-class ARC2_StoreSelectQueryHandler extends ARC2_StoreQueryHandler {
-
-  function __construct($a, &$caller) {/* caller has to be a store */
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* db_con */
-    parent::__init();
-    $this->store = $this->caller;
-    $con = $this->store->getDBCon();
-    $this->handler_type = 'select';
-    $this->engine_type = $this->v('store_engine_type', 'MyISAM', $this->a);
-    $this->cache_results = $this->v('store_cache_results', 0, $this->a);
-  }
-
-  /*  */
-
-  function runQuery($infos) {
-    $con = $this->store->getDBCon();
-    $rf = $this->v('result_format', '', $infos);
-    $this->infos = $infos;
-    $this->infos['null_vars'] = array();
-    $this->indexes = array();
-    $this->pattern_order_offset = 0;
-    $q_sql = $this->getSQL();
-
-    /* debug result formats */
-    if ($rf == 'sql') return $q_sql;
-    if ($rf == 'structure') return $this->infos;
-    if ($rf == 'index') return $this->indexes;
-    /* create intermediate results (ID-based) */
-    $tmp_tbl = $this->createTempTable($q_sql);
-    /* join values */
-    $r = $this->getFinalQueryResult($q_sql, $tmp_tbl);
-    /* remove intermediate results */
-    if (!$this->cache_results) {
-      $this->queryDB('DROP TABLE IF EXISTS ' . $tmp_tbl, $con);
-    }
-    return $r;
-  }
-
-  function getSQL() {
-    $r = '';
-    $nl = "\n";
-    $this->buildInitialIndexes();
-    foreach ($this->indexes as $i => $index) {
-      $this->index = array_merge($this->getEmptyIndex(), $index);
-      $this->analyzeIndex($this->getPattern('0'));
-      $sub_r = $this->getQuerySQL();
-      $r .= $r ? $nl . 'UNION' . $this->getDistinctSQL() . $nl : '';
-      $r .= $this->is_union_query ? '(' . $sub_r . ')' : $sub_r;
-      $this->indexes[$i] = $this->index;
-    }
-    $r .= $this->is_union_query ? $this->getLIMITSQL() : '';
-    if ($this->v('order_infos', 0, $this->infos['query'])) {
-      $r = preg_replace('/SELECT(\s+DISTINCT)?\s*/', 'SELECT\\1 NULL AS `_pos_`, ', $r);
-    }
-    if ($pd_count = $this->problematicDependencies()) {
-      /* re-arranging the patterns sometimes reduces the LEFT JOIN dependencies */
-      $set_sql = 0;
-      if (!$this->pattern_order_offset) $set_sql = 1;
-      if (!$set_sql && ($pd_count < $this->opt_sql_pd_count)) $set_sql = 1;
-      if (!$set_sql && ($pd_count == $this->opt_sql_pd_count) && (strlen($r) < strlen($this->opt_sql))) $set_sql = 1;
-      if ($set_sql) {
-        $this->opt_sql = $r;
-        $this->opt_sql_pd_count = $pd_count;
-      }
-      $this->pattern_order_offset++;
-      if ($this->pattern_order_offset > 5) {
-        return $this->opt_sql;
-      }
-      return $this->getSQL();
-    }
-    return $r;
-  }
-
-  function buildInitialIndexes() {
-    $this->dependency_log = array();
-    $this->index = $this->getEmptyIndex();
-    $this->buildIndex($this->infos['query']['pattern'], 0);
-    $tmp = $this->index;
-    $this->analyzeIndex($this->getPattern('0'));
-    $this->initial_index = $this->index;
-    $this->index = $tmp;
-    $this->is_union_query = $this->index['union_branches'] ? 1 : 0;
-    $this->indexes = $this->is_union_query ? $this->getUnionIndexes($this->index) : array($this->index);
-  }
-
-  function createTempTable($q_sql) {
-    $con = $this->store->getDBCon();
-    $v = $this->store->getDBVersion();
-    if ($this->cache_results) {
-      $tbl = $this->store->getTablePrefix() . 'Q' . md5($q_sql);
-    }
-    else {
-      $tbl = $this->store->getTablePrefix() . 'Q' . md5($q_sql . time() . uniqid(rand()));
-    }
-    if (strlen($tbl) > 64) $tbl = 'Q' . md5($tbl);
-    $tmp_sql = 'CREATE TEMPORARY TABLE ' . $tbl . ' ( ' . $this->getTempTableDef($tbl, $q_sql) . ') ';
-    $tmp_sql .= (($v < '04-01-00') && ($v >= '04-00-18')) ? 'ENGINE' : (($v >= '04-01-02') ? 'ENGINE' : 'TYPE');
-    $tmp_sql .= '=' . $this->engine_type;/* HEAP doesn't support AUTO_INCREMENT, and MySQL breaks on MEMORY sometimes */
-    if (!$this->queryDB($tmp_sql, $con) && !$this->queryDB(str_replace('CREATE TEMPORARY', 'CREATE', $tmp_sql), $con)) {
-      return $this->addError(mysql_error($con));
-    }
-    mysql_unbuffered_query('INSERT INTO ' . $tbl . ' ' . "\n" . $q_sql, $con);
-    if ($er = mysql_error($con)) $this->addError($er);
-    return $tbl;
-  }
-
-  function getEmptyIndex() {
-    return array(
-      'from' => array(),
-      'join' => array(),
-      'left_join' => array(),
-      'vars' => array(), 'graph_vars' => array(), 'graph_uris' => array(),
-      'bnodes' => array(),
-      'triple_patterns' => array(),
-      'sub_joins' => array(),
-      'constraints' => array(),
-      'union_branches'=> array(),
-      'patterns' => array(),
-      'havings' => array()
-    );
-  }
-
-  function getTempTableDef($tmp_tbl, $q_sql) {
-    $col_part = preg_replace('/^SELECT\s*(DISTINCT)?(.*)FROM.*$/s', '\\2', $q_sql);
-    $parts = explode(',', $col_part);
-    $has_order_infos = $this->v('order_infos', 0, $this->infos['query']);
-    $r = '';
-    $added = array();
-    foreach ($parts as $part) {
-      if (preg_match('/\.?(.+)\s+AS\s+`(.+)`/U', trim($part), $m) && !isset($added[$m[2]])) {
-        $col = $m[1];
-        $alias = $m[2];
-        if ($alias == '_pos_') continue;
-        $r .= $r ? ',' : '';
-        $r .= "\n `" . $alias . "` int UNSIGNED";
-        $added[$alias] = 1;
-      }
-    }
-    if ($has_order_infos) {
-      $r = "\n" . '`_pos_` mediumint NOT NULL AUTO_INCREMENT PRIMARY KEY, ' . $r;
-    }
-    return  $r ? $r . "\n" : ''; 
-  }
-    
-  function getFinalQueryResult($q_sql, $tmp_tbl) {
-    /* var names */
-    $vars = array();
-    $aggregate_vars = array();
-    foreach ($this->infos['query']['result_vars'] as $entry) {
-      if ($entry['aggregate']) {
-        $vars[] = $entry['alias'];
-        $aggregate_vars[] = $entry['alias'];
-      }
-      else {
-        $vars[] = $entry['var'];
-      }
-    }
-    /* result */
-    $r = array('variables' => $vars);
-    $v_sql = $this->getValueSQL($tmp_tbl, $q_sql);
-    //echo "\n\n" . $v_sql;
-    $t1 = ARC2::mtime();
-    $con = $this->store->getDBCon();
-    $rs = mysql_unbuffered_query($v_sql, $con);
-    if ($er = mysql_error($con)) {
-      $this->addError($er);
-    }
-    $t2 = ARC2::mtime();
-    $rows = array();
-    $types = array(0 => 'uri', 1 => 'bnode', 2 => 'literal');
-    if ($rs) {
-  		while ($pre_row = mysql_fetch_array($rs)) {
-        $row = array();
-        foreach ($vars as $var) {
-          if (isset($pre_row[$var])) {
-            $row[$var] = $pre_row[$var];
-            $row[$var . ' type'] = isset($pre_row[$var . ' type']) ? $types[$pre_row[$var . ' type']] : (in_array($var, $aggregate_vars) ? 'literal' : 'uri');
-            if (isset($pre_row[$var . ' lang_dt']) && ($lang_dt = $pre_row[$var . ' lang_dt'])) {
-              if (preg_match('/^([a-z]+(\-[a-z0-9]+)*)$/i', $lang_dt)) {
-                $row[$var . ' lang'] = $lang_dt;
-              }
-              else {
-                $row[$var . ' datatype'] = $lang_dt;
-              }
-            }
-          }
-        }
-        if ($row || !$vars) {
-          $rows[] = $row;
-        }
-      }
-    }
-    $r['rows'] = $rows;
-    return $r;
-  }
-  
-  /*  */
-  
-  function buildIndex($pattern, $id) {
-    $pattern['id'] = $id;
-    $type = $this->v('type', '', $pattern);
-    if (($type == 'filter') && $this->v('constraint', 0, $pattern)) {
-      $sub_pattern = $pattern['constraint'];
-      $sub_pattern['parent_id'] = $id;
-      $sub_id = $id . '_0';
-      $this->buildIndex($sub_pattern, $sub_id);
-      $pattern['constraint'] = $sub_id;
-    }
-    else {
-      $sub_patterns = $this->v('patterns', array(), $pattern);
-      $keys = array_keys($sub_patterns);
-      $spc = count($sub_patterns);
-      if (($spc > 4) && $this->pattern_order_offset) {
-        $keys = array();
-        for ($i = 0 ; $i < $spc; $i++) {
-          $keys[$i] = $i + $this->pattern_order_offset;
-          while ($keys[$i] >= $spc) $keys[$i] -= $spc;
-        }
-      }
-      foreach ($keys as $i => $key) {
-        $sub_pattern = $sub_patterns[$key];
-        $sub_pattern['parent_id'] = $id;
-        $sub_id = $id . '_' . $key;
-        $this->buildIndex($sub_pattern, $sub_id);
-        $pattern['patterns'][$i] = $sub_id;
-        if ($type == 'union') {
-          $this->index['union_branches'][] = $sub_id;
-        }
-      }
-    }
-    $this->index['patterns'][$id] = $pattern;
-  }
-  
-  /*  */
-
-  function analyzeIndex($pattern) {
-    $type = $pattern['type'];
-    $id = $pattern['id'];
-    /* triple */
-    if ($type == 'triple') {
-      foreach (array('s', 'p', 'o') as $term) {
-        if ($pattern[$term . '_type'] == 'var') {
-          $val = $pattern[$term];
-          $this->index['vars'][$val] = array_merge($this->v($val, array(), $this->index['vars']), array(array('table' => $pattern['id'], 'col' =>$term)));
-        }
-        if ($pattern[$term . '_type'] == 'bnode') {
-          $val = $pattern[$term];
-          $this->index['bnodes'][$val] = array_merge($this->v($val, array(), $this->index['bnodes']), array(array('table' => $pattern['id'], 'col' =>$term)));
-        }
-      }
-      $this->index['triple_patterns'][] = $pattern['id'];
-      /* joins */
-      if ($this->isOptionalPattern($id)) {
-        $this->index['left_join'][] = $id;
-      }
-      elseif (!$this->index['from']) {
-        $this->index['from'][] = $id;
-      }
-      elseif (!$this->getJoinInfos($id)) {
-        $this->index['from'][] = $id;
-      }
-      else {
-        $this->index['join'][] = $id;
-      }
-      /* graph infos, graph vars */
-      $this->index['patterns'][$id]['graph_infos'] = $this->getGraphInfos($id);
-      foreach ($this->index['patterns'][$id]['graph_infos'] as $info) {
-        if ($info['type'] == 'graph') {
-          if ($info['var']) {
-            $val = $info['var']['value'];
-            $this->index['graph_vars'][$val] = array_merge($this->v($val, array(), $this->index['graph_vars']), array(array('table' => $id)));
-          }
-          elseif ($info['uri']) {
-            $val = $info['uri'];
-            $this->index['graph_uris'][$val] = array_merge($this->v($val, array(), $this->index['graph_uris']), array(array('table' => $id)));
-          }
-        }
-      }
-    }
-    $sub_ids = $this->v('patterns', array(), $pattern);
-    foreach ($sub_ids as $sub_id) {
-      $this->analyzeIndex($this->getPattern($sub_id));
-    }
-  }
-  
-  /*  */
-
-  function getGraphInfos($id) {
-    $r = array();
-    if ($id) {
-      $pattern = $this->index['patterns'][$id];
-      $type = $pattern['type'];
-      /* graph */
-      if ($type == 'graph') {
-        $r[] = array('type' => 'graph', 'var' => $pattern['var'], 'uri' => $pattern['uri']);
-      }
-      $p_pattern = $this->index['patterns'][$pattern['parent_id']];
-      if (isset($p_pattern['graph_infos'])) {
-        return array_merge($p_pattern['graph_infos'], $r);
-      }
-      return array_merge($this->getGraphInfos($pattern['parent_id']), $r);
-    }
-    /* FROM / FROM NAMED */
-    else {
-      if (isset($this->infos['query']['dataset'])) {
-        foreach ($this->infos['query']['dataset'] as $set) {
-          $r[] = array_merge(array('type' => 'dataset'), $set);
-        }
-      }
-    }
-    return $r;
-  }
-  
-  /*  */
-
-  function getPattern($id) {
-    if (is_array($id)) {
-      return $id;
-    }
-    return $this->v($id, array(), $this->index['patterns']);
-  }
-
-  function getInitialPattern($id) {
-    return $this->v($id, array(), $this->initial_index['patterns']);
-  }
-
-  /*  */
-  
-  function getUnionIndexes($pre_index) {
-    $r = array();
-    $branches = array();
-    $min_depth = 1000;
-    /* only process branches with minimum depth */
-    foreach ($pre_index['union_branches'] as $id) {
-      $branches[$id] = count(preg_split('/\_/', $id));
-      $min_depth = min($min_depth, $branches[$id]);
-    }
-    foreach ($branches as $branch_id => $depth) {
-      if ($depth == $min_depth) {
-        $union_id = preg_replace('/\_[0-9]+$/', '', $branch_id);
-        $index = array('keeping' => $branch_id, 'union_branches' => array(), 'patterns' => $pre_index['patterns']);
-        $old_branches = $index['patterns'][$union_id]['patterns'];
-        $skip_id = ($old_branches[0] == $branch_id) ? $old_branches[1] : $old_branches[0];
-        $index['patterns'][$union_id]['type'] = 'group';
-        $index['patterns'][$union_id]['patterns'] = array($branch_id);
-        $has_sub_unions = 0;
-        foreach ($index['patterns'] as $pattern_id => $pattern) {
-          if (preg_match('/^' .$skip_id. '/', $pattern_id)) {
-             unset($index['patterns'][$pattern_id]);
-          }
-          elseif ($pattern['type'] == 'union') {
-            foreach ($pattern['patterns'] as $sub_union_branch_id) {
-              $index['union_branches'][] = $sub_union_branch_id;
-            }
-          }
-        }    
-        if ($index['union_branches']) {
-          $r = array_merge($r, $this->getUnionIndexes($index));
+class ARC2_StoreSelectQueryHandler extends ARC2_StoreQueryHandler
+{
+    public function __construct($a, &$caller)
+    {/* caller has to be a store */
+        parent::__construct($a, $caller);
+    }
+
+    public function __init()
+    {
+        parent::__init();
+        $this->store = $this->caller;
+        $this->handler_type = 'select';
+        $this->engine_type = $this->v('store_engine_type', 'MyISAM', $this->a);
+        $this->cache_results = $this->v('store_cache_results', 0, $this->a);
+    }
+
+    public function runQuery($infos)
+    {
+        $rf = $this->v('result_format', '', $infos);
+        $this->infos = $infos;
+        $this->infos['null_vars'] = [];
+        $this->indexes = [];
+        $this->pattern_order_offset = 0;
+        $q_sql = $this->getSQL();
+
+        /* debug result formats */
+        if ('sql' == $rf) {
+            return $q_sql;
         }
+        if ('structure' == $rf) {
+            return $this->infos;
+        }
+        if ('index' == $rf) {
+            return $this->indexes;
+        }
+        /* create intermediate results (ID-based) */
+        $tmp_tbl = $this->createTempTable($q_sql);
+        /* join values */
+        $r = $this->getFinalQueryResult($q_sql, $tmp_tbl);
+        /* remove intermediate results */
+        if (!$this->cache_results) {
+            $this->getDBObjectFromARC2Class()->simpleQuery('DROP TABLE IF EXISTS '.$tmp_tbl);
+        }
+
+        return $r;
+    }
+
+    public function getSQL()
+    {
+        $r = '';
+        $nl = "\n";
+        $this->buildInitialIndexes();
+        foreach ($this->indexes as $i => $index) {
+            $this->index = array_merge($this->getEmptyIndex(), $index);
+            $this->analyzeIndex($this->getPattern('0'));
+            $sub_r = $this->getQuerySQL();
+            $r .= $r ? $nl.'UNION'.$this->getDistinctSQL().$nl : '';
+            $r .= $this->is_union_query ? '('.$sub_r.')' : $sub_r;
+            $this->indexes[$i] = $this->index;
+        }
+        $r .= $this->is_union_query ? $this->getLIMITSQL() : '';
+        if ($this->v('order_infos', 0, $this->infos['query'])) {
+            $r = preg_replace('/SELECT(\s+DISTINCT)?\s*/', 'SELECT\\1 NULL AS `_pos_`, ', $r);
+        }
+        $pd_count = $this->problematicDependencies();
+        if ($pd_count) {
+            /* re-arranging the patterns sometimes reduces the LEFT JOIN dependencies */
+            $set_sql = 0;
+            if (!$this->pattern_order_offset) {
+                $set_sql = 1;
+            }
+            if (!$set_sql && ($pd_count < $this->opt_sql_pd_count)) {
+                $set_sql = 1;
+            }
+            if (!$set_sql && ($pd_count == $this->opt_sql_pd_count) && (strlen($r) < strlen($this->opt_sql))) {
+                $set_sql = 1;
+            }
+            if ($set_sql) {
+                $this->opt_sql = $r;
+                $this->opt_sql_pd_count = $pd_count;
+            }
+            ++$this->pattern_order_offset;
+            if ($this->pattern_order_offset > 5) {
+                return $this->opt_sql;
+            }
+
+            return $this->getSQL();
+        }
+
+        return $r;
+    }
+
+    public function buildInitialIndexes()
+    {
+        $this->dependency_log = [];
+        $this->index = $this->getEmptyIndex();
+        // if no pattern is in the query, the index "pattern" is undefined, which leads to an error.
+        // TODO throw an exception/raise an error and avoid "Undefined index: pattern" notification
+        $this->buildIndex($this->infos['query']['pattern'], 0);
+        $tmp = $this->index;
+        $this->analyzeIndex($this->getPattern('0'));
+        $this->initial_index = $this->index;
+        $this->index = $tmp;
+        $this->is_union_query = $this->index['union_branches'] ? 1 : 0;
+        $this->indexes = $this->is_union_query ? $this->getUnionIndexes($this->index) : [$this->index];
+    }
+
+    public function createTempTable($q_sql)
+    {
+        $v = $this->store->getDBVersion();
+        if ($this->cache_results) {
+            $tbl = $this->store->getTablePrefix().'Q'.md5($q_sql);
+        } else {
+            $tbl = $this->store->getTablePrefix().'Q'.md5($q_sql.time().uniqid(rand()));
+        }
+        if (strlen($tbl) > 64) {
+            $tbl = 'Q'.md5($tbl);
+        }
+        $tmp_sql = 'CREATE TEMPORARY TABLE '.$tbl.' ( '.$this->getTempTableDef($tbl, $q_sql).') ';
+        $tmp_sql .= (($v < '04-01-00') && ($v >= '04-00-18')) ? 'ENGINE' : (($v >= '04-01-02') ? 'ENGINE' : 'TYPE');
+        $tmp_sql .= '='.$this->engine_type; /* HEAP doesn't support AUTO_INCREMENT, and MySQL breaks on MEMORY sometimes */
+        if (!$this->store->a['db_object']->simpleQuery($tmp_sql)
+            && !$this->store->a['db_object']->simpleQuery(str_replace('CREATE TEMPORARY', 'CREATE', $tmp_sql))) {
+            return $this->addError($this->store->a['db_object']->getErrorMessage());
+        }
+        if (false == $this->store->a['db_object']->simpleQuery('INSERT INTO '.$tbl.' '."\n".$q_sql)) {
+            $this->addError($this->store->a['db_object']->getErrorMessage());
+        }
+
+        return $tbl;
+    }
+
+    public function getEmptyIndex()
+    {
+        return [
+            'from' => [],
+            'join' => [],
+            'left_join' => [],
+            'vars' => [], 'graph_vars' => [], 'graph_uris' => [],
+            'bnodes' => [],
+            'triple_patterns' => [],
+            'sub_joins' => [],
+            'constraints' => [],
+            'union_branches' => [],
+            'patterns' => [],
+            'havings' => [],
+        ];
+    }
+
+    public function getTempTableDef($tmp_tbl, $q_sql)
+    {
+        $col_part = preg_replace('/^SELECT\s*(DISTINCT)?(.*)FROM.*$/s', '\\2', $q_sql);
+        $parts = explode(',', $col_part);
+        $has_order_infos = $this->v('order_infos', 0, $this->infos['query']);
+        $r = '';
+        $added = [];
+        foreach ($parts as $part) {
+            if (preg_match('/\.?(.+)\s+AS\s+`(.+)`/U', trim($part), $m) && !isset($added[$m[2]])) {
+                $col = $m[1];
+                $alias = $m[2];
+                if ('_pos_' == $alias) {
+                    continue;
+                }
+                $r .= $r ? ',' : '';
+                $r .= "\n `".$alias.'` int UNSIGNED';
+                $added[$alias] = 1;
+            }
+        }
+        if ($has_order_infos) {
+            $r = "\n".'`_pos_` mediumint NOT NULL AUTO_INCREMENT PRIMARY KEY, '.$r;
+        }
+
+        return  $r ? $r."\n" : '';
+    }
+
+    public function getFinalQueryResult($q_sql, $tmp_tbl)
+    {
+        /* var names */
+        $vars = [];
+        $aggregate_vars = [];
+        foreach ($this->infos['query']['result_vars'] as $entry) {
+            if ($entry['aggregate']) {
+                $vars[] = $entry['alias'];
+                $aggregate_vars[] = $entry['alias'];
+            } else {
+                $vars[] = $entry['var'];
+            }
+        }
+        /* result */
+        $r = ['variables' => $vars];
+        $v_sql = $this->getValueSQL($tmp_tbl, $q_sql);
+
+        $t1 = ARC2::mtime();
+
+        try {
+            $entries = []; // in case an exception gets thrown
+
+            $entries = $this->store->a['db_object']->fetchList($v_sql);
+        } catch (\Exception $e) {
+            $this->addError($e->getMessage());
+        }
+
+        $t2 = ARC2::mtime();
+        $rows = [];
+        $types = [0 => 'uri', 1 => 'bnode', 2 => 'literal'];
+        if (0 < count($entries)) {
+            foreach($entries as $pre_row) {
+                $row = [];
+                foreach ($vars as $var) {
+                    if (isset($pre_row[$var])) {
+                        $row[$var] = $pre_row[$var];
+                        $row[$var.' type'] = isset($pre_row[$var.' type'])
+                            ? $types[$pre_row[$var.' type']]
+                            : (
+                                in_array($var, $aggregate_vars)
+                                    ? 'literal'
+                                    : 'uri'
+                              );
+                        if (isset($pre_row[$var.' lang_dt']) && ($lang_dt = $pre_row[$var.' lang_dt'])) {
+                            if (preg_match('/^([a-z]+(\-[a-z0-9]+)*)$/i', $lang_dt)) {
+                                $row[$var.' lang'] = $lang_dt;
+                            } else {
+                                $row[$var.' datatype'] = $lang_dt;
+                            }
+                        }
+                    }
+                }
+                if ($row || !$vars) {
+                    $rows[] = $row;
+                }
+            }
+        }
+        $r['rows'] = $rows;
+
+        return $r;
+    }
+
+    public function buildIndex($pattern, $id)
+    {
+        $pattern['id'] = $id;
+        $type = $this->v('type', '', $pattern);
+        if (('filter' == $type) && $this->v('constraint', 0, $pattern)) {
+            $sub_pattern = $pattern['constraint'];
+            $sub_pattern['parent_id'] = $id;
+            $sub_id = $id.'_0';
+            $this->buildIndex($sub_pattern, $sub_id);
+            $pattern['constraint'] = $sub_id;
+        } else {
+            $sub_patterns = $this->v('patterns', [], $pattern);
+            $keys = array_keys($sub_patterns);
+            $spc = count($sub_patterns);
+            if (($spc > 4) && $this->pattern_order_offset) {
+                $keys = [];
+                for ($i = 0; $i < $spc; ++$i) {
+                    $keys[$i] = $i + $this->pattern_order_offset;
+                    while ($keys[$i] >= $spc) {
+                        $keys[$i] -= $spc;
+                    }
+                }
+            }
+            foreach ($keys as $i => $key) {
+                $sub_pattern = $sub_patterns[$key];
+                $sub_pattern['parent_id'] = $id;
+                $sub_id = $id.'_'.$key;
+                $this->buildIndex($sub_pattern, $sub_id);
+                $pattern['patterns'][$i] = $sub_id;
+                if ('union' == $type) {
+                    $this->index['union_branches'][] = $sub_id;
+                }
+            }
+        }
+        $this->index['patterns'][$id] = $pattern;
+    }
+
+    public function analyzeIndex($pattern)
+    {
+        $type = $this->v('type', '', $pattern);
+        if (!$type) {
+            //echo '<!-- ' . var_export($this->infos, 1) . ' -->';
+            return false;
+        }
+        $type = $pattern['type'];
+        $id = $pattern['id'];
+        /* triple */
+        if ('triple' == $type) {
+            foreach (['s', 'p', 'o'] as $term) {
+                if ('var' == $pattern[$term.'_type']) {
+                    $val = $pattern[$term];
+                    $this->index['vars'][$val] = array_merge($this->v($val, [], $this->index['vars']), [['table' => $pattern['id'], 'col' => $term]]);
+                }
+                if ('bnode' == $pattern[$term.'_type']) {
+                    $val = $pattern[$term];
+                    $this->index['bnodes'][$val] = array_merge($this->v($val, [], $this->index['bnodes']), [['table' => $pattern['id'], 'col' => $term]]);
+                }
+            }
+            $this->index['triple_patterns'][] = $pattern['id'];
+            /* joins */
+            if ($this->isOptionalPattern($id)) {
+                $this->index['left_join'][] = $id;
+            } elseif (!$this->index['from']) {
+                $this->index['from'][] = $id;
+            } elseif (!$this->getJoinInfos($id)) {
+                $this->index['from'][] = $id;
+            } else {
+                $this->index['join'][] = $id;
+            }
+            /* graph infos, graph vars */
+            $this->index['patterns'][$id]['graph_infos'] = $this->getGraphInfos($id);
+            foreach ($this->index['patterns'][$id]['graph_infos'] as $info) {
+                if ('graph' == $info['type']) {
+                    if ($info['var']) {
+                        $val = $info['var']['value'];
+                        $this->index['graph_vars'][$val] = array_merge($this->v($val, [], $this->index['graph_vars']), [['table' => $id]]);
+                    } elseif ($info['uri']) {
+                        $val = $info['uri'];
+                        $this->index['graph_uris'][$val] = array_merge($this->v($val, [], $this->index['graph_uris']), [['table' => $id]]);
+                    }
+                }
+            }
+        }
+        $sub_ids = $this->v('patterns', [], $pattern);
+        foreach ($sub_ids as $sub_id) {
+            $this->analyzeIndex($this->getPattern($sub_id));
+        }
+    }
+
+    public function getGraphInfos($id)
+    {
+        $r = [];
+        if ($id) {
+            $pattern = $this->index['patterns'][$id];
+            $type = $pattern['type'];
+            /* graph */
+            if ('graph' == $type) {
+                $r[] = ['type' => 'graph', 'var' => $pattern['var'], 'uri' => $pattern['uri']];
+            }
+            $p_pattern = $this->index['patterns'][$pattern['parent_id']];
+            if (isset($p_pattern['graph_infos'])) {
+                return array_merge($p_pattern['graph_infos'], $r);
+            }
+
+            return array_merge($this->getGraphInfos($pattern['parent_id']), $r);
+        }
+        /* FROM / FROM NAMED */
         else {
-          $r[] = $index;
-        }
-      }
-    }
-    return $r;
-  }
-
-  /*  */
-
-  function isOptionalPattern($id) {
-    $pattern = $this->getPattern($id);
-    if ($this->v('type', '', $pattern) == 'optional') {
-      return 1;
-    }
-    if ($this->v('parent_id', '0', $pattern) == '0') {
-      return 0;
-    }
-    return $this->isOptionalPattern($pattern['parent_id']);
-  }
-
-  function getOptionalPattern($id) {
-    $pn = $this->getPattern($id);
-    do {
-      $pn = $this->getPattern($pn['parent_id']);
-    } while ($pn['parent_id'] && ($pn['type'] != 'optional'));
-    return $pn['id'];
-  }
-  
-  function sameOptional($id, $id2) {
-    return $this->getOptionalPattern($id) == $this->getOptionalPattern($id2);
-  }
-  
-  /*  */
-
-  function isUnionPattern($id) {
-    $pattern = $this->getPattern($id);
-    if ($this->v('type', '', $pattern) == 'union') {
-      return 1;
-    }
-    if ($this->v('parent_id', '0', $pattern) == '0') {
-      return 0;
-    }
-    return $this->isUnionPattern($pattern['parent_id']);
-  }
-  
-  /*  */
-
-  function getValueTable($col) {
-    return $this->store->getTablePrefix() . (preg_match('/^(s|o)$/', $col) ? $col . '2val' : 'id2val');
-  }
-  
-  function getGraphTable() {
-    return $this->store->getTablePrefix() . 'g2t';
-  }
-  
-  /*  */
-  
-  function getQuerySQL() {
-    $nl = "\n";
-    $where_sql = $this->getWHERESQL();  /* pre-fills $index['sub_joins'] $index['constraints'] */
-    $order_sql = $this->getORDERSQL();  /* pre-fills $index['sub_joins'] $index['constraints'] */
-    return '' .
-      ($this->is_union_query ? 'SELECT' : 'SELECT' . $this->getDistinctSQL()) . $nl .
-      $this->getResultVarsSQL() . $nl . /* fills $index['sub_joins'] */
-      $this->getFROMSQL() . 
-      $this->getAllJoinsSQL() . 
-      $this->getWHERESQL() . 
-      $this->getGROUPSQL() . 
-      $this->getORDERSQL() . 
-      ($this->is_union_query ? '' : $this->getLIMITSQL()) .
-      $nl .
-    '';
-  }
-
-  /*  */
-  
-  function getDistinctSQL() {
-    if ($this->is_union_query) {
-      return ($this->v('distinct', 0, $this->infos['query']) || $this->v('reduced', 0, $this->infos['query'])) ? '' : ' ALL';  
-    }
-    return ($this->v('distinct', 0, $this->infos['query']) || $this->v('reduced', 0, $this->infos['query'])) ? ' DISTINCT' : '';  
-  }
-
-  /*  */
-  
-  function getResultVarsSQL() {
-    $r = '';
-    $vars = $this->infos['query']['result_vars'];
-    $nl = "\n";
-    $added = array();
-    foreach ($vars as $var) {
-      $var_name = $var['var'];
-      $tbl_alias = '';
-      if ($tbl_infos = $this->getVarTableInfos($var_name, 0)) {
-        $tbl = $tbl_infos['table'];
-        $col = $tbl_infos['col'];
-        $tbl_alias = $tbl_infos['table_alias'];
-      }
-      elseif ($var_name == 1) {/* ASK query */
-        $r .= '1 AS `success`';
-      }
-      else {
-        $this->addError('Result variable "' .$var_name. '" not used in query.');
-      }
-      if ($tbl_alias) {
-        /* aggregate */
-        if ($var['aggregate']) {
-          $conv_code = '';
-          if (strtolower($var['aggregate']) != 'count') {
-            $tbl_alias = 'V_' . $tbl . '_' . $col . '.val';
-            $conv_code = '0 + ';
-          }
-          if (!isset($added[$var['alias']])) {
-            $r .= $r ? ',' . $nl . '  ' : '  ';
-            $distinct_code = (strtolower($var['aggregate']) == 'count') && $this->v('distinct', 0, $this->infos['query']) ? 'DISTINCT ' : '';
-            $r .= $var['aggregate'] . '(' . $conv_code . $distinct_code . $tbl_alias. ') AS `' . $var['alias'] . '`';
-            $added[$var['alias']] = 1;
-          }
-        }
-        /* normal var */
-        else {
-          if (!isset($added[$var_name])) {
-            $r .= $r ? ',' . $nl . '  ' : '  ';
-            $r .= $tbl_alias . ' AS `' . $var_name . '`';
-            $is_s = ($col == 's');
-            $is_p = ($col == 'p');
-            $is_o = ($col == 'o');
-            if ($tbl_alias == 'NULL') {
-              /* type / add in UNION queries? */
-              if ($is_s || $is_o) {
-                $r .= ', ' . $nl . '    NULL AS `' . $var_name . ' type`';
-              }
-              /* lang_dt / always add it in UNION queries, the var may be used as s/p/o */
-              if ($is_o || $this->is_union_query) {
-                $r .= ', ' . $nl . '    NULL AS `' . $var_name . ' lang_dt`';
-              }
-            }
-            else {
-              /* type */
-              if ($is_s || $is_o) {
-                $r .= ', ' . $nl . '    ' .$tbl_alias . '_type AS `' . $var_name . ' type`';
-              }
-              /* lang_dt / always add it in UNION queries, the var may be used as s/p/o */
-              if ($is_o) {
-                $r .= ', ' . $nl . '    ' .$tbl_alias . '_lang_dt AS `' . $var_name . ' lang_dt`';
-              }
-              elseif ($this->is_union_query) {
-                $r .= ', ' . $nl . '    NULL AS `' . $var_name . ' lang_dt`';
-              }
-            }
-            $added[$var_name] = 1;
-          }
+            if (isset($this->infos['query']['dataset'])) {
+                foreach ($this->infos['query']['dataset'] as $set) {
+                    $r[] = array_merge(['type' => 'dataset'], $set);
+                }
+            }
         }
-        if (!in_array($tbl_alias, $this->index['sub_joins'])) {
-          $this->index['sub_joins'][] = $tbl_alias;
-        }
-      }
-    }
-    return $r ? $r : '1 AS `success`';
-  }
-  
-  function getVarTableInfos($var, $ignore_initial_index = 1) {
-    if ($var == '*') {
-      return array('table' => '', 'col' => '', 'table_alias' => '*');
-    }
-    if ($infos = $this->v($var, 0, $this->index['vars'])) {
-      $infos[0]['table_alias'] = 'T_' . $infos[0]['table'] . '.' . $infos[0]['col'];
-      return $infos[0];
-    }
-    if ($infos = $this->v($var, 0, $this->index['graph_vars'])) {
-      $infos[0]['col'] = 'g';
-      $infos[0]['table_alias'] = 'G_' . $infos[0]['table'] . '.' . $infos[0]['col'];
-      return $infos[0];
-    }
-    if ($this->is_union_query && !$ignore_initial_index) {
-      if (($infos = $this->v($var, 0, $this->initial_index['vars'])) || ($infos = $this->v($var, 0, $this->initial_index['graph_vars']))) {
-        if (!in_array($var, $this->infos['null_vars'])) {
-          $this->infos['null_vars'][] = $var;
-        }
-        $infos[0]['table_alias'] = 'NULL';
-        $infos[0]['col'] = !isset($infos[0]['col']) ? '' : $infos[0]['col'];
-        return $infos[0];
-      }
-    }
-    return 0;
-  }
-  
-  /*  */
-  
-  function getFROMSQL() {
-    $r = '';
-    foreach ($this->index['from'] as $id) {
-      $r .= $r ? ', ' : 'FROM (';
-      $r .= $this->getTripleTable($id) . ' T_' . $id;
-    }
-    return $r ? $r . ')' : '';
-  }
-
-  /*  */
-  
-  function getOrderedJoinIDs() {
-    return array_merge($this->index['from'], $this->index['join'], $this->index['left_join']);
-  }
-
-  function getJoinInfos($id) {
-    $r = array();
-    $tbl_ids = $this->getOrderedJoinIDs();
-    $pattern = $this->getPattern($id);
-    foreach ($tbl_ids as $tbl_id) {
-      $tbl_pattern = $this->getPattern($tbl_id);
-      if ($tbl_id != $id) {
-        foreach (array('s', 'p', 'o') as $tbl_term) {
-          foreach (array('var', 'bnode', 'uri') as $term_type) {
-            if ($tbl_pattern[$tbl_term . '_type'] == $term_type) {
-              foreach (array('s', 'p', 'o') as $term) {
-                if (($pattern[$term . '_type'] == $term_type) && ($tbl_pattern[$tbl_term] == $pattern[$term])) {
-                  $r[] = array('term' => $term, 'join_tbl' => $tbl_id, 'join_term' => $tbl_term);
+
+        return $r;
+    }
+
+    public function getPattern($id)
+    {
+        if (is_array($id)) {
+            return $id;
+        }
+
+        return $this->v($id, [], $this->index['patterns']);
+    }
+
+    public function getInitialPattern($id)
+    {
+        return $this->v($id, [], $this->initial_index['patterns']);
+    }
+
+    public function getUnionIndexes($pre_index)
+    {
+        $r = [];
+        $branches = [];
+        $min_depth = 1000;
+        /* only process branches with minimum depth */
+        foreach ($pre_index['union_branches'] as $id) {
+            $branches[$id] = count(preg_split('/\_/', $id));
+            $min_depth = min($min_depth, $branches[$id]);
+        }
+        foreach ($branches as $branch_id => $depth) {
+            if ($depth == $min_depth) {
+                $union_id = preg_replace('/\_[0-9]+$/', '', $branch_id);
+                $index = ['keeping' => $branch_id, 'union_branches' => [], 'patterns' => $pre_index['patterns']];
+                $old_branches = $index['patterns'][$union_id]['patterns'];
+                $skip_id = ($old_branches[0] == $branch_id) ? $old_branches[1] : $old_branches[0];
+                $index['patterns'][$union_id]['type'] = 'group';
+                $index['patterns'][$union_id]['patterns'] = [$branch_id];
+                $has_sub_unions = 0;
+                foreach ($index['patterns'] as $pattern_id => $pattern) {
+                    if (preg_match('/^'.$skip_id.'/', $pattern_id)) {
+                        unset($index['patterns'][$pattern_id]);
+                    } elseif ('union' == $pattern['type']) {
+                        foreach ($pattern['patterns'] as $sub_union_branch_id) {
+                            $index['union_branches'][] = $sub_union_branch_id;
+                        }
+                    }
+                }
+                if ($index['union_branches']) {
+                    $r = array_merge($r, $this->getUnionIndexes($index));
+                } else {
+                    $r[] = $index;
+                }
+            }
+        }
+
+        return $r;
+    }
+
+    public function isOptionalPattern($id)
+    {
+        $pattern = $this->getPattern($id);
+        if ('optional' == $this->v('type', '', $pattern)) {
+            return 1;
+        }
+        if ('0' == $this->v('parent_id', '0', $pattern)) {
+            return 0;
+        }
+
+        return $this->isOptionalPattern($pattern['parent_id']);
+    }
+
+    public function getOptionalPattern($id)
+    {
+        $pn = $this->getPattern($id);
+        do {
+            $pn = $this->getPattern($pn['parent_id']);
+        } while ($pn['parent_id'] && ('optional' != $pn['type']));
+
+        return $pn['id'];
+    }
+
+    public function sameOptional($id, $id2)
+    {
+        return $this->getOptionalPattern($id) == $this->getOptionalPattern($id2);
+    }
+
+    public function isUnionPattern($id)
+    {
+        $pattern = $this->getPattern($id);
+        if ('union' == $this->v('type', '', $pattern)) {
+            return 1;
+        }
+        if ('0' == $this->v('parent_id', '0', $pattern)) {
+            return 0;
+        }
+
+        return $this->isUnionPattern($pattern['parent_id']);
+    }
+
+    public function getValueTable($col)
+    {
+        return $this->store->getTablePrefix().(preg_match('/^(s|o)$/', $col) ? $col.'2val' : 'id2val');
+    }
+
+    public function getGraphTable()
+    {
+        return $this->store->getTablePrefix().'g2t';
+    }
+
+    public function getQuerySQL()
+    {
+        $nl = "\n";
+        $where_sql = $this->getWHERESQL();  /* pre-fills $index['sub_joins'] $index['constraints'] */
+        $order_sql = $this->getORDERSQL();  /* pre-fills $index['sub_joins'] $index['constraints'] */
+        return ''. (
+            $this->is_union_query
+                ? 'SELECT'
+                : 'SELECT'.$this->getDistinctSQL()).$nl.
+                    $this->getResultVarsSQL().$nl. /* fills $index['sub_joins'] */
+                    $this->getFROMSQL().
+                    $this->getAllJoinsSQL().
+                    $this->getWHERESQL().
+                    $this->getGROUPSQL().
+                    $this->getORDERSQL().
+                    ($this->is_union_query
+                        ? ''
+                        : $this->getLIMITSQL()).$nl.'';
+    }
+
+    public function getDistinctSQL()
+    {
+        if ($this->is_union_query) {
+            return ($this->v('distinct', 0, $this->infos['query']) || $this->v('reduced', 0, $this->infos['query'])) ? '' : ' ALL';
+        }
+
+        return ($this->v('distinct', 0, $this->infos['query']) || $this->v('reduced', 0, $this->infos['query'])) ? ' DISTINCT' : '';
+    }
+
+    public function getResultVarsSQL()
+    {
+        $r = '';
+        $vars = $this->infos['query']['result_vars'];
+        $nl = "\n";
+        $added = [];
+        foreach ($vars as $var) {
+            $var_name = $var['var'];
+            $tbl_alias = '';
+            if ($tbl_infos = $this->getVarTableInfos($var_name, 0)) {
+                $tbl = $tbl_infos['table'];
+                $col = $tbl_infos['col'];
+                $tbl_alias = $tbl_infos['table_alias'];
+            } elseif (1 == $var_name) {/* ASK query */
+                $r .= '1 AS `success`';
+            } else {
+                $this->addError('Result variable "'.$var_name.'" not used in query.');
+            }
+            if ($tbl_alias) {
+                /* aggregate */
+                if ($var['aggregate']) {
+                    $conv_code = '';
+                    if ('count' != strtolower($var['aggregate'])) {
+                        $tbl_alias = 'V_'.$tbl.'_'.$col.'.val';
+                        $conv_code = '0 + ';
+                    }
+                    if (!isset($added[$var['alias']])) {
+                        $r .= $r ? ','.$nl.'  ' : '  ';
+                        $distinct_code = ('count' == strtolower($var['aggregate'])) && $this->v('distinct', 0, $this->infos['query']) ? 'DISTINCT ' : '';
+                        $r .= $var['aggregate'].'('.$conv_code.$distinct_code.$tbl_alias.') AS `'.$var['alias'].'`';
+                        $added[$var['alias']] = 1;
+                    }
+                }
+                /* normal var */
+                else {
+                    if (!isset($added[$var_name])) {
+                        $r .= $r ? ','.$nl.'  ' : '  ';
+                        $r .= $tbl_alias.' AS `'.$var_name.'`';
+                        $is_s = ('s' == $col);
+                        $is_p = ('p' == $col);
+                        $is_o = ('o' == $col);
+                        if ('NULL' == $tbl_alias) {
+                            /* type / add in UNION queries? */
+                            if ($is_s || $is_o) {
+                                $r .= ', '.$nl.'    NULL AS `'.$var_name.' type`';
+                            }
+                            /* lang_dt / always add it in UNION queries, the var may be used as s/p/o */
+                            if ($is_o || $this->is_union_query) {
+                                $r .= ', '.$nl.'    NULL AS `'.$var_name.' lang_dt`';
+                            }
+                        } else {
+                            /* type */
+                            if ($is_s || $is_o) {
+                                $r .= ', '.$nl.'    '.$tbl_alias.'_type AS `'.$var_name.' type`';
+                            }
+                            /* lang_dt / always add it in UNION queries, the var may be used as s/p/o */
+                            if ($is_o) {
+                                $r .= ', '.$nl.'    '.$tbl_alias.'_lang_dt AS `'.$var_name.' lang_dt`';
+                            } elseif ($this->is_union_query) {
+                                $r .= ', '.$nl.'    NULL AS `'.$var_name.' lang_dt`';
+                            }
+                        }
+                        $added[$var_name] = 1;
+                    }
+                }
+                if (!in_array($tbl_alias, $this->index['sub_joins'])) {
+                    $this->index['sub_joins'][] = $tbl_alias;
                 }
-              }
-            }
-          }
-        }
-      }
-    }
-    return $r;
-  }
-  
-  function getAllJoinsSQL() {
-    $js = $this->getJoins();
-    $ljs = $this->getLeftJoins();
-    $entries = array_merge($js, $ljs);
-    $id2code = array();
-    foreach ($entries as $entry) {
-      if (preg_match('/([^\s]+) ON (.*)/s', $entry, $m)) {
-        $id2code[$m[1]] = $entry;
-      }
-    }
-    $deps = array();
-    foreach ($id2code as $id => $code) {
-      $deps[$id]['rank'] = 0;
-      foreach ($id2code as $other_id => $other_code) {
-        $deps[$id]['rank'] += ($id != $other_id) && preg_match('/' . $other_id . '/', $code) ? 1 : 0;
-        $deps[$id][$other_id] = ($id != $other_id) && preg_match('/' . $other_id . '/', $code) ? 1 : 0;
-      }
-    }
-    $r = '';
-    do {
-      /* get next 0-rank */
-      $next_id = 0;
-      foreach ($deps as $id => $infos) {
-        if ($infos['rank'] == 0) {
-          $next_id = $id;
-          break;
-        }
-      }
-      if ($next_id) {
-        $r .= "\n" . $id2code[$next_id];
-        unset($deps[$next_id]);
-        foreach ($deps as $id => $infos) {
-          $deps[$id]['rank'] = 0;
-          unset($deps[$id][$next_id]);
-          foreach ($infos as $k => $v) {
-            if (!in_array($k, array('rank', $next_id))) {
-              $deps[$id]['rank'] += $v;
-              $deps[$id][$k] = $v;
-            }
-          }
-        }
-      }
-    }
-    while ($next_id);
-    if ($deps) {
-      $this->addError('Not all patterns could be rewritten to SQL JOINs');
-    }
-    return $r;
-  }
-  
-  function getJoins() {
-    $r = array();
-    $nl = "\n";
-    foreach ($this->index['join'] as $id) {
-      $sub_r = $this->getJoinConditionSQL($id);
-      $r[] = 'JOIN ' . $this->getTripleTable($id) . ' T_' . $id . ' ON (' . $sub_r . $nl . ')';
-    }
-    foreach (array_merge($this->index['from'], $this->index['join']) as $id) {
-      if ($sub_r = $this->getRequiredSubJoinSQL($id)) {
-        $r[] = $sub_r;
-      }
-    }
-    return $r;
-  }
-  
-  function getLeftJoins() {
-    $r = array();
-    $nl = "\n";
-    foreach ($this->index['left_join'] as $id) {
-      $sub_r = $this->getJoinConditionSQL($id);
-      $r[] = 'LEFT JOIN ' . $this->getTripleTable($id) . ' T_' . $id . ' ON (' . $sub_r . $nl . ')';
-    }
-    foreach ($this->index['left_join'] as $id) {
-      if ($sub_r = $this->getRequiredSubJoinSQL($id, 'LEFT')) {
-        $r[] = $sub_r;
-      }
-    }
-    return $r;
-  }
-  
-  function getJoinConditionSQL($id) {
-    $r = '';
-    $nl = "\n";
-    $infos = $this->getJoinInfos($id);
-    $pattern = $this->getPattern($id);
-    
-    $tbl = 'T_' . $id;
-    /* core dependency */
-    $d_tbls = $this->getDependentJoins($id);
-    foreach ($d_tbls as $d_tbl) {
-      if (preg_match('/^T_([0-9\_]+)\.[spo]+/', $d_tbl, $m) && ($m[1] != $id)) {
-        if ($this->isJoinedBefore($m[1], $id) && !in_array($m[1], array_merge($this->index['from'], $this->index['join']))) {
-          $r .= $r ? $nl . '  AND ' : $nl . '  ';
-          $r .= '(' . $d_tbl . ' IS NOT NULL)';
-        }
-        $this->logDependency($id, $d_tbl);
-      }
-    }
-    /* triple-based join info */
-    foreach ($infos as $info) {
-      if ($this->isJoinedBefore($info['join_tbl'], $id) && $this->joinDependsOn($id, $info['join_tbl'])) {
-        $r .= $r ? $nl . '  AND ' : $nl . '  ';
-        $r .= '(' . $tbl . '.' . $info['term'] . ' = T_' . $info['join_tbl'] . '.' . $info['join_term'] . ')';
-      }
-    }
-    /* filters etc */
-    if ($sub_r = $this->getPatternSQL($pattern, 'join__T_' . $id)) {
-      $r .= $r ? $nl . '  AND ' . $sub_r  : $nl . '  ' . '(' . $sub_r . ')';
-    }
-    return $r;
-  }
-
-  /**
-   * A log of identified table join dependencies in getJoinConditionSQL
-   *
-  */
-
-  function logDependency($id, $tbl) {
-    if (!isset($this->dependency_log[$id])) $this->dependency_log[$id] = array();
-    if (!in_array($tbl, $this->dependency_log[$id])) {
-      $this->dependency_log[$id][] = $tbl;
-    }
-  }
-
-  /**
-   * checks whether entries in the dependecy log could perhaps be optimized
-   * (triggers re-ordering of patterns
-  */
-
-  function problematicDependencies() {
-    foreach ($this->dependency_log as $id => $tbls) {
-      if (count($tbls) > 1) return count($tbls);
-    }
-    return 0;
-  }
-  
-  function isJoinedBefore($tbl_1, $tbl_2) {
-    $tbl_ids = $this->getOrderedJoinIDs();
-    foreach ($tbl_ids as $id) {
-      if ($id == $tbl_1) {
-        return 1;
-      }
-      if ($id == $tbl_2) {
+            }
+        }
+
+        return $r ? $r : '1 AS `success`';
+    }
+
+    public function getVarTableInfos($var, $ignore_initial_index = 1)
+    {
+        if ('*' == $var) {
+            return ['table' => '', 'col' => '', 'table_alias' => '*'];
+        }
+        if ($infos = $this->v($var, 0, $this->index['vars'])) {
+            $infos[0]['table_alias'] = 'T_'.$infos[0]['table'].'.'.$infos[0]['col'];
+
+            return $infos[0];
+        }
+        if ($infos = $this->v($var, 0, $this->index['graph_vars'])) {
+            $infos[0]['col'] = 'g';
+            $infos[0]['table_alias'] = 'G_'.$infos[0]['table'].'.'.$infos[0]['col'];
+
+            return $infos[0];
+        }
+        if ($this->is_union_query && !$ignore_initial_index) {
+            if (($infos = $this->v($var, 0, $this->initial_index['vars'])) || ($infos = $this->v($var, 0, $this->initial_index['graph_vars']))) {
+                if (!in_array($var, $this->infos['null_vars'])) {
+                    $this->infos['null_vars'][] = $var;
+                }
+                $infos[0]['table_alias'] = 'NULL';
+                $infos[0]['col'] = !isset($infos[0]['col']) ? '' : $infos[0]['col'];
+
+                return $infos[0];
+            }
+        }
+
         return 0;
-      }
-    }
-  }
-  
-  function joinDependsOn($id, $id2) {
-    if (in_array($id2, array_merge($this->index['from'], $this->index['join']))) {
-      return 1;
-    }
-    $d_tbls = $this->getDependentJoins($id2);
-    //echo $id . ' :: ' . $id2 . '=>' . print_r($d_tbls, 1);
-    foreach ($d_tbls as $d_tbl) {
-      if (preg_match('/^T_' .$id. '\./', $d_tbl)) {
-        return 1;
-      }
-    }
-    return 0;
-  }
-  
-  function getDependentJoins($id) {
-    $r = array();
-    /* sub joins */
-    foreach ($this->index['sub_joins'] as $alias) {
-      if (preg_match('/^(T|V|G)_' . $id . '/', $alias)) {
-        $r[] = $alias;
-      }
-    }
-    /* siblings in shared optional */
-    $o_id = $this->getOptionalPattern($id);
-    foreach ($this->index['sub_joins'] as $alias) {
-      if (preg_match('/^(T|V|G)_' . $o_id . '/', $alias) && !in_array($alias, $r)) {
-        $r[] = $alias;
-      }
-    }
-    foreach ($this->index['left_join'] as $alias) {
-      if (preg_match('/^' . $o_id . '/', $alias) && !in_array($alias, $r)) {
-        $r[] = 'T_' . $alias . '.s';
-      }
-    }
-    return $r;
-  }
-  
-  /*  */
-  
-  function getRequiredSubJoinSQL($id, $prefix = '') {/* id is a triple pattern id. Optional FILTERS and GRAPHs are getting added to the join directly */
-    $nl = "\n";
-    $r = '';
-    foreach ($this->index['sub_joins'] as $alias) {
-      if (preg_match('/^V_' . $id . '_([a-z\_]+)\.val$/', $alias, $m)) {
-        $col = $m[1];
-        $sub_r = '';
-        if ($this->isOptionalPattern($id)) {
-          $pattern = $this->getPattern($id);
-          do {
-            $pattern = $this->getPattern($pattern['parent_id']);
-          } while ($pattern['parent_id'] && ($pattern['type'] != 'optional'));
-          $sub_r = $this->getPatternSQL($pattern, 'sub_join__V_' . $id);
+    }
+
+    public function getFROMSQL()
+    {
+        $from_ids = $this->index['from'];
+        $r = '';
+        foreach ($from_ids as $from_id) {
+            $r .= $r ? ', ' : '';
+            $r .= $this->getTripleTable($from_id).' T_'.$from_id;
+        }
+        /* MySQL 5 requires parentheses in case of multiple tables */
+        /* MySQL >5.5 (?) does not allow parentheses in case of a single table anymore! */
+        $r = (count($from_ids) > 1) ? '('.$r.')' : $r;
+
+        return $r ? 'FROM '.$r : '';
+    }
+
+    public function getOrderedJoinIDs()
+    {
+        return array_merge($this->index['from'], $this->index['join'], $this->index['left_join']);
+    }
+
+    public function getJoinInfos($id)
+    {
+        $r = [];
+        $tbl_ids = $this->getOrderedJoinIDs();
+        $pattern = $this->getPattern($id);
+        foreach ($tbl_ids as $tbl_id) {
+            $tbl_pattern = $this->getPattern($tbl_id);
+            if ($tbl_id != $id) {
+                foreach (['s', 'p', 'o'] as $tbl_term) {
+                    foreach (['var', 'bnode', 'uri'] as $term_type) {
+                        if ($tbl_pattern[$tbl_term.'_type'] == $term_type) {
+                            foreach (['s', 'p', 'o'] as $term) {
+                                if (($pattern[$term.'_type'] == $term_type) && ($tbl_pattern[$tbl_term] == $pattern[$term])) {
+                                    $r[] = ['term' => $term, 'join_tbl' => $tbl_id, 'join_term' => $tbl_term];
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return $r;
+    }
+
+    public function getAllJoinsSQL()
+    {
+        $js = $this->getJoins();
+        $ljs = $this->getLeftJoins();
+        $entries = array_merge($js, $ljs);
+        $id2code = [];
+        foreach ($entries as $entry) {
+            if (preg_match('/([^\s]+) ON (.*)/s', $entry, $m)) {
+                $id2code[$m[1]] = $entry;
+            }
         }
-        $sub_r = $sub_r ? $nl . '  AND (' . $sub_r . ')' : '';
-        /* lang dt only on literals */
-        if ($col == 'o_lang_dt') {
-          $sub_sub_r = 'T_' . $id . '.o_type = 2'; 
-          $sub_r .= $nl . '  AND (' . $sub_sub_r . ')';
+        $deps = [];
+        foreach ($id2code as $id => $code) {
+            $deps[$id]['rank'] = 0;
+            foreach ($id2code as $other_id => $other_code) {
+                $deps[$id]['rank'] += ($id != $other_id) && preg_match('/'.$other_id.'/', $code) ? 1 : 0;
+                $deps[$id][$other_id] = ($id != $other_id) && preg_match('/'.$other_id.'/', $code) ? 1 : 0;
+            }
         }
-        //$cur_prefix = $prefix ? $prefix . ' ' : 'STRAIGHT_';
-        $cur_prefix = $prefix ? $prefix . ' ' : '';
-        if ($col == 'g') {
-          $r .= trim($cur_prefix . 'JOIN '. $this->getValueTable($col) . ' V_' .$id . '_' . $col. ' ON (' .$nl. '  (G_' . $id . '.' . $col. ' = V_' . $id. '_' . $col. '.id) ' . $sub_r . $nl . ')');
+        $r = '';
+        do {
+            /* get next 0-rank */
+            $next_id = 0;
+            foreach ($deps as $id => $infos) {
+                if (0 == $infos['rank']) {
+                    $next_id = $id;
+                    break;
+                }
+            }
+            if ($next_id) {
+                $r .= "\n".$id2code[$next_id];
+                unset($deps[$next_id]);
+                foreach ($deps as $id => $infos) {
+                    $deps[$id]['rank'] = 0;
+                    unset($deps[$id][$next_id]);
+                    foreach ($infos as $k => $v) {
+                        if (!in_array($k, ['rank', $next_id])) {
+                            $deps[$id]['rank'] += $v;
+                            $deps[$id][$k] = $v;
+                        }
+                    }
+                }
+            }
+        } while ($next_id);
+        if ($deps) {
+            $this->addError('Not all patterns could be rewritten to SQL JOINs');
         }
-        else {
-          $r .= trim($cur_prefix . 'JOIN '. $this->getValueTable($col) . ' V_' .$id . '_' . $col. ' ON (' .$nl. '  (T_' . $id . '.' . $col. ' = V_' . $id. '_' . $col. '.id) ' . $sub_r . $nl . ')');
+
+        return $r;
+    }
+
+    public function getJoins()
+    {
+        $r = [];
+        $nl = "\n";
+        foreach ($this->index['join'] as $id) {
+            $sub_r = $this->getJoinConditionSQL($id);
+            $r[] = 'JOIN '.$this->getTripleTable($id).' T_'.$id.' ON ('.$sub_r.$nl.')';
         }
-      }
-      elseif (preg_match('/^G_' . $id . '\.g$/', $alias, $m)) {
+        foreach (array_merge($this->index['from'], $this->index['join']) as $id) {
+            if ($sub_r = $this->getRequiredSubJoinSQL($id)) {
+                $r[] = $sub_r;
+            }
+        }
+
+        return $r;
+    }
+
+    public function getLeftJoins()
+    {
+        $r = [];
+        $nl = "\n";
+        foreach ($this->index['left_join'] as $id) {
+            $sub_r = $this->getJoinConditionSQL($id);
+            $r[] = 'LEFT JOIN '.$this->getTripleTable($id).' T_'.$id.' ON ('.$sub_r.$nl.')';
+        }
+        foreach ($this->index['left_join'] as $id) {
+            if ($sub_r = $this->getRequiredSubJoinSQL($id, 'LEFT')) {
+                $r[] = $sub_r;
+            }
+        }
+
+        return $r;
+    }
+
+    public function getJoinConditionSQL($id)
+    {
+        $r = '';
+        $nl = "\n";
+        $infos = $this->getJoinInfos($id);
         $pattern = $this->getPattern($id);
-        $sub_r = $this->getPatternSQL($pattern, 'graph_sub_join__G_' . $id);
-        $sub_r = $sub_r ? $nl . '  AND ' . $sub_r : '';
-        /* dataset restrictions */
-        $gi = $this->getGraphInfos($id);
-        $sub_sub_r = '';
-        $added_gts = array();
-        foreach ($gi as $set) {
-          if (isset($set['graph']) && !in_array($set['graph'], $added_gts)) {
-            $sub_sub_r .= $sub_sub_r !== '' ? ',' : '';
-            $sub_sub_r .= $this->getTermID($set['graph'], 'g'); 
-            $added_gts[] = $set['graph'];
-          }
-        }
-        $sub_r .= ($sub_sub_r !== '') ? $nl . ' AND (G_' . $id . '.g IN (' . $sub_sub_r . '))' : ''; // /* ' . str_replace('#' , '::', $set['graph']) . ' */';
-        /* other graph join conditions */
-        foreach ($this->index['graph_vars'] as $var => $occurs) {
-          $occur_tbls = array();
-          foreach ($occurs as $occur) {
-            $occur_tbls[] = $occur['table'];
-            if ($occur['table'] == $id) break;
-          }
-          foreach($occur_tbls as $tbl) {
-            if (($tbl != $id) && in_array($id, $occur_tbls) && $this->isJoinedBefore($tbl, $id)) {
-              $sub_r .= $nl . '  AND (G_' .$id. '.g = G_' .$tbl. '.g)'; 
-            }
-          }
-        }
-        //$cur_prefix = $prefix ? $prefix . ' ' : 'STRAIGHT_';
-        $cur_prefix = $prefix ? $prefix . ' ' : '';
-        $r .= trim($cur_prefix . 'JOIN '. $this->getGraphTable() . ' G_' .$id . ' ON (' .$nl. '  (T_' . $id . '.t = G_' .$id. '.t)' . $sub_r . $nl . ')');
-      }
-    }
-    return $r;
-  }
-
-  /*  */
-
-  function getWHERESQL() {
-    $r = '';
-    $nl = "\n";
-    /* standard constraints */
-    $sub_r = $this->getPatternSQL($this->getPattern('0'), 'where');
-    /* additional constraints */
-    foreach ($this->index['from'] as $id) {
-      if ($sub_sub_r = $this->getConstraintSQL($id)) {
-        $sub_r .= $sub_r ? $nl . ' AND ' . $sub_sub_r : $sub_sub_r;
-      }
-    }
-    $r .= $sub_r ? $sub_r : '';
-    /* left join dependencies */
-    foreach ($this->index['left_join'] as $id) {
-      $d_joins = $this->getDependentJoins($id);
-      $added = array();
-      $d_aliases = array();
-      //echo $id . ' =>' . print_r($d_joins, 1);
-      $id_alias = 'T_' . $id . '.s';
-      foreach ($d_joins as $alias) {
-        if (preg_match('/^(T|V|G)_([0-9\_]+)(_[spo])?\.([a-z\_]+)/', $alias, $m)) {
-          $tbl_type = $m[1];
-          $tbl_pattern_id = $m[2];
-          $suffix = $m[3];
-          if (($tbl_pattern_id >= $id) && $this->sameOptional($tbl_pattern_id, $id)) {/* get rid of dependency permutations and nested optionals */
-            if (!in_array($tbl_type . '_' . $tbl_pattern_id . $suffix, $added)) {
-              $sub_r .= $sub_r ? ' AND ' : '';
-              $sub_r .= $alias . ' IS NULL';
-              $d_aliases[] = $alias;
-              $added[] = $tbl_type . '_' . $tbl_pattern_id . $suffix;
-              $id_alias = ($tbl_pattern_id == $id) ? $alias : $id_alias;
-            }
-          }
-        }
-      }
-      if (count($d_aliases) > 2) {/* @@todo fix this! */
-        $sub_r1 = '  /* '.$id_alias.' dependencies */';
-        $sub_r2 = '((' . $id_alias . ' IS NULL) OR (CONCAT(' . join(', ', $d_aliases) . ') IS NOT NULL))';
-        $r .= $r ? $nl . $sub_r1 . $nl . '  AND ' .$sub_r2 : $sub_r1 . $nl . $sub_r2;
-      }
-    }
-    return $r ? $nl . 'WHERE ' . $r : '';
-  }
-
-  /*  */
-  
-  function addConstraintSQLEntry($id, $sql) {
-    if (!isset($this->index['constraints'][$id])) {
-      $this->index['constraints'][$id] = array();
-    }
-    if (!in_array($sql, $this->index['constraints'][$id])) {
-      $this->index['constraints'][$id][] = $sql;
-    }
-  }
-  
-  function getConstraintSQL($id) {
-    $r = '';
-    $nl = "\n";
-    $constraints = $this->v($id, array(), $this->index['constraints']);
-    foreach ($constraints as $constraint) {
-      $r .= $r ? $nl . '  AND ' . $constraint : $constraint;
-    }
-    return $r;
-  }
-  
-  /*  */
-  
-  function getPatternSQL($pattern, $context) {
-    $type = $pattern['type'];
-    $m = 'get' . ucfirst($type) . 'PatternSQL';
-    return method_exists($this, $m) ? $this->$m($pattern, $context) : $this->getDefaultPatternSQL($pattern, $context);
-  }
-
-  function getDefaultPatternSQL($pattern, $context) {
-    $r = '';
-    $nl = "\n";
-    $sub_ids = $this->v('patterns', array(), $pattern);
-    foreach ($sub_ids as $sub_id) {
-      $sub_r = $this->getPatternSQL($this->getPattern($sub_id), $context);
-      $r .= ($r && $sub_r) ? $nl . '  AND (' . $sub_r . ')' : ($sub_r ? $sub_r  : '');
-    }
-    return $r ? $r : '';
-  }
-  
-  function getTriplePatternSQL($pattern, $context) {
-    $r = '';
-    $nl = "\n";
-    $id = $pattern['id'];
-    /* s p o */
-    $vars = array();
-    foreach (array('s', 'p', 'o') as $term) {
-      $sub_r = '';
-      $type = $pattern[$term . '_type'];
-      if ($type == 'uri') {
-        $term_id = $this->getTermID($pattern[$term], $term);
-        $sub_r = '(T_' . $id . '.' . $term . ' = ' . $term_id . ') /* ' . str_replace('#' , '::', $pattern[$term]) . ' */';
-      }
-      elseif ($type == 'literal') {
-        $term_id = $this->getTermID($pattern[$term], $term);
-        $sub_r = '(T_' . $id . '.' . $term . ' = ' . $term_id . ') /* ' . preg_replace('/[\#\n]/' , ' ', $pattern[$term]) . ' */';
-        if (($lang_dt = $this->v1($term . '_lang', '', $pattern)) || ($lang_dt = $this->v1($term . '_datatype', '', $pattern))) {
-          $lang_dt_id = $this->getTermID($lang_dt);
-          $sub_r .= $nl . '  AND (T_' . $id . '.' .$term. '_lang_dt = ' . $lang_dt_id . ') /* ' . str_replace('#' , '::', $lang_dt) . ' */';
-        }
-      }
-      elseif ($type == 'var') {
-        $val = $pattern[$term];
-        if (isset($vars[$val])) {/* repeated var in pattern */
-          $sub_r = '(T_' . $id . '.' . $term . '=' . 'T_' . $id . '.' . $vars[$val] . ')';
-        }
-        $vars[$val] = $term;
-        if ($infos = $this->v($val, 0, $this->index['graph_vars'])) {/* graph var in triple pattern */
-          $sub_r .= $sub_r ? $nl . '  AND ' : '';
-          $tbl = $infos[0]['table'];
-          $sub_r .= 'G_' . $tbl . '.g = T_' . $id . '.' . $term;
-        }
-      }
-      if ($sub_r) {
-        if (preg_match('/^(join)/', $context) || (preg_match('/^where/', $context) && in_array($id, $this->index['from']))) {
-          $r .= $r ? $nl . '  AND ' . $sub_r  : $sub_r;
-        }
-      }
-    }
-    /* g */
-    if ($infos = $pattern['graph_infos']) {
-      $tbl_alias = 'G_' . $id . '.g';
-      if (!in_array($tbl_alias, $this->index['sub_joins'])) {
-        $this->index['sub_joins'][] = $tbl_alias;
-      }
-      $sub_r = array('graph_var' => '', 'graph_uri' => '', 'from' => '', 'from_named' => '');
-      foreach ($infos as $info) {
-        $type = $info['type'];
-        if ($type == 'graph') {
-          if ($info['uri']) {
-            $term_id = $this->getTermID($info['uri'], 'g');
-            $sub_r['graph_uri'] .= $sub_r['graph_uri'] ? $nl . ' AND ' : '';
-            $sub_r['graph_uri'] .= '(' .$tbl_alias. ' = ' . $term_id . ') /* ' . str_replace('#' , '::', $info['uri']) . ' */';
-          }
-        }
-      }
-      if ($sub_r['from'] && $sub_r['from_named']) {
-        $sub_r['from_named'] = '';
-      }
-      if (!$sub_r['from'] && !$sub_r['from_named']) {
-        $sub_r['graph_var'] = '';
-      }
-      if (preg_match('/^(graph_sub_join)/', $context)) {
-        foreach ($sub_r as $g_type => $g_sql) {
-          if ($g_sql) {
-            $r .= $r ? $nl . '  AND ' . $g_sql  : $g_sql;
-          }
-        }
-      }
-    }
-    /* optional sibling filters? */
-    if (preg_match('/^(join|sub_join)/', $context) && $this->isOptionalPattern($id)) {
-      $o_pattern = $pattern;
-      do {
-        $o_pattern = $this->getPattern($o_pattern['parent_id']);
-      } while ($o_pattern['parent_id'] && ($o_pattern['type'] != 'optional'));
-      if ($sub_r = $this->getPatternSQL($o_pattern, 'optional_filter' . preg_replace('/^(.*)(__.*)$/', '\\2', $context))) {
-        $r .= $r ? $nl . '  AND ' . $sub_r  : $sub_r;
-      }
-      /* created constraints */
-      if ($sub_r = $this->getConstraintSQL($id)) {
-        $r .= $r ? $nl . '  AND ' . $sub_r  : $sub_r;
-      }
-    }
-    /* result */
-    if (preg_match('/^(where)/', $context) && $this->isOptionalPattern($id)) {
-      return '';
-    }
-    return $r;
-  }
-  
-  /*  */
-  
-  function getFilterPatternSQL($pattern, $context) {
-    $r = '';
-    $id = $pattern['id'];
-    $constraint_id = $this->v1('constraint', '', $pattern);
-    $constraint = $this->getPattern($constraint_id);
-    $constraint_type = $constraint['type'];
-    if ($constraint_type == 'built_in_call') {
-      $r = $this->getBuiltInCallSQL($constraint, $context);
-    }
-    elseif ($constraint_type == 'expression') {
-      $r = $this->getExpressionSQL($constraint, $context, '', 'filter');
-    }
-    else {
-      $m = 'get' . ucfirst($constraint_type) . 'ExpressionSQL';
-      if (method_exists($this, $m)) {
-        $r = $this->$m($constraint, $context, '', 'filter');
-      }
-    }
-    if ($this->isOptionalPattern($id) && !preg_match('/^(join|optional_filter)/', $context)) {
-      return '';
-    }
-    /* unconnected vars in FILTERs eval to false */
-    $sub_r = $this->hasUnconnectedFilterVars($id);
-    if ($sub_r) {
-      if ($sub_r == 'alias') {
-        if (!in_array($r, $this->index['havings'])) $this->index['havings'][] = $r;
-        return '';
-      }
-      elseif (preg_match('/^T([^\s]+\.)g (.*)$/s', $r, $m)) {/* graph filter */
-        return 'G' . $m[1] . 't ' . $m[2];
-      }
-      elseif (preg_match('/^\(*V[^\s]+_g\.val .*$/s', $r, $m)) {/* graph value filter, @@improveMe */
-        //return $r;
-      }
-      else {
-        return 'FALSE';
-      }
-    }
-    /* some really ugly tweaks */
-    /* empty language filter: FILTER ( lang(?v) = '' ) */
-    $r = preg_replace('/\(\/\* language call \*\/ ([^\s]+) = ""\)/s', '((\\1 = "") OR (\\1 LIKE "%:%"))', $r);
-    return $r;
-  }
-  
-  /**
-   * Checks if vars in the given (filter) pattern are used within the filter's scope.
-   */
-  
-  function hasUnconnectedFilterVars($filter_pattern_id) {
-    $scope_id = $this->getFilterScope($filter_pattern_id);
-    $vars = $this->getFilterVars($filter_pattern_id);
-    $r = 0;
-    foreach ($vars as $var_name) {
-      if ($this->isUsedTripleVar($var_name, $scope_id)) continue;
-      if ($this->isAliasVar($var_name)) {
-        $r = 'alias';
-        break;
-      }
-      $r = 1;
-      break;
-    }
-    return $r;
-  }
-
-  /**
-   * Returns the given filter pattern's scope (the id of the parent group pattern).
-   */
-
-  function getFilterScope($filter_pattern_id) {
-    $patterns = $this->initial_index['patterns'];
-    $r = '';
-    foreach ($patterns as $id => $p) {
-      /* the id has to be sub-part of the given filter id */
-      if (!preg_match('/^' . $id . '.+/', $filter_pattern_id)) continue;
-      /* we are looking for a group or union */
-      if (!preg_match('/^(group|union)$/', $p['type'])) continue;
-      /* we are looking for the longest/deepest match */
-      if (strlen($id) > strlen($r)) $r = $id;
-    }
-    return $r;
-  }
-
-  /**
-   * Builds a list of vars used in the given (filter) pattern.
-   */
-
-  function getFilterVars($filter_pattern_id) {
-    $r = array();
-    $patterns = $this->initial_index['patterns'];
-    /* find vars in the given filter (i.e. the given id is part of their pattern id) */
-    foreach ($patterns as $id => $p) {
-      if (!preg_match('/^' . $filter_pattern_id . '.+/', $id)) continue;
-      $var_name = '';
-      if ($p['type'] == 'var') {
-        $var_name = $p['value'];
-      }
-      elseif (($p['type'] == 'built_in_call') && ($p['call'] == 'bound')) {
-        $var_name = $p['args'][0]['value'];
-      }
-      if ($var_name && !in_array($var_name, $r)) {
-        $r[] = $var_name;
-      }
-    }
-    return $r;
-  }
-
-  /**
-   * Checks if $var_name appears as result projection alias.
-   */
-
-  function isAliasVar($var_name) {
-    foreach ($this->infos['query']['result_vars'] as $r_var) {
-      if ($r_var['alias'] == $var_name) return 1;
-    }
-    return 0;
-  }
-
-  /**
-   * Checks if $var_name is used in a triple pattern in the given scope
-   */
-
-  function isUsedTripleVar($var_name, $scope_id = '0') {
-    $patterns = $this->initial_index['patterns'];
-    foreach ($patterns as $id => $p) {
-      if ($p['type'] != 'triple') continue;
-      if (!preg_match('/^' . $scope_id . '.+/', $id)) continue;
-      foreach (array('s', 'p', 'o') as $term) {
-        if ($p[$term . '_type'] != 'var') continue;
-        if ($p[$term] == $var_name) return 1;
-      }
-    }
-  }
-
-  /*  */
-
-  function getExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
-    $r = '';
-    $nl = "\n";
-    $type = $this->v1('type', '', $pattern);
-    $sub_type = $this->v1('sub_type', $type, $pattern);
-    if (preg_match('/^(and|or)$/', $sub_type)) {
-      foreach ($pattern['patterns'] as $sub_id) {
-        $sub_pattern = $this->getPattern($sub_id);
-        $sub_pattern_type = $sub_pattern['type'];
-        if ($sub_pattern_type == 'built_in_call') {
-          $sub_r = $this->getBuiltInCallSQL($sub_pattern, $context, '', $parent_type);
+
+        $tbl = 'T_'.$id;
+        /* core dependency */
+        $d_tbls = $this->getDependentJoins($id);
+        foreach ($d_tbls as $d_tbl) {
+            if (preg_match('/^T_([0-9\_]+)\.[spo]+/', $d_tbl, $m) && ($m[1] != $id)) {
+                if ($this->isJoinedBefore($m[1], $id) && !in_array($m[1], array_merge($this->index['from'], $this->index['join']))) {
+                    $r .= $r ? $nl.'  AND ' : $nl.'  ';
+                    $r .= '('.$d_tbl.' IS NOT NULL)';
+                }
+                $this->logDependency($id, $d_tbl);
+            }
         }
-        else {
-          $sub_r = $this->getExpressionSQL($sub_pattern, $context, '', $parent_type);
+        /* triple-based join info */
+        foreach ($infos as $info) {
+            if ($this->isJoinedBefore($info['join_tbl'], $id) && $this->joinDependsOn($id, $info['join_tbl'])) {
+                $r .= $r ? $nl.'  AND ' : $nl.'  ';
+                $r .= '('.$tbl.'.'.$info['term'].' = T_'.$info['join_tbl'].'.'.$info['join_term'].')';
+            }
+        }
+        /* filters etc */
+        if ($sub_r = $this->getPatternSQL($pattern, 'join__T_'.$id)) {
+            $r .= $r ? $nl.'  AND '.$sub_r : $nl.'  '.'('.$sub_r.')';
+        }
+
+        return $r;
+    }
+
+    /**
+     * A log of identified table join dependencies in getJoinConditionSQL.
+     */
+    public function logDependency($id, $tbl)
+    {
+        if (!isset($this->dependency_log[$id])) {
+            $this->dependency_log[$id] = [];
+        }
+        if (!in_array($tbl, $this->dependency_log[$id])) {
+            $this->dependency_log[$id][] = $tbl;
+        }
+    }
+
+    /**
+     * checks whether entries in the dependecy log could perhaps be optimized
+     * (triggers re-ordering of patterns.
+     */
+    public function problematicDependencies()
+    {
+        foreach ($this->dependency_log as $id => $tbls) {
+            if (count($tbls) > 1) {
+                return count($tbls);
+            }
+        }
+
+        return 0;
+    }
+
+    public function isJoinedBefore($tbl_1, $tbl_2)
+    {
+        $tbl_ids = $this->getOrderedJoinIDs();
+        foreach ($tbl_ids as $id) {
+            if ($id == $tbl_1) {
+                return 1;
+            }
+            if ($id == $tbl_2) {
+                return 0;
+            }
+        }
+    }
+
+    public function joinDependsOn($id, $id2)
+    {
+        if (in_array($id2, array_merge($this->index['from'], $this->index['join']))) {
+            return 1;
+        }
+        $d_tbls = $this->getDependentJoins($id2);
+        //echo $id . ' :: ' . $id2 . '=>' . print_r($d_tbls, 1);
+        foreach ($d_tbls as $d_tbl) {
+            if (preg_match('/^T_'.$id.'\./', $d_tbl)) {
+                return 1;
+            }
+        }
+
+        return 0;
+    }
+
+    public function getDependentJoins($id)
+    {
+        $r = [];
+        /* sub joins */
+        foreach ($this->index['sub_joins'] as $alias) {
+            if (preg_match('/^(T|V|G)_'.$id.'/', $alias)) {
+                $r[] = $alias;
+            }
+        }
+        /* siblings in shared optional */
+        $o_id = $this->getOptionalPattern($id);
+        foreach ($this->index['sub_joins'] as $alias) {
+            if (preg_match('/^(T|V|G)_'.$o_id.'/', $alias) && !in_array($alias, $r)) {
+                $r[] = $alias;
+            }
+        }
+        foreach ($this->index['left_join'] as $alias) {
+            if (preg_match('/^'.$o_id.'/', $alias) && !in_array($alias, $r)) {
+                $r[] = 'T_'.$alias.'.s';
+            }
+        }
+
+        return $r;
+    }
+
+    public function getRequiredSubJoinSQL($id, $prefix = '')
+    {
+        /* id is a triple pattern id. Optional FILTERS and GRAPHs are getting added to the join directly */
+        $nl = "\n";
+        $r = '';
+        foreach ($this->index['sub_joins'] as $alias) {
+            if (preg_match('/^V_'.$id.'_([a-z\_]+)\.val$/', $alias, $m)) {
+                $col = $m[1];
+                $sub_r = '';
+                if ($this->isOptionalPattern($id)) {
+                    $pattern = $this->getPattern($id);
+                    do {
+                        $pattern = $this->getPattern($pattern['parent_id']);
+                    } while ($pattern['parent_id'] && ('optional' != $pattern['type']));
+                    $sub_r = $this->getPatternSQL($pattern, 'sub_join__V_'.$id);
+                }
+                $sub_r = $sub_r ? $nl.'  AND ('.$sub_r.')' : '';
+                /* lang dt only on literals */
+                if ('o_lang_dt' == $col) {
+                    $sub_sub_r = 'T_'.$id.'.o_type = 2';
+                    $sub_r .= $nl.'  AND ('.$sub_sub_r.')';
+                }
+                $cur_prefix = $prefix ? $prefix.' ' : '';
+                if ('g' == $col) {
+                    $r .= trim($cur_prefix.'JOIN '.$this->getValueTable($col).' V_'.$id.'_'.$col.' ON ('.$nl.'  (G_'.$id.'.'.$col.' = V_'.$id.'_'.$col.'.id) '.$sub_r.$nl.')');
+                } else {
+                    $r .= trim($cur_prefix.'JOIN '.$this->getValueTable($col).' V_'.$id.'_'.$col.' ON ('.$nl.'  (T_'.$id.'.'.$col.' = V_'.$id.'_'.$col.'.id) '.$sub_r.$nl.')');
+                }
+            } elseif (preg_match('/^G_'.$id.'\.g$/', $alias, $m)) {
+                $pattern = $this->getPattern($id);
+                $sub_r = $this->getPatternSQL($pattern, 'graph_sub_join__G_'.$id);
+                $sub_r = $sub_r ? $nl.'  AND '.$sub_r : '';
+                /* dataset restrictions */
+                $gi = $this->getGraphInfos($id);
+                $sub_sub_r = '';
+                $added_gts = [];
+                foreach ($gi as $set) {
+                    if (isset($set['graph']) && !in_array($set['graph'], $added_gts)) {
+                        $sub_sub_r .= '' !== $sub_sub_r ? ',' : '';
+                        $sub_sub_r .= $this->getTermID($set['graph'], 'g');
+                        $added_gts[] = $set['graph'];
+                    }
+                }
+                $sub_r .= ('' !== $sub_sub_r) ? $nl.' AND (G_'.$id.'.g IN ('.$sub_sub_r.'))' : '';
+                /* other graph join conditions */
+                foreach ($this->index['graph_vars'] as $var => $occurs) {
+                    $occur_tbls = [];
+                    foreach ($occurs as $occur) {
+                        $occur_tbls[] = $occur['table'];
+                        if ($occur['table'] == $id) {
+                            break;
+                        }
+                    }
+                    foreach ($occur_tbls as $tbl) {
+                        if (($tbl != $id) && in_array($id, $occur_tbls) && $this->isJoinedBefore($tbl, $id)) {
+                            $sub_r .= $nl.'  AND (G_'.$id.'.g = G_'.$tbl.'.g)';
+                        }
+                    }
+                }
+                $cur_prefix = $prefix ? $prefix.' ' : '';
+                $r .= trim($cur_prefix.'JOIN '.$this->getGraphTable().' G_'.$id.' ON ('.$nl.'  (T_'.$id.'.t = G_'.$id.'.t)'.$sub_r.$nl.')');
+            }
+        }
+
+        return $r;
+    }
+
+    public function getWHERESQL()
+    {
+        $r = '';
+        $nl = "\n";
+        /* standard constraints */
+        $sub_r = $this->getPatternSQL($this->getPattern('0'), 'where');
+        /* additional constraints */
+        foreach ($this->index['from'] as $id) {
+            if ($sub_sub_r = $this->getConstraintSQL($id)) {
+                $sub_r .= $sub_r ? $nl.' AND '.$sub_sub_r : $sub_sub_r;
+            }
+        }
+        $r .= $sub_r ? $sub_r : '';
+        /* left join dependencies */
+        foreach ($this->index['left_join'] as $id) {
+            $d_joins = $this->getDependentJoins($id);
+            $added = [];
+            $d_aliases = [];
+            $id_alias = 'T_'.$id.'.s';
+            foreach ($d_joins as $alias) {
+                if (preg_match('/^(T|V|G)_([0-9\_]+)(_[spo])?\.([a-z\_]+)/', $alias, $m)) {
+                    $tbl_type = $m[1];
+                    $tbl_pattern_id = $m[2];
+                    $suffix = $m[3];
+                    /* get rid of dependency permutations and nested optionals */
+                    if (($tbl_pattern_id >= $id) && $this->sameOptional($tbl_pattern_id, $id)) {
+                        if (!in_array($tbl_type.'_'.$tbl_pattern_id.$suffix, $added)) {
+                            $sub_r .= $sub_r ? ' AND ' : '';
+                            $sub_r .= $alias.' IS NULL';
+                            $d_aliases[] = $alias;
+                            $added[] = $tbl_type.'_'.$tbl_pattern_id.$suffix;
+                            $id_alias = ($tbl_pattern_id == $id) ? $alias : $id_alias;
+                        }
+                    }
+                }
+            }
+            /* TODO fix this! */
+            if (count($d_aliases) > 2) {
+                $sub_r1 = '  /* '.$id_alias.' dependencies */';
+                $sub_r2 = '(('.$id_alias.' IS NULL) OR (CONCAT('.implode(', ', $d_aliases).') IS NOT NULL))';
+                $r .= $r ? $nl.$sub_r1.$nl.'  AND '.$sub_r2 : $sub_r1.$nl.$sub_r2;
+            }
+        }
+
+        return $r ? $nl.'WHERE '.$r : '';
+    }
+
+    public function addConstraintSQLEntry($id, $sql)
+    {
+        if (!isset($this->index['constraints'][$id])) {
+            $this->index['constraints'][$id] = [];
+        }
+        if (!in_array($sql, $this->index['constraints'][$id])) {
+            $this->index['constraints'][$id][] = $sql;
+        }
+    }
+
+    public function getConstraintSQL($id)
+    {
+        $r = '';
+        $nl = "\n";
+        $constraints = $this->v($id, [], $this->index['constraints']);
+        foreach ($constraints as $constraint) {
+            $r .= $r ? $nl.'  AND '.$constraint : $constraint;
         }
+
+        return $r;
+    }
+
+    public function getPatternSQL($pattern, $context)
+    {
+        $type = $this->v('type', '', $pattern);
+        if (!$type) {
+            return '';
+        }
+        $m = 'get'.ucfirst($type).'PatternSQL';
+
+        return method_exists($this, $m) ? $this->$m($pattern, $context) : $this->getDefaultPatternSQL($pattern, $context);
+    }
+
+    public function getDefaultPatternSQL($pattern, $context)
+    {
+        $r = '';
+        $nl = "\n";
+        $sub_ids = $this->v('patterns', [], $pattern);
+        foreach ($sub_ids as $sub_id) {
+            $sub_r = $this->getPatternSQL($this->getPattern($sub_id), $context);
+            $r .= ($r && $sub_r) ? $nl.'  AND ('.$sub_r.')' : ($sub_r ? $sub_r : '');
+        }
+
+        return $r ? $r : '';
+    }
+
+    public function getTriplePatternSQL($pattern, $context)
+    {
+        $r = '';
+        $nl = "\n";
+        $id = $pattern['id'];
+        /* s p o */
+        $vars = [];
+        foreach (['s', 'p', 'o'] as $term) {
+            $sub_r = '';
+            $type = $pattern[$term.'_type'];
+            if ('uri' == $type) {
+                $term_id = $this->getTermID($pattern[$term], $term);
+                $sub_r = '(T_'.$id.'.'.$term.' = '.$term_id.') /* '.preg_replace('/[\#\*\>]/', '::', $pattern[$term]).' */';
+            } elseif ('literal' == $type) {
+                $term_id = $this->getTermID($pattern[$term], $term);
+                $sub_r = '(T_'.$id.'.'.$term.' = '.$term_id.') /* '.preg_replace('/[\#\n\*\>]/', ' ', $pattern[$term]).' */';
+                if (($lang_dt = $this->v1($term.'_lang', '', $pattern)) || ($lang_dt = $this->v1($term.'_datatype', '', $pattern))) {
+                    $lang_dt_id = $this->getTermID($lang_dt);
+                    $sub_r .= $nl.'  AND (T_'.$id.'.'.$term.'_lang_dt = '.$lang_dt_id.') /* '.preg_replace('/[\#\*\>]/', '::', $lang_dt).' */';
+                }
+            } elseif ('var' == $type) {
+                $val = $pattern[$term];
+                if (isset($vars[$val])) {/* repeated var in pattern */
+                    $sub_r = '(T_'.$id.'.'.$term.'='.'T_'.$id.'.'.$vars[$val].')';
+                }
+                $vars[$val] = $term;
+                if ($infos = $this->v($val, 0, $this->index['graph_vars'])) {/* graph var in triple pattern */
+                    $sub_r .= $sub_r ? $nl.'  AND ' : '';
+                    $tbl = $infos[0]['table'];
+                    $sub_r .= 'G_'.$tbl.'.g = T_'.$id.'.'.$term;
+                }
+            }
+            if ($sub_r) {
+                if (preg_match('/^(join)/', $context) || (preg_match('/^where/', $context) && in_array($id, $this->index['from']))) {
+                    $r .= $r ? $nl.'  AND '.$sub_r : $sub_r;
+                }
+            }
+        }
+        /* g */
+        if ($infos = $pattern['graph_infos']) {
+            $tbl_alias = 'G_'.$id.'.g';
+            if (!in_array($tbl_alias, $this->index['sub_joins'])) {
+                $this->index['sub_joins'][] = $tbl_alias;
+            }
+            $sub_r = ['graph_var' => '', 'graph_uri' => '', 'from' => '', 'from_named' => ''];
+            foreach ($infos as $info) {
+                $type = $info['type'];
+                if ('graph' == $type) {
+                    if ($info['uri']) {
+                        $term_id = $this->getTermID($info['uri'], 'g');
+                        $sub_r['graph_uri'] .= $sub_r['graph_uri'] ? $nl.' AND ' : '';
+                        $sub_r['graph_uri'] .= '('.$tbl_alias.' = '.$term_id.') /* '.preg_replace('/[\#\*\>]/', '::', $info['uri']).' */';
+                    }
+                }
+            }
+            if ($sub_r['from'] && $sub_r['from_named']) {
+                $sub_r['from_named'] = '';
+            }
+            if (!$sub_r['from'] && !$sub_r['from_named']) {
+                $sub_r['graph_var'] = '';
+            }
+            if (preg_match('/^(graph_sub_join)/', $context)) {
+                foreach ($sub_r as $g_type => $g_sql) {
+                    if ($g_sql) {
+                        $r .= $r ? $nl.'  AND '.$g_sql : $g_sql;
+                    }
+                }
+            }
+        }
+        /* optional sibling filters? */
+        if (preg_match('/^(join|sub_join)/', $context) && $this->isOptionalPattern($id)) {
+            $o_pattern = $pattern;
+            do {
+                $o_pattern = $this->getPattern($o_pattern['parent_id']);
+            } while ($o_pattern['parent_id'] && ('optional' != $o_pattern['type']));
+            if ($sub_r = $this->getPatternSQL($o_pattern, 'optional_filter'.preg_replace('/^(.*)(__.*)$/', '\\2', $context))) {
+                $r .= $r ? $nl.'  AND '.$sub_r : $sub_r;
+            }
+            /* created constraints */
+            if ($sub_r = $this->getConstraintSQL($id)) {
+                $r .= $r ? $nl.'  AND '.$sub_r : $sub_r;
+            }
+        }
+        /* result */
+        if (preg_match('/^(where)/', $context) && $this->isOptionalPattern($id)) {
+            return '';
+        }
+
+        return $r;
+    }
+
+    public function getFilterPatternSQL($pattern, $context)
+    {
+        $r = '';
+        $id = $pattern['id'];
+        $constraint_id = $this->v1('constraint', '', $pattern);
+        $constraint = $this->getPattern($constraint_id);
+        $constraint_type = $constraint['type'];
+        if ('built_in_call' == $constraint_type) {
+            $r = $this->getBuiltInCallSQL($constraint, $context);
+        } elseif ('expression' == $constraint_type) {
+            $r = $this->getExpressionSQL($constraint, $context, '', 'filter');
+        } else {
+            $m = 'get'.ucfirst($constraint_type).'ExpressionSQL';
+            if (method_exists($this, $m)) {
+                $r = $this->$m($constraint, $context, '', 'filter');
+            }
+        }
+        if ($this->isOptionalPattern($id) && !preg_match('/^(join|optional_filter)/', $context)) {
+            return '';
+        }
+        /* unconnected vars in FILTERs eval to false */
+        $sub_r = $this->hasUnconnectedFilterVars($id);
         if ($sub_r) {
-          $r .= $r ? ' ' . strtoupper($sub_type). ' (' .$sub_r. ')' : '(' . $sub_r . ')';
-        }
-      }
-    }
-    elseif ($sub_type == 'built_in_call') {
-      $r = $this->getBuiltInCallSQL($pattern, $context, $val_type, $parent_type);
-    }
-    elseif (preg_match('/literal/', $sub_type)) {
-      $r = $this->getLiteralExpressionSQL($pattern, $context, $val_type, $parent_type);
-    }
-    elseif ($sub_type) {
-      $m = 'get' . ucfirst($sub_type) . 'ExpressionSQL';
-      if (method_exists($this, $m)) {
-        $r = $this->$m($pattern, $context, '', $parent_type);
-      }
-    }
-    /* skip expressions that reference non-yet-joined tables */
-    if (preg_match('/__(T|V|G)_(.+)$/', $context, $m)) {
-      $context_pattern_id = $m[2];
-      $context_table_type = $m[1];
-      if (preg_match_all('/((T|V|G)(\_[0-9])+)/', $r, $m)) {
-        $aliases = $m[1];
-        $keep = 1;
-        foreach ($aliases as $alias) {
-          if (preg_match('/(T|V|G)_(.*)$/', $alias, $m)) {
-            $tbl_type = $m[1];
-            $tbl = $m[2];
-            if (!$this->isJoinedBefore($tbl, $context_pattern_id)) {
-              $keep = 0;
-            }
-            elseif (($context_pattern_id == $tbl) && preg_match('/(TV)/', $context_table_type . $tbl_type)) {
-              $keep = 0;
-            }
-          }
-        }
-        $r = $keep ? $r : '';
-      }
-    }
-    return $r ? '(' . $r . ')' : $r;
-  }
-  
-  function detectExpressionValueType($pattern_ids) {
-    foreach ($pattern_ids as $id) {
-      $pattern = $this->getPattern($id);
-      $type = $this->v('type', '', $pattern);
-      if (($type == 'literal') && isset($pattern['datatype'])) {
-        if (in_array($pattern['datatype'], array($this->xsd . 'integer', $this->xsd . 'float', $this->xsd . 'double'))) {
-          return 'numeric';
-        }
-      }
-    }
-    return '';
-  }
-
-  /*  */
-
-  function getRelationalExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
-    $r = '';
-    $val_type = $this->detectExpressionValueType($pattern['patterns']);
-    $op = $pattern['operator'];
-    foreach ($pattern['patterns'] as $sub_id) {
-      $sub_pattern = $this->getPattern($sub_id);
-      $sub_pattern['parent_op'] = $op;
-      $sub_type = $sub_pattern['type'];
-      $m = ($sub_type == 'built_in_call') ? 'getBuiltInCallSQL' : 'get' . ucfirst($sub_type) . 'ExpressionSQL';
-      $m = str_replace('ExpressionExpression', 'Expression', $m);
-      $sub_r = method_exists($this, $m) ? $this->$m($sub_pattern, $context, $val_type, 'relational') : '';
-      $r .= $r ? ' ' . $op . ' ' . $sub_r : $sub_r;
-    }
-    return $r ? '(' . $r . ')' : $r;
-  }
-
-  function getAdditiveExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
-    $r = '';
-    $val_type = $this->detectExpressionValueType($pattern['patterns']);
-    foreach ($pattern['patterns'] as $sub_id) {
-      $sub_pattern = $this->getPattern($sub_id);
-      $sub_type = $this->v('type', '', $sub_pattern);
-      $m = ($sub_type == 'built_in_call') ? 'getBuiltInCallSQL' : 'get' . ucfirst($sub_type) . 'ExpressionSQL';
-      $m = str_replace('ExpressionExpression', 'Expression', $m);
-      $sub_r = method_exists($this, $m) ? $this->$m($sub_pattern, $context, $val_type, 'additive') : '';
-      $r .= $r ? ' ' . $sub_r : $sub_r;
-    }
-    return $r;
-  }
-
-  function getMultiplicativeExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
-    $r = '';
-    $val_type = $this->detectExpressionValueType($pattern['patterns']);
-    foreach ($pattern['patterns'] as $sub_id) {
-      $sub_pattern = $this->getPattern($sub_id);
-      $sub_type = $sub_pattern['type'];
-      $m = ($sub_type == 'built_in_call') ? 'getBuiltInCallSQL' : 'get' . ucfirst($sub_type) . 'ExpressionSQL';
-      $m = str_replace('ExpressionExpression', 'Expression', $m);
-      $sub_r = method_exists($this, $m) ? $this->$m($sub_pattern, $context, $val_type, 'multiplicative') : '';
-      $r .= $r ? ' ' . $sub_r : $sub_r;
-    }
-    return $r;
-  }
-
-  /*  */
-
-  function getVarExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
-    $var = $pattern['value'];
-    $info = $this->getVarTableInfos($var);
-    if (!$tbl = $info['table']) {
-      /* might be an aggregate var */
-      $vars = $this->infos['query']['result_vars'];
-      foreach ($vars as $test_var) {
-        if ($test_var['alias'] == $pattern['value']) {
-          return '`' . $pattern['value'] . '`';
-        }
-      }
-      return '';
-    }
-    $col = $info['col'];
-    if (($context == 'order') && ($col == 'o')) {
-      $tbl_alias = 'T_' . $tbl . '.o_comp';
-    }
-    elseif ($context == 'sameterm') {
-      $tbl_alias = 'T_' . $tbl . '.' . $col;
-    }
-    elseif (($parent_type == 'relational') && ($col == 'o') && (preg_match('/[\<\>]/', $this->v('parent_op', '', $pattern)))) {
-      $tbl_alias = 'T_' . $tbl . '.o_comp';
-    }
-    else {
-      $tbl_alias = 'V_' . $tbl . '_' . $col . '.val';
-      if (!in_array($tbl_alias, $this->index['sub_joins'])) {
-        $this->index['sub_joins'][] = $tbl_alias;
-      }
-    }
-    $op = $this->v('operator', '', $pattern);
-    if (preg_match('/^(filter|and)/', $parent_type)) {
-      if ($op == '!') {
-        $r = '(((' . $tbl_alias . ' = 0) AND (CONCAT("1", ' . $tbl_alias . ') != 1))'; /* 0 and no string */
-        $r .= ' OR (' . $tbl_alias . ' IN ("", "false")))'; /* or "", or "false" */
-      }
-      else {
-        $r = '((' . $tbl_alias . ' != 0)'; /* not null */
-        $r .= ' OR ((CONCAT("1", ' . $tbl_alias . ') = 1) AND (' . $tbl_alias . ' NOT IN ("", "false"))))'; /* string, and not "" or "false" */
-      }
-    }
-    else {
-      $r = trim($op . ' ' . $tbl_alias);
-      if ($val_type == 'numeric') {
+            if ('alias' == $sub_r) {
+                if (!in_array($r, $this->index['havings'])) {
+                    $this->index['havings'][] = $r;
+                }
+
+                return '';
+            } elseif (preg_match('/^T([^\s]+\.)g (.*)$/s', $r, $m)) {/* graph filter */
+                return 'G'.$m[1].'t '.$m[2];
+            } elseif (preg_match('/^\(*V[^\s]+_g\.val .*$/s', $r, $m)) {/* graph value filter, @@improveMe */
+        //return $r;
+            } else {
+                return 'FALSE';
+            }
+        }
+        /* some really ugly tweaks */
+        /* empty language filter: FILTER ( lang(?v) = '' ) */
+        $r = preg_replace('/\(\/\* language call \*\/ ([^\s]+) = ""\)/s', '((\\1 = "") OR (\\1 LIKE "%:%"))', $r);
+
+        return $r;
+    }
+
+    /**
+     * Checks if vars in the given (filter) pattern are used within the filter's scope.
+     */
+    public function hasUnconnectedFilterVars($filter_pattern_id)
+    {
+        $scope_id = $this->getFilterScope($filter_pattern_id);
+        $vars = $this->getFilterVars($filter_pattern_id);
+        $r = 0;
+        foreach ($vars as $var_name) {
+            if ($this->isUsedTripleVar($var_name, $scope_id)) {
+                continue;
+            }
+            if ($this->isAliasVar($var_name)) {
+                $r = 'alias';
+                break;
+            }
+            $r = 1;
+            break;
+        }
+
+        return $r;
+    }
+
+    /**
+     * Returns the given filter pattern's scope (the id of the parent group pattern).
+     */
+    public function getFilterScope($filter_pattern_id)
+    {
+        $patterns = $this->initial_index['patterns'];
+        $r = '';
+        foreach ($patterns as $id => $p) {
+            /* the id has to be sub-part of the given filter id */
+            if (!preg_match('/^'.$id.'.+/', $filter_pattern_id)) {
+                continue;
+            }
+            /* we are looking for a group or union */
+            if (!preg_match('/^(group|union)$/', $p['type'])) {
+                continue;
+            }
+            /* we are looking for the longest/deepest match */
+            if (strlen($id) > strlen($r)) {
+                $r = $id;
+            }
+        }
+
+        return $r;
+    }
+
+    /**
+     * Builds a list of vars used in the given (filter) pattern.
+     */
+    public function getFilterVars($filter_pattern_id)
+    {
+        $r = [];
+        $patterns = $this->initial_index['patterns'];
+        /* find vars in the given filter (i.e. the given id is part of their pattern id) */
+        foreach ($patterns as $id => $p) {
+            if (!preg_match('/^'.$filter_pattern_id.'.+/', $id)) {
+                continue;
+            }
+            $var_name = '';
+            if ('var' == $p['type']) {
+                $var_name = $p['value'];
+            } elseif (('built_in_call' == $p['type']) && ('bound' == $p['call'])) {
+                $var_name = $p['args'][0]['value'];
+            }
+            if ($var_name && !in_array($var_name, $r)) {
+                $r[] = $var_name;
+            }
+        }
+
+        return $r;
+    }
+
+    /**
+     * Checks if $var_name appears as result projection alias.
+     */
+    public function isAliasVar($var_name)
+    {
+        foreach ($this->infos['query']['result_vars'] as $r_var) {
+            if ($r_var['alias'] == $var_name) {
+                return 1;
+            }
+        }
+
+        return 0;
+    }
+
+    /**
+     * Checks if $var_name is used in a triple pattern in the given scope.
+     */
+    public function isUsedTripleVar($var_name, $scope_id = '0')
+    {
+        $patterns = $this->initial_index['patterns'];
+        foreach ($patterns as $id => $p) {
+            if ('triple' != $p['type']) {
+                continue;
+            }
+            if (!preg_match('/^'.$scope_id.'.+/', $id)) {
+                continue;
+            }
+            foreach (['s', 'p', 'o'] as $term) {
+                if ('var' != $p[$term.'_type']) {
+                    continue;
+                }
+                if ($p[$term] == $var_name) {
+                    return 1;
+                }
+            }
+        }
+    }
+
+    public function getExpressionSQL($pattern, $context, $val_type = '', $parent_type = '')
+    {
+        $r = '';
+        $nl = "\n";
+        $type = $this->v1('type', '', $pattern);
+        $sub_type = $this->v1('sub_type', $type, $pattern);
+        if (preg_match('/^(and|or)$/', $sub_type)) {
+            foreach ($pattern['patterns'] as $sub_id) {
+                $sub_pattern = $this->getPattern($sub_id);
+                $sub_pattern_type = $sub_pattern['type'];
+                if ('built_in_call' == $sub_pattern_type) {
+                    $sub_r = $this->getBuiltInCallSQL($sub_pattern, $context, '', $parent_type);
+                } else {
+                    $sub_r = $this->getExpressionSQL($sub_pattern, $context, '', $parent_type);
+                }
+                if ($sub_r) {
+                    $r .= $r ? ' '.strtoupper($sub_type).' ('.$sub_r.')' : '('.$sub_r.')';
+                }
+            }
+        } elseif ('built_in_call' == $sub_type) {
+            $r = $this->getBuiltInCallSQL($pattern, $context, $val_type, $parent_type);
+        } elseif (preg_match('/literal/', $sub_type)) {
+            $r = $this->getLiteralExpressionSQL($pattern, $context, $val_type, $parent_type);
+        } elseif ($sub_type) {
+            $m = 'get'.ucfirst($sub_type).'ExpressionSQL';
+            if (method_exists($this, $m)) {
+                $r = $this->$m($pattern, $context, '', $parent_type);
+            }
+        }
+        /* skip expressions that reference non-yet-joined tables */
         if (preg_match('/__(T|V|G)_(.+)$/', $context, $m)) {
-          $context_pattern_id = $m[2];
-          $context_table_type = $m[1];
+            $context_pattern_id = $m[2];
+            $context_table_type = $m[1];
+            if (preg_match_all('/((T|V|G)(\_[0-9])+)/', $r, $m)) {
+                $aliases = $m[1];
+                $keep = 1;
+                foreach ($aliases as $alias) {
+                    if (preg_match('/(T|V|G)_(.*)$/', $alias, $m)) {
+                        $tbl_type = $m[1];
+                        $tbl = $m[2];
+                        if (!$this->isJoinedBefore($tbl, $context_pattern_id)) {
+                            $keep = 0;
+                        } elseif (($context_pattern_id == $tbl) && preg_match('/(TV)/', $context_table_type.$tbl_type)) {
+                            $keep = 0;
+                        }
+                    }
+                }
+                $r = $keep ? $r : '';
+            }
         }
-        else {
-          $context_pattern_id = $pattern['id'];
-          $context_table_type = 'T';
-        }
-        if ($this->isJoinedBefore($tbl, $context_pattern_id)) {
-          $add = ($tbl != $context_pattern_id) ? 1 : 0;
-          $add = (!$add && ($context_table_type == 'V')) ? 1 : 0;
-          if ($add) {
-            $this->addConstraintSQLEntry($context_pattern_id, '(' .$r. ' = "0" OR ' . $r . '*1.0 != 0)');
-          }
-        }
-      }
-    }
-    return $r;
-  }
-  
-  /*  */
-
-  function getUriExpressionSQL($pattern, $context, $val_type = '') {
-    $val = $pattern['uri'];
-    $r = $pattern['operator'];
-    $r .= is_numeric($val) ? ' ' . $val : ' "' . mysql_real_escape_string($val, $this->store->getDBCon()) . '"';
-    return $r;
-  }
-  
-  /*  */
-
-  function getLiteralExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
-    $val = $pattern['value'];
-    $r = $pattern['operator'];
-    if (is_numeric($val) && $this->v('datatype', 0, $pattern)) {
-      $r .= ' ' . $val;
-    }
-    elseif (preg_match('/^(true|false)$/i', $val) && ($this->v1('datatype', '', $pattern) == 'http://www.w3.org/2001/XMLSchema#boolean')) {
-      $r .= ' ' . strtoupper($val);
-    }
-    elseif ($parent_type == 'regex') {
-      $sub_r = mysql_real_escape_string($val, $this->store->getDBCon());
-      $r .= ' "' . preg_replace('/\x5c\x5c/', '\\', $sub_r) . '"';
-    }
-    else {
-      $r .= ' "' . mysql_real_escape_string($val, $this->store->getDBCon()) . '"';
-    }
-    if (($lang_dt = $this->v1('lang', '', $pattern)) || ($lang_dt = $this->v1('datatype', '', $pattern))) {
-      /* try table/alias via var in siblings */
-      if ($var = $this->findSiblingVarExpression($pattern['id'])) {
-        if (isset($this->index['vars'][$var])) {
-          $infos = $this->index['vars'][$var];
-          foreach ($infos as $info) {
-            if ($info['col'] == 'o') {
-              $tbl = $info['table'];
-              $term_id = $this->getTermID($lang_dt);
-              if ($pattern['operator'] != '!=') {
+
+        return $r ? '('.$r.')' : $r;
+    }
+
+    public function detectExpressionValueType($pattern_ids)
+    {
+        foreach ($pattern_ids as $id) {
+            $pattern = $this->getPattern($id);
+            $type = $this->v('type', '', $pattern);
+            if (('literal' == $type) && isset($pattern['datatype'])) {
+                if (in_array($pattern['datatype'], [$this->xsd.'integer', $this->xsd.'float', $this->xsd.'double'])) {
+                    return 'numeric';
+                }
+            }
+        }
+
+        return '';
+    }
+
+    /**
+     * @todo not in use, so remove?
+     */
+    public function getRelationalExpressionSQL($pattern, $context, $val_type = '', $parent_type = '')
+    {
+        $r = '';
+        $val_type = $this->detectExpressionValueType($pattern['patterns']);
+        $op = $pattern['operator'];
+        foreach ($pattern['patterns'] as $sub_id) {
+            $sub_pattern = $this->getPattern($sub_id);
+            $sub_pattern['parent_op'] = $op;
+            $sub_type = $sub_pattern['type'];
+            $m = ('built_in_call' == $sub_type) ? 'getBuiltInCallSQL' : 'get'.ucfirst($sub_type).'ExpressionSQL';
+            $m = str_replace('ExpressionExpression', 'Expression', $m);
+            $sub_r = method_exists($this, $m) ? $this->$m($sub_pattern, $context, $val_type, 'relational') : '';
+            $r .= $r ? ' '.$op.' '.$sub_r : $sub_r;
+        }
+
+        return $r ? '('.$r.')' : $r;
+    }
+
+    /**
+     * @todo not in use, so remove?
+     */
+    public function getAdditiveExpressionSQL($pattern, $context, $val_type = '', $parent_type = '')
+    {
+        $r = '';
+        $val_type = $this->detectExpressionValueType($pattern['patterns']);
+        foreach ($pattern['patterns'] as $sub_id) {
+            $sub_pattern = $this->getPattern($sub_id);
+            $sub_type = $this->v('type', '', $sub_pattern);
+            $m = ('built_in_call' == $sub_type) ? 'getBuiltInCallSQL' : 'get'.ucfirst($sub_type).'ExpressionSQL';
+            $m = str_replace('ExpressionExpression', 'Expression', $m);
+            $sub_r = method_exists($this, $m) ? $this->$m($sub_pattern, $context, $val_type, 'additive') : '';
+            $r .= $r ? ' '.$sub_r : $sub_r;
+        }
+
+        return $r;
+    }
+
+    /**
+     * @todo not in use, so remove?
+     */
+    public function getMultiplicativeExpressionSQL($pattern, $context, $val_type = '', $parent_type = '')
+    {
+        $r = '';
+        $val_type = $this->detectExpressionValueType($pattern['patterns']);
+        foreach ($pattern['patterns'] as $sub_id) {
+            $sub_pattern = $this->getPattern($sub_id);
+            $sub_type = $sub_pattern['type'];
+            $m = ('built_in_call' == $sub_type) ? 'getBuiltInCallSQL' : 'get'.ucfirst($sub_type).'ExpressionSQL';
+            $m = str_replace('ExpressionExpression', 'Expression', $m);
+            $sub_r = method_exists($this, $m) ? $this->$m($sub_pattern, $context, $val_type, 'multiplicative') : '';
+            $r .= $r ? ' '.$sub_r : $sub_r;
+        }
+
+        return $r;
+    }
+
+    public function getVarExpressionSQL($pattern, $context, $val_type = '', $parent_type = '')
+    {
+        $var = $pattern['value'];
+        $info = $this->getVarTableInfos($var);
+
+        $tbl = false;
+        if (isset($info['table'])) {
+            $tbl = $info['table'];
+        }
+
+        if (!$tbl) {
+            /* might be an aggregate var */
+            $vars = $this->infos['query']['result_vars'];
+            foreach ($vars as $test_var) {
+                if ($test_var['alias'] == $pattern['value']) {
+                    return '`'.$pattern['value'].'`';
+                }
+            }
+
+            return '';
+        }
+        $col = $info['col'];
+        if (('order' == $context) && ('o' == $col)) {
+            $tbl_alias = 'T_'.$tbl.'.o_comp';
+        } elseif ('sameterm' == $context) {
+            $tbl_alias = 'T_'.$tbl.'.'.$col;
+        } elseif (('relational' == $parent_type) && ('o' == $col) && (preg_match('/[\<\>]/', $this->v('parent_op', '', $pattern)))) {
+            $tbl_alias = 'T_'.$tbl.'.o_comp';
+        } else {
+            $tbl_alias = 'V_'.$tbl.'_'.$col.'.val';
+            if (!in_array($tbl_alias, $this->index['sub_joins'])) {
+                $this->index['sub_joins'][] = $tbl_alias;
+            }
+        }
+        $op = $this->v('operator', '', $pattern);
+        if (preg_match('/^(filter|and)/', $parent_type)) {
+            if ('!' == $op) {
+                $r = '((('.$tbl_alias.' = 0) AND (CONCAT("1", '.$tbl_alias.') != 1))'; /* 0 and no string */
+                $r .= ' OR ('.$tbl_alias.' IN ("", "false")))'; /* or "", or "false" */
+            } else {
+                $r = '(('.$tbl_alias.' != 0)'; /* not null */
+                $r .= ' OR ((CONCAT("1", '.$tbl_alias.') = 1) AND ('.$tbl_alias.' NOT IN ("", "false"))))'; /* string, and not "" or "false" */
+            }
+        } else {
+            $r = trim($op.' '.$tbl_alias);
+            if ('numeric' == $val_type) {
                 if (preg_match('/__(T|V|G)_(.+)$/', $context, $m)) {
-                  $context_pattern_id = $m[2];
-                  $context_table_type = $m[1];
+                    $context_pattern_id = $m[2];
+                    $context_table_type = $m[1];
+                } else {
+                    $context_pattern_id = $pattern['id'];
+                    $context_table_type = 'T';
                 }
-                elseif ($context == 'where') {
-                  $context_pattern_id = $tbl;
+                if ($this->isJoinedBefore($tbl, $context_pattern_id)) {
+                    $add = ($tbl != $context_pattern_id) ? 1 : 0;
+                    $add = (!$add && ('V' == $context_table_type)) ? 1 : 0;
+                    if ($add) {
+                        $this->addConstraintSQLEntry($context_pattern_id, '('.$r.' = "0" OR '.$r.'*1.0 != 0)');
+                    }
                 }
-                else {
-                  $context_pattern_id = $pattern['id'];
+            }
+        }
+
+        return $r;
+    }
+
+    public function getUriExpressionSQL($pattern, $context, $val_type = '')
+    {
+        $val = $pattern['uri'];
+        $r = $pattern['operator'];
+        $r .= is_numeric($val) ? ' '.$val : ' "'.$this->store->a['db_object']->escape($val).'"';
+
+        return $r;
+    }
+
+    public function getLiteralExpressionSQL($pattern, $context, $val_type = '', $parent_type = '')
+    {
+        $val = $pattern['value'];
+        $r = $pattern['operator'];
+        if (is_numeric($val) && $this->v('datatype', 0, $pattern)) {
+            $r .= ' '.$val;
+        } elseif (preg_match('/^(true|false)$/i', $val) && ('http://www.w3.org/2001/XMLSchema#boolean' == $this->v1('datatype', '', $pattern))) {
+            $r .= ' '.strtoupper($val);
+        } elseif ('regex' == $parent_type) {
+            $sub_r = $this->store->a['db_object']->escape($val);
+            $r .= ' "'.preg_replace('/\x5c\x5c/', '\\', $sub_r).'"';
+        } else {
+            $r .= ' "'.$this->store->a['db_object']->escape($val).'"';
+        }
+        if (($lang_dt = $this->v1('lang', '', $pattern)) || ($lang_dt = $this->v1('datatype', '', $pattern))) {
+            /* try table/alias via var in siblings */
+            if ($var = $this->findSiblingVarExpression($pattern['id'])) {
+                if (isset($this->index['vars'][$var])) {
+                    $infos = $this->index['vars'][$var];
+                    foreach ($infos as $info) {
+                        if ('o' == $info['col']) {
+                            $tbl = $info['table'];
+                            $term_id = $this->getTermID($lang_dt);
+                            if ('!=' != $pattern['operator']) {
+                                if (preg_match('/__(T|V|G)_(.+)$/', $context, $m)) {
+                                    $context_pattern_id = $m[2];
+                                    $context_table_type = $m[1];
+                                } elseif ('where' == $context) {
+                                    $context_pattern_id = $tbl;
+                                } else {
+                                    $context_pattern_id = $pattern['id'];
+                                }
+                                // TODO better dependency check
+                                if ($tbl == $context_pattern_id) {
+                                    if ($term_id || ('http://www.w3.org/2001/XMLSchema#integer' != $lang_dt)) {
+                                        /* skip, if simple int, but no id */
+                                        $this->addConstraintSQLEntry($context_pattern_id, 'T_'.$tbl.'.o_lang_dt = '.$term_id.' /* '.preg_replace('/[\#\*\>]/', '::', $lang_dt).' */');
+                                    }
+                                }
+                            }
+                            break;
+                        }
+                    }
                 }
-                if ($tbl == $context_pattern_id) {/* @todo better dependency check */
-                  if ($term_id || ($lang_dt != 'http://www.w3.org/2001/XMLSchema#integer')) {/* skip if simple int, but no id */
-                    $this->addConstraintSQLEntry($context_pattern_id, 'T_' . $tbl . '.o_lang_dt = ' . $term_id . ' /* ' . str_replace('#' , '::', $lang_dt) . ' */');
-                  }
+            }
+        }
+
+        return trim($r);
+    }
+
+    public function findSiblingVarExpression($id)
+    {
+        $pattern = $this->getPattern($id);
+        do {
+            $pattern = $this->getPattern($pattern['parent_id']);
+        } while ($pattern['parent_id'] && ('expression' != $pattern['type']));
+        $sub_patterns = $this->v('patterns', [], $pattern);
+        foreach ($sub_patterns as $sub_id) {
+            $sub_pattern = $this->getPattern($sub_id);
+            if ('var' == $sub_pattern['type']) {
+                return $sub_pattern['value'];
+            }
+        }
+
+        return '';
+    }
+
+    public function getFunctionExpressionSQL($pattern, $context, $val_type = '', $parent_type = '')
+    {
+        $fnc_uri = $pattern['uri'];
+        $op = $this->v('operator', '', $pattern);
+        if ($op) {
+            $op .= ' ';
+        }
+        if ($this->allow_extension_functions) {
+            /* mysql functions */
+            if (preg_match('/^http\:\/\/web\-semantics\.org\/ns\/mysql\/(.*)$/', $fnc_uri, $m)) {
+                $fnc_name = strtoupper($m[1]);
+                $sub_r = '';
+                foreach ($pattern['args'] as $arg) {
+                    $sub_r .= $sub_r ? ', ' : '';
+                    $sub_r .= $this->getExpressionSQL($arg, $context, $val_type, $parent_type);
                 }
-              }
-              break;
-            }
-          }
-        }
-      }
-    }
-    return trim($r);
-  }
-  
-  function findSiblingVarExpression($id) {
-    $pattern = $this->getPattern($id);
-    do {
-      $pattern = $this->getPattern($pattern['parent_id']);
-    } while ($pattern['parent_id'] && ($pattern['type'] != 'expression'));
-    $sub_patterns = $this->v('patterns', array(), $pattern);
-    foreach ($sub_patterns as $sub_id) {
-      $sub_pattern = $this->getPattern($sub_id);
-      if ($sub_pattern['type'] == 'var') {
-        return $sub_pattern['value'];
-      }
-    }
-    return '';
-  }
-  
-  /*  */
-
-  function getFunctionExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
-    $fnc_uri = $pattern['uri'];
-    $op = $this->v('operator', '', $pattern);
-    if ($op) $op .= ' ';
-    if ($this->allow_extension_functions) {
-      /* mysql functions */
-      if (preg_match('/^http\:\/\/web\-semantics\.org\/ns\/mysql\/(.*)$/', $fnc_uri, $m)) {
-        $fnc_name = strtoupper($m[1]);
-        $sub_r = '';
-        foreach ($pattern['args'] as $arg) {
-          $sub_r .= $sub_r ? ', ' : '';
-          $sub_r .= $this->getExpressionSQL($arg, $context, $val_type, $parent_type);
-        }
-        return $op . $fnc_name . '(' . $sub_r . ')';
-      }
-      /* any other: ignore */
-    }
-    /* simple type conversions */
-    if (strpos($fnc_uri, 'http://www.w3.org/2001/XMLSchema#') === 0) {
-      return $op . $this->getExpressionSQL($pattern['args'][0], $context, $val_type, $parent_type);
-    }
-    return '';
-  }
-
-  /*  */
-
-  function getBuiltInCallSQL($pattern, $context) {
-    $call = $pattern['call'];
-    $m = 'get' . ucfirst($call) . 'CallSQL';
-    if (method_exists($this, $m)) {
-      return $this->$m($pattern, $context);
-    }
-    else {
-      $this->addError('Unknown built-in call "' . $call . '"');
-    }
-    return '';
-  }
-  
-  function getBoundCallSQL($pattern, $context) {
-    $r = '';
-    $var = $pattern['args'][0]['value'];
-    $info = $this->getVarTableInfos($var);
-    if (!$tbl = $info['table']) {
-      return '';
-    }
-    $col = $info['col'];
-    $tbl_alias = 'T_' . $tbl . '.' . $col;
-    if ($pattern['operator'] == '!') {
-      return $tbl_alias . ' IS NULL';
-    }
-    return $tbl_alias . ' IS NOT NULL';
-  }
-
-  function getHasTypeCallSQL($pattern, $context, $type) {
-    $r = '';
-    $var = $pattern['args'][0]['value'];
-    $info = $this->getVarTableInfos($var);
-    if (!$tbl = $info['table']) {
-      return '';
-    }
-    $col = $info['col'];
-    $tbl_alias = 'T_' . $tbl . '.' . $col . '_type';
-    return $tbl_alias . ' ' .$this->v('operator', '', $pattern) . '= ' . $type;
-  }
-
-  function getIsliteralCallSQL($pattern, $context) {
-    return $this->getHasTypeCallSQL($pattern, $context, 2);
-  }
-
-  function getIsblankCallSQL($pattern, $context) {
-    return $this->getHasTypeCallSQL($pattern, $context, 1);
-  }
-
-  function getIsiriCallSQL($pattern, $context) {
-    return $this->getHasTypeCallSQL($pattern, $context, 0);
-  }
-
-  function getIsuriCallSQL($pattern, $context) {
-    return $this->getHasTypeCallSQL($pattern, $context, 0);
-  }
-
-  function getStrCallSQL($pattern, $context) {
-    $sub_pattern = $pattern['args'][0];
-    $sub_type = $sub_pattern['type'];
-    $m = 'get' . ucfirst($sub_type) . 'ExpressionSQL';
-    if (method_exists($this, $m)) {
-      return $this->$m($sub_pattern, $context);
-    }
-  }
-  
-  function getFunctionCallSQL($pattern, $context) {
-    $f_uri = $pattern['uri'];
-    if (preg_match('/(integer|double|float|string)$/', $f_uri)) {/* skip conversions */
-      $sub_pattern = $pattern['args'][0];
-      $sub_type = $sub_pattern['type'];
-      $m = 'get' . ucfirst($sub_type) . 'ExpressionSQL';
-      if (method_exists($this, $m)) {
-        return $this->$m($sub_pattern, $context);
-      }
-    }
-  }
-  
-  function getLangDatatypeCallSQL($pattern, $context) {
-    $r = '';
-    if (isset($pattern['patterns'])) { /* proceed with first argument only (assumed as base type for type promotion) */
-      $sub_pattern = array('args' => array($pattern['patterns'][0]));
-      return $this->getLangDatatypeCallSQL($sub_pattern, $context);
-    }
-    if (!isset($pattern['args'])) {
-      return 'FALSE';
-    }
-    $sub_type = $pattern['args'][0]['type'];
-    if ($sub_type != 'var') {
-      return $this->getLangDatatypeCallSQL($pattern['args'][0], $context);
-    }
-    $var = $pattern['args'][0]['value'];
-    $info = $this->getVarTableInfos($var);
-    if (!$tbl = $info['table']) {
-      return '';
-    }
-    $col = 'o_lang_dt';
-    $tbl_alias = 'V_' . $tbl . '_' . $col . '.val';
-    if (!in_array($tbl_alias, $this->index['sub_joins'])) {
-      $this->index['sub_joins'][] = $tbl_alias;
-    }
-    $op = $this->v('operator', '', $pattern);
-    $r = trim($op . ' ' . $tbl_alias);
-    return $r;
-  }
-
-  function getDatatypeCallSQL($pattern, $context) {
-    return '/* datatype call */ ' . $this->getLangDatatypeCallSQL($pattern, $context);
-  }
-
-  function getLangCallSQL($pattern, $context) {
-    return '/* language call */ ' . $this->getLangDatatypeCallSQL($pattern, $context);
-  }
-  
-  function getLangmatchesCallSQL($pattern, $context) {
-    if (count($pattern['args']) == 2) {
-      $arg_1 = $pattern['args'][0];
-      $arg_2 = $pattern['args'][1];
-      $sub_r_1 = $this->getBuiltInCallSQL($arg_1, $context);/* adds value join */
-      $sub_r_2 = $this->getExpressionSQL($arg_2, $context);
-      $op = $this->v('operator', '', $pattern);
-      if (preg_match('/^([\"\'])([^\'\"]+)/', $sub_r_2, $m)) {
-        if ($m[2] == '*') {
-          $r = ($op == '!') ? 'NOT (' . $sub_r_1 . ' REGEXP "^[a-zA-Z\-]+$"' . ')' : $sub_r_1 . ' REGEXP "^[a-zA-Z\-]+$"';
+
+                return $op.$fnc_name.'('.$sub_r.')';
+            }
+            /* any other: ignore */
         }
-        else {
-          $r = ($op == '!') ? $sub_r_1 . ' NOT LIKE ' . $m[1] . $m[2] . '%' . $m[1] : $sub_r_1 . ' LIKE ' . $m[1] . $m[2] . '%' . $m[1];
-        }
-      }
-      else {
-        $r = ($op == '!') ? $sub_r_1 . ' NOT LIKE CONCAT(' . $sub_r_2 . ', "%")' : $sub_r_1 . ' LIKE CONCAT(' . $sub_r_2 . ', "%")';
-      }
-      return $r;
-    }
-    return '';
-  }
-  
-  function getSametermCallSQL($pattern, $context) {
-    if (count($pattern['args']) == 2) {
-      $arg_1 = $pattern['args'][0];
-      $arg_2 = $pattern['args'][1];
-      $sub_r_1 = $this->getExpressionSQL($arg_1, 'sameterm');
-      $sub_r_2 = $this->getExpressionSQL($arg_2, 'sameterm');
-      $op = $this->v('operator', '', $pattern);
-      $r = $sub_r_1 . ' ' . $op . '= ' . $sub_r_2; 
-      return $r;
-    }
-    return '';
-  }
-  
-  function getRegexCallSQL($pattern, $context) {
-    $ac = count($pattern['args']);
-    if ($ac >= 2) {
-      foreach ($pattern['args'] as $i => $arg) {
-        $var = 'sub_r_' . ($i + 1);
-        $$var = $this->getExpressionSQL($arg, $context, '', 'regex');
-      }
-      $sub_r_3 = (isset($sub_r_3) && preg_match('/[\"\'](.+)[\"\']/', $sub_r_3, $m)) ? strtolower($m[1]) : '';
-      $op = ($this->v('operator', '', $pattern) == '!') ? ' NOT' : '';
-      if (!$sub_r_1 || !$sub_r_2) return '';
-      $is_simple_search = preg_match('/^[\(\"]+(\^)?([a-z0-9\_\-\s]+)(\$)?[\)\"]+$/is', $sub_r_2, $m);
-      $is_simple_search = preg_match('/^[\(\"]+(\^)?([^\\\*\[\]\}\{\(\)\"\'\?\+\.]+)(\$)?[\)\"]+$/is', $sub_r_2, $m);
-      $is_o_search = preg_match('/o\.val\)*$/', $sub_r_1);
-      /* fulltext search (may have "|") */
-      if ($is_simple_search && $is_o_search && !$op && (strlen($m[2]) > 8) && $this->store->hasFulltextIndex()) {
-        /* MATCH variations */
-        if (($val_parts = preg_split('/\|/', $m[2]))) {
-          return 'MATCH(' . trim($sub_r_1, '()') . ') AGAINST("' . join(' ', $val_parts) . '")';
+        /* simple type conversions */
+        if (0 === strpos($fnc_uri, 'http://www.w3.org/2001/XMLSchema#')) {
+            return $op.$this->getExpressionSQL($pattern['args'][0], $context, $val_type, $parent_type);
         }
-        else {
-          return 'MATCH(' . trim($sub_r_1, '()') . ') AGAINST("' . $m[2] . '")';
-        }
-      }
-      if (preg_match('/\|/', $sub_r_2)) $is_simple_search = 0;
-      /* LIKE */
-      if ($is_simple_search && ($sub_r_3 == 'i')) {
-        $sub_r_2 = $m[1] ? $m[2] : '%' . $m[2];
-        $sub_r_2 .= isset($m[3]) && $m[3] ? '' : '%';
-        return $sub_r_1 . $op . ' LIKE "' . $sub_r_2 . '"';
-      }
-      /* REGEXP */
-      $opt = ($sub_r_3 == 'i') ? '' : 'BINARY ';
-      return $sub_r_1 . $op . ' REGEXP ' . $opt . $sub_r_2;
-    }
-    return '';
-  }
-  
-  /*  */
-
-  function getGROUPSQL() {
-    $r = '';
-    $nl = "\n";
-    $infos = $this->v('group_infos', array(), $this->infos['query']);
-    foreach ($infos as $info) {
-      $var = $info['value'];
-      if ($tbl_infos = $this->getVarTableInfos($var, 0)) {
-        $tbl_alias = $tbl_infos['table_alias'];
-        $r .= $r ? ', ' : 'GROUP BY '; 
-        $r .= $tbl_alias;
-      }
-    }
-    $hr = '';
-    foreach ($this->index['havings'] as $having) {
-      $hr .= $hr ? ' AND' : ' HAVING';
-      $hr .= '(' . $having . ')';
-    }
-    $r .= $hr;
-    return $r ? $nl . $r : $r;
-  }
-  
-  /*  */
-  
-  function getORDERSQL() {
-    $r = '';
-    $nl = "\n";
-    $infos = $this->v('order_infos', array(), $this->infos['query']);
-    foreach ($infos as $info) {
-      $type = $info['type'];
-      $ms = array('expression' => 'getExpressionSQL', 'built_in_call' => 'getBuiltInCallSQL', 'function_call' => 'getFunctionCallSQL');
-      $m = isset($ms[$type]) ? $ms[$type] : 'get' . ucfirst($type) . 'ExpressionSQL';
-      if (method_exists($this, $m)) {
-        $sub_r = '(' . $this->$m($info, 'order') . ')';
-        $sub_r .= $this->v('direction', '', $info) == 'desc' ? ' DESC' : '';
-        $r .= $r ? ',' .$nl . $sub_r : $sub_r;
-      }
-    }
-    return $r ? $nl . 'ORDER BY ' . $r : '';
-  }
-  
-  /*  */
-  
-  function getLIMITSQL() {
-    $r = '';
-    $nl = "\n";
-    $limit = $this->v('limit', -1, $this->infos['query']);
-    $offset = $this->v('offset', -1, $this->infos['query']);
-    if ($limit != -1) {
-      $offset = ($offset == -1) ? 0 : mysql_real_escape_string($offset, $this->store->getDBCon());
-      $r = 'LIMIT ' . $offset . ',' . $limit; 
-    }
-    elseif ($offset != -1) {
-      $r = 'LIMIT ' . mysql_real_escape_string($offset, $this->store->getDBCon()) . ',999999999999'; /* mysql doesn't support stand-alone offsets .. */
-    }
-    return $r ? $nl . $r : '';
-  }
-
-  /*  */
-  
-  function getValueSQL($q_tbl, $q_sql) {
-    $r = '';
-    /* result vars */
-    $vars = $this->infos['query']['result_vars'];
-    $nl = "\n";
-    $v_tbls = array('JOIN' => array(), 'LEFT JOIN' => array());
-    $vc = 1;
-    foreach ($vars as $var) {
-      $var_name = $var['var'];
-      $r .= $r ? ',' . $nl . '  ' : '  ';
-      $col = '';
-      $tbl = '';
-      if ($var_name != '*') {
-        if (in_array($var_name, $this->infos['null_vars'])) {
-          if (isset($this->initial_index['vars'][$var_name])) {
-            $col = $this->initial_index['vars'][$var_name][0]['col'];
-            $tbl = $this->initial_index['vars'][$var_name][0]['table'];
-          }
-          if (isset($this->initial_index['graph_vars'][$var_name])) {
-            $col = 'g';
-            $tbl = $this->initial_index['graph_vars'][$var_name][0]['table'];
-          }
-        }
-        elseif (isset($this->index['vars'][$var_name])) {
-          $col = $this->index['vars'][$var_name][0]['col'];
-          $tbl = $this->index['vars'][$var_name][0]['table'];
-        }
-      }
-      if ($var['aggregate']) {
-        $r .= 'TMP.`' . $var['alias'] . '`';
-      }
-      else {
-        $join_type = in_array($tbl, array_merge($this->index['from'], $this->index['join'])) ? 'JOIN' : 'LEFT JOIN';/* val may be NULL */
-        $v_tbls[$join_type][] = array('t_col' => $col, 'q_col' => $var_name, 'vc' => $vc);
-        $r .= 'V' . $vc . '.val AS `' . $var_name . '`';
-        if (in_array($col, array('s', 'o'))) {
-          if (strpos($q_sql, '`' . $var_name . ' type`')) {
-            $r .= ', ' . $nl . '    TMP.`' . $var_name . ' type` AS `' . $var_name . ' type`';
-            //$r .= ', ' . $nl . '    CASE TMP.`' . $var_name . ' type` WHEN 2 THEN "literal" WHEN 1 THEN "bnode" ELSE "uri" END AS `' . $var_name . ' type`';
-          }
-          else {
-            $r .= ', ' . $nl . '    NULL AS `' . $var_name . ' type`';
-          }
-        }
-        $vc++;
-        if ($col == 'o') {
-          $v_tbls[$join_type][] = array('t_col' => 'id', 'q_col' => $var_name . ' lang_dt', 'vc' => $vc);
-          if (strpos($q_sql, '`' . $var_name . ' lang_dt`')) {
-            $r .= ', ' .$nl. '    V' . $vc . '.val AS `' . $var_name . ' lang_dt`';
-            $vc++;
-          }
-          else {
-            $r .= ', ' .$nl. '    NULL AS `' . $var_name . ' lang_dt`';
-          }
-        }
-      }
-    }
-    if (!$r) $r = '*';
-    /* from */
-    $r .= $nl . 'FROM (' . $q_tbl . ' TMP)';
-    foreach (array('JOIN', 'LEFT JOIN') as $join_type) {
-      foreach ($v_tbls[$join_type] as $v_tbl) {
-        $tbl = $this->getValueTable($v_tbl['t_col']);
-        $var_name = preg_replace('/^([^\s]+)(.*)$/', '\\1', $v_tbl['q_col']);
-        $cur_join_type = in_array($var_name, $this->infos['null_vars']) ? 'LEFT JOIN' : $join_type;
-        if (!strpos($q_sql, '`' . $v_tbl['q_col'].'`')) continue;
-        $r .= $nl . ' ' . $cur_join_type . ' ' . $tbl . ' V' . $v_tbl['vc'] . ' ON (
-            (V' . $v_tbl['vc'] . '.id = TMP.`' . $v_tbl['q_col'].'`)
-        )';
-      }
+
+        return '';
     }
-    /* create pos columns, id needed */
-    if ($this->v('order_infos', array(), $this->infos['query'])) {
-      $r .= $nl . ' ORDER BY _pos_';
+
+    public function getBuiltInCallSQL($pattern, $context)
+    {
+        $call = $pattern['call'];
+        $m = 'get'.ucfirst($call).'CallSQL';
+        if (method_exists($this, $m)) {
+            return $this->$m($pattern, $context);
+        } else {
+            $this->addError('Unknown built-in call "'.$call.'"');
+        }
+
+        return '';
     }
-    return 'SELECT' . $nl . $r;
-  }
-  
-  /*  */
 
-}
+    public function getBoundCallSQL($pattern, $context)
+    {
+        $r = '';
+        $var = $pattern['args'][0]['value'];
+        $info = $this->getVarTableInfos($var);
+        if (!$tbl = $info['table']) {
+            return '';
+        }
+        $col = $info['col'];
+        $tbl_alias = 'T_'.$tbl.'.'.$col;
+        if ('!' == $pattern['operator']) {
+            return $tbl_alias.' IS NULL';
+        }
 
+        return $tbl_alias.' IS NOT NULL';
+    }
+
+    public function getHasTypeCallSQL($pattern, $context, $type)
+    {
+        $r = '';
+        $var = $pattern['args'][0]['value'];
+        $info = $this->getVarTableInfos($var);
+        if (!$tbl = $info['table']) {
+            return '';
+        }
+        $col = $info['col'];
+        $tbl_alias = 'T_'.$tbl.'.'.$col.'_type';
+
+        return $tbl_alias.' '.$this->v('operator', '', $pattern).'= '.$type;
+    }
+
+    public function getIsliteralCallSQL($pattern, $context)
+    {
+        return $this->getHasTypeCallSQL($pattern, $context, 2);
+    }
 
+    public function getIsblankCallSQL($pattern, $context)
+    {
+        return $this->getHasTypeCallSQL($pattern, $context, 1);
+    }
+
+    public function getIsiriCallSQL($pattern, $context)
+    {
+        return $this->getHasTypeCallSQL($pattern, $context, 0);
+    }
+
+    public function getIsuriCallSQL($pattern, $context)
+    {
+        return $this->getHasTypeCallSQL($pattern, $context, 0);
+    }
+
+    public function getStrCallSQL($pattern, $context)
+    {
+        $sub_pattern = $pattern['args'][0];
+        $sub_type = $sub_pattern['type'];
+        $m = 'get'.ucfirst($sub_type).'ExpressionSQL';
+        if (method_exists($this, $m)) {
+            return $this->$m($sub_pattern, $context);
+        }
+    }
+
+    public function getFunctionCallSQL($pattern, $context)
+    {
+        $f_uri = $pattern['uri'];
+        if (preg_match('/(integer|double|float|string)$/', $f_uri)) {/* skip conversions */
+            $sub_pattern = $pattern['args'][0];
+            $sub_type = $sub_pattern['type'];
+            $m = 'get'.ucfirst($sub_type).'ExpressionSQL';
+            if (method_exists($this, $m)) {
+                return $this->$m($sub_pattern, $context);
+            }
+        }
+    }
+
+    public function getLangDatatypeCallSQL($pattern, $context)
+    {
+        $r = '';
+        if (isset($pattern['patterns'])) { /* proceed with first argument only (assumed as base type for type promotion) */
+            $sub_pattern = ['args' => [$pattern['patterns'][0]]];
+
+            return $this->getLangDatatypeCallSQL($sub_pattern, $context);
+        }
+        if (!isset($pattern['args'])) {
+            return 'FALSE';
+        }
+        $sub_type = $pattern['args'][0]['type'];
+        if ('var' != $sub_type) {
+            return $this->getLangDatatypeCallSQL($pattern['args'][0], $context);
+        }
+        $var = $pattern['args'][0]['value'];
+        $info = $this->getVarTableInfos($var);
+        if (!$tbl = $info['table']) {
+            return '';
+        }
+        $col = 'o_lang_dt';
+        $tbl_alias = 'V_'.$tbl.'_'.$col.'.val';
+        if (!in_array($tbl_alias, $this->index['sub_joins'])) {
+            $this->index['sub_joins'][] = $tbl_alias;
+        }
+        $op = $this->v('operator', '', $pattern);
+        $r = trim($op.' '.$tbl_alias);
+
+        return $r;
+    }
+
+    public function getDatatypeCallSQL($pattern, $context)
+    {
+        return '/* datatype call */ '.$this->getLangDatatypeCallSQL($pattern, $context);
+    }
+
+    public function getLangCallSQL($pattern, $context)
+    {
+        return '/* language call */ '.$this->getLangDatatypeCallSQL($pattern, $context);
+    }
+
+    public function getLangmatchesCallSQL($pattern, $context)
+    {
+        if (2 == count($pattern['args'])) {
+            $arg_1 = $pattern['args'][0];
+            $arg_2 = $pattern['args'][1];
+            $sub_r_1 = $this->getBuiltInCallSQL($arg_1, $context); /* adds value join */
+            $sub_r_2 = $this->getExpressionSQL($arg_2, $context);
+            $op = $this->v('operator', '', $pattern);
+            if (preg_match('/^([\"\'])([^\'\"]+)/', $sub_r_2, $m)) {
+                if ('*' == $m[2]) {
+                    $r = ('!' == $op) ? 'NOT ('.$sub_r_1.' REGEXP "^[a-zA-Z\-]+$"'.')' : $sub_r_1.' REGEXP "^[a-zA-Z\-]+$"';
+                } else {
+                    $r = ('!' == $op) ? $sub_r_1.' NOT LIKE '.$m[1].$m[2].'%'.$m[1] : $sub_r_1.' LIKE '.$m[1].$m[2].'%'.$m[1];
+                }
+            } else {
+                $r = ('!' == $op) ? $sub_r_1.' NOT LIKE CONCAT('.$sub_r_2.', "%")' : $sub_r_1.' LIKE CONCAT('.$sub_r_2.', "%")';
+            }
+
+            return $r;
+        }
+
+        return '';
+    }
+
+    /**
+     * @todo not in use, so remove?
+     */
+    public function getSametermCallSQL($pattern, $context)
+    {
+        if (2 == count($pattern['args'])) {
+            $arg_1 = $pattern['args'][0];
+            $arg_2 = $pattern['args'][1];
+            $sub_r_1 = $this->getExpressionSQL($arg_1, 'sameterm');
+            $sub_r_2 = $this->getExpressionSQL($arg_2, 'sameterm');
+            $op = $this->v('operator', '', $pattern);
+            $r = $sub_r_1.' '.$op.'= '.$sub_r_2;
+
+            return $r;
+        }
+
+        return '';
+    }
+
+    public function getRegexCallSQL($pattern, $context)
+    {
+        $ac = count($pattern['args']);
+        if ($ac >= 2) {
+            foreach ($pattern['args'] as $i => $arg) {
+                $var = 'sub_r_'.($i + 1);
+                $$var = $this->getExpressionSQL($arg, $context, '', 'regex');
+            }
+            $sub_r_3 = (isset($sub_r_3) && preg_match('/[\"\'](.+)[\"\']/', $sub_r_3, $m)) ? strtolower($m[1]) : '';
+            $op = ('!' == $this->v('operator', '', $pattern)) ? ' NOT' : '';
+            if (!$sub_r_1 || !$sub_r_2) {
+                return '';
+            }
+            $is_simple_search = preg_match('/^[\(\"]+(\^)?([a-z0-9\_\-\s]+)(\$)?[\)\"]+$/is', $sub_r_2, $m);
+            $is_simple_search = preg_match('/^[\(\"]+(\^)?([^\\\*\[\]\}\{\(\)\"\'\?\+\.]+)(\$)?[\)\"]+$/is', $sub_r_2, $m);
+            $is_o_search = preg_match('/o\.val\)*$/', $sub_r_1);
+            /* fulltext search (may have "|") */
+            if ($is_simple_search && $is_o_search && !$op && (strlen($m[2]) > 8) && $this->store->hasFulltextIndex()) {
+                /* MATCH variations */
+                if (($val_parts = preg_split('/\|/', $m[2]))) {
+                    return 'MATCH('.trim($sub_r_1, '()').') AGAINST("'.implode(' ', $val_parts).'")';
+                } else {
+                    return 'MATCH('.trim($sub_r_1, '()').') AGAINST("'.$m[2].'")';
+                }
+            }
+            if (preg_match('/\|/', $sub_r_2)) {
+                $is_simple_search = 0;
+            }
+            /* LIKE */
+            if ($is_simple_search && ('i' == $sub_r_3)) {
+                $sub_r_2 = $m[1] ? $m[2] : '%'.$m[2];
+                $sub_r_2 .= isset($m[3]) && $m[3] ? '' : '%';
+
+                return $sub_r_1.$op.' LIKE "'.$sub_r_2.'"';
+            }
+            /* REGEXP */
+            $opt = ('i' == $sub_r_3) ? '' : 'BINARY ';
+
+            return $sub_r_1.$op.' REGEXP '.$opt.$sub_r_2;
+        }
+
+        return '';
+    }
+
+    public function getGROUPSQL()
+    {
+        $r = '';
+        $nl = "\n";
+        $infos = $this->v('group_infos', [], $this->infos['query']);
+        foreach ($infos as $info) {
+            $var = $info['value'];
+            if ($tbl_infos = $this->getVarTableInfos($var, 0)) {
+                $tbl_alias = $tbl_infos['table_alias'];
+                $r .= $r ? ', ' : 'GROUP BY ';
+                $r .= $tbl_alias;
+            }
+        }
+        $hr = '';
+        foreach ($this->index['havings'] as $having) {
+            $hr .= $hr ? ' AND' : ' HAVING';
+            $hr .= '('.$having.')';
+        }
+        $r .= $hr;
+
+        return $r ? $nl.$r : $r;
+    }
+
+    public function getORDERSQL()
+    {
+        $r = '';
+        $nl = "\n";
+        $infos = $this->v('order_infos', [], $this->infos['query']);
+        foreach ($infos as $info) {
+            $type = $info['type'];
+            $ms = ['expression' => 'getExpressionSQL', 'built_in_call' => 'getBuiltInCallSQL', 'function_call' => 'getFunctionCallSQL'];
+            $m = isset($ms[$type]) ? $ms[$type] : 'get'.ucfirst($type).'ExpressionSQL';
+            if (method_exists($this, $m)) {
+                $sub_r = '('.$this->$m($info, 'order').')';
+                $sub_r .= 'desc' == $this->v('direction', '', $info) ? ' DESC' : '';
+                $r .= $r ? ','.$nl.$sub_r : $sub_r;
+            }
+        }
+
+        return $r ? $nl.'ORDER BY '.$r : '';
+    }
+
+    public function getLIMITSQL()
+    {
+        $r = '';
+        $nl = "\n";
+        $limit = $this->v('limit', -1, $this->infos['query']);
+        $offset = $this->v('offset', -1, $this->infos['query']);
+        if ($limit != -1) {
+            $offset = ($offset == -1) ? 0 : $this->store->a['db_object']->escape($offset);
+            $r = 'LIMIT '.$offset.','.$limit;
+        } elseif ($offset != -1) {
+            // mysql doesn't support stand-alone offsets
+            $r = 'LIMIT '.$this->store->a['db_object']->escape($offset).',999999999999';
+        }
+
+        return $r ? $nl.$r : '';
+    }
+
+    public function getValueSQL($q_tbl, $q_sql)
+    {
+        $r = '';
+        /* result vars */
+        $vars = $this->infos['query']['result_vars'];
+        $nl = "\n";
+        $v_tbls = ['JOIN' => [], 'LEFT JOIN' => []];
+        $vc = 1;
+        foreach ($vars as $var) {
+            $var_name = $var['var'];
+            $r .= $r ? ','.$nl.'  ' : '  ';
+            $col = '';
+            $tbl = '';
+            if ('*' != $var_name) {
+                if (in_array($var_name, $this->infos['null_vars'])) {
+                    if (isset($this->initial_index['vars'][$var_name])) {
+                        $col = $this->initial_index['vars'][$var_name][0]['col'];
+                        $tbl = $this->initial_index['vars'][$var_name][0]['table'];
+                    }
+                    if (isset($this->initial_index['graph_vars'][$var_name])) {
+                        $col = 'g';
+                        $tbl = $this->initial_index['graph_vars'][$var_name][0]['table'];
+                    }
+                } elseif (isset($this->index['vars'][$var_name])) {
+                    $col = $this->index['vars'][$var_name][0]['col'];
+                    $tbl = $this->index['vars'][$var_name][0]['table'];
+                }
+            }
+            if ($var['aggregate']) {
+                $r .= 'TMP.`'.$var['alias'].'`';
+            } else {
+                $join_type = in_array($tbl, array_merge($this->index['from'], $this->index['join'])) ? 'JOIN' : 'LEFT JOIN'; /* val may be NULL */
+                $v_tbls[$join_type][] = ['t_col' => $col, 'q_col' => $var_name, 'vc' => $vc];
+                $r .= 'V'.$vc.'.val AS `'.$var_name.'`';
+                if (in_array($col, ['s', 'o'])) {
+                    if (strpos($q_sql, '`'.$var_name.' type`')) {
+                        $r .= ', '.$nl.'    TMP.`'.$var_name.' type` AS `'.$var_name.' type`';
+                    //$r .= ', ' . $nl . '    CASE TMP.`' . $var_name . ' type` WHEN 2 THEN "literal" WHEN 1 THEN "bnode" ELSE "uri" END AS `' . $var_name . ' type`';
+                    } else {
+                        $r .= ', '.$nl.'    NULL AS `'.$var_name.' type`';
+                    }
+                }
+                ++$vc;
+                if ('o' == $col) {
+                    $v_tbls[$join_type][] = ['t_col' => 'id', 'q_col' => $var_name.' lang_dt', 'vc' => $vc];
+                    if (strpos($q_sql, '`'.$var_name.' lang_dt`')) {
+                        $r .= ', '.$nl.'    V'.$vc.'.val AS `'.$var_name.' lang_dt`';
+                        ++$vc;
+                    } else {
+                        $r .= ', '.$nl.'    NULL AS `'.$var_name.' lang_dt`';
+                    }
+                }
+            }
+        }
+        if (!$r) {
+            $r = '*';
+        }
+        /* from */
+        $r .= $nl.'FROM ('.$q_tbl.' TMP)';
+        foreach (['JOIN', 'LEFT JOIN'] as $join_type) {
+            foreach ($v_tbls[$join_type] as $v_tbl) {
+                $tbl = $this->getValueTable($v_tbl['t_col']);
+                $var_name = preg_replace('/^([^\s]+)(.*)$/', '\\1', $v_tbl['q_col']);
+                $cur_join_type = in_array($var_name, $this->infos['null_vars']) ? 'LEFT JOIN' : $join_type;
+                if (!strpos($q_sql, '`'.$v_tbl['q_col'].'`')) {
+                    continue;
+                }
+                $r .= $nl.' '.$cur_join_type.' '.$tbl.' V'.$v_tbl['vc'].' ON (
+            (V'.$v_tbl['vc'].'.id = TMP.`'.$v_tbl['q_col'].'`)
+        )';
+            }
+        }
+        /* create pos columns, id needed */
+        if ($this->v('order_infos', [], $this->infos['query'])) {
+            $r .= $nl.' ORDER BY _pos_';
+        }
+
+        return 'SELECT'.$nl.$r;
+    }
+}
diff --git a/lib/arc2/store/ARC2_StoreSemHTMLLoader.php b/lib/arc2/store/ARC2_StoreSemHTMLLoader.php
index 941093e85815d9d5e520d6b4c6023ba955ab46c5..0b2b6a37efc03e6455a5e010789636113a72c46b 100644
--- a/lib/arc2/store/ARC2_StoreSemHTMLLoader.php
+++ b/lib/arc2/store/ARC2_StoreSemHTMLLoader.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 Store SemHTML Loader
 author:   Benjamin Nowack
@@ -10,27 +10,26 @@ version:  2010-11-16
 
 ARC2::inc('SemHTMLParser');
 
-class ARC2_StoreSemHTMLLoader extends ARC2_SemHTMLParser {
+class ARC2_StoreSemHTMLLoader extends ARC2_SemHTMLParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
 
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-  }
+    public function __init()
+    {
+        parent::__init();
+    }
 
-  /*  */
-  
-  function done() {
-    $this->extractRDF();
-  }
-  
-  function addT($t) {
-    $this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
-    $this->t_count++;
-  }
-
-  /*  */
+    public function done()
+    {
+        $this->extractRDF();
+    }
 
+    public function addT($t)
+    {
+        $this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
+        ++$this->t_count;
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreTableManager.php b/lib/arc2/store/ARC2_StoreTableManager.php
old mode 100644
new mode 100755
index cc171cadb27ea495c142bb313eea38632172418e..38d9830ec75398383a98c78d0b7df0ac603cf529
--- a/lib/arc2/store/ARC2_StoreTableManager.php
+++ b/lib/arc2/store/ARC2_StoreTableManager.php
@@ -1,72 +1,68 @@
 <?php
 /**
- * ARC2 RDF Store Table Manager
+ * ARC2 RDF Store Table Manager.
  *
- * @license   http://arc.semsol.org/license
+ * @license   W3C Software License and GPL
  * @author    Benjamin Nowack
- * @version   2010-11-16
  *
-*/
-
+ * @version   2010-11-16
+ */
 ARC2::inc('Store');
 
-class ARC2_StoreTableManager extends ARC2_Store {
-
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {/* db_con */
-    parent::__init();
-    $this->engine_type = $this->v('store_engine_type', 'MyISAM', $this->a);
-  }
-
-  /*  */
-  
-  function getTableOptionsCode() {
-    $v = $this->getDBVersion();
-    $r = "";
-    $r .= (($v < '04-01-00') && ($v >= '04-00-18')) ? 'ENGINE' : (($v >= '04-01-02') ? 'ENGINE' : 'TYPE');
-    $r .= "=" . $this->engine_type;
-    $r .= ($v >= '04-00-00') ? " CHARACTER SET utf8" : "";
-    $r .= ($v >= '04-01-00') ? " COLLATE utf8_unicode_ci" : "";
-    $r .= " DELAY_KEY_WRITE = 1";
-    return $r;
-  }
-  
-  /*  */
-  
-  function createTables() {
-    $con = $this->getDBCon();
-    if(!$this->createTripleTable()) {
-      return $this->addError('Could not create "triple" table (' . mysql_error($con) . ').');
-    }
-    if(!$this->createG2TTable()) {
-      return $this->addError('Could not create "g2t" table (' . mysql_error($con) . ').');
+class ARC2_StoreTableManager extends ARC2_Store
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
     }
-    if(!$this->createID2ValTable()) {
-      return $this->addError('Could not create "id2val" table (' . mysql_error($con) . ').');
-    }
-    if(!$this->createS2ValTable()) {
-      return $this->addError('Could not create "s2val" table (' . mysql_error($con) . ').');
+
+    public function __init()
+    {
+        parent::__init();
+        $this->engine_type = $this->v('store_engine_type', 'MyISAM', $this->a);
     }
-    if(!$this->createO2ValTable()) {
-      return $this->addError('Could not create "o2val" table (' . mysql_error($con) . ').');
+
+    public function getTableOptionsCode()
+    {
+        $r = 'ENGINE='.$this->engine_type;
+        $r .= ' CHARACTER SET utf8';
+        $r .= ' COLLATE utf8_unicode_ci';
+        $r .= ' DELAY_KEY_WRITE = 1';
+
+        return $r;
     }
-    if(!$this->createSettingTable()) {
-      return $this->addError('Could not create "setting" table (' . mysql_error($con) . ').');
+
+    public function createTables()
+    {
+        if (!$this->createTripleTable()) {
+            return $this->addError('Could not create "triple" table ('.$this->a['db_object']->getErrorMessage().').');
+        }
+        if (!$this->createG2TTable()) {
+            return $this->addError('Could not create "g2t" table ('.$this->a['db_object']->getErrorMessage().').');
+        }
+        if (!$this->createID2ValTable()) {
+            return $this->addError('Could not create "id2val" table ('.$this->a['db_object']->getErrorMessage().').');
+        }
+        if (!$this->createS2ValTable()) {
+            return $this->addError('Could not create "s2val" table ('.$this->a['db_object']->getErrorMessage().').');
+        }
+        if (!$this->createO2ValTable()) {
+            return $this->addError('Could not create "o2val" table ('.$this->a['db_object']->getErrorMessage().').');
+        }
+        if (!$this->createSettingTable()) {
+            return $this->addError('Could not create "setting" table ('.$this->a['db_object']->getErrorMessage().').');
+        }
+
+        return 1;
     }
-    return 1;
-  }
-  
-  /*  */
-  
-  function createTripleTable($suffix = 'triple') {
-    /* keep in sync with merge def in StoreQueryHandler ! */
-    $indexes = $this->v('store_indexes', array('sp (s,p)', 'os (o,s)', 'po (p,o)'), $this->a);
-    $index_code = $indexes ? 'KEY ' . join(', KEY ',  $indexes) . ', ' : '';
-    $sql = "
-      CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . $suffix . " (
+
+    public function createTripleTable($suffix = 'triple')
+    {
+        /* keep in sync with merge def in StoreQueryHandler ! */
+        $indexes = $this->v('store_indexes', ['sp (s,p)', 'os (o,s)', 'po (p,o)'], $this->a);
+        $index_code = $indexes ? 'KEY '.implode(', KEY ', $indexes).', ' : '';
+        $sql = '
+      CREATE TABLE IF NOT EXISTS '.$this->getTablePrefix().$suffix.' (
         t mediumint UNSIGNED NOT NULL,
         s mediumint UNSIGNED NOT NULL,
         p mediumint UNSIGNED NOT NULL,
@@ -76,215 +72,230 @@ class ARC2_StoreTableManager extends ARC2_Store {
         s_type tinyint(1) NOT NULL default 0,       /* uri/bnode => 0/1 */
         o_type tinyint(1) NOT NULL default 0,       /* uri/bnode/literal => 0/1/2 */
         misc tinyint(1) NOT NULL default 0,         /* temporary flags */
-        UNIQUE KEY (t), " . $index_code . " KEY (misc)
-      ) ". $this->getTableOptionsCode() . "
-    ";
-    return mysql_query($sql, $this->getDBCon());
-  }
-
-  function extendTripleTableColumns($suffix = 'triple') {
-    $sql = "
-      ALTER TABLE " . $this->getTablePrefix() . $suffix . "
+        UNIQUE KEY (t), '.$index_code.' KEY (misc)
+      ) '.$this->getTableOptionsCode().'
+    ';
+        return $this->a['db_object']->simpleQuery($sql);
+    }
+
+    public function extendTripleTableColumns($suffix = 'triple')
+    {
+        $sql = '
+      ALTER TABLE '.$this->getTablePrefix().$suffix.'
       MODIFY t int(10) UNSIGNED NOT NULL,
       MODIFY s int(10) UNSIGNED NOT NULL,
       MODIFY p int(10) UNSIGNED NOT NULL,
       MODIFY o int(10) UNSIGNED NOT NULL,
       MODIFY o_lang_dt int(10) UNSIGNED NOT NULL
-    ";
-    return mysql_query($sql, $this->getDBCon());
-  }
-  
-  /*  */
-  
-  function createG2TTable() {
-    $sql = "
-      CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . "g2t (
+    ';
+
+        return $this->a['db_object']->simpleQuery($sql);
+    }
+
+    public function createG2TTable()
+    {
+        $sql = '
+      CREATE TABLE IF NOT EXISTS '.$this->getTablePrefix().'g2t (
         g mediumint UNSIGNED NOT NULL,
         t mediumint UNSIGNED NOT NULL,
         UNIQUE KEY gt (g,t), KEY tg (t,g)
-      ) ". $this->getTableOptionsCode() . "
-    ";
-    return mysql_query($sql, $this->getDBCon());
-  }  
-  
-  function extendG2tTableColumns($suffix = 'g2t') {
-    $sql = "
-      ALTER TABLE " . $this->getTablePrefix() . $suffix . "
+      ) '.$this->getTableOptionsCode().'
+    ';
+
+        return $this->a['db_object']->simpleQuery($sql);
+    }
+
+    public function extendG2tTableColumns($suffix = 'g2t')
+    {
+        $sql = '
+      ALTER TABLE '.$this->getTablePrefix().$suffix.'
       MODIFY g int(10) UNSIGNED NOT NULL,
       MODIFY t int(10) UNSIGNED NOT NULL
-    ";
-    return mysql_query($sql, $this->getDBCon());
-  }
-
-  /*  */
-  
-  function createID2ValTable() {
-    $sql = "
-      CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . "id2val (
-        id mediumint UNSIGNED NOT NULL,
+    ';
+
+        return $this->a['db_object']->simpleQuery($sql);
+    }
+
+    public function createID2ValTable()
+    {
+        $sql = '
+      CREATE TABLE IF NOT EXISTS '.$this->getTablePrefix().'id2val (
+        id mediumint UNSIGNED NOT NULL AUTO_INCREMENT,
         misc tinyint(1) NOT NULL default 0,
         val text NOT NULL,
         val_type tinyint(1) NOT NULL default 0,     /* uri/bnode/literal => 0/1/2 */
-        UNIQUE KEY (id,val_type), KEY v (val(64))
-      ) ". $this->getTableOptionsCode() . "
-    ";
-    return mysql_query($sql, $this->getDBCon());
-  }  
-  
-  function extendId2valTableColumns($suffix = 'id2val') {
-    $sql = "
-      ALTER TABLE " . $this->getTablePrefix() . $suffix . "
+        PRIMARY KEY (`id`),
+        UNIQUE KEY (id,val_type),
+        KEY v (val(64))
+      ) '.$this->getTableOptionsCode().'
+    ';
+
+        return $this->a['db_object']->simpleQuery($sql);
+    }
+
+    public function extendId2valTableColumns($suffix = 'id2val')
+    {
+        $sql = '
+      ALTER TABLE '.$this->getTablePrefix().$suffix.'
       MODIFY id int(10) UNSIGNED NOT NULL
-    ";
-    return mysql_query($sql, $this->getDBCon());
-  }
-
-  /*  */
-  
-  function createS2ValTable() {
-    //$indexes = 'UNIQUE KEY (id), KEY vh (val_hash), KEY v (val(64))';
-    $indexes = 'UNIQUE KEY (id), KEY vh (val_hash)';
-    $sql = "
-      CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . "s2val (
+    ';
+
+        return $this->a['db_object']->simpleQuery($sql);
+    }
+
+    public function createS2ValTable()
+    {
+        //$indexes = 'UNIQUE KEY (id), KEY vh (val_hash), KEY v (val(64))';
+        $indexes = 'UNIQUE KEY (id), KEY vh (val_hash)';
+        $sql = '
+      CREATE TABLE IF NOT EXISTS '.$this->getTablePrefix().'s2val (
         id mediumint UNSIGNED NOT NULL,
         misc tinyint(1) NOT NULL default 0,
         val_hash char(32) NOT NULL,
         val text NOT NULL,
-        " . $indexes . "
-      ) " . $this->getTableOptionsCode() . "
-    ";
-    return mysql_query($sql, $this->getDBCon());
-  }  
-  
-  function extendS2valTableColumns($suffix = 's2val') {
-    $sql = "
-      ALTER TABLE " . $this->getTablePrefix() . $suffix . "
+        '.$indexes.'
+      ) '.$this->getTableOptionsCode().'
+    ';
+
+        return $this->a['db_object']->simpleQuery($sql);
+    }
+
+    public function extendS2valTableColumns($suffix = 's2val')
+    {
+        $sql = '
+      ALTER TABLE '.$this->getTablePrefix().$suffix.'
       MODIFY id int(10) UNSIGNED NOT NULL
-    ";
-    return mysql_query($sql, $this->getDBCon());
-  }
-
-  /*  */
-  
-  function createO2ValTable() {
-    /* object value index, e.g. "KEY v (val(64))" and/or "FULLTEXT KEY vft (val)" */
-    $val_index = $this->v('store_object_index', 'KEY v (val(64))', $this->a);
-    if ($val_index) $val_index = ', ' . ltrim($val_index, ',');
-    $sql = "
-      CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . "o2val (
+    ';
+
+        return $this->a['db_object']->simpleQuery($sql);
+    }
+
+    public function createO2ValTable()
+    {
+        /* object value index, e.g. "KEY v (val(64))" and/or "FULLTEXT KEY vft (val)" */
+        $val_index = $this->v('store_object_index', 'KEY v (val(64))', $this->a);
+        if ($val_index) {
+            $val_index = ', '.ltrim($val_index, ',');
+        }
+        $sql = '
+      CREATE TABLE IF NOT EXISTS '.$this->getTablePrefix().'o2val (
         id mediumint UNSIGNED NOT NULL,
         misc tinyint(1) NOT NULL default 0,
         val_hash char(32) NOT NULL,
         val text NOT NULL,
-        UNIQUE KEY (id), KEY vh (val_hash)" . $val_index . "
-      ) ". $this->getTableOptionsCode() . "
-    ";
-    return mysql_query($sql, $this->getDBCon());
-  }  
-  
-  function extendO2valTableColumns($suffix = 'o2val') {
-    $sql = "
-      ALTER TABLE " . $this->getTablePrefix() . $suffix . "
+        UNIQUE KEY (id), KEY vh (val_hash)'.$val_index.'
+      ) '.$this->getTableOptionsCode().'
+    ';
+
+        return $this->a['db_object']->simpleQuery($sql);
+    }
+
+    public function extendO2valTableColumns($suffix = 'o2val')
+    {
+        $sql = '
+      ALTER TABLE '.$this->getTablePrefix().$suffix.'
       MODIFY id int(10) UNSIGNED NOT NULL
-    ";
-    return mysql_query($sql, $this->getDBCon());
-  }
-
-  /*  */
-  
-  function createSettingTable() {
-    $sql = "
-      CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . "setting (
+    ';
+
+        return $this->a['db_object']->simpleQuery($sql);
+    }
+
+    public function createSettingTable()
+    {
+        $sql = '
+      CREATE TABLE IF NOT EXISTS '.$this->getTablePrefix().'setting (
         k char(32) NOT NULL,
         val text NOT NULL,
         UNIQUE KEY (k)
-      ) ". $this->getTableOptionsCode() . "
-    ";
-    return mysql_query($sql, $this->getDBCon());
-  }  
-  
-  /*  */
-
-  function extendColumns() {
-    $con = $this->getDBCon();
-    $tbl_prefix = $this->getTablePrefix();
-    $tbls = $this->getTables();
-    foreach ($tbls as $suffix) {
-      if (preg_match('/^(triple|g2t|id2val|s2val|o2val)/', $suffix, $m)) {
-        $mthd = 'extend' . ucfirst($m[1]) . 'TableColumns';
-        $this->$mthd($suffix);
-      }
+      ) '.$this->getTableOptionsCode().'
+    ';
+
+        return $this->a['db_object']->simpleQuery($sql);
     }
-  }
-
-  /*  */
-
-  function splitTables() {
-    $old_ps = $this->getSetting('split_predicates', array());
-    $new_ps = $this->retrieveSplitPredicates();
-    $add_ps = array_diff($new_ps, $old_ps);
-    $del_ps = array_diff($old_ps, $new_ps);
-    $final_ps = array();
-    foreach ($del_ps as $p) {
-      if (!$this->unsplitPredicate($p)) $final_ps[] = $p;
+
+    public function extendColumns()
+    {
+        $tbl_prefix = $this->getTablePrefix();
+        $tbls = $this->getTables();
+        foreach ($tbls as $suffix) {
+            if (preg_match('/^(triple|g2t|id2val|s2val|o2val)/', $suffix, $m)) {
+                $mthd = 'extend'.ucfirst($m[1]).'TableColumns';
+                $this->$mthd($suffix);
+            }
+        }
     }
-    foreach ($add_ps as $p) {
-      if ($this->splitPredicate($p)) $final_ps[] = $p;
+
+    public function splitTables()
+    {
+        $old_ps = $this->getSetting('split_predicates', []);
+        $new_ps = $this->retrieveSplitPredicates();
+        $add_ps = array_diff($new_ps, $old_ps);
+        $del_ps = array_diff($old_ps, $new_ps);
+        $final_ps = [];
+        foreach ($del_ps as $p) {
+            if (!$this->unsplitPredicate($p)) {
+                $final_ps[] = $p;
+            }
+        }
+        foreach ($add_ps as $p) {
+            if ($this->splitPredicate($p)) {
+                $final_ps[] = $p;
+            }
+        }
+        $this->setSetting('split_predicates', $new_ps);
     }
-    $this->setSetting('split_predicates', $new_ps);
-  }
-
-  function unsplitPredicate($p) {
-    $suffix = 'triple_' . abs(crc32($p));
-    $old_tbl = $this->getTablePrefix() . $suffix;
-    $new_tbl = $this->getTablePrefix() . 'triple';
-    $p_id = $this->getTermID($p, 'p');
-    $con = $this->getDBCon();
-    $sql = '
-      INSERT IGNORE INTO ' . $new_tbl .'
-      SELECT * FROM ' . $old_tbl . ' WHERE ' . $old_tbl . '.p = ' . $p_id . '
+
+    public function unsplitPredicate($p)
+    {
+        $suffix = 'triple_'.abs(crc32($p));
+        $old_tbl = $this->getTablePrefix().$suffix;
+        $new_tbl = $this->getTablePrefix().'triple';
+        $p_id = $this->getTermID($p, 'p');
+        $sql = '
+      INSERT IGNORE INTO '.$new_tbl.'
+      SELECT * FROM '.$old_tbl.' WHERE '.$old_tbl.'.p = '.$p_id.'
     ';
-    if ($rs = mysql_query($sql, $con)) {
-      mysql_query('DROP TABLE ' . $old_tbl, $con);
-      return 1;
-    }
-    else {
-      return 0;
+        if ($this->a['db_object']->simpleQuery($sql)) {
+            $this->a['db_object']->simpleQuery('DROP TABLE '.$old_tbl);
+
+            return 1;
+        } else {
+            return 0;
+        }
     }
-  }
-
-  function splitPredicate($p) {
-    $suffix = 'triple_' . abs(crc32($p));
-    $this->createTripleTable($suffix);
-    $old_tbl = $this->getTablePrefix() . 'triple';
-    $new_tbl = $this->getTablePrefix() . $suffix;
-    $p_id = $this->getTermID($p, 'p');
-    $con = $this->getDBCon();
-    $sql = '
-      INSERT IGNORE INTO ' . $new_tbl .'
-      SELECT * FROM ' . $old_tbl . ' WHERE ' . $old_tbl . '.p = ' . $p_id . '
+
+    public function splitPredicate($p)
+    {
+        $suffix = 'triple_'.abs(crc32($p));
+        $this->createTripleTable($suffix);
+        $old_tbl = $this->getTablePrefix().'triple';
+        $new_tbl = $this->getTablePrefix().$suffix;
+        $p_id = $this->getTermID($p, 'p');
+        $sql = '
+      INSERT IGNORE INTO '.$new_tbl.'
+      SELECT * FROM '.$old_tbl.' WHERE '.$old_tbl.'.p = '.$p_id.'
     ';
-    if ($rs = mysql_query($sql, $con)) {
-      mysql_query('DELETE FROM ' . $old_tbl . ' WHERE ' . $old_tbl . '.p = ' . $p_id, $con);
-      return 1;
-    }
-    else {
-      mysql_query('DROP TABLE ' . $new_tbl, $con);
-      return 0;
-    }
-  }
-
-  function retrieveSplitPredicates() {
-    $r = $this->split_predicates;
-    $limit = $this->max_split_tables - count($r);
-    $q = 'SELECT ?p COUNT(?p) AS ?pc WHERE { ?s ?p ?o } GROUP BY ?p ORDER BY DESC(?pc) LIMIT ' . $limit;
-    $rows = $this->query($q, 'rows');
-    foreach ($rows as $row) {
-      $r[] = $row['p'];
+        if ($this->a['db_object']->simpleQuery($sql)) {
+            $this->a['db_object']->simpleQuery('DELETE FROM '.$old_tbl.' WHERE '.$old_tbl.'.p = '.$p_id);
+
+            return 1;
+        } else {
+            $this->a['db_object']->simpleQuery('DROP TABLE '.$new_tbl);
+
+            return 0;
+        }
     }
-    return $r;
-  }
 
-  /*  */
+    public function retrieveSplitPredicates()
+    {
+        $r = $this->split_predicates;
+        $limit = $this->max_split_tables - count($r);
+        $q = 'SELECT ?p COUNT(?p) AS ?pc WHERE { ?s ?p ?o } GROUP BY ?p ORDER BY DESC(?pc) LIMIT '.$limit;
+        $rows = $this->query($q, 'rows');
+        foreach ($rows as $row) {
+            $r[] = $row['p'];
+        }
 
+        return $r;
+    }
 }
diff --git a/lib/arc2/store/ARC2_StoreTurtleLoader.php b/lib/arc2/store/ARC2_StoreTurtleLoader.php
index f12d3b065ddc03976db3a9c3968e9c97a67c80c6..2fd90a27dd4e4bdb4e70fb02dd8292619abb7434 100644
--- a/lib/arc2/store/ARC2_StoreTurtleLoader.php
+++ b/lib/arc2/store/ARC2_StoreTurtleLoader.php
@@ -1,7 +1,7 @@
 <?php
 /*
-homepage: http://arc.semsol.org/
-license:  http://arc.semsol.org/license
+@homepage <https://github.com/semsol/arc2>
+@license W3C Software License and GPL
 
 class:    ARC2 Store Turtle Loader
 author:   Benjamin Nowack
@@ -10,23 +10,21 @@ version:  2010-11-16
 
 ARC2::inc('TurtleParser');
 
-class ARC2_StoreTurtleLoader extends ARC2_TurtleParser {
+class ARC2_StoreTurtleLoader extends ARC2_TurtleParser
+{
+    public function __construct($a, &$caller)
+    {
+        parent::__construct($a, $caller);
+    }
 
-  function __construct($a, &$caller) {
-    parent::__construct($a, $caller);
-  }
-  
-  function __init() {
-    parent::__init();
-  }
-
-  /*  */
-  
-  function addT($t) {
-    $this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
-    $this->t_count++;
-  }
-
-  /*  */
+    public function __init()
+    {
+        parent::__init();
+    }
 
+    public function addT($t)
+    {
+        $this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
+        ++$this->t_count;
+    }
 }
diff --git a/lib/arc2/tests/ARC2_TestCase.php b/lib/arc2/tests/ARC2_TestCase.php
new file mode 100644
index 0000000000000000000000000000000000000000..8b348d08c3b2617ce6a30d5e29ca687e1334b0ea
--- /dev/null
+++ b/lib/arc2/tests/ARC2_TestCase.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Tests;
+
+use Psr\SimpleCache\CacheInterface;
+
+class ARC2_TestCase extends \PHPUnit\Framework\TestCase
+{
+    /**
+     * Store configuration to connect with the database.
+     *
+     * @var array
+     */
+    protected $dbConfig;
+
+    /**
+     * Subject under test.
+     *
+     * @var mixed
+     */
+    protected $fixture;
+
+    public function setUp(): void
+    {
+        global $dbConfig;
+
+        $this->dbConfig = $dbConfig;
+
+        // in case we run with a cache, clear it
+        if (isset($this->dbConfig['cache_instance']) && $this->dbConfig['cache_instance'] instanceof CacheInterface) {
+            $this->dbConfig['cache_instance']->clear();
+        }
+    }
+
+    public function tearDown(): void
+    {
+        // in case we run with a cache, clear it
+        if (isset($this->dbConfig['cache_instance']) && $this->dbConfig['cache_instance'] instanceof CacheInterface) {
+            $this->dbConfig['cache_instance']->clear();
+        }
+
+        parent::tearDown();
+    }
+}
diff --git a/lib/arc2/ARC2_TestHandler.php b/lib/arc2/tests/ARC2_TestHandler.php
similarity index 99%
rename from lib/arc2/ARC2_TestHandler.php
rename to lib/arc2/tests/ARC2_TestHandler.php
index c4f75b2bb223db6a4307fd13635d1347421c9795..bbe8523f93878086608831264c8e91ca4e568cc6 100644
--- a/lib/arc2/ARC2_TestHandler.php
+++ b/lib/arc2/tests/ARC2_TestHandler.php
@@ -5,7 +5,7 @@ license:  http://arc.web-semantics.org/license
 
 class:    ARC2 DAWG Test Handler
 author:   Benjamin Nowack
-version:  2010-11-16
+version:  2011-12-01
 */
 
 ARC2::inc('Class');
@@ -50,6 +50,9 @@ class ARC2_TestHandler extends ARC2_Class {
     $fname = 'f' . crc32($url) . '.txt';
     if (!file_exists('tmp/' . $fname)) {
       $r = '';
+      if (!isset($this->reader)) {
+        $this->reader = new ARC2_Reader($this->a, $this);
+      }
       $this->reader->activate($url);
       while ($d = $this->reader->readStream()) {
         $r .= $d;
diff --git a/lib/arc2/tests/bootstrap.php b/lib/arc2/tests/bootstrap.php
new file mode 100644
index 0000000000000000000000000000000000000000..ea2e476e1fcebcd7b796ed6bb47ac27e8e2eb889
--- /dev/null
+++ b/lib/arc2/tests/bootstrap.php
@@ -0,0 +1,54 @@
+<?php
+
+require_once __DIR__ .'/../vendor/autoload.php';
+
+error_reporting(E_ALL);
+
+require 'ARC2_TestHandler.php';
+
+global $dbConfig;
+
+if (file_exists(__DIR__ .'/config.php')) {
+    // use custom DB credentials, if available
+    $dbConfig = require 'config.php';
+
+} else {
+    // standard DB credentials (ready to use in Travis)
+    $dbConfig = array(
+        'db_name' => 'testdb',
+        'db_user' => 'root',
+        'db_pwd'  => '',
+        'db_host' => '127.0.0.1',
+    );
+}
+
+// set defaults for dbConfig entries
+if (false == isset($dbConfig['store_name'])) {
+    $dbConfig['store_name'] = 'arc';
+}
+
+if (false == isset($dbConfig['db_table_prefix'])) {
+    $dbConfig['db_table_prefix'] = null;
+}
+
+// set DB adapter (see related phpunit-xx.xml file), possible values: mysqli, pdo
+if ('pdo' == getenv('DB_ADAPTER')) {
+    if (!empty(getenv('DB_PDO_PROTOCOL'))) {
+        $dbConfig['db_adapter'] = 'pdo';
+        $dbConfig['db_pdo_protocol'] = getenv('DB_PDO_PROTOCOL');
+    } else {
+        throw new \Exception('Environment variable DB_PDO_PROTOCOL not set. Possible values are: mysql');
+    }
+} else {
+    $dbConfig['db_adapter'] = 'mysqli';
+}
+
+/*
+ * set cache enable
+ *
+ * if enabled, we use an instance of ArrayCache which is very fast
+ */
+if (true ===\getenv('CACHE_ENABLED') || 'true' == \getenv('CACHE_ENABLED')) {
+    $dbConfig['cache_enabled'] = true;
+    $dbConfig['cache_instance'] = new Symfony\Component\Cache\Simple\ArrayCache();
+}
diff --git a/lib/arc2/tests/config.php.dist b/lib/arc2/tests/config.php.dist
new file mode 100644
index 0000000000000000000000000000000000000000..98b7ac2d1afed1b73eb93ae89fa9bfafcc5b9401
--- /dev/null
+++ b/lib/arc2/tests/config.php.dist
@@ -0,0 +1,12 @@
+<?php
+
+/*
+ * adapt this file, if you want to define custom database credentials.
+ */
+
+return array(
+    'db_name' => 'testdb',
+    'db_user' => 'root',
+    'db_pwd'  => 'Pass123',
+    'db_host' => 'localhost',
+);
diff --git a/lib/arc2/tests/data/atom/feed.atom b/lib/arc2/tests/data/atom/feed.atom
new file mode 100755
index 0000000000000000000000000000000000000000..446c13122bbf776bfe2aaf0b512d9f0f4c6b54b9
--- /dev/null
+++ b/lib/arc2/tests/data/atom/feed.atom
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+
+  <title>Example Feed</title>
+  <link href="http://example.org/"/>
+  <updated>2003-12-13T18:30:02Z</updated>
+  <author>
+    <name>John Doe</name>
+  </author>
+  <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
+
+  <entry>
+    <title>Atom-Powered Robots Run Amok</title>
+    <link href="http://example.org/2003/12/13/atom03"/>
+    <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+    <updated>2003-12-13T18:30:02Z</updated>
+    <summary>Some text.</summary>
+  </entry>
+
+</feed>
\ No newline at end of file
diff --git a/lib/arc2/tests/data/json/crunchbase-facebook.js b/lib/arc2/tests/data/json/crunchbase-facebook.js
new file mode 100755
index 0000000000000000000000000000000000000000..99745594aedb433e0df74a1dcd5d90af891a182e
--- /dev/null
+++ b/lib/arc2/tests/data/json/crunchbase-facebook.js
@@ -0,0 +1,450 @@
+{"name": "Facebook",
+ "permalink": "facebook",
+ "homepage_url": "http://facebook.com",
+ "blog_url": "http://blog.facebook.com",
+ "blog_feed_url": "http://blog.facebook.com/atom.php",
+ "category_code": "web",
+ "number_of_employees": 450,
+ "founded_year": 2004,
+ "founded_month": 2,
+ "founded_day": 1,
+ "deadpooled_year": null,
+ "deadpooled_month": null,
+ "deadpooled_day": null,
+ "deadpooled_url": "",
+ "tag_list": "social, facebook, college, students, profiles, network, socialnetwork, socialmedia, platform",
+ "email_address": "",
+ "phone_number": "",
+ "overview": "\u003Cp\u003EOn February 4th, 2004 \u003Ca href=\"http://www.crunchbase.com/person/mark-zuckerberg\" title=\"Mark Zuckerberg\"\u003EMark Zuckerberg\u003C/a\u003E launched The Facebook, a social network that was at the time exclusively for Harvard students. It was a huge hit, in 2 weeks, half of the student body at Harvard had signed up.  Other schools in the Boston area began demanding a Facebook network. Zuckerberg immediately recruited his friends \u003Ca href=\"http://www.crunchbase.com/person/dustin-moskovitz\" title=\"Dustin Moskowitz\"\u003EDustin Moskowitz\u003C/a\u003E and Chris Hughes to help build Facebook, and within four months, Facebook added 30 more college networks. \u003C/p\u003E\n\n\u003Cp\u003EThe original idea for the term Facebook came from Zuckerberg\u0026#8217;s high school (Phillips Exeter Academy). The Exeter Face Book was passed around to every student as a way for students to get to know their classmates for the following year. It was a physical paper book until Zuckerberg brought it to the internet.\u003C/p\u003E\n\n\u003Cp\u003EWith this success, Zuckerberg, Moskowitz and Hughes moved out to Palo Alto for the summer and rented a sublet. A few weeks later, Zuckerberg ran into the former cofounder of Napster, Sean Parker. Parker soon moved in to Zuckerberg\u0026#8217;s apartment and they began working together.  Parker provided the introduction to their first investor, Peter Thiel, cofounder of PayPal and managing partner of the Founders Fund. Thiel invested $500,000 into Facebook. \u003C/p\u003E\n\n\u003Cp\u003EWith millions more users, Friendster \u003Ca href=\"http://www.techcrunch.com/2006/12/12/yahoos-project-fraternity-docs-leaked/\" title=\"attempted\"\u003Eattempted\u003C/a\u003E to acquire the company for $10 million in mid 2004. Facebook turned down the offer and subsequently received $12.7 million in funding from Accel Partners, at a valuation of \u003Ca href=\"http://www.techcrunch.com/2005/09/07/85-of-college-students-use-facebook/\" title=\"around $100 million\"\u003Earound $100 million\u003C/a\u003E. Facebook continued to grow, opening up to high school students in September 2005 and adding an immensely popular photo sharing feature the next month. The next spring, Facebook received $25 million in funding from Greylock Partners and Meritech Capital, as well as previous investors Accel Partners and Peter Thiel. The pre-money valuation for this deal was about $525 million. Facebook subsequently \u003Ca href=\"http://www.techcrunch.com/2006/04/26/facebook-goes-beyond-college-high-school-markets/\" title=\"opened\"\u003Eopened\u003C/a\u003E up to work networks, eventually amassing over 20,000 work networks. Finally in September 2006, Facebook \u003Ca href=\"http://www.techcrunch.com/2006/09/26/facebook-just-launched-open-registrations/\" title=\"opened\"\u003Eopened\u003C/a\u003E to anyone with an email address. \u003C/p\u003E\n\n\u003Cp\u003EIn the summer of 2006, Yahoo \u003Ca href=\"http://www.techcrunch.com/2006/09/21/facebook-and-yahoo-in-acquisition-talks-for-1-billion/\" title=\"attempted to acquire\"\u003Eattempted to acquire\u003C/a\u003E the company for $1 billion dollars. \u003Ca href=\"http://www.wired.com/techbiz/startups/news/2007/09/ff_facebook\" title=\"Reports\" rel=\"nofollow\"\u003EReports\u003C/a\u003E actually indicated that Zuckerberg made a verbal agreement to sell Facebook to Yahoo. A few days later when Yahoo\u0026#8217;s stock price took a dive, the offer was lowered to $800 million and Zuckerberg walked away from the deal.  Yahoo later \u003Ca href=\"http://www.techcrunch.com/2006/12/12/yahoos-project-fraternity-docs-leaked/\" title=\"offered\"\u003Eoffered\u003C/a\u003E $1 billion again, this time Zuckerberg turned Yahoo down and earned instant notoriety as the \u0026#8220;kid\u0026#8221; who turned down a billion. This was not the first time Zuckerberg turned down an acquisition offer; Viacom had previously \u003Ca href=\"http://www.techcrunch.com/2006/03/28/facebook-is-doing-the-skype-dance/\" title=\"unsuccessfully\"\u003Eunsuccessfully\u003C/a\u003E attempted to acquire the company for $750 million in March, 2006. \u003C/p\u003E\n\n\u003Cp\u003EOne sour note for Facebook has been the \u003Ca href=\"http://www.techcrunch.com/2007/07/16/the-ghost-of-zuckerbergs-past-may-haunt-facebook-ipo/\" title=\"controversy\"\u003Econtroversy\u003C/a\u003E with social network Uconnect. The founders of Uconnect, former classmates of Mark Zuckerberg at Harvard, allege that Zuckerberg stole their original source code for Facebook. The ordeal has \u003Ca href=\"http://www.techcrunch.com/2007/10/10/facebook-vs-connectu-facebook-makes-untrue-assertions-claims-connectu/\" title=\"gone to court\"\u003Egone to court\u003C/a\u003E, but is still unresolved. \u003C/p\u003E\n\n\u003Cp\u003ENotwithstanding this lingering controversy, Facebook\u0026#8217;s growth in the fall of 2007 was staggering. Over 1 million new users signed up every week, 200,000 daily, totaling over 50 million active users. Facebook received 40 billion page views a month.  Long gone were the days of Facebook as a social network for college students. 11% of users are over the age of 35, and the fastest growing demographic is users over 30. Facebook has also seen huge growth internationally; 15% of the user base is in Canada.  Facebook users\u0026#8217; \u003Ca href=\"http://www.techcrunch.com/2007/11/13/i-just-cant-be-a-college-student-without-facebook/\" title=\"passion\"\u003Epassion\u003C/a\u003E, or \u003Ca href=\"http://www.techcrunch.com/2007/03/09/career-advice-dont-choose-facebook-over-your-job/\" title=\"addiction\"\u003Eaddiction\u003C/a\u003E, to the site is unparalleled: more than half use the product every single day and users spend an average of 19 minutes a day on Facebook. Facebook is 6th most trafficked site in the US and top photo sharing site with \u003Ca href=\"http://www.techcrunch.com/2007/11/13/2-billion-photos-on-flickr/\" title=\"4.1 billion photos uploaded\"\u003E4.1 billion photos uploaded\u003C/a\u003E. \u003C/p\u003E\n\n\u003Cp\u003EBased on these types of numbers, \u003Ca href=\"http://www.techcrunch.com/2007/10/24/facebook-takes-the-microsoft-money-and-runs/\" title=\"Microsoft invested\"\u003EMicrosoft invested\u003C/a\u003E $240 million into Facebook for 1.6 percent of the company in October 2007.  This meant a valuation of over $15 billion, making Facebook the \u003Ca href=\"http://www.techcrunch.com/2007/10/25/perspective-facebook-is-now-5th-most-valuable-us-internet-company/\" title=\"5th most valuable US Internet company\"\u003E5th most valuable US Internet company\u003C/a\u003E, yet with only $150 million in annual revenue. Many explained Microsoft\u0026#8217;s decision as being solely driven by the desire to outbid Google. \u003C/p\u003E\n\n\u003Cp\u003EFacebook\u0026#8217;s competitors include \u003Ca href=\"http://www.crunchbase.com/company/myspace\" title=\"MySpace\"\u003EMySpace\u003C/a\u003E, \u003Ca href=\"http://www.crunchbase.com/company/Bebo\" title=\"Bebo\"\u003EBebo\u003C/a\u003E, \u003Ca href=\"http://www.crunchbase.com/company/Friendster\" title=\"Friendster\"\u003EFriendster\u003C/a\u003E, \u003Ca href=\"http://www.crunchbase.com/company/LinkedIn\" title=\"LinkedIn\"\u003ELinkedIn\u003C/a\u003E, \u003Ca href=\"http://www.crunchbase.com/company/tagged\" title=\"Tagged\"\u003ETagged\u003C/a\u003E, \u003Ca href=\"http://www.techcrunch.com/2007/01/20/hi5-traffic-surges-may-be-second-largest-social-network/\" title=\"Hi5\"\u003EHi5\u003C/a\u003E, \u003Ca href=\"http://www.techcrunch.com/2006/09/25/a-look-at-piczo-and-its-competitors/\" title=\"Piczo\"\u003EPiczo\u003C/a\u003E, and \u003Ca href=\"http://www.techcrunch.com/2007/10/30/details-revealed-google-opensocial-to-be-common-apis-for-building-social-apps/\" title=\"Open Social\"\u003EOpen Social\u003C/a\u003E. \u003C/p\u003E\n\n\u003Cp\u003E\u003Cimg src=\"http://farm3.static.flickr.com/2059/2046940872_73672f2007.jpg\" alt=\"Facebook Traffic\"/\u003E\u003C/p\u003E",
+ "image":
+  {"available_sizes":
+    [[[150,
+       56],
+      "assets/images/resized/0000/4552/4552v2-max-150x150.jpg"],
+     [[250,
+       94],
+      "assets/images/resized/0000/4552/4552v2-max-250x250.jpg"],
+     [[450,
+       169],
+      "assets/images/resized/0000/4552/4552v2-max-450x450.jpg"]],
+   "attribution": null},
+ "products":
+  [{"name": "Facebook Platform",
+    "permalink": "facebook-platform"},
+   {"name": "Facebook News Feed",
+    "permalink": "facebook-news-feed"},
+   {"name": "Facebook Chat",
+    "permalink": "facebook-chat"},
+   {"name": "Facebook Connect",
+    "permalink": "facebook-connect"},
+   {"name": "Facebook iPhone App",
+    "permalink": "facebook-iphone-app"}],
+ "relationships":
+  [{"is_past": false,
+    "title": "Founder and CEO, Board Of Directors",
+    "person":
+     {"first_name": "Mark",
+      "last_name": "Zuckerberg",
+      "permalink": "mark-zuckerberg"}},
+   {"is_past": false,
+    "title": "Co-founder and VP Engineering",
+    "person":
+     {"first_name": "Dustin",
+      "last_name": "Moskovitz",
+      "permalink": "dustin-moskovitz"}},
+   {"is_past": true,
+    "title": "Chief Revenue Officer, VP of Operations",
+    "person":
+     {"first_name": "Owen",
+      "last_name": "Van Natta",
+      "permalink": "owen-van-natta"}},
+   {"is_past": true,
+    "title": "VP of Product Management",
+    "person":
+     {"first_name": "Matt",
+      "last_name": "Cohler",
+      "permalink": "matt-cohler"}},
+   {"is_past": false,
+    "title": "Co-founder",
+    "person":
+     {"first_name": "Chris",
+      "last_name": "Hughes",
+      "permalink": "chris-hughes"}},
+   {"is_past": false,
+    "title": "VP of Product Marketing",
+    "person":
+     {"first_name": "Chamath",
+      "last_name": "Palihapitiya",
+      "permalink": "chamath-palihapitiya"}},
+   {"is_past": false,
+    "title": "CFO",
+    "person":
+     {"first_name": "Gideon",
+      "last_name": "Yu",
+      "permalink": "gideon-yu"}},
+   {"is_past": true,
+    "title": "CTO",
+    "person":
+     {"first_name": "Adam",
+      "last_name": "D'Angelo",
+      "permalink": "adam-d-angelo"}},
+   {"is_past": false,
+    "title": "COO",
+    "person":
+     {"first_name": "Sheryl",
+      "last_name": "Sandberg",
+      "permalink": "sheryl-sandberg"}},
+   {"is_past": false,
+    "title": "Senior Platform Manager",
+    "person":
+     {"first_name": "Dave",
+      "last_name": "Morin",
+      "permalink": "dave-morin"}},
+   {"is_past": false,
+    "title": "Director of Business Development",
+    "person":
+     {"first_name": "Ethan",
+      "last_name": "Beard",
+      "permalink": "ethan-beard"}},
+   {"is_past": false,
+    "title": "Chief Privacy Officer",
+    "person":
+     {"first_name": "Chris",
+      "last_name": "Kelly",
+      "permalink": "chris-kelly"}},
+   {"is_past": false,
+    "title": "",
+    "person":
+     {"first_name": "Justin",
+      "last_name": "Rosenstein",
+      "permalink": "justin-rosenstein"}},
+   {"is_past": false,
+    "title": "VP of Technical Operations",
+    "person":
+     {"first_name": "Jonathan",
+      "last_name": "Heiliger",
+      "permalink": "jonathan-heiliger"}},
+   {"is_past": false,
+    "title": "Director Platform Product Marketing",
+    "person":
+     {"first_name": "Ben",
+      "last_name": "Ling",
+      "permalink": "ben-ling"}},
+   {"is_past": false,
+    "title": "Product Lead for Facebook Platform",
+    "person":
+     {"first_name": "Ruchi",
+      "last_name": "Sanghvi",
+      "permalink": "ruchi-sanghvi"}},
+   {"is_past": false,
+    "title": "Board Of Directors",
+    "person":
+     {"first_name": "Jim",
+      "last_name": "Breyer",
+      "permalink": "jim-breyer"}},
+   {"is_past": false,
+    "title": "VP of Communications and Public Policy",
+    "person":
+     {"first_name": "Elliot",
+      "last_name": "Schrage",
+      "permalink": "elliot-schrage"}},
+   {"is_past": false,
+    "title": "Board Of Directors",
+    "person":
+     {"first_name": "Peter",
+      "last_name": "Thiel",
+      "permalink": "peter-thiel"}},
+   {"is_past": false,
+    "title": "Observer to Board of Directors",
+    "person":
+     {"first_name": "David",
+      "last_name": "Sze",
+      "permalink": "david-sze"}},
+   {"is_past": true,
+    "title": "President, Board of Directors",
+    "person":
+     {"first_name": "Sean",
+      "last_name": "Parker",
+      "permalink": "sean-parker"}},
+   {"is_past": false,
+    "title": "Board of directors",
+    "person":
+     {"first_name": "Marc",
+      "last_name": "Andreessen",
+      "permalink": "marc-andreessen"}}],
+ "competitions":
+  [{"competitor":
+     {"name": "MySpace",
+      "permalink": "myspace"}},
+   {"competitor":
+     {"name": "Friendster",
+      "permalink": "friendster"}},
+   {"competitor":
+     {"name": "Slide",
+      "permalink": "slide"}},
+   {"competitor":
+     {"name": "Zvents",
+      "permalink": "zvents"}},
+   {"competitor":
+     {"name": "FriendFeed",
+      "permalink": "friendfeed"}},
+   {"competitor":
+     {"name": "Qik",
+      "permalink": "qik"}},
+   {"competitor":
+     {"name": "hi5",
+      "permalink": "hi5"}},
+   {"competitor":
+     {"name": "Photobucket",
+      "permalink": "photobucket"}},
+   {"competitor":
+     {"name": "Webshots",
+      "permalink": "webshots"}},
+   {"competitor":
+     {"name": "Flickr",
+      "permalink": "flickr"}},
+   {"competitor":
+     {"name": "Spokeo",
+      "permalink": "spokeo"}},
+   {"competitor":
+     {"name": "HOT or NOT",
+      "permalink": "hotornot"}},
+   {"competitor":
+     {"name": "Piczo",
+      "permalink": "piczo"}},
+   {"competitor":
+     {"name": "Zyb",
+      "permalink": "zyb"}},
+   {"competitor":
+     {"name": "Multiply",
+      "permalink": "multiply"}},
+   {"competitor":
+     {"name": "YouTube",
+      "permalink": "youtube"}},
+   {"competitor":
+     {"name": "badoo",
+      "permalink": "badoo"}},
+   {"competitor":
+     {"name": "openPeople",
+      "permalink": "openpeople"}},
+   {"competitor":
+     {"name": "Bigsight Media Group",
+      "permalink": "bigsight-media-group"}},
+   {"competitor":
+     {"name": "Xiaonei",
+      "permalink": "xiaonei"}},
+   {"competitor":
+     {"name": "Daikana",
+      "permalink": "daikana"}},
+   {"competitor":
+     {"name": "Bebo",
+      "permalink": "bebo"}},
+   {"competitor":
+     {"name": "AOL",
+      "permalink": "aol"}},
+   {"competitor":
+     {"name": "CityIN",
+      "permalink": "cityin"}},
+   {"competitor":
+     {"name": "Xanga",
+      "permalink": "xanga"}},
+   {"competitor":
+     {"name": "Spleak",
+      "permalink": "spleak"}},
+   {"competitor":
+     {"name": "yuwie",
+      "permalink": "yuwie"}},
+   {"competitor":
+     {"name": "Rekatu",
+      "permalink": "rekatu"}},
+   {"competitor":
+     {"name": "5icampus",
+      "permalink": "5icampus"}},
+   {"competitor":
+     {"name": "Tagged",
+      "permalink": "tagged"}}],
+ "providerships":
+  [{"title": "",
+    "is_past": false,
+    "provider":
+     {"name": "OutCast Communications",
+      "permalink": "outcast-communications"}},
+   {"title": "Public Relations",
+    "is_past": false,
+    "provider":
+     {"name": "Blanc \u0026 Otus",
+      "permalink": "blanc-otus"}}],
+ "funding_rounds":
+  [{"round_code": "angel",
+    "source_url": "",
+    "source_description": "",
+    "raised_amount": 500000.0,
+    "raised_currency_code": "USD",
+    "funded_year": 2004,
+    "funded_month": 9,
+    "funded_day": 1,
+    "investments":
+     [{"company": null,
+       "financial_org":
+        {"name": "The Founders Fund",
+         "permalink": "founders-fund"},
+       "person": null}]},
+   {"round_code": "a",
+    "source_url": "http://www.techcrunch.com/2007/11/02/jim-breyer-extra-500-million-round-for-facebook-a-total-fiction/",
+    "source_description": "Jim Breyer: Extra $500 Million Round For Facebook A \u201cTotal Fiction\u201d",
+    "raised_amount": 12700000.0,
+    "raised_currency_code": "USD",
+    "funded_year": 2005,
+    "funded_month": 5,
+    "funded_day": 1,
+    "investments":
+     [{"company": null,
+       "financial_org":
+        {"name": "Accel Partners",
+         "permalink": "accel-partners"},
+       "person": null}]},
+   {"round_code": "b",
+    "source_url": "http://www.facebook.com/press/info.php?factsheet",
+    "source_description": "Facebook Funding",
+    "raised_amount": 27500000.0,
+    "raised_currency_code": "USD",
+    "funded_year": 2006,
+    "funded_month": 4,
+    "funded_day": 1,
+    "investments":
+     [{"company": null,
+       "financial_org":
+        {"name": "Greylock",
+         "permalink": "greylock"},
+       "person": null},
+      {"company": null,
+       "financial_org":
+        {"name": "Meritech Capital Partners",
+         "permalink": "meritech-capital-partners"},
+       "person": null},
+      {"company": null,
+       "financial_org": null,
+       "person":
+        {"first_name": "Peter",
+         "last_name": "Thiel",
+         "permalink": "peter-thiel"}}]},
+   {"round_code": "c",
+    "source_url": "http://www.techcrunch.com/2007/10/24/liveblogging-the-facebook-press-conference/#more-10260",
+    "source_description": "Liveblogging The Facebook Press Conference",
+    "raised_amount": 300000000.0,
+    "raised_currency_code": "USD",
+    "funded_year": 2007,
+    "funded_month": 10,
+    "funded_day": 1,
+    "investments":
+     [{"company":
+        {"name": "Microsoft",
+         "permalink": "microsoft"},
+       "financial_org": null,
+       "person": null},
+      {"company": null,
+       "financial_org": null,
+       "person":
+        {"first_name": "Li",
+         "last_name": "Ka-shing",
+         "permalink": "li-ka-shing"}},
+      {"company": null,
+       "financial_org": null,
+       "person":
+        {"first_name": "Marc",
+         "last_name": "Samwer",
+         "permalink": "marc-samwer"}},
+      {"company": null,
+       "financial_org": null,
+       "person":
+        {"first_name": "Oliver",
+         "last_name": "Samwer",
+         "permalink": "oliver-samwer"}},
+      {"company": null,
+       "financial_org": null,
+       "person":
+        {"first_name": "Alexander",
+         "last_name": "Samwer",
+         "permalink": "alexander-samwer"}}]},
+   {"round_code": "c",
+    "source_url": "http://www.marketwatch.com/news/story/hong-kong-tycoon-li-raises/story.aspx?guid=%7BE4097AA2-9EA3-4773-9100-456E68EE1C9A%7D",
+    "source_description": "",
+    "raised_amount": 40000000.0,
+    "raised_currency_code": "USD",
+    "funded_year": 2008,
+    "funded_month": 3,
+    "funded_day": null,
+    "investments":
+     [{"company": null,
+       "financial_org": null,
+       "person":
+        {"first_name": "Li",
+         "last_name": "Ka-shing",
+         "permalink": "li-ka-shing"}}]},
+   {"round_code": "c",
+    "source_url": "",
+    "source_description": "Reneigh is sexy",
+    "raised_amount": 15000000.0,
+    "raised_currency_code": "USD",
+    "funded_year": 2008,
+    "funded_month": 1,
+    "funded_day": 15,
+    "investments":
+     [{"company": null,
+       "financial_org":
+        {"name": "European Founders Fund",
+         "permalink": "european-founders-fund"},
+       "person": null}]},
+   {"round_code": "debt_round",
+    "source_url": "http://www.businessweek.com/technology/content/may2008/tc2008059_855064.htm",
+    "source_description": "",
+    "raised_amount": 100000000.0,
+    "raised_currency_code": "USD",
+    "funded_year": 2008,
+    "funded_month": 5,
+    "funded_day": null,
+    "investments":
+     [{"company": null,
+       "financial_org":
+        {"name": "TriplePoint Capital",
+         "permalink": "triplepoint-capital"},
+       "person": null}]}],
+ "investments":
+  [],
+ "acquisition": null,
+ "acquisitions":
+  [{"price_amount": null,
+    "price_currency_code": "USD",
+    "term_code": "cash",
+    "source_url": null,
+    "source_description": null,
+    "acquired_year": 2007,
+    "acquired_month": 7,
+    "acquired_day": 1,
+    "company":
+     {"name": "Parakey",
+      "permalink": "parakey"}}],
+ "offices":
+  [{"description": null,
+    "address1": "156 University Avenue",
+    "address2": "",
+    "zip_code": "94301",
+    "city": "Palo Alto",
+    "state_code": "CA",
+    "country_code": "USA",
+    "latitude": 37.444173,
+    "longitude": -122.163294}],
+ "milestones":
+  [{"description": "Facebook adds comments to Mini-Feed",
+    "stoned_year": 2008,
+    "stoned_month": 6,
+    "stoned_day": 25,
+    "source_url": "http://venturebeat.com/2008/06/25/facebook-adds-comment-to-the-mini-feed-its-like-friendfeed-is-looking-in-the-mirror/",
+    "source_description": "Facebook adds comments to the Mini-Feed. It\u2019s like FriendFeed is looking in the mirror"}],
+ "ipo": null,
+ "video_embeds":
+  [{"embed_code": "\u003Cscript type=\"text/javascript\" src=\"http://www.podtech.net/player/popup.js\"\u003E\u003C/script\u003E\u003Cobject classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" codebase=\"http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0\" width=\"450\" height=\"299\" id=\"player73536e08d3f742de9d31b25a319af359\" align=\"middle\"\u003E\u003Cparam name=\"allowScriptAccess\" value=\"always\" /\u003E\u003Cparam name=\"FlashVars\" value=\"content=http://media1.podtech.net/media/2007/09/PID012533/PodtechRandiZuckerberg2.flv\u0026totalTime=2149000\u0026permalink=http://www.podtech.net/home/4118/the-first-sister-of-facebook\u0026breadcrumb=73536e08d3f742de9d31b25a319af359\" height=\"299\" width=\"450\" /\u003E\u003Cparam name=\"movie\" value=\"http://www.podtech.net/player/podtech-player.swf?bc=73536e08d3f742de9d31b25a319af359\" /\u003E\u003Cparam name=\"quality\" value=\"high\" /\u003E\u003Cparam name=\"scale\" value=\"noscale\" /\u003E\u003Cparam name=\"bgcolor\" value=\"#000000\" /\u003E\u003Cembed name=\"player73536e08d3f742de9d31b25a319af359\" type=\"application/x-shockwave-flash\" src=\"http://www.podtech.net/player/podtech-player.swf?bc=73536e08d3f742de9d31b25a319af359\" flashvars=\"content=http://media1.podtech.net/media/2007/09/PID012533/PodtechRandiZuckerberg2.flv\u0026totalTime=2149000\u0026permalink=http://www.podtech.net/home/4118/the-first-sister-of-facebook\u0026breadcrumb=73536e08d3f742de9d31b25a319af359\" height=\"299\" width=\"450\" allowScriptAccess=\"always\" /\u003E\u003C/object\u003E\u003Cnoscript\u003EYour browser does not support JavaScript. This media can be viewed at http://www.podtech.net/home/4118/the-first-sister-of-facebook\u003C/noscript\u003E",
+    "description": "\u003Cp\u003ERobert Scoble\u2019s video from www.podtech.net/scobleshow:\u003C/p\u003E"}],
+ "external_links":
+  [{"external_url": "http://www.marketwatch.com/news/story/story.aspx?guid={E4097AA2-9EA3-4773-9100-456E68EE1C9A}",
+    "title": "Hong Kong tycoon Li raises personal Facebook investment above $100 mln"}]}
\ No newline at end of file
diff --git a/lib/arc2/tests/data/json/sparql-select-result.json b/lib/arc2/tests/data/json/sparql-select-result.json
new file mode 100644
index 0000000000000000000000000000000000000000..2276f3fa5287478a2d8f4c9728795ed6581ed03b
--- /dev/null
+++ b/lib/arc2/tests/data/json/sparql-select-result.json
@@ -0,0 +1,78 @@
+{
+	"head": {
+	   "link": [
+		   "http://www.w3.org/TR/rdf-sparql-XMLres/example.rq"
+		   ],
+	   "vars": [
+		   "x",
+		   "hpage",
+		   "name",
+		   "mbox",
+		   "age",
+		   "blurb",
+		   "friend"
+		   ]
+	   },
+   "results": {
+       "bindings": [
+               {
+                   "x" : {
+                     "type": "bnode",
+                     "value": "r1"
+                   },
+
+                   "hpage" : {
+                     "type": "uri",
+                     "value": "http://work.example.org/alice/"
+                   },
+
+                   "name" : {
+                     "type": "literal",
+                     "value": "Alice"
+                   },
+                   
+                   "mbox" : {
+                     "type": "literal",
+                     "value": ""
+                   },
+
+                   "blurb" : {
+                     "datatype": "http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral",
+                     "type": "typed-literal",
+                     "value": "<p xmlns=\"http://www.w3.org/1999/xhtml\">My name is <b>alice</b></p>"
+                   },
+
+                   "friend" : {
+                     "type": "bnode",
+                     "value": "r2"
+                   }
+               },{
+                   "x" : {
+                     "type": "bnode",
+                     "value": "r2"
+                   },
+                   
+                   "hpage" : {
+                     "type": "uri",
+                     "value": "http://work.example.org/bob/"
+                   },
+                   
+                   "name" : {
+                     "type": "literal",
+                     "value": "Bob",
+                     "xml:lang": "en"
+                   },
+
+                   "mbox" : {
+                     "type": "uri",
+                     "value": "mailto:bob@work.example.org"
+                   },
+
+                   "friend" : {
+                     "type": "bnode",
+                     "value": "r1"
+                   }
+               }
+           ]
+       }
+   }
diff --git a/lib/arc2/tests/data/nt/saft-arc2-addition-regression1.nt b/lib/arc2/tests/data/nt/saft-arc2-addition-regression1.nt
new file mode 100644
index 0000000000000000000000000000000000000000..3d6ca2e59c168d523e4e4d0efe0806e9f5390f1e
--- /dev/null
+++ b/lib/arc2/tests/data/nt/saft-arc2-addition-regression1.nt
@@ -0,0 +1,442 @@
+<http://dbpedia.org/resource/Sydney> <http://xmlns.com/foaf/0.1/name> "Cumberland"@en .
+<http://dbpedia.org/resource/Sydney> <http://xmlns.com/foaf/0.1/name> "Sydney"@en .
+<http://dbpedia.org/resource/Sydney> <http://www.w3.org/2003/01/geo/wgs84_pos#long> "151.2111111111111"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Sydney> <http://dbpedia.org/ontology/populationTotal> "4399722"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/Sydney> <http://www.georss.org/georss/point> "33.859972222222225 151.2111111111111"@en .
+<http://dbpedia.org/resource/Sydney> <http://www.w3.org/2003/01/geo/wgs84_pos#lat> "33.859972222222225"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Sydney> <http://dbpedia.org/ontology/country> <http://dbpedia.org/resource/Australia> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/foundingYear> "1911"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/percentageOfAreaWater> "0.4"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/populationDensity> "1.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/areaLand> "3.53533377060864E9"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/areaLand> "3.534E9"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/areaWater> "1.4E7"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/state> <http://dbpedia.org/resource/Idaho> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://xmlns.com/foaf/0.1/name> "Adams County"@en .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/countySeat> <http://dbpedia.org/resource/Council,_Idaho> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/populationDensity> "0.9652553963561148"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/censusYear> "2000"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/largestCity> <http://dbpedia.org/resource/Council,_Idaho> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/areaWater> "1.294994055168E7"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/country> <http://dbpedia.org/resource/United_States> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/populationTotal> "3476"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/areaTotal> "3.548E9"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Adams_County,_Idaho> <http://dbpedia.org/ontology/areaTotal> "3.54828371116032E9"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Chuck_Cecil> <http://dbpedia.org/ontology/highschool> <http://dbpedia.org/resource/Helix_High_School> .
+<http://dbpedia.org/resource/Chuck_Cecil> <http://xmlns.com/foaf/0.1/name> "Charles Douglas Cecil"@en .
+<http://dbpedia.org/resource/Chuck_Cecil> <http://dbpedia.org/ontology/number> "26"^^<http://www.w3.org/2001/XMLSchema#integer> .
+<http://dbpedia.org/resource/Chuck_Cecil> <http://dbpedia.org/ontology/college> <http://dbpedia.org/resource/University_of_Arizona> .
+<http://dbpedia.org/resource/Chuck_Cecil> <http://dbpedia.org/ontology/birthPlace> <http://dbpedia.org/resource/Red_Bluff,_California> .
+<http://dbpedia.org/resource/Chuck_Cecil> <http://xmlns.com/foaf/0.1/name> "Chuck Cecil"@en .
+<http://dbpedia.org/resource/Chuck_Cecil> <http://dbpedia.org/ontology/position> "Free safety"@en .
+<http://dbpedia.org/resource/Chuck_Cecil> <http://dbpedia.org/ontology/height> "1.8288"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Chuck_Cecil> <http://dbpedia.org/ontology/team> <http://dbpedia.org/resource/Tennessee_Titans> .
+<http://dbpedia.org/resource/Chuck_Cecil> <http://dbpedia.org/ontology/birthDate> "1964-11-08"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://dbpedia.org/resource/Chuck_Cecil> <http://dbpedia.org/ontology/weight> "83462.4"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Chuck_Cecil> <http://dbpedia.org/ontology/status> "Active (coach)"@en .
+<http://dbpedia.org/resource/Chuck_Cecil> <http://dbpedia.org/ontology/birthPlace> <http://dbpedia.org/resource/United_States> .
+<http://dbpedia.org/resource/Daugava_River> <http://dbpedia.org/ontology/sourceCountry> <http://dbpedia.org/resource/Latvia> .
+<http://dbpedia.org/resource/Daugava_River> <http://dbpedia.org/ontology/riverMouth> <http://dbpedia.org/resource/Gulf_of_Riga> .
+<http://dbpedia.org/resource/Daugava_River> <http://dbpedia.org/ontology/mouthElevation> "0.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Daugava_River> <http://dbpedia.org/ontology/elevation> "221.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Daugava_River> <http://dbpedia.org/ontology/sourceCountry> <http://dbpedia.org/resource/Lithuania> .
+<http://dbpedia.org/resource/Daugava_River> <http://dbpedia.org/ontology/sourceCountry> <http://dbpedia.org/resource/Russia> .
+<http://dbpedia.org/resource/Daugava_River> <http://dbpedia.org/ontology/riverMouth> <http://dbpedia.org/resource/Baltic_Sea> .
+<http://dbpedia.org/resource/Daugava_River> <http://dbpedia.org/ontology/origin> <http://dbpedia.org/resource/Russia> .
+<http://dbpedia.org/resource/Daugava_River> <http://xmlns.com/foaf/0.1/name> "Daugava"@en .
+<http://dbpedia.org/resource/Daugava_River> <http://dbpedia.org/ontology/length> "1020000.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Daugava_River> <http://dbpedia.org/ontology/watershed> "8.79E10"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Daugava_River> <http://dbpedia.org/ontology/sourceCountry> <http://dbpedia.org/resource/Estonia> .
+<http://dbpedia.org/resource/Daugava_River> <http://dbpedia.org/ontology/sourceCountry> <http://dbpedia.org/resource/Belarus> .
+<http://dbpedia.org/resource/Daugava_River> <http://dbpedia.org/ontology/discharge> "678.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/inflow> <http://dbpedia.org/resource/St._Marys_River_%28Michigan-Ontario%29> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/city> <http://dbpedia.org/resource/Michigan> .
+<http://dbpedia.org/resource/Lake_Huron> <http://www.w3.org/2003/01/geo/wgs84_pos#long> "-82.4"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/city> <http://dbpedia.org/resource/Sarnia,_Ontario> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/city> <http://dbpedia.org/resource/Goderich,_Ontario> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/location> <http://dbpedia.org/resource/North_America> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/width> "244620.288"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/length> "331524.864"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/outflow> <http://dbpedia.org/resource/St._Clair_River> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/city> <http://dbpedia.org/resource/St._Ignace,_Michigan> .
+<http://dbpedia.org/resource/Lake_Huron> <http://www.w3.org/2003/01/geo/wgs84_pos#lat> "44.8"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Lake_Huron> <http://xmlns.com/foaf/0.1/name> "Lake Huron"@en .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/depth> "228.6"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/areaOfCatchment> "1.934721118420992E11"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/inflow> <http://dbpedia.org/resource/Straits_of_Mackinac> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/elevation> "175.8696"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/city> <http://dbpedia.org/resource/Alpena,_Michigan> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/city> <http://dbpedia.org/resource/Ontario> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/city> <http://dbpedia.org/resource/Bay_City,_Michigan> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/city> <http://dbpedia.org/resource/Cheboygan,_Michigan> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/depth> "59.436"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/island> <http://dbpedia.org/resource/Manitoulin_Island> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/shoreLength> "6155740.8"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Lake_Huron> <http://www.georss.org/georss/point> "44.8 -82.4"@en .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/city> <http://dbpedia.org/resource/Port_Huron,_Michigan> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/volume> "3.5387863697990693E12"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Lake_Huron> <http://dbpedia.org/ontology/areaTotal> "5.959562641883136E10"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Manzanar> <http://dbpedia.org/ontology/location> <http://dbpedia.org/resource/Inyo_County,_California> .
+<http://dbpedia.org/resource/Manzanar> <http://www.w3.org/2003/01/geo/wgs84_pos#long> "-118.15444444444445"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Manzanar> <http://www.w3.org/2003/01/geo/wgs84_pos#lat> "36.72833333333333"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Manzanar> <http://www.georss.org/georss/point> "36.72833333333333 -118.15444444444445"@en .
+<http://dbpedia.org/resource/Manzanar> <http://dbpedia.org/ontology/numberOfVisitorsAsOf> "2008"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/Manzanar> <http://dbpedia.org/ontology/added> "1976-07-30"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://dbpedia.org/resource/Manzanar> <http://dbpedia.org/ontology/numberOfVisitors> "78468"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/Manzanar> <http://dbpedia.org/ontology/area> "3293903.278336"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Manzanar> <http://xmlns.com/foaf/0.1/name> "Manzanar War Relocation Center"@en .
+<http://dbpedia.org/resource/Manzanar> <http://dbpedia.org/ontology/nearestCity> <http://dbpedia.org/resource/Independence,_California> .
+<http://dbpedia.org/resource/Manzanar> <http://dbpedia.org/ontology/governingBody> <http://dbpedia.org/resource/National_Park_Service> .
+<http://dbpedia.org/resource/Manzanar> <http://dbpedia.org/ontology/nrhpReferenceNumber> "76000484"@en .
+<http://dbpedia.org/resource/Manzanar> <http://dbpedia.org/ontology/yearOfConstruction> "1942"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/Charles_Dickens__1> <http://dbpedia.org/ontology/title> "Writer"@en .
+<http://dbpedia.org/resource/Delaware_River__sourcePosition__1> <http://www.w3.org/2003/01/geo/wgs84_pos#lat> "42.45333333333333"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Delaware_River__sourcePosition__1> <http://www.w3.org/2003/01/geo/wgs84_pos#long> "-74.60722222222222"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Delaware_River__sourcePosition__1> <http://www.georss.org/georss/point> "42.45333333333333 -74.60722222222222"@en .
+<http://dbpedia.org/resource/Johnny_Unitas> <http://dbpedia.org/ontology/deathDate> "2002-09-11"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://dbpedia.org/resource/Johnny_Unitas> <http://dbpedia.org/ontology/height> "1.8542"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Johnny_Unitas> <http://dbpedia.org/ontology/formerTeam> <http://dbpedia.org/resource/San_Diego_Chargers> .
+<http://dbpedia.org/resource/Johnny_Unitas> <http://dbpedia.org/ontology/activeYearsEndYear> "1973"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/Johnny_Unitas> <http://dbpedia.org/ontology/draftPick> "102"@en .
+<http://dbpedia.org/resource/Johnny_Unitas> <http://dbpedia.org/ontology/activeYearsStartYear> "1956"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/Johnny_Unitas> <http://dbpedia.org/ontology/draftRound> "9"@en .
+<http://dbpedia.org/resource/Johnny_Unitas> <http://dbpedia.org/ontology/weight> "87998.4"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Johnny_Unitas> <http://dbpedia.org/ontology/formerTeam> <http://dbpedia.org/resource/Pittsburgh_Steelers> .
+<http://dbpedia.org/resource/Johnny_Unitas> <http://dbpedia.org/ontology/draftYear> "1955"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/Johnny_Unitas> <http://dbpedia.org/ontology/birthDate> "1933-05-07"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://dbpedia.org/resource/Johnny_Unitas> <http://dbpedia.org/ontology/number> "19"^^<http://www.w3.org/2001/XMLSchema#integer> .
+<http://dbpedia.org/resource/Johnny_Unitas> <http://dbpedia.org/ontology/formerTeam> <http://dbpedia.org/resource/History_of_the_Indianapolis_Colts> .
+<http://dbpedia.org/resource/Johnny_Unitas> <http://dbpedia.org/ontology/debutTeam> <http://dbpedia.org/resource/History_of_the_Indianapolis_Colts> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/numberOfPostgraduateStudents> "17024"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://xmlns.com/foaf/0.1/homepage> <http://www.usc.edu/> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/provost> <http://dbpedia.org/resource/C._L._Max_Nikias> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://xmlns.com/foaf/0.1/nick> "Men/Women of Troy"@en .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/numberOfStudents> "33389"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/type> <http://dbpedia.org/resource/Private_university> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/staff> "14300"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/motto> "Let whoever earns the palm bear it"@en .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/president> <http://dbpedia.org/resource/Steven_B._Sample> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/facultySize> "4597"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/city> <http://dbpedia.org/resource/Los_Angeles,_California> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/affiliation> <http://dbpedia.org/resource/Pacific-10_Conference> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/state> <http://dbpedia.org/resource/California> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://xmlns.com/foaf/0.1/nick> "Trojans"@en .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/athletics> <http://dbpedia.org/resource/National_Collegiate_Athletic_Association> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/campus> <http://dbpedia.org/resource/Urban_area> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://xmlns.com/foaf/0.1/name> "University of Southern California"@en .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/endowment> "2.5E9"^^<http://dbpedia.org/datatype/usDollar> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/mascot> "Traveler"@en .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/motto> "Palmam qui meruit ferat"@en .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/officialSchoolColour> "USC Cardinal and USC Gold"@en .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/numberOfUndergraduateStudents> "16384"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/country> <http://dbpedia.org/resource/United_States> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/affiliation> <http://dbpedia.org/resource/Association_of_American_Universities> .
+<http://dbpedia.org/resource/University_of_Southern_California> <http://dbpedia.org/ontology/affiliation> <http://dbpedia.org/resource/Mountain_Pacific_Sports_Federation> .
+<http://dbpedia.org/resource/Mount_Hood> <http://www.w3.org/2003/01/geo/wgs84_pos#lat> "45.37351388888889"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Mount_Hood> <http://dbpedia.org/ontology/eruptionYear> "1866"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/Mount_Hood> <http://dbpedia.org/ontology/locatedInArea> <http://dbpedia.org/resource/United_States> .
+<http://dbpedia.org/resource/Mount_Hood> <http://dbpedia.org/ontology/mountainRange> <http://dbpedia.org/resource/Cascade_Range> .
+<http://dbpedia.org/resource/Mount_Hood> <http://www.w3.org/2003/01/geo/wgs84_pos#long> "-121.69591944444444"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Mount_Hood> <http://www.georss.org/georss/point> "45.37351388888889 -121.69591944444444"@en .
+<http://dbpedia.org/resource/Mount_Hood> <http://dbpedia.org/ontology/type> <http://dbpedia.org/resource/Stratovolcano> .
+<http://dbpedia.org/resource/Mount_Hood> <http://dbpedia.org/ontology/prominence> "2348.7888"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Mount_Hood> <http://dbpedia.org/ontology/locatedInArea> <http://dbpedia.org/resource/Clackamas_County,_Oregon> .
+<http://dbpedia.org/resource/Mount_Hood> <http://dbpedia.org/ontology/locatedInArea> <http://dbpedia.org/resource/Oregon> .
+<http://dbpedia.org/resource/Mount_Hood> <http://dbpedia.org/ontology/firstAscentYear> "1857"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/Mount_Hood> <http://dbpedia.org/ontology/elevation> "3428.6952"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Mount_Hood> <http://dbpedia.org/ontology/firstAscentPerson> <http://dbpedia.org/resource/Henry_Pittock> .
+<http://dbpedia.org/resource/Mount_Hood> <http://dbpedia.org/ontology/nationalTopographicSystemMapNumber> "USGS Mount Hood South 45121-C6"@en .
+<http://dbpedia.org/resource/Mount_Hood> <http://dbpedia.org/ontology/locatedInArea> <http://dbpedia.org/resource/Hood_River_County,_Oregon> .
+<http://dbpedia.org/resource/Mount_Hood> <http://xmlns.com/foaf/0.1/name> "Mount Hood"@en .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://xmlns.com/foaf/0.1/name> "Wah Yan College, Hong Kong"@en .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://xmlns.com/foaf/0.1/homepage> <http://www.wahyan.edu.hk> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://www.w3.org/2003/01/geo/wgs84_pos#lat> "22.27408"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/religion> <http://dbpedia.org/resource/Roman_Catholic> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://www.georss.org/georss/point> "22.27408 114.17615"@en .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/authority> <http://dbpedia.org/resource/Society_of_Jesus> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/sport> <http://dbpedia.org/resource/Swimming_%28sport%29> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/campusSize> "20000.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/foundingYear> "1919"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/region> <http://dbpedia.org/resource/Wan_Chai> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/sport> <http://dbpedia.org/resource/Orienteering> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/alumni> <http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong%23Notable_alumni> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/sport> <http://dbpedia.org/resource/Water_polo> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/schoolCode> "WYHK"@en .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/sport> <http://dbpedia.org/resource/Fencing> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/address> "281 Queen's Road East"@en .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/type> <http://dbpedia.org/resource/Secondary_school> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/status> "Open"@en .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/sport> <http://dbpedia.org/resource/Basketball> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/sport> <http://dbpedia.org/resource/Badminton> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/officialSchoolColour> "Red, green, blue, white"@en .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/sport> <http://dbpedia.org/resource/Table_tennis> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/sport> <http://dbpedia.org/resource/Tennis> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/motto> "In Hoc Signo Vinces"@en .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/sport> <http://dbpedia.org/resource/Ice_hockey> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/sport> <http://dbpedia.org/resource/Athletics_%28track_and_field%29> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://www.w3.org/2003/01/geo/wgs84_pos#long> "114.17615"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/head> <http://dbpedia.org/resource/Tam_Siu_Ping> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/offeredClasses> "26"@en .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/sport> <http://dbpedia.org/resource/Cross_country_running> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/motto> "(\"In this sign you shall conquer\")"@en .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/sport> <http://dbpedia.org/resource/Association_football> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/city> <http://dbpedia.org/resource/Hong_Kong> .
+<http://dbpedia.org/resource/Wah_Yan_College,_Hong_Kong> <http://dbpedia.org/ontology/numberOfStudents> "944"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/Radio_Free_Europe/Radio_Liberty__2> <http://dbpedia.org/ontology/title> "President"@en .
+<http://dbpedia.org/resource/Radio_Free_Europe/Radio_Liberty__2> <http://dbpedia.org/ontology/person> <http://dbpedia.org/resource/Jeffrey_Gedmin> .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://dbpedia.org/ontology/foundedBy> <http://dbpedia.org/resource/King_Edward_VI> .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://dbpedia.org/ontology/headLabel> "Headmaster"@en .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://dbpedia.org/ontology/country> <http://dbpedia.org/resource/England> .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://dbpedia.org/ontology/motto> "Honour All Men, Love the Brotherhood, Fear God, Honour the King."@en .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://dbpedia.org/ontology/foundingYear> "1552"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://xmlns.com/foaf/0.1/name> "Christ's Hospital"@en .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://dbpedia.org/ontology/county> <http://dbpedia.org/resource/West_Sussex> .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://xmlns.com/foaf/0.1/homepage> <http://www.christs-hospital.org.uk> .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://dbpedia.org/ontology/upperAge> "18"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://dbpedia.org/ontology/type> <http://dbpedia.org/resource/Independent_school> .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://dbpedia.org/ontology/religiousHead> <http://dbpedia.org/resource/BSc> .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://dbpedia.org/ontology/head> <http://dbpedia.org/resource/John_Franklin_%28headmaster%29> .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://dbpedia.org/ontology/officialSchoolColour> "Blue & Yellow"@en .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://dbpedia.org/ontology/numberOfStudents> "831"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://dbpedia.org/ontology/lowerAge> "11"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://dbpedia.org/ontology/country> <http://dbpedia.org/resource/United_Kingdom> .
+<http://dbpedia.org/resource/Christ%27s_Hospital> <http://dbpedia.org/ontology/president> <http://dbpedia.org/resource/Prince_Richard,_Duke_of_Gloucester> .
+<http://dbpedia.org/resource/WKHX-FM> <http://xmlns.com/foaf/0.1/homepage> <http://www.kicks1015.com> .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/slogan> "Today's Best Country Hits"@en .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/city> <http://dbpedia.org/resource/Marietta,_Georgia> .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/sisterStation> <http://dbpedia.org/resource/WYAY> .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/shareOfAudience> "4.0"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/formerCallsign> "WBIE-FM (1968-1981)"@en .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/shareSource> "R&R"@en .
+<http://dbpedia.org/resource/WKHX-FM> <http://www.georss.org/georss/point> "33.80722222222222 -84.33944444444444"@en .
+<http://dbpedia.org/resource/WKHX-FM> <http://www.w3.org/2003/01/geo/wgs84_pos#lat> "33.80722222222222"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/programmeFormat> <http://dbpedia.org/resource/Country_music> .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/licensee> "Radio License Holding II, LLC, Debtor in possession"@en .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/formerCallsign> "WKHX (1981-1987)"@en .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/broadcastNetwork> <http://dbpedia.org/resource/Premiere_Radio_Networks> .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/frequency> "1.015E8"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/owner> <http://dbpedia.org/resource/Citadel_Broadcasting> .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/broadcastStationClass> "C0"@en .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/facilityId> "73161"^^<http://www.w3.org/2001/XMLSchema#integer> .
+<http://dbpedia.org/resource/WKHX-FM> <http://xmlns.com/foaf/0.1/name> "WKHX-FM"@en .
+<http://dbpedia.org/resource/WKHX-FM> <http://www.w3.org/2003/01/geo/wgs84_pos#long> "-84.33944444444444"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/city> <http://dbpedia.org/resource/Georgia_%28U.S._state%29> .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/alias> "Kicks 101.5"@en .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/broadcastNetwork> <http://dbpedia.org/resource/ABC_Radio> .
+<http://dbpedia.org/resource/WKHX-FM> <http://dbpedia.org/ontology/broadcastArea> <http://dbpedia.org/resource/Atlanta_metropolitan_area> .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/height> "1.8288"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/shoots> "Left"@en .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/activeYearsStartYear> "1990"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/formerTeam> <http://dbpedia.org/resource/National_Hockey_League> .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/team> <http://dbpedia.org/resource/Modo_Hockey> .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/draftYear> "1991"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/draftTeam> <http://dbpedia.org/resource/Philadelphia_Flyers> .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/position> "Centre"@en .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/draft> "6th overall"@en .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/birthDate> "1973-07-20"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/formerTeam> <http://dbpedia.org/resource/Philadelphia_Flyers> .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/formerTeam> <http://dbpedia.org/resource/Quebec_Nordiques> .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/birthPlace> <http://dbpedia.org/resource/%C3%96rnsk%C3%B6ldsvik> .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/league> <http://dbpedia.org/resource/Elitserien> .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/formerTeam> <http://dbpedia.org/resource/Nashville_Predators> .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/formerTeam> <http://dbpedia.org/resource/Colorado_Avalanche> .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/weight> "95256.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Peter_Forsberg> <http://dbpedia.org/ontology/birthPlace> <http://dbpedia.org/resource/Sweden> .
+<http://dbpedia.org/resource/German_submarine_U-238> <http://dbpedia.org/ontology/status> "Sunk by Surface Craft, 09 February 1944"@en .
+<http://dbpedia.org/resource/German_submarine_U-238> <http://dbpedia.org/ontology/builder> <http://dbpedia.org/resource/Kiel> .
+<http://dbpedia.org/resource/German_submarine_U-238> <http://xmlns.com/foaf/0.1/name> "U-238"@en .
+<http://dbpedia.org/resource/German_submarine_U-238> <http://dbpedia.org/ontology/shipLaunch> "1943-01-07"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://dbpedia.org/resource/German_submarine_U-238> <http://dbpedia.org/ontology/commissioningDate> "1943-02-20"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://dbpedia.org/resource/German_submarine_U-238> <http://dbpedia.org/ontology/builder> <http://dbpedia.org/resource/Germaniawerft> .
+<http://dbpedia.org/resource/German_submarine_U-238> <http://dbpedia.org/ontology/layingDown> "1942-04-21"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://dbpedia.org/resource/Stairway_to_Heaven> <http://dbpedia.org/ontology/releaseDate> "1971-11-08"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://dbpedia.org/resource/Stairway_to_Heaven> <http://dbpedia.org/ontology/trackNumber> "4"^^<http://www.w3.org/2001/XMLSchema#positiveInteger> .
+<http://dbpedia.org/resource/Stairway_to_Heaven> <http://dbpedia.org/ontology/subsequentWork> <http://dbpedia.org/resource/Misty_Mountain_Hop> .
+<http://dbpedia.org/resource/Stairway_to_Heaven> <http://dbpedia.org/ontology/previousWork> <http://dbpedia.org/resource/The_Battle_of_Evermore> .
+<http://dbpedia.org/resource/Stairway_to_Heaven> <http://dbpedia.org/ontology/album> <http://dbpedia.org/resource/Led_Zeppelin_IV> .
+<http://dbpedia.org/resource/Stairway_to_Heaven> <http://dbpedia.org/ontology/writer> <http://dbpedia.org/resource/Robert_Plant> .
+<http://dbpedia.org/resource/Stairway_to_Heaven> <http://dbpedia.org/ontology/genre> <http://dbpedia.org/resource/Rock_music> .
+<http://dbpedia.org/resource/Stairway_to_Heaven> <http://dbpedia.org/ontology/recordLabel> <http://dbpedia.org/resource/Atlantic_Records> .
+<http://dbpedia.org/resource/Stairway_to_Heaven> <http://dbpedia.org/ontology/writer> <http://dbpedia.org/resource/Jimmy_Page> .
+<http://dbpedia.org/resource/Stairway_to_Heaven> <http://xmlns.com/foaf/0.1/name> "Stairway to Heaven"@en .
+<http://dbpedia.org/resource/Stairway_to_Heaven> <http://dbpedia.org/ontology/producer> <http://dbpedia.org/resource/Jimmy_Page> .
+<http://dbpedia.org/resource/Stairway_to_Heaven> <http://dbpedia.org/ontology/artist> <http://dbpedia.org/resource/Led_Zeppelin> .
+<http://dbpedia.org/resource/Stairway_to_Heaven> <http://dbpedia.org/ontology/runtime> "475.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Frankfurt_am_Main> <http://dbpedia.org/ontology/populationMetro> "5800000"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/Frankfurt_am_Main> <http://xmlns.com/foaf/0.1/name> "Frankfurt am Main"@en .
+<http://dbpedia.org/resource/Frankfurt_am_Main> <http://dbpedia.org/ontology/areaCode> "069, 06109, 06101"@en .
+<http://dbpedia.org/resource/Frankfurt_am_Main> <http://dbpedia.org/ontology/postalCode> "60001-60599, 65901-65936"@en .
+<http://dbpedia.org/resource/Frankfurt_am_Main> <http://dbpedia.org/ontology/populationAsOf> "2008-03-31"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://dbpedia.org/resource/Frankfurt_am_Main> <http://dbpedia.org/ontology/populationTotal> "651899"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/Frankfurt_am_Main> <http://www.georss.org/georss/point> "50.110277777777775 8.682222222222222"@en .
+<http://dbpedia.org/resource/Frankfurt_am_Main> <http://dbpedia.org/ontology/country> <http://dbpedia.org/resource/Germany> .
+<http://dbpedia.org/resource/Frankfurt_am_Main> <http://dbpedia.org/ontology/foundingYear> "0001"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/Frankfurt_am_Main> <http://www.w3.org/2003/01/geo/wgs84_pos#long> "8.682222222222222"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Frankfurt_am_Main> <http://xmlns.com/foaf/0.1/homepage> <http://www.frankfurt.de/> .
+<http://dbpedia.org/resource/Frankfurt_am_Main> <http://dbpedia.org/ontology/areaTotal> "2.4831E8"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Frankfurt_am_Main> <http://dbpedia.org/ontology/administrativeDistrict> <http://dbpedia.org/resource/Darmstadt> .
+<http://dbpedia.org/resource/Frankfurt_am_Main> <http://www.w3.org/2003/01/geo/wgs84_pos#lat> "50.110277777777775"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/network> <http://dbpedia.org/resource/Associated_TeleVision> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/voice> <http://dbpedia.org/resource/Sylvia_Anderson> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/composer> <http://dbpedia.org/resource/Barry_Gray> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/editor> <http://dbpedia.org/resource/David_Lane_%28director%29> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/director> <http://dbpedia.org/resource/David_Elliott_%28director%29> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/author> <http://dbpedia.org/resource/Tony_Barwick> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/voice> <http://dbpedia.org/resource/Peter_Dyneley> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/related> <http://dbpedia.org/resource/Thunderbirds_2086> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/person> <http://dbpedia.org/resource/John_Read_%28producer%29> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/numberOfSeasons> "2"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/format> <http://dbpedia.org/resource/Supermarionation> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/runtime> "3000.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/voice> <http://dbpedia.org/resource/John_Tate_%28actor%29> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/author> <http://dbpedia.org/resource/Gerry_Anderson> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/genre> <http://dbpedia.org/resource/Science_fiction> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/releaseDate> "1965-09-30"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/director> <http://dbpedia.org/resource/Desmond_Saunders> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/country> <http://dbpedia.org/resource/Television_in_the_United_Kingdom> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/voice> <http://dbpedia.org/resource/Shane_Rimmer> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/genre> <http://dbpedia.org/resource/Disaster_film> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/distributor> <http://dbpedia.org/resource/ITC_Entertainment> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/author> <http://dbpedia.org/resource/Alan_Fennell> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/genre> <http://dbpedia.org/resource/Action_%28genre%29> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/genre> <http://dbpedia.org/resource/Adventure_%28genre%29> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/voice> <http://dbpedia.org/resource/Matt_Zimmerman> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/language> <http://dbpedia.org/resource/English_language> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/subsequentWork> <http://dbpedia.org/resource/Thunderbirds_Are_Go> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/company> <http://dbpedia.org/resource/AP_Films> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/voice> <http://dbpedia.org/resource/Jeremy_Wilkin> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/author> <http://dbpedia.org/resource/Sylvia_Anderson> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/producer> <http://dbpedia.org/resource/Reg_Hill> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/voice> <http://dbpedia.org/resource/Charles_Tingwell> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/genre> <http://dbpedia.org/resource/Children%27s_television_series> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/voice> <http://dbpedia.org/resource/Paul_Maxwell> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/author> <http://dbpedia.org/resource/Dennis_Spooner> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/format> <http://dbpedia.org/resource/Monaural> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/creator> <http://dbpedia.org/resource/Sylvia_Anderson> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/voice> <http://dbpedia.org/resource/Christine_Finn> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/format> <http://dbpedia.org/resource/Film> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/numberOfEpisodes> "32"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/voice> <http://dbpedia.org/resource/David_Holliday> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/voice> <http://dbpedia.org/resource/David_Graham_%28actor%29> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/director> <http://dbpedia.org/resource/David_Lane_%28director%29> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/creator> <http://dbpedia.org/resource/Gerry_Anderson> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://dbpedia.org/ontology/voice> <http://dbpedia.org/resource/Ray_Barrett> .
+<http://dbpedia.org/resource/Thunderbirds_%28TV_series%29> <http://xmlns.com/foaf/0.1/name> "Thunderbirds"@en .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/discoverer> <http://dbpedia.org/resource/William_Herschel> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/orbitalPeriod> "3.6908352E9"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/maximumTemperature> "57.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/volume> "6.833E9"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/periapsis> "2.748938461E12"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/density> "1270.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/orbitalPeriod> "2.6610418080000005E9"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/periapsis> "2.748860873947125E12"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/minimumTemperature> "49.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/discovered> "1781-03-13"^^<http://www.w3.org/2001/XMLSchema#date> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/albedo> "0.51"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/orbitalPeriod> "2.661031504799999E9"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/epoch> "J2000"@en .
+<http://dbpedia.org/resource/Uranus> <http://xmlns.com/foaf/0.1/name> "Uranus"@en .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/volume> "63.086"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/escapeVelocity> "76680.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/apparentMagnitude> "5.9"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/apoapsis> "3.004374037087353E12"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/meanTemperature> "76.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/meanTemperature> "53.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/apoapsis> "3.004419704E12"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/averageSpeed> "24516.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Uranus> <http://dbpedia.org/ontology/albedo> "0.3"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/neighboringMunicipality> <http://dbpedia.org/resource/Br%C3%BCtten> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/neighboringMunicipality> <http://dbpedia.org/resource/Seuzach> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/municipalityCode> "0230"@en .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/neighboringMunicipality> <http://dbpedia.org/resource/Neftenbach> .
+<http://dbpedia.org/resource/Winterthur> <http://xmlns.com/foaf/0.1/name> "Winterthur"@en .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/neighboringMunicipality> <http://dbpedia.org/resource/Pfungen> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/country> <http://dbpedia.org/resource/Switzerland> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/maximumElevation> "687.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/twinCity> <http://dbpedia.org/resource/Plze%C5%88> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/postalCode> "8400"@en .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/neighboringMunicipality> <http://dbpedia.org/resource/Elsau> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/neighboringMunicipality> <http://dbpedia.org/resource/Dinhard> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/neighboringMunicipality> <http://dbpedia.org/resource/Oberembrach> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/highestPlace> <http://dbpedia.org/resource/Hulmen> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/populationTotal> "100000"^^<http://www.w3.org/2001/XMLSchema#nonNegativeInteger> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/neighboringMunicipality> <http://dbpedia.org/resource/Wiesendangen> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/areaTotal> "6.793E7"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/neighboringMunicipality> <http://dbpedia.org/resource/Zell,_Zurich> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/neighboringMunicipality> <http://dbpedia.org/resource/Illnau-Effretikon> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/neighboringMunicipality> <http://dbpedia.org/resource/Lindau,_Switzerland> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/twinCity> <http://dbpedia.org/resource/Yverdon-les-Bains> .
+<http://dbpedia.org/resource/Winterthur> <http://www.w3.org/2003/01/geo/wgs84_pos#long> "8.75"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/twinCity> <http://dbpedia.org/resource/Hall_in_Tirol> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/elevation> "439.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/neighboringMunicipality> <http://dbpedia.org/resource/Kyburg,_Zurich> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/district> <http://dbpedia.org/resource/Winterthur_%28district%29> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/canton> <http://dbpedia.org/resource/Zurich_%28canton%29> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/neighboringMunicipality> <http://dbpedia.org/resource/Schlatt,_Zurich> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/neighboringMunicipality> <http://dbpedia.org/resource/Hettlingen> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/twinCity> <http://dbpedia.org/resource/La_Chaux-de-Fonds> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/censusYear> "2008"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/minimumElevation> "393.0"^^<http://www.w3.org/2001/XMLSchema#double> .
+<http://dbpedia.org/resource/Winterthur> <http://dbpedia.org/ontology/neighboringMunicipality> <http://dbpedia.org/resource/Rickenbach,_Zurich> .
+<http://dbpedia.org/resource/Winterthur> <http://www.georss.org/georss/point> "47.5 8.75"@en .
+<http://dbpedia.org/resource/Winterthur> <http://www.w3.org/2003/01/geo/wgs84_pos#lat> "47.5"^^<http://www.w3.org/2001/XMLSchema#float> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/militaryBranch> <http://dbpedia.org/resource/Air_Force> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/militaryUnitSize> "327,452 active personnel"@en .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/country> <http://dbpedia.org/resource/United_States_of_America> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftFighter> <http://dbpedia.org/resource/F-16_Fighting_Falcon> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTransport> <http://dbpedia.org/resource/McDonnell_Douglas_C-9> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftElectronic> <http://dbpedia.org/resource/EC-130> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/colourName> "Ultramarine Blue & Air Force Yellow"@en .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/march> <http://dbpedia.org/resource/The_U.S._Air_Force_%28song%29> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTransport> <http://dbpedia.org/resource/KC-10_Extender> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://xmlns.com/foaf/0.1/name> "United States Air Force"@en .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftBomber> <http://dbpedia.org/resource/B-2_Spirit> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftHelicopter> <http://dbpedia.org/resource/HH-60_Pave_Hawk> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftElectronic> <http://dbpedia.org/resource/E-3_Sentry> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftElectronic> <http://dbpedia.org/resource/Boeing_EC-135> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftElectronic> <http://dbpedia.org/resource/E-8_Joint_STARS> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftAttack> <http://dbpedia.org/resource/A-10_Thunderbolt_II> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTrainer> <http://dbpedia.org/resource/T-1A_Jayhawk> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/activeYearsStartYear> "1947"^^<http://www.w3.org/2001/XMLSchema#gYear> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftRecon> <http://dbpedia.org/resource/Lockheed_U-2> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/commander> <http://dbpedia.org/resource/Norton_A._Schwartz> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTransport> <http://dbpedia.org/resource/C-17_Globemaster_III> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/militaryUnitSize> "450 ICBMs"@en .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftAttack> <http://dbpedia.org/resource/Lockheed_AC-130> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTransport> <http://dbpedia.org/resource/VC-25> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftHelicopter> <http://dbpedia.org/resource/UH-1N_Twin_Huey> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/commandStructure> <http://dbpedia.org/resource/United_States_Department_of_Defense> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTransport> <http://dbpedia.org/resource/C-12_Huron> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftRecon> <http://dbpedia.org/resource/Boeing_RC-135> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTransport> <http://dbpedia.org/resource/KC-135_Stratotanker> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftBomber> <http://dbpedia.org/resource/B-1_Lancer> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftRecon> <http://dbpedia.org/resource/RQ-1_Predator> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTransport> <http://dbpedia.org/resource/C-40_Clipper> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/thirdCommander> <http://dbpedia.org/resource/James_A._Roy> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/identificationSymbol> "50px"@en .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftRecon> <http://dbpedia.org/resource/RQ-4_Global_Hawk> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTransport> <http://dbpedia.org/resource/V-22_Osprey> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTrainer> <http://dbpedia.org/resource/TG-10> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/militaryUnitSize> "5,573 aircraft, of which 2,132 are fighters"@en .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTransport> <http://dbpedia.org/resource/Gulfstream_G500> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTransport> <http://dbpedia.org/resource/C-135> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftBomber> <http://dbpedia.org/resource/B-52_Stratofortress> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/garrison> <http://dbpedia.org/resource/The_Pentagon> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/battle> <http://dbpedia.org/resource/Korean_War> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTrainer> <http://dbpedia.org/resource/Boeing_T-43> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftFighter> <http://dbpedia.org/resource/F-15E_Strike_Eagle> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftFighter> <http://dbpedia.org/resource/F-15_Eagle> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTransport> <http://dbpedia.org/resource/Learjet_35A> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/role> "\"To fly, fight and win ... in air, space and cyberspace.\""@en .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTrainer> <http://dbpedia.org/resource/T-38_Talon> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTransport> <http://dbpedia.org/resource/Boeing_C-32> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/militaryUnitSize> "32 satellites"@en .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/motto> "\"Above All\" (as of 19 Feb. 2008)"@en .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/secondCommander> <http://dbpedia.org/resource/Carrol_H._Chandler> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTrainer> <http://dbpedia.org/resource/T-6_Texan_II> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTransport> <http://dbpedia.org/resource/C-5_Galaxy> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/colour> <http://dbpedia.org/resource/Ultramarine> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftTransport> <http://dbpedia.org/resource/C-130_Hercules> .
+<http://dbpedia.org/resource/United_States_Air_Force> <http://dbpedia.org/ontology/aircraftFighter> <http://dbpedia.org/resource/F-22_Raptor> .
+<http://dbpedia.org/resource/Skuld_%28Oh_My_Goddess%21%29> <http://dbpedia.org/ontology/relative> <http://dbpedia.org/resource/Belldandy> .
+<http://dbpedia.org/resource/Skuld_%28Oh_My_Goddess%21%29> <http://dbpedia.org/ontology/creator> <http://dbpedia.org/resource/Kosuke_Fujishima> .
diff --git a/lib/arc2/tests/data/nt/test.nt b/lib/arc2/tests/data/nt/test.nt
new file mode 100644
index 0000000000000000000000000000000000000000..3e52881499f97debaf4675c3f41eae850a586f1d
--- /dev/null
+++ b/lib/arc2/tests/data/nt/test.nt
@@ -0,0 +1,78 @@
+#
+# Copyright World Wide Web Consortium, (Massachusetts Institute of
+# Technology, Institut National de Recherche en Informatique et en
+# Automatique, Keio University).
+#
+# All Rights Reserved.
+#
+# Please see the full Copyright clause at
+# <http://www.w3.org/Consortium/Legal/copyright-software.html>
+#
+# Test file with a variety of legal N-Triples
+#
+# Dave Beckett - http://purl.org/net/dajobe/
+# 
+# $Id: test.nt,v 1.7 2003/10/06 15:52:19 dbeckett2 Exp $
+# 
+#####################################################################
+
+# comment lines
+  	  	   # comment line after whitespace
+# empty blank line, then one with spaces and tabs
+
+         	
+<http://example.org/resource1> <http://example.org/property> <http://example.org/resource2> .
+_:anon <http://example.org/property> <http://example.org/resource2> .
+<http://example.org/resource2> <http://example.org/property> _:anon .
+# spaces and tabs throughout:
+ 	 <http://example.org/resource3> 	 <http://example.org/property>	 <http://example.org/resource2> 	.	 
+
+# line ending with CR NL (ASCII 13, ASCII 10)
+<http://example.org/resource4> <http://example.org/property> <http://example.org/resource2> .
+
+# 2 statement lines separated by single CR (ASCII 10)
+<http://example.org/resource5> <http://example.org/property> <http://example.org/resource2> .
<http://example.org/resource6> <http://example.org/property> <http://example.org/resource2> .
+
+
+# All literal escapes
+<http://example.org/resource7> <http://example.org/property> "simple literal" .
+<http://example.org/resource8> <http://example.org/property> "backslash:\\" .
+<http://example.org/resource9> <http://example.org/property> "dquote:\"" .
+<http://example.org/resource10> <http://example.org/property> "newline:\n" .
+<http://example.org/resource11> <http://example.org/property> "return\r" .
+<http://example.org/resource12> <http://example.org/property> "tab:\t" .
+
+# Space is optional before final .
+<http://example.org/resource13> <http://example.org/property> <http://example.org/resource2>.
+<http://example.org/resource14> <http://example.org/property> "x".
+<http://example.org/resource15> <http://example.org/property> _:anon.
+
+# \u and \U escapes
+# latin small letter e with acute symbol \u00E9 - 3 UTF-8 bytes #xC3 #A9
+<http://example.org/resource16> <http://example.org/property> "\u00E9" .
+# Euro symbol \u20ac  - 3 UTF-8 bytes #xE2 #x82 #xAC
+<http://example.org/resource17> <http://example.org/property> "\u20AC" .
+# resource18 test removed
+# resource19 test removed
+# resource20 test removed
+
+# XML Literals as Datatyped Literals
+<http://example.org/resource21> <http://example.org/property> ""^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource22> <http://example.org/property> " "^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource23> <http://example.org/property> "x"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource23> <http://example.org/property> "\""^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource24> <http://example.org/property> "<a></a>"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource25> <http://example.org/property> "a <b></b>"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource26> <http://example.org/property> "a <b></b> c"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource26> <http://example.org/property> "a\n<b></b>\nc"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource27> <http://example.org/property> "chat"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+# resource28 test removed 2003-08-03
+# resource29 test removed 2003-08-03
+
+# Plain literals with languages
+<http://example.org/resource30> <http://example.org/property> "chat"@fr .
+<http://example.org/resource31> <http://example.org/property> "chat"@en .
+
+# Typed Literals
+<http://example.org/resource32> <http://example.org/property> "abc"^^<http://example.org/datatype1> .
+# resource33 test removed 2003-08-03
diff --git a/lib/arc2/tests/data/rdfxml/planetrdf-bloggers.rdf b/lib/arc2/tests/data/rdfxml/planetrdf-bloggers.rdf
new file mode 100644
index 0000000000000000000000000000000000000000..16e5b30a89142f88587758dca5cb5da76f48f751
--- /dev/null
+++ b/lib/arc2/tests/data/rdfxml/planetrdf-bloggers.rdf
@@ -0,0 +1,1439 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this is a comment -->
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:rss="http://purl.org/rss/1.0/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:html="http://www.w3.org/1999/xhtml">
+
+<foaf:Agent rdf:nodeID="id2245565"> 
+<foaf:name>Planet RDF</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.planetrdf.com/"> 
+<dc:title>Planet RDF site blog</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.planetrdf.com/rss.xml"> 
+<foaf:maker rdf:nodeID="id2245565"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245590"> 
+<foaf:name>AKSW Group - University of Leipzig</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.aksw.org/"> 
+<dc:title>AKSW Group - University of Leipzig</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.aksw.org/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2245590"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245615"> 
+<foaf:name>Dean Allemang</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://dallemang.typepad.com/"> 
+<dc:title>S is for Semantics by Dean Allemang</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://dallemang.typepad.com/my_weblog/index.rdf"> 
+<foaf:maker rdf:nodeID="id2245615"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245641"> 
+<foaf:name>Zoltan Andrejkovics</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.andzol.com/"> 
+<dc:title>Zoltan Andrejkovics</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.andzol.com/?feed=rdf"> 
+<foaf:maker rdf:nodeID="id2245641"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245665"> 
+<foaf:name>Al Baker</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>AlBaker_Dev</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://linkedjava.blogspot.com/"> 
+<dc:title>Linked Java by Al Baker</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://linkedjava.blogspot.com/feeds/posts/default"> 
+<foaf:maker rdf:nodeID="id2245665"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245701"> 
+<foaf:name>Dave Beckett</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>dajobe</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://journal.dajobe.org/journal/"> 
+<dc:title>Journalblog by Dave Beckett</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://journal.dajobe.org/journal/comments.rdf"> 
+<foaf:maker rdf:nodeID="id2245701"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245737"> 
+<foaf:name>Tim Berners-Lee</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>timberners_lee</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://dig.csail.mit.edu/breadcrumbs/blog/4"> 
+<dc:title>Tim Berners-Lee</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://dig.csail.mit.edu/breadcrumbs/blog/feed/4"> 
+<foaf:maker rdf:nodeID="id2245737"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245776"> 
+<foaf:name>Uldis Bojars</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>CaptSolo</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://captsolo.net/info/"> 
+<dc:title>Uldis Bojars (Captain Solo)</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://captsolo.net/info/xmlsrv/rdf.php?blog=2&amp;cat=3"> 
+<foaf:maker rdf:nodeID="id2245776"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245809"> 
+<foaf:name>John Breslin</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>johnbreslin</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.johnbreslin.com/blog/"> 
+<dc:title>Cloudlands by John Breslin</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.johnbreslin.com/blog/category/semantic-web/rdf"> 
+<foaf:maker rdf:nodeID="id2245809"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245844"> 
+<foaf:name>Dan Brickley</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>danbri</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://danbri.org/words/"> 
+<dc:title>danbri's foaf stories</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://danbri.org/words/category/technology/rdf"> 
+<foaf:maker rdf:nodeID="id2245844"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245877"> 
+<foaf:name>Jeen Broekstra</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>jeenbroekstra</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://rivuli-development.com/weblog/"> 
+<dc:title>Rivuli by Jeen Broekstra</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://rivuli-development.com/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2245877"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245911"> 
+<foaf:name>Dries Buytaert</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>dries</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://buytaert.net/tag/semantic-web"> 
+<dc:title>Dries Buytaert - Semantic Web</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://buytaert.net/taxonomy/term/61/0/feed"> 
+<foaf:maker rdf:nodeID="id2245911"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245946"> 
+<foaf:name>Cambridge Semantics</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.cambridgesemantics.com/blog/"> 
+<dc:title>Cambridge Semantics</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://feeds.feedburner.com/EnterpriseSemantics"> 
+<foaf:maker rdf:nodeID="id2245946"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245972"> 
+<foaf:name>Clark and Parsia</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>candp</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://clarkparsia.com/weblog/"> 
+<dc:title>Tales of a Semantic Web Consultancy by Clark and Parsia</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://clarkparsia.com/weblog/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2245972"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257265"> 
+<foaf:name>Dan Connolly</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>dckc</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.madmode.com/"> 
+<dc:title>Dan Connolly</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.madmode.com/feeds/posts/default"> 
+<foaf:maker rdf:nodeID="id2257265"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257300"> 
+<foaf:name>Richard Cyganiak</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>cygri</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://dowhatimean.net/"> 
+<dc:title>Richard Cyganiak</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://dowhatimean.net/category/semantic-web/rdf"> 
+<foaf:maker rdf:nodeID="id2257300"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257332"> 
+<foaf:name>Datagraph</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>datagraph</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.datagraph.org/"> 
+<dc:title>Datagraph</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://feeds.feedburner.com/datagraph"> 
+<foaf:maker rdf:nodeID="id2257332"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257365"> 
+<foaf:name>Phil Dawes</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>phildawes</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.phildawes.net/blog/"> 
+<dc:title>Phil Dawes</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.phildawes.net/blog/category/semantic-web/rdf"> 
+<foaf:maker rdf:nodeID="id2257365"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257399"> 
+<foaf:name>Yves Raimond</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>moustaki</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.dbtune.org/"> 
+<dc:title>DBTune by Yves Raimond</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.dbtune.org/feed/rss2"> 
+<foaf:maker rdf:nodeID="id2257399"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257433"> 
+<foaf:name>DERI Galway</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.deri.ie/"> 
+<dc:title>DERI Galway</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.deri.ie/fileadmin/feed.rdf"> 
+<foaf:maker rdf:nodeID="id2257433"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257457"> 
+<foaf:name>DOAP Project</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://usefulinc.com/doap"> 
+<dc:title>DOAP Project</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://usefulinc.com/doap/news/rss"> 
+<foaf:maker rdf:nodeID="id2257457"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257481"> 
+<foaf:name>Leigh Dodds</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>ldodds</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://ldodds.com/blog/"> 
+<dc:title>Lost Boy by Leigh Dodds</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.ldodds.com/blog/index.rdf"> 
+<foaf:maker rdf:nodeID="id2257481"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257514"> 
+<foaf:name>Dublin Core Metadata Initiative</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>DublinCore</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.dublincore.org/"> 
+<dc:title>Dublin Core Metadata Initiative</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://dublincore.org/news.rss"> 
+<foaf:maker rdf:nodeID="id2257514"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257547"> 
+<foaf:name>Bob DuCharme</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>bobdc</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.snee.com/bobdc.blog/"> 
+<dc:title>bobdc.blog by Bob DuCharme</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.snee.com/bobdc.blog/bobdcblog.rdf"> 
+<foaf:maker rdf:nodeID="id2257547"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257581"> 
+<foaf:name>Edd Dumbill</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>edd</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://usefulinc.com/edd/blog"> 
+<dc:title>behind the times by Edd Dumbill</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://times.usefulinc.com/rss"> 
+<foaf:maker rdf:nodeID="id2257581"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257615"> 
+<foaf:name>Ebiquity research group UMBC</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://ebiquity.umbc.edu/blogger"> 
+<dc:title>Ebiquity research group UMBC</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://ebiquity.umbc.edu/blogger/category/semanticweb/rdf"> 
+<foaf:maker rdf:nodeID="id2257615"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257642"> 
+<foaf:name>Dydra</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>dydradata</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.dydra.com/"> 
+<dc:title>Dydra</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://feeds.feedburner.com/dydra"> 
+<foaf:maker rdf:nodeID="id2257642"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257675"> 
+<foaf:name>EnAKTing project</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blogs.ecs.soton.ac.uk/enakting/"> 
+<dc:title>EnAKTing project</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blogs.ecs.soton.ac.uk/enakting/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2257675"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257701"> 
+<foaf:name>Orri Erling</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.openlinksw.com/weblogs/oerling/"> 
+<dc:title>Orri Erling by </dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.openlinksw.com/weblogs/oerling/gems/index.rdf"> 
+<foaf:maker rdf:nodeID="id2257701"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257726"> 
+<foaf:name>Lee Feigenbaum</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>LeeFeigenbaum</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.thefigtrees.net/lee/blog/semantic_web/"> 
+<dc:title>Lee Feigenbaum</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://thefigtrees.net/lee/blog/semantic_web/index.rdf"> 
+<foaf:maker rdf:nodeID="id2257726"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257760"> 
+<foaf:name>Sergio Fernández</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.wikier.org/blog/"> 
+<dc:title>Sergio Fernández</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://feeds.feedburner.com/wikier-semantics"> 
+<foaf:maker rdf:nodeID="id2257760"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257787"> 
+<foaf:name>FOAF Project</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.foaf-project.org/"> 
+<dc:title>FOAF Project blog</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.foaf-project.org/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2257787"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257813"> 
+<foaf:name>Morten Frederiksen</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>mortenf</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.wasab.dk/morten/blog/"> 
+<dc:title>Binary Relations by Morten Frederiksen</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.wasab.dk/morten/blog/archives/category/semweb/feed/"> 
+<foaf:maker rdf:nodeID="id2257813"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257847"> 
+<foaf:name>Frederick Giasson</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://fgiasson.com/blog/"> 
+<dc:title>Frederick Giasson</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://fgiasson.com/blog/index.php/category/fredblog/web/semantic-web/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2257847"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257872"> 
+<foaf:name>John Goodwin</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>gothwin</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://johngoodwin225.wordpress.com/"> 
+<dc:title>John Goodwin</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://johngoodwin225.wordpress.com/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2257872"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257906"> 
+<foaf:name>Richard Hancock</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.3kbo.com/"> 
+<dc:title>3kbo by Richard Hancock</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.3kbo.com/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2257906"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257931"> 
+<foaf:name>Michael Hausenblas</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>mhausenblas</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://webofdata.wordpress.com/"> 
+<dc:title>Web of Data by Michael Hausenblas</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://webofdata.wordpress.com/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2257931"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257966"> 
+<foaf:name>Sandro Hawke</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>sandhawke</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://decentralyze.com/"> 
+<dc:title> Decentralyze – Programming the Data Cloud by Sandro Hawke</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://decentralyze.com/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2257966"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258003"> 
+<foaf:name>Tom Heath</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>tommyh</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://tomheath.com/blog/"> 
+<dc:title>Displacement Activities by Tom Heath</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://tomheath.com/blog/comments/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2258003"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258035"> 
+<foaf:name>Ivan Herman</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>ivan_herman</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://ivanherman.wordpress.com/tag/work-related/semantic-web/"> 
+<dc:title>Ivan Herman</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://ivan-herman.name/category/work-related/semantic-web/feed"> 
+<foaf:maker rdf:nodeID="id2258035"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258069"> 
+<foaf:name>Kingsley Idehen</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>Kidehen</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.openlinksw.com/blog/~kidehen/"> 
+<dc:title>Data Space by Kingsley Idehen</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.openlinksw.com/blog/~kidehen/gems/index.rdf"> 
+<foaf:maker rdf:nodeID="id2258069"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258104"> 
+<foaf:name>Learn Linked Data</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>learnlinkeddata</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://learnlinkeddata.com/"> 
+<dc:title>Learn Linked Data</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://feeds.feedburner.com/learnlinkeddata"> 
+<foaf:maker rdf:nodeID="id2258104"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258138"> 
+<foaf:name>Talis</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>nodalities</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blogs.talis.com/nodalities/"> 
+<dc:title>Nodalities by Talis</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blogs.talis.com/nodalities/index.rdf"> 
+<foaf:maker rdf:nodeID="id2258138"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258172"> 
+<foaf:name>Seevl</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>seevl</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.seevl.net/category/technology/"> 
+<dc:title>Seevl technology</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.seevl.net/category/technology/feed/"> 
+<foaf:maker rdf:nodeID="id2258172"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258208"> 
+<foaf:name>Semantic Web Company (Austria)</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>semwebcompany</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.semantic-web.at/"> 
+<dc:title>Semantic Puzzle by Semantic Web Company (Austria)</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.semantic-web.at/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2258208"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258266"> 
+<foaf:name>SchemaWeb</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.schemaweb.info/"> 
+<dc:title>SchemaWeb</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.schemaweb.info/blogrss.aspx?blogid=2"> 
+<foaf:maker rdf:nodeID="id2258266"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258290"> 
+<foaf:name>Ora Lassila</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.lassila.org/blog/"> 
+<dc:title>Wilbur-and-O by Ora Lassila</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.lassila.org/blog/index.rdf"> 
+<foaf:maker rdf:nodeID="id2258290"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258316"> 
+<foaf:name>Peter Mika</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://tripletalk.wordpress.com/"> 
+<dc:title>Tripletalk by Peter Mika</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://tripletalk.wordpress.com/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2258316"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258342"> 
+<foaf:name>Andrew Matthews</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://aabs.wordpress.com/"> 
+<dc:title>The Wandering Glitch 2 by Andrew Matthews</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://aabs.wordpress.com/category/semanticweb/rdf"> 
+<foaf:maker rdf:nodeID="id2258342"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258368"> 
+<foaf:name>ZDNet Semantic Web by Paul Miller</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>PaulMiller</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blogs.zdnet.com/semantic-web/"> 
+<dc:title>ZDNet Semantic Web by Paul Miller</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.zdnet.com/blog/semantic-web/rss"> 
+<foaf:maker rdf:nodeID="id2258368"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258402"> 
+<foaf:name>Libby Miller</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>libbymiller</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://planb.nicecupoftea.org/"> 
+<dc:title>Plan B by Libby Miller</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://planb.nicecupoftea.org/feed/?feed=rdf"> 
+<foaf:maker rdf:nodeID="id2258402"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258436"> 
+<foaf:name>Benjamin Nowack</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>bengee</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.bnode.org/en-semweblog"> 
+<dc:title>bnode by Benjamin Nowack</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.bnode.org/rdfxml/page/en-semweblog"> 
+<foaf:maker rdf:nodeID="id2258436"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258470"> 
+<foaf:name>Open Sahara blog</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://opensahara.com/en/blog"> 
+<dc:title>Open Sahara blog</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://feeds.feedburner.com/OpenSahara-Blog"> 
+<foaf:maker rdf:nodeID="id2258470"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258505"> 
+<foaf:name>Alexandre Passant</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>terraces</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://apassant.net/blog/"> 
+<dc:title>Alexandre Passant</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://apassant.net/taxonomy/term/3/feed"> 
+<foaf:maker rdf:nodeID="id2258505"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258537"> 
+<foaf:name>Davide Palmisano</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>dpalmisano</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://davidepalmisano.wordpress.com/"> 
+<dc:title>turn off the lights, please by Davide Palmisano</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://davidepalmisano.wordpress.com/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2258537"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258573"> 
+<foaf:name>POWDER WG blog</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.w3.org/blog/powder"> 
+<dc:title>POWDER WG blog</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.w3.org/blog/powder?tempskin=_rdf"> 
+<foaf:maker rdf:nodeID="id2258573"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258598"> 
+<foaf:name>RDFa</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://rdfa.info/"> 
+<dc:title>RDFa</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://rdfa.info/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2258598"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258622"> 
+<foaf:name>Dave Raggett</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>draggett</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://people.w3.org/~dsr/blog/"> 
+<dc:title>Dave Raggett</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://people.w3.org/~dsr/blog/?feed=rdf"> 
+<foaf:maker rdf:nodeID="id2258622"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258655"> 
+<foaf:name>David Robillard</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>drobilla</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://drobilla.net/category/semweb/"> 
+<dc:title>David Robillard</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://drobilla.net/category/semweb/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2258655"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258688"> 
+<foaf:name>RDF Resource Guide</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://planetrdf.com/guide/"> 
+<dc:title>Dave Beckett's RDF Resource Guide</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://planetrdf.com/guide/rss.rdf"> 
+<foaf:maker rdf:nodeID="id2258688"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258714"> 
+<foaf:name>Peter Shaw</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://shawfactor.com/"> 
+<dc:title>Shawfactor by Peter Shaw</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://shawfactor.com/tag/semantic/feed/"> 
+<foaf:maker rdf:nodeID="id2258714"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258740"> 
+<foaf:name>schema.org</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.schema.org/"> 
+<dc:title>schema.org</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.schema.org/feeds/posts/default?alt=rss"> 
+<foaf:maker rdf:nodeID="id2258740"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258766"> 
+<foaf:name>Henry Story</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>bblfish</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blogs.sun.com/bblfish/"> 
+<dc:title>BabelFish by Henry Story</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blogs.sun.com/bblfish/page/rss10.xml"> 
+<foaf:maker rdf:nodeID="id2258766"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258801"> 
+<foaf:name>Jeni Tennison</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>JeniT</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.jenitennison.com/blog/"> 
+<dc:title>Jeni Tennison - Musings</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.jenitennison.com/blog/atom/feed"> 
+<foaf:maker rdf:nodeID="id2258801"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258835"> 
+<foaf:name>Tetherless World Constellation group RPI</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>jahendler</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://tw.rpi.edu/weblog/feed/rdf/"> 
+<dc:title>Tetherless World Constellation group RPI</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://tw.rpi.edu/weblog/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2258835"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258869"> 
+<foaf:name>Elias Torres</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://torrez.us/"> 
+<dc:title>Elias Torres</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://torrez.us/archives/category/semweb/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2258869"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258903"> 
+<foaf:name>Sebastian Trueg</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://trueg.wordpress.com/"> 
+<dc:title>Semantic Desktop by Sebastian Trueg</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://trueg.wordpress.com/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2258903"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258928"> 
+<foaf:name>W3C Semantic Web News</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.w3.org/2001/sw/"> 
+<dc:title>W3C Semantic Web News</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.w3.org/blog/xmlsrv/rdf.php?blog=13"> 
+<foaf:maker rdf:nodeID="id2258928"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258952"> 
+<foaf:name>W3C Read Write Web Community Group</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.w3.org/community/rww/"> 
+<dc:title>W3C Read Write Web Community Group Blog</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.w3.org/community/rww/feed/"> 
+<foaf:maker rdf:nodeID="id2258952"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258979"> 
+<foaf:name>W3C Blog Semantic Web News</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.w3.org/QA/"> 
+<dc:title>W3C Blog Semantic Web News</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.ivan-herman.net/cgi-bin/toRss1.py?uri=http://www.w3.org/QA/atom.xml&amp;categories=[Semantic+Web]&amp;title=W3C+QA+Blog,+Semantic+Web&amp;link=http://www.w3.org/QA/atom.xml"> 
+<foaf:maker rdf:nodeID="id2258979"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259004"> 
+<foaf:name>Norm Walsh</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>ndw</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://norman.walsh.name/"> 
+<dc:title>Norm Walsh</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://norman.walsh.name/index.rss"> 
+<foaf:maker rdf:nodeID="id2259004"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259036"> 
+<foaf:name>Mark Watson</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>mark_l_watson</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://markwatson.com/blog/"> 
+<dc:title>Mark Watson</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://markwatson.com/blog/atom.xml"> 
+<foaf:maker rdf:nodeID="id2259036"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259070"> 
+<foaf:name>Danny Weitzner</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>djweitzner</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://people.w3.org/~djweitzner/blog/?cat=8"> 
+<dc:title>Open Internet Policy by Danny Weitzner</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://people.w3.org/~djweitzner/blog/?cat=8&amp;feed=rdf"> 
+<foaf:maker rdf:nodeID="id2259070"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259105"> 
+<foaf:name>Web of Data</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://webofdata.wordpress.com/"> 
+<dc:title>Web of Data</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://webofdata.wordpress.com/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2259105"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259130"> 
+<foaf:name>Bill Roberts</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>billroberts</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.webofdatablog.com/"> 
+<dc:title>Web of Data by Bill Roberts</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://feeds2.feedburner.com/webofdatablog"> 
+<foaf:maker rdf:nodeID="id2259130"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259165"> 
+<foaf:name>Web Semántica Hoy</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.wshoy.sidar.org/index.php"> 
+<dc:title>Web Semántica Hoy</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.wshoy.sidar.org/rss.php"> 
+<foaf:maker rdf:nodeID="id2259165"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259199"> 
+<foaf:name>Gregory Williams</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>kasei</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://kasei.us/"> 
+<dc:title>Gregory Williams</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://kasei.us/archives/categories/technology/semantic_web/index.rdf"> 
+<foaf:maker rdf:nodeID="id2259199"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259232"> 
+<foaf:name>Egon Willighagen</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>egonwillighagen</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://chem-bla-ics.blogspot.com/"> 
+<dc:title>chem-bla-ics by Egon Willighagen</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://chem-bla-ics.blogspot.com/feeds/posts/default/-/RDF?alt=rss"> 
+<foaf:maker rdf:nodeID="id2259232"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+</rdf:RDF> 
+
diff --git a/lib/arc2/tests/data/turtle/manifest.ttl b/lib/arc2/tests/data/turtle/manifest.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..a5f909eb2c975d8e89b26b9af96b1e36e4c8fb9e
--- /dev/null
+++ b/lib/arc2/tests/data/turtle/manifest.ttl
@@ -0,0 +1,2190 @@
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You under the Apache License, Version 2.0
+#  (the "License"); you may not use this file except in compliance with
+#  the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+# Test named *subm* are (c) W3C and taken from the Turtle submission.
+
+@prefix rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs:    <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+@prefix qt:     <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
+
+@prefix rdft:   <http://www.w3.org/ns/rdftest#> .
+
+<>  rdf:type mf:Manifest ;
+    rdfs:comment "Turtle tests" ;
+    mf:entries
+    (
+
+    # atomic tests
+    <#IRI_subject>
+    <#IRI_with_four_digit_numeric_escape>
+    <#IRI_with_eight_digit_numeric_escape>
+    <#IRI_with_all_punctuation>
+    <#bareword_a_predicate>
+    <#old_style_prefix>
+    <#SPARQL_style_prefix>
+    <#prefixed_IRI_predicate>
+    <#prefixed_IRI_object>
+    <#prefix_only_IRI>
+    <#prefix_with_PN_CHARS_BASE_character_boundaries>
+    <#prefix_with_non_leading_extras>
+    <#default_namespace_IRI>
+    <#prefix_reassigned_and_used>
+    <#reserved_escaped_localName>
+    <#percent_escaped_localName>
+    <#HYPHEN_MINUS_in_localName>
+    <#underscore_in_localName>
+    <#localname_with_COLON>
+    <#localName_with_assigned_nfc_bmp_PN_CHARS_BASE_character_boundaries>
+    <#localName_with_assigned_nfc_PN_CHARS_BASE_character_boundaries>
+    <#localName_with_nfc_PN_CHARS_BASE_character_boundaries>
+    <#localName_with_PN_CHARS_BASE_character_boundaries>
+    <#localName_with_leading_underscore>
+    <#localName_with_leading_digit>
+    <#localName_with_non_leading_extras>
+    <#old_style_base>
+    <#SPARQL_style_base>
+    <#labeled_blank_node_subject>
+    <#labeled_blank_node_object>
+    <#labeled_blank_node_with_PN_CHARS_BASE_character_boundaries>
+    <#labeled_blank_node_with_leading_underscore>
+    <#labeled_blank_node_with_leading_digit>
+    <#labeled_blank_node_with_non_leading_extras>
+    <#anonymous_blank_node_subject>
+    <#anonymous_blank_node_object>
+    <#sole_blankNodePropertyList>
+    <#blankNodePropertyList_as_subject>
+    <#blankNodePropertyList_as_object>
+    <#blankNodePropertyList_with_multiple_triples>
+    <#nested_blankNodePropertyLists>
+    <#blankNodePropertyList_containing_collection>
+    <#collection_subject>
+    <#collection_object>
+    <#empty_collection>
+    <#nested_collection>
+    <#first>
+    <#last>
+    <#LITERAL1>
+    <#LITERAL1_ascii_boundaries>
+    <#LITERAL1_with_UTF8_boundaries>
+    <#LITERAL1_all_controls>
+    <#LITERAL1_all_punctuation>
+    <#LITERAL_LONG1>
+    <#LITERAL_LONG1_ascii_boundaries>
+    <#LITERAL_LONG1_with_UTF8_boundaries>
+    <#LITERAL_LONG1_with_1_squote>
+    <#LITERAL_LONG1_with_2_squotes>
+    <#LITERAL2>
+    <#LITERAL2_ascii_boundaries>
+    <#LITERAL2_with_UTF8_boundaries>
+    <#LITERAL_LONG2>
+    <#LITERAL_LONG2_ascii_boundaries>
+    <#LITERAL_LONG2_with_UTF8_boundaries>
+    <#LITERAL_LONG2_with_1_squote>
+    <#LITERAL_LONG2_with_2_squotes>
+    <#literal_with_CHARACTER_TABULATION>
+    <#literal_with_BACKSPACE>
+    <#literal_with_LINE_FEED>
+    <#literal_with_CARRIAGE_RETURN>
+    <#literal_with_FORM_FEED>
+    <#literal_with_REVERSE_SOLIDUS>
+    <#literal_with_escaped_CHARACTER_TABULATION>
+    <#literal_with_escaped_BACKSPACE>
+    <#literal_with_escaped_LINE_FEED>
+    <#literal_with_escaped_CARRIAGE_RETURN>
+    <#literal_with_escaped_FORM_FEED>
+    <#literal_with_numeric_escape4>
+    <#literal_with_numeric_escape8>
+    <#IRIREF_datatype>
+    <#prefixed_name_datatype>
+    <#bareword_integer>
+    <#bareword_decimal>
+    <#bareword_double>
+    <#double_lower_case_e>
+    <#negative_numeric>
+    <#positive_numeric>
+    <#numeric_with_leading_0>
+    <#literal_true>
+    <#literal_false>
+    <#langtagged_non_LONG>
+    <#langtagged_LONG>
+    <#lantag_with_subtag>
+    <#objectList_with_two_objects>
+    <#predicateObjectList_with_two_objectLists>
+    <#repeated_semis_at_end>
+    <#repeated_semis_not_at_end>
+
+    # original tests-ttl
+    <#turtle-syntax-file-01>
+    <#turtle-syntax-file-02>
+    <#turtle-syntax-file-03>
+    <#turtle-syntax-uri-01>
+    <#turtle-syntax-uri-02>
+    <#turtle-syntax-uri-03>
+    <#turtle-syntax-uri-04>
+    <#turtle-syntax-base-01>
+    <#turtle-syntax-base-02>
+    <#turtle-syntax-base-03>
+    <#turtle-syntax-base-04>
+    <#turtle-syntax-prefix-01>
+    <#turtle-syntax-prefix-02>
+    <#turtle-syntax-prefix-03>
+    <#turtle-syntax-prefix-04>
+    <#turtle-syntax-prefix-05>
+    <#turtle-syntax-prefix-06>
+    <#turtle-syntax-prefix-07>
+    <#turtle-syntax-prefix-08>
+    <#turtle-syntax-prefix-09>
+    <#turtle-syntax-string-01>
+    <#turtle-syntax-string-02>
+    <#turtle-syntax-string-03>
+    <#turtle-syntax-string-04>
+    <#turtle-syntax-string-05>
+    <#turtle-syntax-string-06>
+    <#turtle-syntax-string-07>
+    <#turtle-syntax-string-08>
+    <#turtle-syntax-string-09>
+    <#turtle-syntax-string-10>
+    <#turtle-syntax-string-11>
+    <#turtle-syntax-str-esc-01>
+    <#turtle-syntax-str-esc-02>
+    <#turtle-syntax-str-esc-03>
+    <#turtle-syntax-pname-esc-01>
+    <#turtle-syntax-pname-esc-02>
+    <#turtle-syntax-pname-esc-03>
+    <#turtle-syntax-bnode-01>
+    <#turtle-syntax-bnode-02>
+    <#turtle-syntax-bnode-03>
+    <#turtle-syntax-bnode-04>
+    <#turtle-syntax-bnode-05>
+    <#turtle-syntax-bnode-06>
+    <#turtle-syntax-bnode-07>
+    <#turtle-syntax-bnode-08>
+    <#turtle-syntax-bnode-09>
+    <#turtle-syntax-bnode-10>
+    <#turtle-syntax-number-01>
+    <#turtle-syntax-number-02>
+    <#turtle-syntax-number-03>
+    <#turtle-syntax-number-04>
+    <#turtle-syntax-number-05>
+    <#turtle-syntax-number-06>
+    <#turtle-syntax-number-07>
+    <#turtle-syntax-number-08>
+    <#turtle-syntax-number-09>
+    <#turtle-syntax-number-10>
+    <#turtle-syntax-number-11>
+    <#turtle-syntax-datatypes-01>
+    <#turtle-syntax-datatypes-02>
+    <#turtle-syntax-kw-01>
+    <#turtle-syntax-kw-02>
+    <#turtle-syntax-kw-03>
+    <#turtle-syntax-struct-01>
+    <#turtle-syntax-struct-02>
+    <#turtle-syntax-struct-03>
+    <#turtle-syntax-struct-04>
+    <#turtle-syntax-struct-05>
+    <#turtle-syntax-lists-01>
+    <#turtle-syntax-lists-02>
+    <#turtle-syntax-lists-03>
+    <#turtle-syntax-lists-04>
+    <#turtle-syntax-lists-05>
+    <#turtle-syntax-bad-uri-01>
+    <#turtle-syntax-bad-uri-02>
+    <#turtle-syntax-bad-uri-03>
+    <#turtle-syntax-bad-uri-04>
+    <#turtle-syntax-bad-uri-05>
+    <#turtle-syntax-bad-prefix-01>
+    <#turtle-syntax-bad-prefix-02>
+    <#turtle-syntax-bad-prefix-03>
+    <#turtle-syntax-bad-prefix-04>
+    <#turtle-syntax-bad-prefix-05>
+    <#turtle-syntax-bad-base-01>
+    <#turtle-syntax-bad-base-02>
+    <#turtle-syntax-bad-base-03>
+    <#turtle-syntax-bad-struct-01>
+    <#turtle-syntax-bad-struct-02>
+    <#turtle-syntax-bad-struct-03>
+    <#turtle-syntax-bad-struct-04>
+    <#turtle-syntax-bad-struct-05>
+    <#turtle-syntax-bad-struct-06>
+    <#turtle-syntax-bad-struct-07>
+    <#turtle-syntax-bad-kw-01>
+    <#turtle-syntax-bad-kw-02>
+    <#turtle-syntax-bad-kw-03>
+    <#turtle-syntax-bad-kw-04>
+    <#turtle-syntax-bad-kw-05>
+    <#turtle-syntax-bad-n3-extras-01>
+    <#turtle-syntax-bad-n3-extras-02>
+    <#turtle-syntax-bad-n3-extras-03>
+    <#turtle-syntax-bad-n3-extras-04>
+    <#turtle-syntax-bad-n3-extras-05>
+    <#turtle-syntax-bad-n3-extras-06>
+    <#turtle-syntax-bad-n3-extras-07>
+    <#turtle-syntax-bad-n3-extras-08>
+    <#turtle-syntax-bad-n3-extras-09>
+    <#turtle-syntax-bad-n3-extras-10>
+    <#turtle-syntax-bad-n3-extras-11>
+    <#turtle-syntax-bad-n3-extras-12>
+    <#turtle-syntax-bad-n3-extras-13>
+    <#turtle-syntax-bad-struct-08>
+    <#turtle-syntax-bad-struct-09>
+    <#turtle-syntax-bad-struct-10>
+    <#turtle-syntax-bad-struct-11>
+    <#turtle-syntax-bad-struct-12>
+    <#turtle-syntax-bad-struct-13>
+    <#turtle-syntax-bad-struct-14>
+    <#turtle-syntax-bad-struct-15>
+    <#turtle-syntax-bad-struct-16>
+    <#turtle-syntax-bad-struct-17>
+    <#turtle-syntax-bad-lang-01>
+    <#turtle-syntax-bad-esc-01>
+    <#turtle-syntax-bad-esc-02>
+    <#turtle-syntax-bad-esc-03>
+    <#turtle-syntax-bad-esc-04>
+    <#turtle-syntax-bad-pname-01>
+    <#turtle-syntax-bad-pname-02>
+    <#turtle-syntax-bad-pname-03>
+    <#turtle-syntax-bad-string-01>
+    <#turtle-syntax-bad-string-02>
+    <#turtle-syntax-bad-string-03>
+    <#turtle-syntax-bad-string-04>
+    <#turtle-syntax-bad-string-05>
+    <#turtle-syntax-bad-string-06>
+    <#turtle-syntax-bad-string-07>
+    <#turtle-syntax-bad-num-01>
+    <#turtle-syntax-bad-num-02>
+    <#turtle-syntax-bad-num-03>
+    <#turtle-syntax-bad-num-04>
+    <#turtle-syntax-bad-num-05>
+    <#turtle-eval-struct-01>
+    <#turtle-eval-struct-02>
+    <#turtle-subm-01>
+    <#turtle-subm-02>
+    <#turtle-subm-03>
+    <#turtle-subm-04>
+    <#turtle-subm-05>
+    <#turtle-subm-06>
+    <#turtle-subm-07>
+    <#turtle-subm-08>
+    <#turtle-subm-09>
+    <#turtle-subm-10>
+    <#turtle-subm-11>
+    <#turtle-subm-12>
+    <#turtle-subm-13>
+    <#turtle-subm-14>
+    <#turtle-subm-15>
+    <#turtle-subm-16>
+    <#turtle-subm-17>
+    <#turtle-subm-18>
+    <#turtle-subm-19>
+    <#turtle-subm-20>
+    <#turtle-subm-21>
+    <#turtle-subm-22>
+    <#turtle-subm-23>
+    <#turtle-subm-24>
+    <#turtle-subm-25>
+    <#turtle-subm-26>
+    <#turtle-subm-27>
+    <#turtle-eval-bad-01>
+    <#turtle-eval-bad-02>
+    <#turtle-eval-bad-03>
+    <#turtle-eval-bad-04>
+
+    # tests from Dave Beckett
+    # http://www.w3.org/2011/rdf-wg/wiki/Turtle_Candidate_Recommendation_Comments#c28
+    <#LITERAL_LONG2_with_REVERSE_SOLIDUS>
+    <#turtle-syntax-bad-LITERAL2_with_langtag_and_datatype>
+    <#two_LITERAL_LONG2s>
+    <#langtagged_LONG_with_subtag>
+
+    # tests from David Robillard
+    # http://www.w3.org/2011/rdf-wg/wiki/Turtle_Candidate_Recommendation_Comments#c21
+    <#turtle-syntax-bad-blank-label-dot-end>
+    <#turtle-syntax-bad-ln-dash-start>
+    <#turtle-syntax-bad-ln-escape-start>
+    <#turtle-syntax-bad-ln-escape>
+    <#turtle-syntax-bad-missing-ns-dot-end>
+    <#turtle-syntax-bad-missing-ns-dot-start>
+    <#turtle-syntax-bad-ns-dot-end>
+    <#turtle-syntax-bad-ns-dot-start>
+    <#turtle-syntax-bad-number-dot-in-anon>
+    <#turtle-syntax-blank-label>
+    <#turtle-syntax-ln-colons>
+    <#turtle-syntax-ln-dots>
+    <#turtle-syntax-ns-dots>
+    ) .
+
+# atomic tests
+<#IRI_subject> rdf:type rdft:TestTurtleEval ;
+   mf:name      "IRI_subject" ;
+   rdfs:comment "IRI subject" ;
+   mf:action    <IRI_subject.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#IRI_with_four_digit_numeric_escape> rdf:type rdft:TestTurtleEval ;
+   mf:name      "IRI_with_four_digit_numeric_escape" ;
+   rdfs:comment "IRI with four digit numeric escape (\\u)" ;
+   mf:action    <IRI_with_four_digit_numeric_escape.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#IRI_with_eight_digit_numeric_escape> rdf:type rdft:TestTurtleEval ;
+   mf:name      "IRI_with_eight_digit_numeric_escape" ;
+   rdfs:comment "IRI with eight digit numeric escape (\\U)" ;
+   mf:action    <IRI_with_eight_digit_numeric_escape.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#IRI_with_all_punctuation> rdf:type rdft:TestTurtleEval ;
+   mf:name      "IRI_with_all_punctuation" ;
+   rdfs:comment "IRI with all punctuation" ;
+   mf:action    <IRI_with_all_punctuation.ttl> ;
+   mf:result    <IRI_with_all_punctuation.nt> ;
+   .
+
+<#bareword_a_predicate> rdf:type rdft:TestTurtleEval ;
+   mf:name      "bareword_a_predicate" ;
+   rdfs:comment "bareword a predicate" ;
+   mf:action    <bareword_a_predicate.ttl> ;
+   mf:result    <bareword_a_predicate.nt> ;
+   .
+
+<#old_style_prefix> rdf:type rdft:TestTurtleEval ;
+   mf:name      "old_style_prefix" ;
+   rdfs:comment "old-style prefix" ;
+   mf:action    <old_style_prefix.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#SPARQL_style_prefix> rdf:type rdft:TestTurtleEval ;
+   mf:name      "SPARQL_style_prefix" ;
+   rdfs:comment "SPARQL-style prefix" ;
+   mf:action    <SPARQL_style_prefix.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#prefixed_IRI_predicate> rdf:type rdft:TestTurtleEval ;
+   mf:name      "prefixed_IRI_predicate" ;
+   rdfs:comment "prefixed IRI predicate" ;
+   mf:action    <prefixed_IRI_predicate.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#prefixed_IRI_object> rdf:type rdft:TestTurtleEval ;
+   mf:name      "prefixed_IRI_object" ;
+   rdfs:comment "prefixed IRI object" ;
+   mf:action    <prefixed_IRI_object.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#prefix_only_IRI> rdf:type rdft:TestTurtleEval ;
+   mf:name      "prefix_only_IRI" ;
+   rdfs:comment "prefix-only IRI (p:)" ;
+   mf:action    <prefix_only_IRI.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#prefix_with_PN_CHARS_BASE_character_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "prefix_with_PN_CHARS_BASE_character_boundaries" ;
+   rdfs:comment "prefix with PN CHARS BASE character boundaries (prefix: AZazÀÖØöø...:)" ;
+   mf:action    <prefix_with_PN_CHARS_BASE_character_boundaries.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#prefix_with_non_leading_extras> rdf:type rdft:TestTurtleEval ;
+   mf:name      "prefix_with_non_leading_extras" ;
+   rdfs:comment "prefix with_non_leading_extras (_:a·̀ͯ‿.⁀)" ;
+   mf:action    <prefix_with_non_leading_extras.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#localName_with_assigned_nfc_bmp_PN_CHARS_BASE_character_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localName_with_assigned_nfc_bmp_PN_CHARS_BASE_character_boundaries" ;
+   rdfs:comment "localName with assigned, NFC-normalized, basic-multilingual-plane PN CHARS BASE character boundaries (p:AZazÀÖØöø...)" ;
+   mf:action    <localName_with_assigned_nfc_bmp_PN_CHARS_BASE_character_boundaries.ttl> ;
+   mf:result    <localName_with_assigned_nfc_bmp_PN_CHARS_BASE_character_boundaries.nt> ;
+   .
+
+<#localName_with_assigned_nfc_PN_CHARS_BASE_character_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localName_with_assigned_nfc_PN_CHARS_BASE_character_boundaries" ;
+   rdfs:comment "localName with assigned, NFC-normalized PN CHARS BASE character boundaries (p:AZazÀÖØöø...)" ;
+   mf:action    <localName_with_assigned_nfc_PN_CHARS_BASE_character_boundaries.ttl> ;
+   mf:result    <localName_with_assigned_nfc_PN_CHARS_BASE_character_boundaries.nt> ;
+   .
+
+<#localName_with_nfc_PN_CHARS_BASE_character_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localName_with_nfc_PN_CHARS_BASE_character_boundaries" ;
+   rdfs:comment "localName with nfc-normalize PN CHARS BASE character boundaries (p:AZazÀÖØöø...)" ;
+   mf:action    <localName_with_nfc_PN_CHARS_BASE_character_boundaries.ttl> ;
+   mf:result    <localName_with_nfc_PN_CHARS_BASE_character_boundaries.nt> ;
+   .
+
+<#localName_with_PN_CHARS_BASE_character_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localName_with_PN_CHARS_BASE_character_boundaries" ;
+   rdfs:comment "localName with PN CHARS BASE character boundaries (p:AZazÀÖØöø...)" ;
+   mf:action    <localName_with_PN_CHARS_BASE_character_boundaries.ttl> ;
+   mf:result    <localName_with_PN_CHARS_BASE_character_boundaries.nt> ;
+   .
+
+<#default_namespace_IRI> rdf:type rdft:TestTurtleEval ;
+   mf:name      "default_namespace_IRI" ;
+   rdfs:comment "default namespace IRI (:ln)" ;
+   mf:action    <default_namespace_IRI.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#prefix_reassigned_and_used> rdf:type rdft:TestTurtleEval ;
+   mf:name      "prefix_reassigned_and_used" ;
+   rdfs:comment "prefix reassigned and used" ;
+   mf:action    <prefix_reassigned_and_used.ttl> ;
+   mf:result    <prefix_reassigned_and_used.nt> ;
+   .
+
+<#reserved_escaped_localName> rdf:type rdft:TestTurtleEval ;
+   mf:name      "reserved_escaped_localName" ;
+   rdfs:comment "reserved-escaped local name" ;
+   mf:action    <reserved_escaped_localName.ttl> ;
+   mf:result    <reserved_escaped_localName.nt> ;
+   .
+
+<#percent_escaped_localName> rdf:type rdft:TestTurtleEval ;
+   mf:name      "percent_escaped_localName" ;
+   rdfs:comment "percent-escaped local name" ;
+   mf:action    <percent_escaped_localName.ttl> ;
+   mf:result    <percent_escaped_localName.nt> ;
+   .
+
+<#HYPHEN_MINUS_in_localName> rdf:type rdft:TestTurtleEval ;
+   mf:name      "HYPHEN_MINUS_in_localName" ;
+   rdfs:comment "HYPHEN-MINUS in local name" ;
+   mf:action    <HYPHEN_MINUS_in_localName.ttl> ;
+   mf:result    <HYPHEN_MINUS_in_localName.nt> ;
+   .
+
+<#underscore_in_localName> rdf:type rdft:TestTurtleEval ;
+   mf:name      "underscore_in_localName" ;
+   rdfs:comment "underscore in local name" ;
+   mf:action    <underscore_in_localName.ttl> ;
+   mf:result    <underscore_in_localName.nt> ;
+   .
+
+<#localname_with_COLON> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localname_with_COLON" ;
+   rdfs:comment "localname with COLON" ;
+   mf:action    <localname_with_COLON.ttl> ;
+   mf:result    <localname_with_COLON.nt> ;
+   .
+
+<#localName_with_leading_underscore> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localName_with_leading_underscore" ;
+   rdfs:comment "localName with leading underscore (p:_)" ;
+   mf:action    <localName_with_leading_underscore.ttl> ;
+   mf:result    <localName_with_leading_underscore.nt> ;
+   .
+
+<#localName_with_leading_digit> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localName_with_leading_digit" ;
+   rdfs:comment "localName with leading digit (p:_)" ;
+   mf:action    <localName_with_leading_digit.ttl> ;
+   mf:result    <localName_with_leading_digit.nt> ;
+   .
+
+<#localName_with_non_leading_extras> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localName_with_non_leading_extras" ;
+   rdfs:comment "localName with_non_leading_extras (_:a·̀ͯ‿.⁀)" ;
+   mf:action    <localName_with_non_leading_extras.ttl> ;
+   mf:result    <localName_with_non_leading_extras.nt> ;
+   .
+
+<#old_style_base> rdf:type rdft:TestTurtleEval ;
+   mf:name      "old_style_base" ;
+   rdfs:comment "old-style base" ;
+   mf:action    <old_style_base.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#SPARQL_style_base> rdf:type rdft:TestTurtleEval ;
+   mf:name      "SPARQL_style_base" ;
+   rdfs:comment "SPARQL-style base" ;
+   mf:action    <SPARQL_style_base.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#labeled_blank_node_subject> rdf:type rdft:TestTurtleEval ;
+   mf:name      "labeled_blank_node_subject" ;
+   rdfs:comment "labeled blank node subject" ;
+   mf:action    <labeled_blank_node_subject.ttl> ;
+   mf:result    <labeled_blank_node_subject.nt> ;
+   .
+
+<#labeled_blank_node_object> rdf:type rdft:TestTurtleEval ;
+   mf:name      "labeled_blank_node_object" ;
+   rdfs:comment "labeled blank node object" ;
+   mf:action    <labeled_blank_node_object.ttl> ;
+   mf:result    <labeled_blank_node_object.nt> ;
+   .
+
+<#labeled_blank_node_with_PN_CHARS_BASE_character_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "labeled_blank_node_with_PN_CHARS_BASE_character_boundaries" ;
+   rdfs:comment "labeled blank node with PN_CHARS_BASE character boundaries (_:AZazÀÖØöø...)" ;
+   mf:action    <labeled_blank_node_with_PN_CHARS_BASE_character_boundaries.ttl> ;
+   mf:result    <labeled_blank_node_object.nt> ;
+   .
+
+<#labeled_blank_node_with_leading_underscore> rdf:type rdft:TestTurtleEval ;
+   mf:name      "labeled_blank_node_with_leading_underscore" ;
+   rdfs:comment "labeled blank node with_leading_underscore (_:_)" ;
+   mf:action    <labeled_blank_node_with_leading_underscore.ttl> ;
+   mf:result    <labeled_blank_node_object.nt> ;
+   .
+
+<#labeled_blank_node_with_leading_digit> rdf:type rdft:TestTurtleEval ;
+   mf:name      "labeled_blank_node_with_leading_digit" ;
+   rdfs:comment "labeled blank node with_leading_digit (_:0)" ;
+   mf:action    <labeled_blank_node_with_leading_digit.ttl> ;
+   mf:result    <labeled_blank_node_object.nt> ;
+   .
+
+<#labeled_blank_node_with_non_leading_extras> rdf:type rdft:TestTurtleEval ;
+   mf:name      "labeled_blank_node_with_non_leading_extras" ;
+   rdfs:comment "labeled blank node with_non_leading_extras (_:a·̀ͯ‿.⁀)" ;
+   mf:action    <labeled_blank_node_with_non_leading_extras.ttl> ;
+   mf:result    <labeled_blank_node_object.nt> ;
+   .
+
+<#anonymous_blank_node_subject> rdf:type rdft:TestTurtleEval ;
+   mf:name      "anonymous_blank_node_subject" ;
+   rdfs:comment "anonymous blank node subject" ;
+   mf:action    <anonymous_blank_node_subject.ttl> ;
+   mf:result    <labeled_blank_node_subject.nt> ;
+   .
+
+<#anonymous_blank_node_object> rdf:type rdft:TestTurtleEval ;
+   mf:name      "anonymous_blank_node_object" ;
+   rdfs:comment "anonymous blank node object" ;
+   mf:action    <anonymous_blank_node_object.ttl> ;
+   mf:result    <labeled_blank_node_object.nt> ;
+   .
+
+<#sole_blankNodePropertyList> rdf:type rdft:TestTurtleEval ;
+   mf:name      "sole_blankNodePropertyList" ;
+   rdfs:comment "sole blankNodePropertyList [ <p> <o> ] ." ;
+   mf:action    <sole_blankNodePropertyList.ttl> ;
+   mf:result    <labeled_blank_node_subject.nt> ;
+   .
+
+<#blankNodePropertyList_as_subject> rdf:type rdft:TestTurtleEval ;
+   mf:name      "blankNodePropertyList_as_subject" ;
+   rdfs:comment "blankNodePropertyList as subject [ … ] <p> <o> ." ;
+   mf:action    <blankNodePropertyList_as_subject.ttl> ;
+   mf:result    <blankNodePropertyList_as_subject.nt> ;
+   .
+
+<#blankNodePropertyList_as_object> rdf:type rdft:TestTurtleEval ;
+   mf:name      "blankNodePropertyList_as_object" ;
+   rdfs:comment "blankNodePropertyList as object <s> <p> [ … ] ." ;
+   mf:action    <blankNodePropertyList_as_object.ttl> ;
+   mf:result    <blankNodePropertyList_as_object.nt> ;
+   .
+
+<#blankNodePropertyList_with_multiple_triples> rdf:type rdft:TestTurtleEval ;
+   mf:name      "blankNodePropertyList_with_multiple_triples" ;
+   rdfs:comment "blankNodePropertyList with multiple triples [ <s> <p> ; <s2> <p2> ]" ;
+   mf:action    <blankNodePropertyList_with_multiple_triples.ttl> ;
+   mf:result    <blankNodePropertyList_with_multiple_triples.nt> ;
+   .
+
+<#nested_blankNodePropertyLists> rdf:type rdft:TestTurtleEval ;
+   mf:name      "nested_blankNodePropertyLists" ;
+   rdfs:comment "nested blankNodePropertyLists [ <p1> [ <p2> <o2> ] ; <p3> <o3> ]" ;
+   mf:action    <nested_blankNodePropertyLists.ttl> ;
+   mf:result    <nested_blankNodePropertyLists.nt> ;
+   .
+
+<#blankNodePropertyList_containing_collection> rdf:type rdft:TestTurtleEval ;
+   mf:name      "blankNodePropertyList_containing_collection" ;
+   rdfs:comment "blankNodePropertyList containing collection [ <p1> ( … ) ]" ;
+   mf:action    <blankNodePropertyList_containing_collection.ttl> ;
+   mf:result    <blankNodePropertyList_containing_collection.nt> ;
+   .
+
+<#collection_subject> rdf:type rdft:TestTurtleEval ;
+   mf:name      "collection_subject" ;
+   rdfs:comment "collection subject" ;
+   mf:action    <collection_subject.ttl> ;
+   mf:result    <collection_subject.nt> ;
+   .
+
+<#collection_object> rdf:type rdft:TestTurtleEval ;
+   mf:name      "collection_object" ;
+   rdfs:comment "collection object" ;
+   mf:action    <collection_object.ttl> ;
+   mf:result    <collection_object.nt> ;
+   .
+
+<#empty_collection> rdf:type rdft:TestTurtleEval ;
+   mf:name      "empty_collection" ;
+   rdfs:comment "empty collection ()" ;
+   mf:action    <empty_collection.ttl> ;
+   mf:result    <empty_collection.nt> ;
+   .
+
+<#nested_collection> rdf:type rdft:TestTurtleEval ;
+   mf:name      "nested_collection" ;
+   rdfs:comment "nested collection (())" ;
+   mf:action    <nested_collection.ttl> ;
+   mf:result    <nested_collection.nt> ;
+   .
+
+<#first> rdf:type rdft:TestTurtleEval ;
+   mf:name      "first" ;
+   rdfs:comment "first, not last, non-empty nested collection" ;
+   mf:action    <first.ttl> ;
+   mf:result    <first.nt> ;
+   .
+
+<#last> rdf:type rdft:TestTurtleEval ;
+   mf:name      "last" ;
+   rdfs:comment "last, not first, non-empty nested collection" ;
+   mf:action    <last.ttl> ;
+   mf:result    <last.nt> ;
+   .
+
+<#LITERAL1> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL1" ;
+   rdfs:comment "LITERAL1 'x'" ;
+   mf:action    <LITERAL1.ttl> ;
+   mf:result    <LITERAL1.nt> ;
+   .
+
+<#LITERAL1_ascii_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL1_ascii_boundaries" ;
+   rdfs:comment "LITERAL1_ascii_boundaries '\\x00\\x09\\x0b\\x0c\\x0e\\x26\\x28...'" ;
+   mf:action    <LITERAL1_ascii_boundaries.ttl> ;
+   mf:result    <LITERAL1_ascii_boundaries.nt> ;
+   .
+
+<#LITERAL1_with_UTF8_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL1_with_UTF8_boundaries" ;
+   rdfs:comment "LITERAL1_with_UTF8_boundaries '\\x80\\x7ff\\x800\\xfff...'" ;
+   mf:action    <LITERAL1_with_UTF8_boundaries.ttl> ;
+   mf:result    <LITERAL_with_UTF8_boundaries.nt> ;
+   .
+
+<#LITERAL1_all_controls> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL1_all_controls" ;
+   rdfs:comment "LITERAL1_all_controls '\\x00\\x01\\x02\\x03\\x04...'" ;
+   mf:action    <LITERAL1_all_controls.ttl> ;
+   mf:result    <LITERAL1_all_controls.nt> ;
+   .
+
+<#LITERAL1_all_punctuation> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL1_all_punctuation" ;
+   rdfs:comment "LITERAL1_all_punctuation '!\"#$%&()...'" ;
+   mf:action    <LITERAL1_all_punctuation.ttl> ;
+   mf:result    <LITERAL1_all_punctuation.nt> ;
+   .
+
+<#LITERAL_LONG1> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG1" ;
+   rdfs:comment "LITERAL_LONG1 '''x'''" ;
+   mf:action    <LITERAL_LONG1.ttl> ;
+   mf:result    <LITERAL1.nt> ;
+   .
+
+<#LITERAL_LONG1_ascii_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG1_ascii_boundaries" ;
+   rdfs:comment "LITERAL_LONG1_ascii_boundaries '\\x00\\x26\\x28...'" ;
+   mf:action    <LITERAL_LONG1_ascii_boundaries.ttl> ;
+   mf:result    <LITERAL_LONG1_ascii_boundaries.nt> ;
+   .
+
+<#LITERAL_LONG1_with_UTF8_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG1_with_UTF8_boundaries" ;
+   rdfs:comment "LITERAL_LONG1_with_UTF8_boundaries '\\x80\\x7ff\\x800\\xfff...'" ;
+   mf:action    <LITERAL_LONG1_with_UTF8_boundaries.ttl> ;
+   mf:result    <LITERAL_with_UTF8_boundaries.nt> ;
+   .
+
+<#LITERAL_LONG1_with_1_squote> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG1_with_1_squote" ;
+   rdfs:comment "LITERAL_LONG1 with 1 squote '''a'b'''" ;
+   mf:action    <LITERAL_LONG1_with_1_squote.ttl> ;
+   mf:result    <LITERAL_LONG1_with_1_squote.nt> ;
+   .
+
+<#LITERAL_LONG1_with_2_squotes> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG1_with_2_squotes" ;
+   rdfs:comment "LITERAL_LONG1 with 2 squotes '''a''b'''" ;
+   mf:action    <LITERAL_LONG1_with_2_squotes.ttl> ;
+   mf:result    <LITERAL_LONG1_with_2_squotes.nt> ;
+   .
+
+<#LITERAL2> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL2" ;
+   rdfs:comment "LITERAL2 \"x\"" ;
+   mf:action    <LITERAL2.ttl> ;
+   mf:result    <LITERAL1.nt> ;
+   .
+
+<#LITERAL2_ascii_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL2_ascii_boundaries" ;
+   rdfs:comment "LITERAL2_ascii_boundaries '\\x00\\x09\\x0b\\x0c\\x0e\\x21\\x23...'" ;
+   mf:action    <LITERAL2_ascii_boundaries.ttl> ;
+   mf:result    <LITERAL2_ascii_boundaries.nt> ;
+   .
+
+<#LITERAL2_with_UTF8_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL2_with_UTF8_boundaries" ;
+   rdfs:comment "LITERAL2_with_UTF8_boundaries '\\x80\\x7ff\\x800\\xfff...'" ;
+   mf:action    <LITERAL2_with_UTF8_boundaries.ttl> ;
+   mf:result    <LITERAL_with_UTF8_boundaries.nt> ;
+   .
+
+<#LITERAL_LONG2> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG2" ;
+   rdfs:comment "LITERAL_LONG2 \"\"\"x\"\"\"" ;
+   mf:action    <LITERAL_LONG2.ttl> ;
+   mf:result    <LITERAL1.nt> ;
+   .
+
+<#LITERAL_LONG2_ascii_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG2_ascii_boundaries" ;
+   rdfs:comment "LITERAL_LONG2_ascii_boundaries '\\x00\\x21\\x23...'" ;
+   mf:action    <LITERAL_LONG2_ascii_boundaries.ttl> ;
+   mf:result    <LITERAL_LONG2_ascii_boundaries.nt> ;
+   .
+
+<#LITERAL_LONG2_with_UTF8_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG2_with_UTF8_boundaries" ;
+   rdfs:comment "LITERAL_LONG2_with_UTF8_boundaries '\\x80\\x7ff\\x800\\xfff...'" ;
+   mf:action    <LITERAL_LONG2_with_UTF8_boundaries.ttl> ;
+   mf:result    <LITERAL_with_UTF8_boundaries.nt> ;
+   .
+
+<#LITERAL_LONG2_with_1_squote> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG2_with_1_squote" ;
+   rdfs:comment "LITERAL_LONG2 with 1 squote \"\"\"a\"b\"\"\"" ;
+   mf:action    <LITERAL_LONG2_with_1_squote.ttl> ;
+   mf:result    <LITERAL_LONG2_with_1_squote.nt> ;
+   .
+
+<#LITERAL_LONG2_with_2_squotes> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG2_with_2_squotes" ;
+   rdfs:comment "LITERAL_LONG2 with 2 squotes \"\"\"a\"\"b\"\"\"" ;
+   mf:action    <LITERAL_LONG2_with_2_squotes.ttl> ;
+   mf:result    <LITERAL_LONG2_with_2_squotes.nt> ;
+   .
+
+<#literal_with_CHARACTER_TABULATION> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_CHARACTER_TABULATION" ;
+   rdfs:comment "literal with CHARACTER TABULATION" ;
+   mf:action    <literal_with_CHARACTER_TABULATION.ttl> ;
+   mf:result    <literal_with_CHARACTER_TABULATION.nt> ;
+   .
+
+<#literal_with_BACKSPACE> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_BACKSPACE" ;
+   rdfs:comment "literal with BACKSPACE" ;
+   mf:action    <literal_with_BACKSPACE.ttl> ;
+   mf:result    <literal_with_BACKSPACE.nt> ;
+   .
+
+<#literal_with_LINE_FEED> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_LINE_FEED" ;
+   rdfs:comment "literal with LINE FEED" ;
+   mf:action    <literal_with_LINE_FEED.ttl> ;
+   mf:result    <literal_with_LINE_FEED.nt> ;
+   .
+
+<#literal_with_CARRIAGE_RETURN> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_CARRIAGE_RETURN" ;
+   rdfs:comment "literal with CARRIAGE RETURN" ;
+   mf:action    <literal_with_CARRIAGE_RETURN.ttl> ;
+   mf:result    <literal_with_CARRIAGE_RETURN.nt> ;
+   .
+
+<#literal_with_FORM_FEED> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_FORM_FEED" ;
+   rdfs:comment "literal with FORM FEED" ;
+   mf:action    <literal_with_FORM_FEED.ttl> ;
+   mf:result    <literal_with_FORM_FEED.nt> ;
+   .
+
+<#literal_with_REVERSE_SOLIDUS> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_REVERSE_SOLIDUS" ;
+   rdfs:comment "literal with REVERSE SOLIDUS" ;
+   mf:action    <literal_with_REVERSE_SOLIDUS.ttl> ;
+   mf:result    <literal_with_REVERSE_SOLIDUS.nt> ;
+   .
+
+<#literal_with_escaped_CHARACTER_TABULATION> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_escaped_CHARACTER_TABULATION" ;
+   rdfs:comment "literal with escaped CHARACTER TABULATION" ;
+   mf:action    <literal_with_escaped_CHARACTER_TABULATION.ttl> ;
+   mf:result    <literal_with_CHARACTER_TABULATION.nt> ;
+   .
+
+<#literal_with_escaped_BACKSPACE> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_escaped_BACKSPACE" ;
+   rdfs:comment "literal with escaped BACKSPACE" ;
+   mf:action    <literal_with_escaped_BACKSPACE.ttl> ;
+   mf:result    <literal_with_BACKSPACE.nt> ;
+   .
+
+<#literal_with_escaped_LINE_FEED> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_escaped_LINE_FEED" ;
+   rdfs:comment "literal with escaped LINE FEED" ;
+   mf:action    <literal_with_escaped_LINE_FEED.ttl> ;
+   mf:result    <literal_with_LINE_FEED.nt> ;
+   .
+
+<#literal_with_escaped_CARRIAGE_RETURN> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_escaped_CARRIAGE_RETURN" ;
+   rdfs:comment "literal with escaped CARRIAGE RETURN" ;
+   mf:action    <literal_with_escaped_CARRIAGE_RETURN.ttl> ;
+   mf:result    <literal_with_CARRIAGE_RETURN.nt> ;
+   .
+
+<#literal_with_escaped_FORM_FEED> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_escaped_FORM_FEED" ;
+   rdfs:comment "literal with escaped FORM FEED" ;
+   mf:action    <literal_with_escaped_FORM_FEED.ttl> ;
+   mf:result    <literal_with_FORM_FEED.nt> ;
+   .
+
+<#literal_with_numeric_escape4> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_numeric_escape4" ;
+   rdfs:comment "literal with numeric escape4 \\u" ;
+   mf:action    <literal_with_numeric_escape4.ttl> ;
+   mf:result    <literal_with_numeric_escape4.nt> ;
+   .
+
+<#literal_with_numeric_escape8> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_numeric_escape8" ;
+   rdfs:comment "literal with numeric escape8 \\U" ;
+   mf:action    <literal_with_numeric_escape8.ttl> ;
+   mf:result    <literal_with_numeric_escape4.nt> ;
+   .
+
+<#IRIREF_datatype> rdf:type rdft:TestTurtleEval ;
+   mf:name      "IRIREF_datatype" ;
+   rdfs:comment "IRIREF datatype \"\"^^<t>" ;
+   mf:action    <IRIREF_datatype.ttl> ;
+   mf:result    <IRIREF_datatype.nt> ;
+   .
+
+<#prefixed_name_datatype> rdf:type rdft:TestTurtleEval ;
+   mf:name      "prefixed_name_datatype" ;
+   rdfs:comment "prefixed name datatype \"\"^^p:t" ;
+   mf:action    <prefixed_name_datatype.ttl> ;
+   mf:result    <IRIREF_datatype.nt> ;
+   .
+
+<#bareword_integer> rdf:type rdft:TestTurtleEval ;
+   mf:name      "bareword_integer" ;
+   rdfs:comment "bareword integer" ;
+   mf:action    <bareword_integer.ttl> ;
+   mf:result    <IRIREF_datatype.nt> ;
+   .
+
+<#bareword_decimal> rdf:type rdft:TestTurtleEval ;
+   mf:name      "bareword_decimal" ;
+   rdfs:comment "bareword decimal" ;
+   mf:action    <bareword_decimal.ttl> ;
+   mf:result    <bareword_decimal.nt> ;
+   .
+
+<#bareword_double> rdf:type rdft:TestTurtleEval ;
+   mf:name      "bareword_double" ;
+   rdfs:comment "bareword double" ;
+   mf:action    <bareword_double.ttl> ;
+   mf:result    <bareword_double.nt> ;
+   .
+
+<#double_lower_case_e> rdf:type rdft:TestTurtleEval ;
+   mf:name      "double_lower_case_e" ;
+   rdfs:comment "double lower case e" ;
+   mf:action    <double_lower_case_e.ttl> ;
+   mf:result    <double_lower_case_e.nt> ;
+   .
+
+<#negative_numeric> rdf:type rdft:TestTurtleEval ;
+   mf:name      "negative_numeric" ;
+   rdfs:comment "negative numeric" ;
+   mf:action    <negative_numeric.ttl> ;
+   mf:result    <negative_numeric.nt> ;
+   .
+
+<#positive_numeric> rdf:type rdft:TestTurtleEval ;
+   mf:name      "positive_numeric" ;
+   rdfs:comment "positive numeric" ;
+   mf:action    <positive_numeric.ttl> ;
+   mf:result    <positive_numeric.nt> ;
+   .
+
+<#numeric_with_leading_0> rdf:type rdft:TestTurtleEval ;
+   mf:name      "numeric_with_leading_0" ;
+   rdfs:comment "numeric with leading 0" ;
+   mf:action    <numeric_with_leading_0.ttl> ;
+   mf:result    <numeric_with_leading_0.nt> ;
+   .
+
+<#literal_true> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_true" ;
+   rdfs:comment "literal true" ;
+   mf:action    <literal_true.ttl> ;
+   mf:result    <literal_true.nt> ;
+   .
+
+<#literal_false> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_false" ;
+   rdfs:comment "literal false" ;
+   mf:action    <literal_false.ttl> ;
+   mf:result    <literal_false.nt> ;
+   .
+
+<#langtagged_non_LONG> rdf:type rdft:TestTurtleEval ;
+   mf:name      "langtagged_non_LONG" ;
+   rdfs:comment "langtagged non-LONG \"x\"@en" ;
+   mf:action    <langtagged_non_LONG.ttl> ;
+   mf:result    <langtagged_non_LONG.nt> ;
+   .
+
+<#langtagged_LONG> rdf:type rdft:TestTurtleEval ;
+   mf:name      "langtagged_LONG" ;
+   rdfs:comment "langtagged LONG \"\"\"x\"\"\"@en" ;
+   mf:action    <langtagged_LONG.ttl> ;
+   mf:result    <langtagged_non_LONG.nt> ;
+   .
+
+<#lantag_with_subtag> rdf:type rdft:TestTurtleEval ;
+   mf:name      "lantag_with_subtag" ;
+   rdfs:comment "lantag with subtag \"x\"@en-us" ;
+   mf:action    <lantag_with_subtag.ttl> ;
+   mf:result    <lantag_with_subtag.nt> ;
+   .
+
+<#objectList_with_two_objects> rdf:type rdft:TestTurtleEval ;
+   mf:name      "objectList_with_two_objects" ;
+   rdfs:comment "objectList with two objects … <o1>,<o2>" ;
+   mf:action    <objectList_with_two_objects.ttl> ;
+   mf:result    <objectList_with_two_objects.nt> ;
+   .
+
+<#predicateObjectList_with_two_objectLists> rdf:type rdft:TestTurtleEval ;
+   mf:name      "predicateObjectList_with_two_objectLists" ;
+   rdfs:comment "predicateObjectList with two objectLists … <o1>,<o2>" ;
+   mf:action    <predicateObjectList_with_two_objectLists.ttl> ;
+   mf:result    <predicateObjectList_with_two_objectLists.nt> ;
+   .
+
+<#repeated_semis_at_end> rdf:type rdft:TestTurtleEval ;
+   mf:name      "repeated_semis_at_end" ;
+   rdfs:comment "repeated semis at end <s> <p> <o> ;; <p2> <o2> ." ;
+   mf:action    <repeated_semis_at_end.ttl> ;
+   mf:result    <predicateObjectList_with_two_objectLists.nt> ;
+   .
+
+<#repeated_semis_not_at_end> rdf:type rdft:TestTurtleEval ;
+   mf:name      "repeated_semis_not_at_end" ;
+   rdfs:comment "repeated semis not at end <s> <p> <o> ;;." ;
+   mf:action    <repeated_semis_not_at_end.ttl> ;
+   mf:result    <repeated_semis_not_at_end.nt> ;
+   .
+
+# original tests-ttl
+<#turtle-syntax-file-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-file-01" ;
+   rdfs:comment "Empty file" ;
+   mf:action    <turtle-syntax-file-01.ttl> ;
+   .
+
+<#turtle-syntax-file-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-file-02" ;
+   rdfs:comment "Only comment" ;
+   mf:action    <turtle-syntax-file-02.ttl> ;
+   .
+
+<#turtle-syntax-file-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-file-03" ;
+   rdfs:comment "One comment, one empty line" ;
+   mf:action    <turtle-syntax-file-03.ttl> ;
+   .
+
+<#turtle-syntax-uri-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-uri-01" ;
+   rdfs:comment "Only IRIs" ;
+   mf:action    <turtle-syntax-uri-01.ttl> ;
+   .
+
+<#turtle-syntax-uri-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-uri-02" ;
+   rdfs:comment "IRIs with Unicode escape" ;
+   mf:action    <turtle-syntax-uri-02.ttl> ;
+   .
+
+<#turtle-syntax-uri-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-uri-03" ;
+   rdfs:comment "IRIs with long Unicode escape" ;
+   mf:action    <turtle-syntax-uri-03.ttl> ;
+   .
+
+<#turtle-syntax-uri-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-uri-04" ;
+   rdfs:comment "Legal IRIs" ;
+   mf:action    <turtle-syntax-uri-04.ttl> ;
+   .
+
+<#turtle-syntax-base-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-base-01" ;
+   rdfs:comment "@base" ;
+   mf:action    <turtle-syntax-base-01.ttl> ;
+   .
+
+<#turtle-syntax-base-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-base-02" ;
+   rdfs:comment "BASE" ;
+   mf:action    <turtle-syntax-base-02.ttl> ;
+   .
+
+<#turtle-syntax-base-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-base-03" ;
+   rdfs:comment "@base with relative IRIs" ;
+   mf:action    <turtle-syntax-base-03.ttl> ;
+   .
+
+<#turtle-syntax-base-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-base-04" ;
+   rdfs:comment "base with relative IRIs" ;
+   mf:action    <turtle-syntax-base-04.ttl> ;
+   .
+
+<#turtle-syntax-prefix-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-01" ;
+   rdfs:comment "@prefix" ;
+   mf:action    <turtle-syntax-prefix-01.ttl> ;
+   .
+
+<#turtle-syntax-prefix-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-02" ;
+   rdfs:comment "PreFIX" ;
+   mf:action    <turtle-syntax-prefix-02.ttl> ;
+   .
+
+<#turtle-syntax-prefix-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-03" ;
+   rdfs:comment "Empty PREFIX" ;
+   mf:action    <turtle-syntax-prefix-03.ttl> ;
+   .
+
+<#turtle-syntax-prefix-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-04" ;
+   rdfs:comment "Empty @prefix with % escape" ;
+   mf:action    <turtle-syntax-prefix-04.ttl> ;
+   .
+
+<#turtle-syntax-prefix-05> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-05" ;
+   rdfs:comment "@prefix with no suffix" ;
+   mf:action    <turtle-syntax-prefix-05.ttl> ;
+   .
+
+<#turtle-syntax-prefix-06> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-06" ;
+   rdfs:comment "colon is a legal pname character" ;
+   mf:action    <turtle-syntax-prefix-06.ttl> ;
+   .
+
+<#turtle-syntax-prefix-07> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-07" ;
+   rdfs:comment "dash is a legal pname character" ;
+   mf:action    <turtle-syntax-prefix-07.ttl> ;
+   .
+
+<#turtle-syntax-prefix-08> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-08" ;
+   rdfs:comment "underscore is a legal pname character" ;
+   mf:action    <turtle-syntax-prefix-08.ttl> ;
+   .
+
+<#turtle-syntax-prefix-09> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-09" ;
+   rdfs:comment "percents in pnames" ;
+   mf:action    <turtle-syntax-prefix-09.ttl> ;
+   .
+
+<#turtle-syntax-string-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-01" ;
+   rdfs:comment "string literal" ;
+   mf:action    <turtle-syntax-string-01.ttl> ;
+   .
+
+<#turtle-syntax-string-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-02" ;
+   rdfs:comment "langString literal" ;
+   mf:action    <turtle-syntax-string-02.ttl> ;
+   .
+
+<#turtle-syntax-string-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-03" ;
+   rdfs:comment "langString literal with region" ;
+   mf:action    <turtle-syntax-string-03.ttl> ;
+   .
+
+<#turtle-syntax-string-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-04" ;
+   rdfs:comment "squote string literal" ;
+   mf:action    <turtle-syntax-string-04.ttl> ;
+   .
+
+<#turtle-syntax-string-05> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-05" ;
+   rdfs:comment "squote langString literal" ;
+   mf:action    <turtle-syntax-string-05.ttl> ;
+   .
+
+<#turtle-syntax-string-06> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-06" ;
+   rdfs:comment "squote langString literal with region" ;
+   mf:action    <turtle-syntax-string-06.ttl> ;
+   .
+
+<#turtle-syntax-string-07> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-07" ;
+   rdfs:comment "long string literal with embedded single- and double-quotes" ;
+   mf:action    <turtle-syntax-string-07.ttl> ;
+   .
+
+<#turtle-syntax-string-08> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-08" ;
+   rdfs:comment "long string literal with embedded newline" ;
+   mf:action    <turtle-syntax-string-08.ttl> ;
+   .
+
+<#turtle-syntax-string-09> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-09" ;
+   rdfs:comment "squote long string literal with embedded single- and double-quotes" ;
+   mf:action    <turtle-syntax-string-09.ttl> ;
+   .
+
+<#turtle-syntax-string-10> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-10" ;
+   rdfs:comment "long langString literal with embedded newline" ;
+   mf:action    <turtle-syntax-string-10.ttl> ;
+   .
+
+<#turtle-syntax-string-11> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-11" ;
+   rdfs:comment "squote long langString literal with embedded newline" ;
+   mf:action    <turtle-syntax-string-11.ttl> ;
+   .
+
+<#turtle-syntax-str-esc-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-str-esc-01" ;
+   rdfs:comment "string literal with escaped newline" ;
+   mf:action    <turtle-syntax-str-esc-01.ttl> ;
+   .
+
+<#turtle-syntax-str-esc-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-str-esc-02" ;
+   rdfs:comment "string literal with Unicode escape" ;
+   mf:action    <turtle-syntax-str-esc-02.ttl> ;
+   .
+
+<#turtle-syntax-str-esc-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-str-esc-03" ;
+   rdfs:comment "string literal with long Unicode escape" ;
+   mf:action    <turtle-syntax-str-esc-03.ttl> ;
+   .
+
+<#turtle-syntax-pname-esc-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-pname-esc-01" ;
+   rdfs:comment "pname with back-slash escapes" ;
+   mf:action    <turtle-syntax-pname-esc-01.ttl> ;
+   .
+
+<#turtle-syntax-pname-esc-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-pname-esc-02" ;
+   rdfs:comment "pname with back-slash escapes (2)" ;
+   mf:action    <turtle-syntax-pname-esc-02.ttl> ;
+   .
+
+<#turtle-syntax-pname-esc-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-pname-esc-03" ;
+   rdfs:comment "pname with back-slash escapes (3)" ;
+   mf:action    <turtle-syntax-pname-esc-03.ttl> ;
+   .
+
+<#turtle-syntax-bnode-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-01" ;
+   rdfs:comment "bnode subject" ;
+   mf:action    <turtle-syntax-bnode-01.ttl> ;
+   .
+
+<#turtle-syntax-bnode-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-02" ;
+   rdfs:comment "bnode object" ;
+   mf:action    <turtle-syntax-bnode-02.ttl> ;
+   .
+
+<#turtle-syntax-bnode-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-03" ;
+   rdfs:comment "bnode property list object" ;
+   mf:action    <turtle-syntax-bnode-03.ttl> ;
+   .
+
+<#turtle-syntax-bnode-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-04" ;
+   rdfs:comment "bnode property list object (2)" ;
+   mf:action    <turtle-syntax-bnode-04.ttl> ;
+   .
+
+<#turtle-syntax-bnode-05> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-05" ;
+   rdfs:comment "bnode property list subject" ;
+   mf:action    <turtle-syntax-bnode-05.ttl> ;
+   .
+
+<#turtle-syntax-bnode-06> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-06" ;
+   rdfs:comment "labeled bnode subject" ;
+   mf:action    <turtle-syntax-bnode-06.ttl> ;
+   .
+
+<#turtle-syntax-bnode-07> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-07" ;
+   rdfs:comment "labeled bnode subject and object" ;
+   mf:action    <turtle-syntax-bnode-07.ttl> ;
+   .
+
+<#turtle-syntax-bnode-08> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-08" ;
+   rdfs:comment "bare bnode property list" ;
+   mf:action    <turtle-syntax-bnode-08.ttl> ;
+   .
+
+<#turtle-syntax-bnode-09> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-09" ;
+   rdfs:comment "bnode property list" ;
+   mf:action    <turtle-syntax-bnode-09.ttl> ;
+   .
+
+<#turtle-syntax-bnode-10> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-10" ;
+   rdfs:comment "mixed bnode property list and triple" ;
+   mf:action    <turtle-syntax-bnode-10.ttl> ;
+   .
+
+<#turtle-syntax-number-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-01" ;
+   rdfs:comment "integer literal" ;
+   mf:action    <turtle-syntax-number-01.ttl> ;
+   .
+
+<#turtle-syntax-number-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-02" ;
+   rdfs:comment "negative integer literal" ;
+   mf:action    <turtle-syntax-number-02.ttl> ;
+   .
+
+<#turtle-syntax-number-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-03" ;
+   rdfs:comment "positive integer literal" ;
+   mf:action    <turtle-syntax-number-03.ttl> ;
+   .
+
+<#turtle-syntax-number-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-04" ;
+   rdfs:comment "decimal literal" ;
+   mf:action    <turtle-syntax-number-04.ttl> ;
+   .
+
+<#turtle-syntax-number-05> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-05" ;
+   rdfs:comment "decimal literal (no leading digits)" ;
+   mf:action    <turtle-syntax-number-05.ttl> ;
+   .
+
+<#turtle-syntax-number-06> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-06" ;
+   rdfs:comment "negative decimal literal" ;
+   mf:action    <turtle-syntax-number-06.ttl> ;
+   .
+
+<#turtle-syntax-number-07> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-07" ;
+   rdfs:comment "positive decimal literal" ;
+   mf:action    <turtle-syntax-number-07.ttl> ;
+   .
+
+<#turtle-syntax-number-08> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-08" ;
+   rdfs:comment "integer literal with decimal lexical confusion" ;
+   mf:action    <turtle-syntax-number-08.ttl> ;
+   .
+
+<#turtle-syntax-number-09> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-09" ;
+   rdfs:comment "double literal" ;
+   mf:action    <turtle-syntax-number-09.ttl> ;
+   .
+
+<#turtle-syntax-number-10> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-10" ;
+   rdfs:comment "negative double literal" ;
+   mf:action    <turtle-syntax-number-10.ttl> ;
+   .
+
+<#turtle-syntax-number-11> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-11" ;
+   rdfs:comment "double literal no fraction" ;
+   mf:action    <turtle-syntax-number-11.ttl> ;
+   .
+
+<#turtle-syntax-datatypes-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-datatypes-01" ;
+   rdfs:comment "xsd:byte literal" ;
+   mf:action    <turtle-syntax-datatypes-01.ttl> ;
+   .
+
+<#turtle-syntax-datatypes-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-datatypes-02" ;
+   rdfs:comment "integer as xsd:string" ;
+   mf:action    <turtle-syntax-datatypes-02.ttl> ;
+   .
+
+<#turtle-syntax-kw-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-kw-01" ;
+   rdfs:comment "boolean literal (true)" ;
+   mf:action    <turtle-syntax-kw-01.ttl> ;
+   .
+
+<#turtle-syntax-kw-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-kw-02" ;
+   rdfs:comment "boolean literal (false)" ;
+   mf:action    <turtle-syntax-kw-02.ttl> ;
+   .
+
+<#turtle-syntax-kw-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-kw-03" ;
+   rdfs:comment "'a' as keyword" ;
+   mf:action    <turtle-syntax-kw-03.ttl> ;
+   .
+
+<#turtle-syntax-struct-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-struct-01" ;
+   rdfs:comment "object list" ;
+   mf:action    <turtle-syntax-struct-01.ttl> ;
+   .
+
+<#turtle-syntax-struct-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-struct-02" ;
+   rdfs:comment "predicate list with object list" ;
+   mf:action    <turtle-syntax-struct-02.ttl> ;
+   .
+
+<#turtle-syntax-struct-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-struct-03" ;
+   rdfs:comment "predicate list with object list and dangling ';'" ;
+   mf:action    <turtle-syntax-struct-03.ttl> ;
+   .
+
+<#turtle-syntax-struct-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-struct-04" ;
+   rdfs:comment "predicate list with multiple ;;" ;
+   mf:action    <turtle-syntax-struct-04.ttl> ;
+   .
+
+<#turtle-syntax-struct-05> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-struct-05" ;
+   rdfs:comment "predicate list with multiple ;;" ;
+   mf:action    <turtle-syntax-struct-05.ttl> ;
+   .
+
+<#turtle-syntax-lists-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-lists-01" ;
+   rdfs:comment "empty list" ;
+   mf:action    <turtle-syntax-lists-01.ttl> ;
+   .
+
+<#turtle-syntax-lists-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-lists-02" ;
+   rdfs:comment "mixed list" ;
+   mf:action    <turtle-syntax-lists-02.ttl> ;
+   .
+
+<#turtle-syntax-lists-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-lists-03" ;
+   rdfs:comment "isomorphic list as subject and object" ;
+   mf:action    <turtle-syntax-lists-03.ttl> ;
+   .
+
+<#turtle-syntax-lists-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-lists-04" ;
+   rdfs:comment "lists of lists" ;
+   mf:action    <turtle-syntax-lists-04.ttl> ;
+   .
+
+<#turtle-syntax-lists-05> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-lists-05" ;
+   rdfs:comment "mixed lists with embedded lists" ;
+   mf:action    <turtle-syntax-lists-05.ttl> ;
+   .
+
+<#turtle-syntax-bad-uri-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-uri-01" ;
+   rdfs:comment "Bad IRI : space (negative test)" ;
+   mf:action    <turtle-syntax-bad-uri-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-uri-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-uri-02" ;
+   rdfs:comment "Bad IRI : bad escape (negative test)" ;
+   mf:action    <turtle-syntax-bad-uri-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-uri-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-uri-03" ;
+   rdfs:comment "Bad IRI : bad long escape (negative test)" ;
+   mf:action    <turtle-syntax-bad-uri-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-uri-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-uri-04" ;
+   rdfs:comment "Bad IRI : character escapes not allowed (negative test)" ;
+   mf:action    <turtle-syntax-bad-uri-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-uri-05> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-uri-05" ;
+   rdfs:comment "Bad IRI : character escapes not allowed (2) (negative test)" ;
+   mf:action    <turtle-syntax-bad-uri-05.ttl> ;
+   .
+
+<#turtle-syntax-bad-prefix-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-prefix-01" ;
+   rdfs:comment "No prefix (negative test)" ;
+   mf:action    <turtle-syntax-bad-prefix-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-prefix-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-prefix-02" ;
+   rdfs:comment "No prefix (2) (negative test)" ;
+   mf:action    <turtle-syntax-bad-prefix-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-prefix-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-prefix-03" ;
+   rdfs:comment "@prefix without URI (negative test)" ;
+   mf:action    <turtle-syntax-bad-prefix-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-prefix-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-prefix-04" ;
+   rdfs:comment "@prefix without prefix name (negative test)" ;
+   mf:action    <turtle-syntax-bad-prefix-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-prefix-05> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-prefix-05" ;
+   rdfs:comment "@prefix without ':' (negative test)" ;
+   mf:action    <turtle-syntax-bad-prefix-05.ttl> ;
+   .
+
+<#turtle-syntax-bad-base-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-base-01" ;
+   rdfs:comment "@base without URI (negative test)" ;
+   mf:action    <turtle-syntax-bad-base-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-base-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-base-02" ;
+   rdfs:comment "@base in wrong case (negative test)" ;
+   mf:action    <turtle-syntax-bad-base-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-base-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-base-03" ;
+   rdfs:comment "BASE without URI (negative test)" ;
+   mf:action    <turtle-syntax-bad-base-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-01" ;
+   rdfs:comment "Turtle is not TriG (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-02" ;
+   rdfs:comment "Turtle is not N3 (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-03" ;
+   rdfs:comment "Turtle is not NQuads (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-04" ;
+   rdfs:comment "Turtle does not allow literals-as-subjects (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-05> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-05" ;
+   rdfs:comment "Turtle does not allow literals-as-predicates (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-05.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-06> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-06" ;
+   rdfs:comment "Turtle does not allow bnodes-as-predicates (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-06.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-07> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-07" ;
+   rdfs:comment "Turtle does not allow labeled bnodes-as-predicates (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-07.ttl> ;
+   .
+
+<#turtle-syntax-bad-kw-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-kw-01" ;
+   rdfs:comment "'A' is not a keyword (negative test)" ;
+   mf:action    <turtle-syntax-bad-kw-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-kw-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-kw-02" ;
+   rdfs:comment "'a' cannot be used as subject (negative test)" ;
+   mf:action    <turtle-syntax-bad-kw-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-kw-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-kw-03" ;
+   rdfs:comment "'a' cannot be used as object (negative test)" ;
+   mf:action    <turtle-syntax-bad-kw-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-kw-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-kw-04" ;
+   rdfs:comment "'true' cannot be used as subject (negative test)" ;
+   mf:action    <turtle-syntax-bad-kw-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-kw-05> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-kw-05" ;
+   rdfs:comment "'true' cannot be used as object (negative test)" ;
+   mf:action    <turtle-syntax-bad-kw-05.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-01" ;
+   rdfs:comment "{} fomulae not in Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-02" ;
+   rdfs:comment "= is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-03" ;
+   rdfs:comment "N3 paths not in Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-04" ;
+   rdfs:comment "N3 paths not in Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-05> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-05" ;
+   rdfs:comment "N3 is...of not in Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-05.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-06> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-06" ;
+   rdfs:comment "N3 paths not in Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-06.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-07> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-07" ;
+   rdfs:comment "@keywords is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-07.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-08> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-08" ;
+   rdfs:comment "@keywords is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-08.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-09> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-09" ;
+   rdfs:comment "=> is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-09.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-10> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-10" ;
+   rdfs:comment "<= is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-10.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-11> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-11" ;
+   rdfs:comment "@forSome is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-11.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-12> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-12" ;
+   rdfs:comment "@forAll is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-12.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-13> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-13" ;
+   rdfs:comment "@keywords is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-13.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-08> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-08" ;
+   rdfs:comment "missing '.' (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-08.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-09> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-09" ;
+   rdfs:comment "extra '.' (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-09.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-10> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-10" ;
+   rdfs:comment "extra '.' (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-10.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-11> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-11" ;
+   rdfs:comment "trailing ';' no '.' (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-11.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-12> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-12" ;
+   rdfs:comment "subject, predicate, no object (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-12.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-13> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-13" ;
+   rdfs:comment "subject, predicate, no object (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-13.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-14> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-14" ;
+   rdfs:comment "literal as subject (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-14.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-15> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-15" ;
+   rdfs:comment "literal as predicate (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-15.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-16> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-16" ;
+   rdfs:comment "bnode as predicate (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-16.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-17> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-17" ;
+   rdfs:comment "labeled bnode as predicate (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-17.ttl> ;
+   .
+
+<#turtle-syntax-bad-lang-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-lang-01" ;
+   rdfs:comment "langString with bad lang (negative test)" ;
+   mf:action    <turtle-syntax-bad-lang-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-esc-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-esc-01" ;
+   rdfs:comment "Bad string escape (negative test)" ;
+   mf:action    <turtle-syntax-bad-esc-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-esc-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-esc-02" ;
+   rdfs:comment "Bad string escape (negative test)" ;
+   mf:action    <turtle-syntax-bad-esc-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-esc-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-esc-03" ;
+   rdfs:comment "Bad string escape (negative test)" ;
+   mf:action    <turtle-syntax-bad-esc-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-esc-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-esc-04" ;
+   rdfs:comment "Bad string escape (negative test)" ;
+   mf:action    <turtle-syntax-bad-esc-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-pname-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-pname-01" ;
+   rdfs:comment "'~' must be escaped in pname (negative test)" ;
+   mf:action    <turtle-syntax-bad-pname-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-pname-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-pname-02" ;
+   rdfs:comment "Bad %-sequence in pname (negative test)" ;
+   mf:action    <turtle-syntax-bad-pname-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-pname-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-pname-03" ;
+   rdfs:comment "Bad unicode escape in pname (negative test)" ;
+   mf:action    <turtle-syntax-bad-pname-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-string-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-string-01" ;
+   rdfs:comment "mismatching string literal open/close (negative test)" ;
+   mf:action    <turtle-syntax-bad-string-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-string-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-string-02" ;
+   rdfs:comment "mismatching string literal open/close (negative test)" ;
+   mf:action    <turtle-syntax-bad-string-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-string-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-string-03" ;
+   rdfs:comment "mismatching string literal long/short (negative test)" ;
+   mf:action    <turtle-syntax-bad-string-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-string-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-string-04" ;
+   rdfs:comment "mismatching long string literal open/close (negative test)" ;
+   mf:action    <turtle-syntax-bad-string-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-string-05> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-string-05" ;
+   rdfs:comment "Long literal with missing end (negative test)" ;
+   mf:action    <turtle-syntax-bad-string-05.ttl> ;
+   .
+
+<#turtle-syntax-bad-string-06> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-string-06" ;
+   rdfs:comment "Long literal with extra quote (negative test)" ;
+   mf:action    <turtle-syntax-bad-string-06.ttl> ;
+   .
+
+<#turtle-syntax-bad-string-07> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-string-07" ;
+   rdfs:comment "Long literal with extra squote (negative test)" ;
+   mf:action    <turtle-syntax-bad-string-07.ttl> ;
+   .
+
+<#turtle-syntax-bad-num-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-num-01" ;
+   rdfs:comment "Bad number format (negative test)" ;
+   mf:action    <turtle-syntax-bad-num-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-num-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-num-02" ;
+   rdfs:comment "Bad number format (negative test)" ;
+   mf:action    <turtle-syntax-bad-num-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-num-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-num-03" ;
+   rdfs:comment "Bad number format (negative test)" ;
+   mf:action    <turtle-syntax-bad-num-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-num-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-num-04" ;
+   rdfs:comment "Bad number format (negative test)" ;
+   mf:action    <turtle-syntax-bad-num-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-num-05> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-num-05" ;
+   rdfs:comment "Bad number format (negative test)" ;
+   mf:action    <turtle-syntax-bad-num-05.ttl> ;
+   .
+
+<#turtle-eval-struct-01> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-eval-struct-01" ;
+   rdfs:comment "triple with IRIs" ;
+   mf:action    <turtle-eval-struct-01.ttl> ;
+   mf:result    <turtle-eval-struct-01.nt> ;
+   .
+
+<#turtle-eval-struct-02> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-eval-struct-02" ;
+   rdfs:comment "triple with IRIs and embedded whitespace" ;
+   mf:action    <turtle-eval-struct-02.ttl> ;
+   mf:result    <turtle-eval-struct-02.nt> ;
+   .
+
+<#turtle-subm-01> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-01" ;
+   rdfs:comment "Blank subject" ;
+   mf:action    <turtle-subm-01.ttl> ;
+   mf:result    <turtle-subm-01.nt> ;
+   .
+
+<#turtle-subm-02> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-02" ;
+   rdfs:comment "@prefix and qnames" ;
+   mf:action    <turtle-subm-02.ttl> ;
+   mf:result    <turtle-subm-02.nt> ;
+   .
+
+<#turtle-subm-03> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-03" ;
+   rdfs:comment ", operator" ;
+   mf:action    <turtle-subm-03.ttl> ;
+   mf:result    <turtle-subm-03.nt> ;
+   .
+
+<#turtle-subm-04> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-04" ;
+   rdfs:comment "; operator" ;
+   mf:action    <turtle-subm-04.ttl> ;
+   mf:result    <turtle-subm-04.nt> ;
+   .
+
+<#turtle-subm-05> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-05" ;
+   rdfs:comment "empty [] as subject and object" ;
+   mf:action    <turtle-subm-05.ttl> ;
+   mf:result    <turtle-subm-05.nt> ;
+   .
+
+<#turtle-subm-06> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-06" ;
+   rdfs:comment "non-empty [] as subject and object" ;
+   mf:action    <turtle-subm-06.ttl> ;
+   mf:result    <turtle-subm-06.nt> ;
+   .
+
+<#turtle-subm-07> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-07" ;
+   rdfs:comment "'a' as predicate" ;
+   mf:action    <turtle-subm-07.ttl> ;
+   mf:result    <turtle-subm-07.nt> ;
+   .
+
+<#turtle-subm-08> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-08" ;
+   rdfs:comment "simple collection" ;
+   mf:action    <turtle-subm-08.ttl> ;
+   mf:result    <turtle-subm-08.nt> ;
+   .
+
+<#turtle-subm-09> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-09" ;
+   rdfs:comment "empty collection" ;
+   mf:action    <turtle-subm-09.ttl> ;
+   mf:result    <turtle-subm-09.nt> ;
+   .
+
+<#turtle-subm-10> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-10" ;
+   rdfs:comment "integer datatyped literal" ;
+   mf:action    <turtle-subm-10.ttl> ;
+   mf:result    <turtle-subm-10.nt> ;
+   .
+
+<#turtle-subm-11> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-11" ;
+   rdfs:comment "decimal integer canonicalization" ;
+   mf:action    <turtle-subm-11.ttl> ;
+   mf:result    <turtle-subm-11.nt> ;
+   .
+
+<#turtle-subm-12> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-12" ;
+   rdfs:comment "- and _ in names and qnames" ;
+   mf:action    <turtle-subm-12.ttl> ;
+   mf:result    <turtle-subm-12.nt> ;
+   .
+
+<#turtle-subm-13> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-13" ;
+   rdfs:comment "tests for rdf:_<numbers> and other qnames starting with _" ;
+   mf:action    <turtle-subm-13.ttl> ;
+   mf:result    <turtle-subm-13.nt> ;
+   .
+
+<#turtle-subm-14> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-14" ;
+   rdfs:comment "bare : allowed" ;
+   mf:action    <turtle-subm-14.ttl> ;
+   mf:result    <turtle-subm-14.nt> ;
+   .
+
+<#turtle-subm-15> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-15" ;
+   rdfs:comment "simple long literal" ;
+   mf:action    <turtle-subm-15.ttl> ;
+   mf:result    <turtle-subm-15.nt> ;
+   .
+
+<#turtle-subm-16> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-16" ;
+   rdfs:comment "long literals with escapes" ;
+   mf:action    <turtle-subm-16.ttl> ;
+   mf:result    <turtle-subm-16.nt> ;
+   .
+
+<#turtle-subm-17> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-17" ;
+   rdfs:comment "floating point number" ;
+   mf:action    <turtle-subm-17.ttl> ;
+   mf:result    <turtle-subm-17.nt> ;
+   .
+
+<#turtle-subm-18> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-18" ;
+   rdfs:comment "empty literals, normal and long variant" ;
+   mf:action    <turtle-subm-18.ttl> ;
+   mf:result    <turtle-subm-18.nt> ;
+   .
+
+<#turtle-subm-19> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-19" ;
+   rdfs:comment "positive integer, decimal and doubles" ;
+   mf:action    <turtle-subm-19.ttl> ;
+   mf:result    <turtle-subm-19.nt> ;
+   .
+
+<#turtle-subm-20> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-20" ;
+   rdfs:comment "negative integer, decimal and doubles" ;
+   mf:action    <turtle-subm-20.ttl> ;
+   mf:result    <turtle-subm-20.nt> ;
+   .
+
+<#turtle-subm-21> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-21" ;
+   rdfs:comment "long literal ending in double quote" ;
+   mf:action    <turtle-subm-21.ttl> ;
+   mf:result    <turtle-subm-21.nt> ;
+   .
+
+<#turtle-subm-22> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-22" ;
+   rdfs:comment "boolean literals" ;
+   mf:action    <turtle-subm-22.ttl> ;
+   mf:result    <turtle-subm-22.nt> ;
+   .
+
+<#turtle-subm-23> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-23" ;
+   rdfs:comment "comments" ;
+   mf:action    <turtle-subm-23.ttl> ;
+   mf:result    <turtle-subm-23.nt> ;
+   .
+
+<#turtle-subm-24> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-24" ;
+   rdfs:comment "no final mewline" ;
+   mf:action    <turtle-subm-24.ttl> ;
+   mf:result    <turtle-subm-24.nt> ;
+   .
+
+<#turtle-subm-25> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-25" ;
+   rdfs:comment "repeating a @prefix changes pname definition" ;
+   mf:action    <turtle-subm-25.ttl> ;
+   mf:result    <turtle-subm-25.nt> ;
+   .
+
+<#turtle-subm-26> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-26" ;
+   rdfs:comment "Variations on decimal canonicalization" ;
+   mf:action    <turtle-subm-26.ttl> ;
+   mf:result    <turtle-subm-26.nt> ;
+   .
+
+<#turtle-subm-27> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-27" ;
+   rdfs:comment "Repeating @base changes base for relative IRI lookup" ;
+   mf:action    <turtle-subm-27.ttl> ;
+   mf:result    <turtle-subm-27.nt> ;
+   .
+
+<#turtle-eval-bad-01> rdf:type rdft:TestTurtleNegativeEval ;
+   mf:name    "turtle-eval-bad-01" ;
+   rdfs:comment "Bad IRI : good escape, bad charcater (negative evaluation test)" ;
+   mf:action    <turtle-eval-bad-01.ttl> ;
+   .
+
+<#turtle-eval-bad-02> rdf:type rdft:TestTurtleNegativeEval ;
+   mf:name    "turtle-eval-bad-02" ;
+   rdfs:comment "Bad IRI : hex 3C is < (negative evaluation test)" ;
+   mf:action    <turtle-eval-bad-02.ttl> ;
+   .
+
+<#turtle-eval-bad-03> rdf:type rdft:TestTurtleNegativeEval ;
+   mf:name    "turtle-eval-bad-03" ;
+   rdfs:comment "Bad IRI : hex 3E is  (negative evaluation test)" ;
+   mf:action    <turtle-eval-bad-03.ttl> ;
+   .
+
+<#turtle-eval-bad-04> rdf:type rdft:TestTurtleNegativeEval ;
+   mf:name    "turtle-eval-bad-04" ;
+   rdfs:comment "Bad IRI : {abc} (negative evaluation test)" ;
+   mf:action    <turtle-eval-bad-04.ttl> ;
+   .
+
+# tests from Dave Beckett
+# http://www.w3.org/2011/rdf-wg/wiki/Turtle_Candidate_Recommendation_Comments#c28
+<#LITERAL_LONG2_with_REVERSE_SOLIDUS> rdf:type rdft:TestTurtleEval ;
+   mf:name    "LITERAL_LONG2_with_REVERSE_SOLIDUS" ;
+   rdfs:comment "REVERSE SOLIDUS at end of LITERAL_LONG2" ;
+   mf:action    <LITERAL_LONG2_with_REVERSE_SOLIDUS.ttl> ;
+   mf:result    <LITERAL_LONG2_with_REVERSE_SOLIDUS.nt> ;
+   .
+
+<#turtle-syntax-bad-LITERAL2_with_langtag_and_datatype> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-num-05" ;
+   rdfs:comment "Bad number format (negative test)" ;
+   mf:action    <turtle-syntax-bad-LITERAL2_with_langtag_and_datatype.ttl> ;
+   .
+
+<#two_LITERAL_LONG2s> rdf:type rdft:TestTurtleEval ;
+   mf:name    "two_LITERAL_LONG2s" ;
+   rdfs:comment "two LITERAL_LONG2s testing quote delimiter overrun" ;
+   mf:action    <two_LITERAL_LONG2s.ttl> ;
+   mf:result    <two_LITERAL_LONG2s.nt> ;
+   .
+
+<#langtagged_LONG_with_subtag> rdf:type rdft:TestTurtleEval ;
+   mf:name      "langtagged_LONG_with_subtag" ;
+   rdfs:comment "langtagged LONG with subtag \"\"\"Cheers\"\"\"@en-UK" ;
+   mf:action    <langtagged_LONG_with_subtag.ttl> ;
+   mf:result    <langtagged_LONG_with_subtag.nt> ;
+   .
+
+# tests from David Robillard
+# http://www.w3.org/2011/rdf-wg/wiki/Turtle_Candidate_Recommendation_Comments#c21
+<#turtle-syntax-bad-blank-label-dot-end>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Blank node label must not end in dot" ;
+	mf:name "turtle-syntax-bad-blank-label-dot-end" ;
+	mf:action <turtle-syntax-bad-blank-label-dot-end.ttl> .
+
+<#turtle-syntax-bad-number-dot-in-anon>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Dot delimeter may not appear in anonymous nodes" ;
+	mf:name "turtle-syntax-bad-number-dot-in-anon" ;
+	mf:action <turtle-syntax-bad-number-dot-in-anon.ttl> .
+
+<#turtle-syntax-bad-ln-dash-start>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Local name must not begin with dash" ;
+	mf:name "turtle-syntax-bad-ln-dash-start" ;
+	mf:action <turtle-syntax-bad-ln-dash-start.ttl> .
+
+<#turtle-syntax-bad-ln-escape>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Bad hex escape in local name" ;
+	mf:name "turtle-syntax-bad-ln-escape" ;
+	mf:action <turtle-syntax-bad-ln-escape.ttl> .
+
+<#turtle-syntax-bad-ln-escape-start>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Bad hex escape at start of local name" ;
+	mf:name "turtle-syntax-bad-ln-escape-start" ;
+	mf:action <turtle-syntax-bad-ln-escape-start.ttl> .
+
+<#turtle-syntax-bad-ns-dot-end>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Prefix must not end in dot" ;
+	mf:name "turtle-syntax-bad-ns-dot-end" ;
+	mf:action <turtle-syntax-bad-ns-dot-end.ttl> .
+
+<#turtle-syntax-bad-ns-dot-start>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Prefix must not start with dot" ;
+	mf:name "turtle-syntax-bad-ns-dot-start" ;
+	mf:action <turtle-syntax-bad-ns-dot-start.ttl> .
+
+<#turtle-syntax-bad-missing-ns-dot-end>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Prefix must not end in dot (error in triple, not prefix directive like turtle-syntax-bad-ns-dot-end)" ;
+	mf:name "turtle-syntax-bad-missing-ns-dot-end" ;
+	mf:action <turtle-syntax-bad-missing-ns-dot-end.ttl> .
+
+<#turtle-syntax-bad-missing-ns-dot-start>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Prefix must not start with dot (error in triple, not prefix directive like turtle-syntax-bad-ns-dot-end)" ;
+	mf:name "turtle-syntax-bad-missing-ns-dot-start" ;
+	mf:action <turtle-syntax-bad-missing-ns-dot-start.ttl> .
+
+<#turtle-syntax-ln-dots>
+	rdf:type rdft:TestTurtlePositiveSyntax ;
+	rdfs:comment "Dots in pname local names" ;
+	mf:name "turtle-syntax-ln-dots" ;
+	mf:action <turtle-syntax-ln-dots.ttl> .
+
+<#turtle-syntax-ln-colons>
+	rdf:type rdft:TestTurtlePositiveSyntax ;
+	rdfs:comment "Colons in pname local names" ;
+	mf:name "turtle-syntax-ln-colons" ;
+	mf:action <turtle-syntax-ln-colons.ttl> .
+
+<#turtle-syntax-ns-dots>
+	rdf:type rdft:TestTurtlePositiveSyntax ;
+	rdfs:comment "Dots in namespace names" ;
+	mf:name "turtle-syntax-ns-dots" ;
+	mf:action <turtle-syntax-ns-dots.ttl> .
+
+<#turtle-syntax-blank-label>
+	rdf:type rdft:TestTurtlePositiveSyntax ;
+	rdfs:comment "Characters allowed in blank node labels" ;
+	mf:name "turtle-syntax-blank-label" ;
+	mf:action <turtle-syntax-blank-label.ttl> .
diff --git a/lib/arc2/tests/db_adapter_depended/ARC2_ClassTest.php b/lib/arc2/tests/db_adapter_depended/ARC2_ClassTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..85c4be4cff8b5ddb4ea1f8f2b37b7ef3b5a80bc6
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/ARC2_ClassTest.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace Tests\db_adapter_depended;
+
+use Tests\ARC2_TestCase;
+
+class ARC2_ClassTest extends ARC2_TestCase
+{
+    protected $dbConnection;
+    protected $store;
+
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->store = \ARC2::getStore($this->dbConfig);
+        $this->store->createDBCon();
+        $this->store->setup();
+        $this->dbConnection = $this->store->getDBCon();
+
+        $this->fixture = new \ARC2_Class($this->dbConfig, $this);
+
+        if ('mysqli' !== $this->dbConfig['db_adapter']) {
+            $this->markTestSkipped('Db adapter is not mysqli, therefore skip tests with queryDB.');
+        }
+    }
+
+    /*
+     * Tests for queryDB
+     */
+
+    public function testQueryDB()
+    {
+        $this->store->createDBCon();
+        $this->store->setup();
+
+        $result = $this->fixture->queryDB('SHOW TABLES', $this->dbConnection);
+        $this->assertEquals(1, $result->field_count);
+        $this->assertTrue(0 < $result->num_rows);
+    }
+
+    public function testQueryDBInvalidQuery()
+    {
+        $result = $this->fixture->queryDB('invalid-query', $this->dbConnection);
+        $this->assertFalse($result);
+    }
+
+    public function testQueryDBInvalidQueryWithLog()
+    {
+        $result = $this->fixture->queryDB('invalid-query', $this->dbConnection, true);
+        $this->assertFalse($result);
+
+        if ('mysql' == $this->store->getDBSName()) {
+            $dbsName = 'MySQL';
+        } else {
+            $dbsName = 'MariaDB';
+        }
+
+        $this->assertEquals(
+            [
+                'You have an error in your SQL syntax; check the manual that corresponds to your '
+                .$dbsName.' server version for the right syntax to use near \'invalid-query\' at line 1'
+            ],
+            $this->fixture->errors
+        );
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/AggregatesTest.php b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/AggregatesTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e3c2c04b06a45b22c23190c301649cdde529346d
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/AggregatesTest.php
@@ -0,0 +1,124 @@
+<?php
+
+namespace Tests\db_adapter_depended\sparql_1_1_tests;
+
+/**
+ * Runs W3C tests from https://www.w3.org/2009/sparql/docs/tests/
+ *
+ * Version: 2012-10-23 20:52 (sparql11-test-suite-20121023.tar.gz)
+ *
+ * Tests are located in the w3c-tests folder.
+ */
+class AggregatesTest extends ComplianceTest
+{
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->w3cTestsFolderPath = __DIR__.'/w3c-tests/aggregates';
+        $this->testPref = 'http://www.w3.org/2009/sparql/docs/tests/data-sparql11/aggregates/manifest#';
+    }
+
+    /*
+     * tests
+     */
+
+    public function test_agg_avg_01()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+
+        $testname = 'agg-avg-01';
+
+        // get test data
+        $data = $this->getTestData($this->testPref . $testname);
+
+        // load test data into graph
+        $this->store->insert($data, $this->dataGraphUri);
+
+        // get query to test
+        $testQuery = $this->getTestQuery($this->testPref . $testname);
+
+        // get expected result
+        $expectedResult = $this->getExpectedResult($this->testPref . $testname);
+
+        // get actual result for given test query
+        $actualResult = $this->store->query($testQuery);
+        $actualResultAsXml = $this->getXmlVersionOfResult($actualResult);
+
+        $this->assertEquals(
+            '2',
+            (string) $actualResultAsXml->results->result->binding->literal[0]
+        );
+
+        // remember current behavior, but skip test anyway to show developer here is still a problem.
+        $this->markTestSkipped(
+            'Rounding bug in AVG function. See https://github.com/semsol/arc2/issues/99'
+        );
+    }
+
+    public function test_agg_empty_group()
+    {
+        $this->assertTrue($this->runTestFor('agg-empty-group'));
+    }
+
+    public function test_agg_min_01()
+    {
+        $this->markTestSkipped(
+            'Skipped, because of known bug that ARC2 \'s Turtle parser can not parse decimals. '
+            .'For more information, see #136'
+        );
+
+        /*
+         * it seems the Turtle parser is not able to detect "1.0", but only "1"
+         *
+         * see file db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-numeric.ttl
+         */
+
+        $this->assertTrue($this->runTestFor('agg-min-01'));
+    }
+
+    public function test_agg01()
+    {
+        $this->assertTrue($this->runTestFor('agg01'));
+    }
+
+    public function test_agg02()
+    {
+        $this->assertTrue($this->runTestFor('agg02'));
+    }
+
+    public function test_agg04()
+    {
+        $this->assertTrue($this->runTestFor('agg04'));
+    }
+
+    public function test_agg05()
+    {
+        $this->assertTrue($this->runTestFor('agg05'));
+    }
+
+    public function test_agg08()
+    {
+        $this->assertTrue($this->runTestFor('agg08'));
+    }
+
+    public function test_agg09()
+    {
+        $this->assertTrue($this->runTestFor('agg09'));
+    }
+
+    public function test_agg10()
+    {
+        $this->assertTrue($this->runTestFor('agg10'));
+    }
+
+    public function test_agg11()
+    {
+        $this->assertTrue($this->runTestFor('agg11'));
+    }
+
+    public function test_agg12()
+    {
+        $this->assertTrue($this->runTestFor('agg12'));
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/ComplianceTest.php b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/ComplianceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..679b0c7cbc1e023489a4d222d3b1f8d130618109
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/ComplianceTest.php
@@ -0,0 +1,386 @@
+<?php
+
+namespace Tests\db_adapter_depended\sparql_1_1_tests;
+
+use Tests\ARC2_TestCase;
+
+/**
+ * Runs W3C tests from https://www.w3.org/2009/sparql/docs/tests/
+ *
+ * Version: 2012-10-23 20:52 (sparql11-test-suite-20121023.tar.gz)
+ *
+ * Tests are located in the w3c-tests folder.
+ */
+abstract class ComplianceTest extends ARC2_TestCase
+{
+    /**
+     * @var ARC2_Store
+     */
+    protected $store;
+
+    /**
+     * @var string
+     */
+    protected $dataGraphUri;
+
+    /**
+     * @var string
+     */
+    protected $manifestGraphUri;
+
+    /**
+     * @var string
+     */
+    protected $testPref;
+
+    /**
+     * @var string
+     */
+    protected $w3cTestsFolderPath;
+
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        // set graphs
+        $this->dataGraphUri = 'http://arc/data/';
+        $this->manifestGraphUri = 'http://arc/manifest/';
+
+        /*
+         * Setup a store instance to load test information and data.
+         */
+        $this->store = \ARC2::getStore($this->dbConfig);
+        $this->store->setup();
+    }
+
+    /**
+     *
+     */
+    public function tearDown(): void
+    {
+        $this->store->reset();
+        $this->store->closeDBCon();
+
+        parent::tearDown();
+    }
+
+    /**
+     * Helper function to get expected query result.
+     *
+     * @param string $testUri
+     * @return \SimpleXMLElement Instance of \SimpleXMLElement representing the result.
+     */
+    protected function getExpectedResult($testUri)
+    {
+        /*
+            example:
+
+            :group1 mf:result <group01.srx>
+         */
+        $res = $this->store->query('
+            PREFIX mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+            SELECT * FROM <'. $this->manifestGraphUri .'> WHERE {
+                <'. $testUri .'> mf:result ?resultFile .
+            }
+        ');
+
+        // if no result was given, expect test is of type NegativeSyntaxTest11,
+        // which has no data (group-data-X.ttl) and result (.srx) file.
+        if (0 < count($res['result']['rows'])) {
+            return new \SimpleXMLElement(file_get_contents($res['result']['rows'][0]['resultFile']));
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Helper function to get the number of rows in a table.
+     *
+     * @param string $tableName
+     * @return int Number of rows in the target table.
+     */
+    protected function getRowCount($tableName)
+    {
+        $row = $this->store->getDBObject()->fetchRow(
+            'SELECT COUNT(*) as count FROM '. $tableName,
+            $this->store->getDBCon()
+        );
+        return $row['count'];
+    }
+
+    /**
+     * Helper function to load data for a given test.
+     *
+     * @param string $testUri
+     * @return array Parsed file content.
+     */
+    protected function getTestData($testUri)
+    {
+        /*
+            example:
+
+            :group1 mf:action [
+                qt:data   <group-data-1.ttl>
+            ]
+         */
+        $file = $this->store->query('
+            PREFIX mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+            PREFIX qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
+            SELECT * FROM <'. $this->manifestGraphUri .'> WHERE {
+                <'. $testUri .'> mf:action [ qt:data ?file ] .
+            }
+        ');
+
+        // if no result was given, expect test is of type NegativeSyntaxTest11,
+        // which has no data (group-data-X.ttl) and result (.srx) file.
+        if (0 < count($file['result']['rows'])) {
+            $parser = \ARC2::getTurtleParser();
+            $parser->parse($file['result']['rows'][0]['file']);
+            return $parser->getSimpleIndex();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Helper function to get test query for a given test.
+     *
+     * @param string $testUri
+     * @return string Query to test.
+     */
+    protected function getTestQuery($testUri)
+    {
+        /*
+            example:
+
+            :group1 mf:action [
+                qt:query  <group01.rq>
+            ]
+         */
+        $query = $this->store->query('
+            PREFIX mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+            PREFIX qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
+            SELECT * FROM <'. $this->manifestGraphUri .'> WHERE {
+                <'. $testUri .'> mf:action [ qt:query ?queryFile ] .
+            }
+        ');
+
+        // if test is of type NegativeSyntaxTest11, mf:action points not to a blank node,
+        // but directly to the query file.
+        if (0 == count($query['result']['rows'])) {
+            $query = $this->store->query('
+                PREFIX mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+                SELECT * FROM <'. $this->manifestGraphUri .'> WHERE {
+                    <'. $testUri .'> mf:action ?queryFile .
+                }
+            ');
+        }
+
+        $query = file_get_contents($query['result']['rows'][0]['queryFile']);
+
+        // add data graph information as FROM clause, because ARC2 can't handle default graph
+        // queries. for more information see https://github.com/semsol/arc2/issues/72.
+        if (false !== strpos($query, 'ASK')
+            || false !== strpos($query, 'CONSTRUCT')
+            || false !== strpos($query, 'SELECT')) {
+            $query = str_replace('WHERE', 'FROM <'. $this->dataGraphUri .'> WHERE', $query);
+        }
+
+        return $query;
+    }
+
+    /**
+     * Helper function to get test type.
+     *
+     * @param string $testUri
+     * @return string Type URI
+     */
+    protected function getTestType($testUri)
+    {
+        $type = $this->store->query('
+            PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+            SELECT * FROM <'. $this->manifestGraphUri .'> WHERE {
+                <'. $testUri .'> rdf:type ?type .
+            }
+        ');
+
+        return $type['result']['rows'][0]['type'];
+    }
+
+    /**
+     * Transforms ARC2 query result to a \SimpleXMLElement instance for later comparison.
+     *
+     * @param array $result
+     * @return \SimpleXMLElement
+     */
+    protected function getXmlVersionOfResult(array $result)
+    {
+        $w = new \XMLWriter();
+        $w->openMemory();
+        $w->startDocument('1.0');
+
+        // sparql (root element)
+        $w->startElement('sparql');
+        $w->writeAttribute('xmlns', 'http://www.w3.org/2005/sparql-results#');
+
+        // sparql > head
+        $w->startElement('head');
+
+        foreach ($result['result']['variables'] as $var) {
+            $w->startElement('variable');
+            $w->writeAttribute('name', $var);
+            $w->endElement();
+        }
+
+        // end sparql > head
+        $w->endElement();
+
+        // sparql > results
+        $w->startElement('results');
+
+        foreach ($result['result']['rows'] as $row) {
+            /*
+                example:
+
+                <result>
+                  <binding name="s">
+                    <uri>http://example/s1</uri>
+                  </binding>
+                </result>
+             */
+
+            // new result element
+            $w->startElement('result');
+
+            foreach ($result['result']['variables'] as $var) {
+                if (empty($row[$var])) {
+                    continue;
+                }
+
+                // sparql > results > result > binding
+                $w->startElement('binding');
+                $w->writeAttribute('name', $var);
+
+                // if a variable type is set
+                if (isset($row[$var .' type'])) {
+
+                    // uri
+                    if ('uri' == $row[$var .' type']) {
+                        // example: <uri>http://example/s1</uri>
+                        $w->startElement('uri');
+                        $w->text($row[$var]);
+                        $w->endElement();
+
+                    } elseif ('literal' == $row[$var . ' type']) {
+                        // example: <literal datatype="http://www.w3.org/2001/XMLSchema#integer">9</literal>
+                        $w->startElement('literal');
+
+                        // its not part of the ARC2 result set, but expected later on
+                        if (true === ctype_digit($row[$var])) {
+                            $w->writeAttribute('datatype', 'http://www.w3.org/2001/XMLSchema#integer');
+                        }
+
+                        $w->text($row[$var]);
+                        $w->endElement();
+                    }
+                }
+
+                // end sparql > results > result > binding
+                $w->endElement();
+            }
+
+            // end result
+            $w->endElement();
+        }
+
+        // add <result></result> if no data were found
+        if (0 == count($result['result']['rows'])) {
+            $w->startElement('result');
+            $w->endElement();
+        }
+
+        // end sparql > results
+        $w->endElement();
+
+        // end sparql
+        $w->endElement();
+
+        return new \SimpleXMLElement($w->outputMemory(true));
+    }
+
+    /**
+     * Loads manifest.ttl into manifest graph.
+     *
+     * @param string $folderPath
+     */
+    protected function loadManifestFileIntoStore($folderPath)
+    {
+        // parse manifest.ttl and load its content into $this->manifestGraphUri
+        $parser = \ARC2::getTurtleParser();
+        $parser->parse($folderPath .'/manifest.ttl');
+        $this->store->insert($parser->getSimpleIndex(), $this->manifestGraphUri);
+    }
+
+    /**
+     * @param string $query
+     */
+    protected function makeQueryA1Liner($query)
+    {
+        return preg_replace('/\s\s+/', ' ', $query);
+    }
+
+    /**
+     * Helper function to run a certain test.
+     *
+     * @param string $testName E.g. group01
+     */
+    protected function runTestFor($testName)
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+
+        // get test type (this determines, if we expect a normal test or one, that must fail)
+        $negTestUri = 'http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#NegativeSyntaxTest11';
+        $type = $this->getTestType($this->testPref . $testName);
+
+        // test has to FAIL
+        if ($negTestUri == $type) {
+            // get query to test
+            $testQuery = $this->getTestQuery($this->testPref . $testName);
+
+            $this->assertFalse(empty($testQuery), 'Can not test, because test query is empty.');
+
+            $arc2Result = $this->store->query($testQuery);
+            if (0 == $arc2Result) {
+                $this->assertEquals(0, $arc2Result);
+
+            } elseif (isset($arc2Result['result']['rows'])) {
+                $this->assertEquals(0, count($arc2Result['result']['rows']));
+
+            } else {
+                throw new \Exception('Invalid result by query method: '. json_encode($arc2Result));
+            }
+
+        // test has to be SUCCESSFUL
+        } else {
+            // get test data
+            $data = $this->getTestData($this->testPref . $testName);
+
+            // load test data into graph
+            $this->store->insert($data, $this->dataGraphUri);
+
+            // get query to test
+            $testQuery = $this->getTestQuery($this->testPref . $testName);
+
+            // get expected result
+            $expectedResult = $this->getExpectedResult($this->testPref . $testName);
+
+            // get actual result for given test query
+            $actualResult = $this->store->query($testQuery);
+            $actualResultAsXml = $this->getXmlVersionOfResult($actualResult);
+
+            $this->assertEquals($expectedResult, $actualResultAsXml);
+        }
+
+        return true;
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/ConstructTest.php b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/ConstructTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..99da742bfea769413a084786ffd2ec754dcab70a
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/ConstructTest.php
@@ -0,0 +1,128 @@
+<?php
+
+namespace Tests\db_adapter_depended\sparql_1_1_tests;
+
+/**
+ * Runs W3C tests from https://www.w3.org/2009/sparql/docs/tests/
+ *
+ * Version: 2012-10-23 20:52 (sparql11-test-suite-20121023.tar.gz)
+ *
+ * Tests are located in the w3c-tests folder.
+ */
+class ConstructTest extends ComplianceTest
+{
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->w3cTestsFolderPath = __DIR__.'/w3c-tests/construct';
+        $this->testPref = 'http://www.w3.org/2009/sparql/docs/tests/data-sparql11/construct/manifest#';
+    }
+
+    /**
+     * Overriden. Helper function to get expected query result.
+     *
+     * @param string $testUri
+     * @return array
+     */
+    protected function getExpectedResult($testUri)
+    {
+        $res = $this->store->query('
+            PREFIX mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+            SELECT * FROM <'. $this->manifestGraphUri .'> WHERE {
+                <'. $testUri .'> mf:result ?resultFile .
+            }
+        ');
+
+        // if no result was given, expect test is of type NegativeSyntaxTest11,
+        // which has no data (group-data-X.ttl) and result (.srx) file.
+        if (0 < count($res['result']['rows'])) {
+            $parser = \ARC2::getTurtleParser();
+            $parser->parse(file_get_contents($res['result']['rows'][0]['resultFile']));
+            return $parser->getSimpleIndex();
+
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Overriden, because expected result is of type turtle and not XML.
+     * Helper function to run a certain test.
+     *
+     * @param string $testName E.g. group01
+     */
+    protected function runTestFor($testName)
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+
+        // get test type (this determines, if we expect a normal test or one, that must fail)
+        $negTestUri = 'http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#NegativeSyntaxTest11';
+        $type = $this->getTestType($this->testPref . $testName);;
+        // test has to FAIL
+        if ($negTestUri == $type) {
+            // get query to test
+            $testQuery = $this->getTestQuery($this->testPref . $testName);
+            $this->assertFalse(empty($testQuery), 'Can not test, because test query is empty.');
+
+            $arc2Result = $this->store->query($testQuery);
+            if (0 == $arc2Result) {
+                $this->assertEquals(0, $arc2Result);
+
+            } elseif (isset($arc2Result['result']['rows'])) {
+                $this->assertEquals(0, count($arc2Result['result']['rows']));
+
+            } else {
+                throw new \Exception('Invalid result by query method: '. json_encode($arc2Result));
+            }
+
+        // test has to be SUCCESSFUL
+        } else {
+            // get test data
+            $data = $this->getTestData($this->testPref . $testName);
+
+            // load test data into graph
+            $this->store->insert($data, $this->dataGraphUri);
+
+            // get query to test
+            $testQuery = $this->getTestQuery($this->testPref . $testName);
+
+            // get expected result
+            $expectedResult = $this->getExpectedResult($this->testPref . $testName);
+
+            // get actual result for given test query
+            $actualResult = $this->store->query($testQuery);
+        }
+
+        return true;
+    }
+
+    /*
+     * tests
+     */
+
+    public function test_constructwhere02()
+    {
+        $this->assertTrue($this->runTestFor('constructwhere02'));
+    }
+
+    public function test_constructwhere03()
+    {
+        $this->assertTrue($this->runTestFor('constructwhere03'));
+    }
+
+    public function test_constructwhere04()
+    {
+        $this->assertTrue($this->runTestFor('constructwhere04'));
+    }
+
+    public function test_constructwhere05()
+    {
+        $this->assertTrue($this->runTestFor('constructwhere05'));
+    }
+
+    public function test_constructwhere06()
+    {
+        $this->assertTrue($this->runTestFor('constructwhere06'));
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/DropTest.php b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/DropTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..5f0b3f191e6c51ffa8e1900cf531cc6a27665f80
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/DropTest.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Tests\db_adapter_depended\sparql_1_1_tests;
+
+/**
+ * Runs tests which are based on W3C tests from https://www.w3.org/2009/sparql/docs/tests/
+ *
+ * Version: 2012-10-23 20:52 (sparql11-test-suite-20121023.tar.gz)
+ *
+ * Tests are located in the w3c-tests folder.
+ */
+class DropTest extends ComplianceTest
+{
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->w3cTestsFolderPath = __DIR__.'/w3c-tests/drop';
+        $this->testPref = 'http://www.w3.org/2009/sparql/docs/tests/data-sparql11/drop/manifest#';
+    }
+
+    /**
+     * Helper function to get test query for a given test.
+     *
+     * @param string $testUri
+     * @return string Query to test.
+     */
+    protected function getTestQuery($testUri)
+    {
+        /*
+            example:
+
+            :group1 mf:action [
+                qt:query  <group01.rq>
+            ]
+         */
+        $query = $this->store->query('
+            PREFIX mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+            PREFIX ut: <http://www.w3.org/2009/sparql/tests/test-update#> .
+            SELECT * FROM <'. $this->manifestGraphUri .'> WHERE {
+                <'. $testUri .'> mf:action [ ut:request ?queryFile ] .
+            }
+        ');
+
+        return $query['result']['rows'][0]['queryFile'];
+    }
+
+    /*
+     * tests
+     */
+
+    // this test is not part of the W3C test collection
+    // it tests DELETE FROM <...> command which is the ARC2 equivalent to DROP GRAPH <...>
+    public function test_delete_graph()
+    {
+        $graphUri = 'http://example.org/g1';
+
+        $this->store->query('INSERT INTO <'.$graphUri.'> {
+            <http://example.org/g1> <http://example.org/name> "G1" ;
+                                    <http://example.org/description> "Graph 1" .
+        }');
+
+        // check if graph really contains data
+        $res = $this->store->query('SELECT * WHERE {?s ?p ?o.}');
+        $this->assertTrue(0 < count($res['result']['rows']), 'No test data in graph found.');
+
+        // run test query
+        $res = $this->store->query('DELETE FROM <'. $graphUri .'>');
+
+        // check if test data are still available
+        $res = $this->store->query('SELECT * FROM <'. $graphUri .'> WHERE {?s ?p ?o.}');
+        $this->assertTrue(0 == count($res['result']['rows']));
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/SyntaxUpdate1Test.php b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/SyntaxUpdate1Test.php
new file mode 100644
index 0000000000000000000000000000000000000000..793ff03b7a184ec92815897d64734e236da7e214
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/SyntaxUpdate1Test.php
@@ -0,0 +1,239 @@
+<?php
+
+namespace Tests\db_adapter_depended\sparql_1_1_tests;
+
+/**
+ * Runs W3C tests from https://www.w3.org/2009/sparql/docs/tests/
+ *
+ * Version: 2012-10-23 20:52 (sparql11-test-suite-20121023.tar.gz)
+ *
+ * Tests are located in the w3c-tests folder.
+ */
+class SyntaxUpdate1Test extends ComplianceTest
+{
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->w3cTestsFolderPath = __DIR__.'/w3c-tests/syntax-update-1';
+        $this->testPref = 'http://www.w3.org/2009/sparql/docs/tests/data-sparql11/syntax-update-1/manifest#';
+    }
+
+    /**
+     * Helper function to get test query for a given test.
+     *
+     * @param string $testUri
+     * @return string Query to test.
+     */
+    protected function getTestQuery($testUri)
+    {
+        /*
+            example:
+
+            :test_1 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+               dawgt:approval dawgt:Approved ;
+               dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+               mf:name    "syntax-update-01.ru" ;
+               mf:action  <syntax-update-01.ru> ;.
+         */
+        $query = $this->store->query('
+            PREFIX mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+            SELECT * FROM <'. $this->manifestGraphUri .'> WHERE {
+                <'. $testUri .'> mf:action ?queryFile .
+            }
+        ');
+
+        return file_get_contents($query['result']['rows'][0]['queryFile']);
+    }
+
+    /*
+     * tests
+     */
+
+    public function test_test_1()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+        $query = $this->getTestQuery($this->testPref . 'test_1');
+
+        // fire query
+        $result = $this->store->query($query);
+
+        // check result
+        $this->assertTrue(is_array($result) && isset($result['query_type']));
+    }
+
+    public function test_test_2()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+        $query = $this->getTestQuery($this->testPref . 'test_2');
+
+        // fire query
+        $result = $this->store->query($query);
+
+        // check result
+        $this->assertTrue(is_array($result) && isset($result['query_type']));
+    }
+
+    public function test_test_41()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+        $query = $this->getTestQuery($this->testPref . 'test_41');
+
+        // fire query
+        $result = $this->store->query($query);
+
+        // check result
+        $this->assertEquals(0, $result);
+    }
+
+    public function test_test_42()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+        $query = $this->getTestQuery($this->testPref . 'test_42');
+
+        // fire query
+        $result = $this->store->query($query);
+
+        // check result
+        $this->assertEquals(0, $result);
+    }
+
+    public function test_test_43()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+        $query = $this->getTestQuery($this->testPref . 'test_43');
+
+        // fire query
+        $result = $this->store->query($query);
+
+        // check result
+        $this->assertEquals(0, $result);
+    }
+
+    public function test_test_44()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+        $query = $this->getTestQuery($this->testPref . 'test_44');
+
+        // fire query
+        $result = $this->store->query($query);
+
+        // check result
+        $this->assertEquals(0, $result);
+    }
+
+    public function test_test_45()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+        $query = $this->getTestQuery($this->testPref . 'test_45');
+
+        // fire query
+        $result = $this->store->query($query);
+
+        // check result
+        $this->assertEquals(0, $result);
+    }
+
+    public function test_test_46()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+        $query = $this->getTestQuery($this->testPref . 'test_46');
+
+        // fire query
+        $result = $this->store->query($query);
+
+        // check result
+        $this->assertEquals(0, $result);
+    }
+
+    public function test_test_47()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+        $query = $this->getTestQuery($this->testPref . 'test_47');
+
+        // fire query
+        $result = $this->store->query($query);
+
+        // check result
+        $this->assertEquals(0, $result);
+    }
+
+    public function test_test_48()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+        $query = $this->getTestQuery($this->testPref . 'test_48');
+
+        // fire query
+        $result = $this->store->query($query);
+
+        // check result
+        $this->assertEquals(0, $result);
+    }
+
+    public function test_test_49()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+        $query = $this->getTestQuery($this->testPref . 'test_49');
+
+        // fire query
+        $result = $this->store->query($query);
+
+        // check result
+        $this->assertEquals(0, $result);
+    }
+
+    public function test_test_50()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+        $query = $this->getTestQuery($this->testPref . 'test_50');
+
+        // fire query
+        $result = $this->store->query($query);
+
+        // check result
+        $this->assertEquals(0, $result);
+    }
+
+    public function test_test_51()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+        $query = $this->getTestQuery($this->testPref . 'test_51');
+
+        // fire query
+        $result = $this->store->query($query);
+
+        // check current reaction of ARC2, for compatible reasons
+        $this->assertTrue(is_array($result));
+
+        // check result
+        $this->markTestSkipped(
+            'Query has to fail, but ARC2 returns an array as if query is considered valid. Query: '
+            .PHP_EOL
+            .$this->makeQueryA1Liner($query)
+        );
+    }
+
+    public function test_test_52()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+        $query = $this->getTestQuery($this->testPref . 'test_52');
+
+        // fire query
+        $result = $this->store->query($query);
+
+        // check result
+        $this->assertEquals(0, $result);
+    }
+
+    public function test_test_54()
+    {
+        $this->loadManifestFileIntoStore($this->w3cTestsFolderPath);
+        $query = $this->getTestQuery($this->testPref . 'test_54');
+
+        // fire query
+        $result = $this->store->query($query);
+
+        // check result
+        $this->assertEquals(0, $result);
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-avg-01.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-avg-01.rq
new file mode 100644
index 0000000000000000000000000000000000000000..4e0ecd45d25e8b0f754ebdf92cd675258515ff91
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-avg-01.rq
@@ -0,0 +1,5 @@
+PREFIX : <http://www.example.org/>
+SELECT (AVG(?o) AS ?avg)
+WHERE {
+	?s :dec ?o
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-avg-01.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-avg-01.srx
new file mode 100644
index 0000000000000000000000000000000000000000..8efbd376c5ea07188f11756a570c56264903d2da
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-avg-01.srx
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="avg"/>
+  </head>
+  <results>
+    <result>
+      <binding name="avg">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#decimal">2.22</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-avg-02.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-avg-02.rq
new file mode 100644
index 0000000000000000000000000000000000000000..67fe6e6e24e1c36b872e1563ab3577c8afebf67b
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-avg-02.rq
@@ -0,0 +1,7 @@
+PREFIX : <http://www.example.org/>
+SELECT ?s (AVG(?o) AS ?avg)
+WHERE {
+	?s ?p ?o
+}
+GROUP BY ?s
+HAVING (AVG(?o) <= 2.0)
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-avg-02.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-avg-02.srx
new file mode 100644
index 0000000000000000000000000000000000000000..6a7172c7f861e9ba166899f65be648b12ddc95ee
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-avg-02.srx
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="s"/>
+    <variable name="avg"/>
+  </head>
+  <results>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/mixed1</uri>
+      </binding>
+      <binding name="avg">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#decimal">1.6</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/mixed2</uri>
+      </binding>
+      <binding name="avg">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#double">2.0E-1</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/ints</uri>
+      </binding>
+      <binding name="avg">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#decimal">2.0</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-empty-group.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-empty-group.rq
new file mode 100644
index 0000000000000000000000000000000000000000..55bd4240a048b953d05e8fdacff9df1aebcf9c03
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-empty-group.rq
@@ -0,0 +1,5 @@
+PREFIX ex: <http://example.com/>
+SELECT ?x (MAX(?value) AS ?max)
+WHERE {
+	?x ex:p ?value
+} GROUP BY ?x
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-empty-group.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-empty-group.srx
new file mode 100644
index 0000000000000000000000000000000000000000..c1c696b489b3c9064e6af0e3b9fcb10ffb1edeb2
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-empty-group.srx
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<!--
+    IMPORTANT NOTE: because query in file agg-empty-group.rq looks like SELECT ?x (MAX(?value) AS ?max),
+                    the head has to contain x as variable too. in other files, such variables are available too.
+
+                    another change is the removal of spaces between <result> and </result>.
+-->
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+	<head>
+		<variable name="x"/>
+		<variable name="max"/>
+	</head>
+	<results>
+		<result></result>
+	</results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-01.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-01.rq
new file mode 100644
index 0000000000000000000000000000000000000000..e4c0714192631cfb180c9cbc5f991eb19b568cff
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-01.rq
@@ -0,0 +1,6 @@
+PREFIX : <http://example.com/data/#>
+SELECT ?g (AVG(?p) AS ?avg) ((MIN(?p) + MAX(?p)) / 2 AS ?c)
+WHERE {
+  ?g :p ?p .
+}
+GROUP BY ?g
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-01.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-01.srx
new file mode 100644
index 0000000000000000000000000000000000000000..8dc23e4eccb6914ab973200502200e89b06fd57d
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-01.srx
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<sparql xmlns='http://www.w3.org/2005/sparql-results#'>
+<head>
+<variable name='g'/>
+<variable name='avg'/>
+<variable name='c'/>
+</head>
+<results>
+<result>
+<binding name='g'><uri>http://example.com/data/#x</uri></binding>
+<binding name='avg'><literal datatype='http://www.w3.org/2001/XMLSchema#decimal'>2.5</literal></binding>
+<binding name='c'><literal datatype='http://www.w3.org/2001/XMLSchema#decimal'>2.5</literal></binding>
+</result>
+<result>
+<binding name='g'><uri>http://example.com/data/#y</uri></binding>
+</result>
+<result>
+<binding name='g'><uri>http://example.com/data/#z</uri></binding>
+<binding name='avg'><literal datatype='http://www.w3.org/2001/XMLSchema#decimal'>2.5</literal></binding>
+<binding name='c'><literal datatype='http://www.w3.org/2001/XMLSchema#decimal'>2.5</literal></binding>
+</result>
+</results>
+</sparql>
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-01.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-01.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..5104ea9db9568a07c06e2257808a1549a79c8c63
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-01.ttl
@@ -0,0 +1,5 @@
+@prefix : <http://example.com/data/#> .
+
+:x :p 1, 2, 3, 4 .
+:y :p 1, _:b2, 3, 4 .
+:z :p 1.0, 2.0, 3.0, 4 .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-02.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-02.rq
new file mode 100644
index 0000000000000000000000000000000000000000..b6466c7dcbad58f2601795a642b0d6f424c65318
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-02.rq
@@ -0,0 +1,8 @@
+PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+PREFIX : <http://example.com/data/#>
+SELECT ?g 
+(AVG(IF(isNumeric(?p), ?p, COALESCE(xsd:double(?p),0))) AS ?avg) 
+WHERE {
+  ?g :p ?p .
+}
+GROUP BY ?g
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-02.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-02.srx
new file mode 100644
index 0000000000000000000000000000000000000000..8b1af9e5eb59e0187935e4992285a02723332495
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-02.srx
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="g"/>
+    <variable name="avg"/>
+  </head>
+  <results>
+    <result>
+      <binding name="g">
+        <uri>http://example.com/data/#x</uri>
+      </binding>
+      <binding name="avg">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#double">2.5E0</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="g">
+        <uri>http://example.com/data/#y</uri>
+      </binding>
+      <binding name="avg">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#decimal">2.0</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="g">
+        <uri>http://example.com/data/#z</uri>
+      </binding>
+      <binding name="avg">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#double">2.5E0</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-02.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-02.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..8351860fbc2d9774584cb071ab790e7431300bf8
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-err-02.ttl
@@ -0,0 +1,5 @@
+@prefix : <http://example.com/data/#> .
+
+:x :p 1, "2", 3, 4 .
+:y :p 1, _:b2, 3, 4 .
+:z :p 2.5E0, "not a double" , 3.5, 4 .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-1.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-1.rq
new file mode 100644
index 0000000000000000000000000000000000000000..e6c8e249c3489759d5bc94741ed6928b468f5ef4
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-1.rq
@@ -0,0 +1,7 @@
+PREFIX : <http://www.example.org/>
+ASK {
+	{SELECT (GROUP_CONCAT(?o) AS ?g) WHERE {
+		[] :p1 ?o
+	}}
+	FILTER(?g = "1 22" || ?g = "22 1")
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-1.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-1.srx
new file mode 100644
index 0000000000000000000000000000000000000000..3b6bc6d93f6a0d16500d3896829982e31a737e4b
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-1.srx
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head/>
+  <boolean>true</boolean>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-1.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-1.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..1438f3a4887e11cb0cc90603568241b08175ffcc
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-1.ttl
@@ -0,0 +1,4 @@
+@prefix : <http://www.example.org/> .
+
+:s :p1 "1", "22" .
+:s :p2 "aaa", "bb", "c" .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-2.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-2.rq
new file mode 100644
index 0000000000000000000000000000000000000000..da72015b41457339f2e57ad6e44388c76c4673ce
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-2.rq
@@ -0,0 +1,10 @@
+PREFIX : <http://www.example.org/>
+SELECT (COUNT(*) AS ?c) {
+	{SELECT ?p (GROUP_CONCAT(?o) AS ?g) WHERE {
+		[] ?p ?o
+	} GROUP BY ?p}
+	FILTER(
+		(?p = :p1 && (?g = "1 22" || ?g = "22 1"))
+		|| (?p = :p2 && (?g = "aaa bb c" || ?g = "aaa c bb" || ?g = "bb aaa c" || ?g = "bb c aaa" || ?g = "c aaa bb" || ?g = "c bb aaa"))
+	)
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-2.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-2.srx
new file mode 100644
index 0000000000000000000000000000000000000000..5f2ef92a1d6548746896b5212c696ae9d6d37ea7
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-2.srx
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="c"/>
+  </head>
+  <results>
+    <result>
+      <binding name="c">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-3.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-3.rq
new file mode 100644
index 0000000000000000000000000000000000000000..1a4953300cece1b91ad72733edb7b7ce0814b0b0
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-3.rq
@@ -0,0 +1,7 @@
+PREFIX : <http://www.example.org/>
+ASK {
+	{SELECT (GROUP_CONCAT(?o;SEPARATOR=":") AS ?g) WHERE {
+		[] :p1 ?o
+	}}
+	FILTER(?g = "1:22" || ?g = "22:1")
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-3.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-3.srx
new file mode 100644
index 0000000000000000000000000000000000000000..3b6bc6d93f6a0d16500d3896829982e31a737e4b
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-groupconcat-3.srx
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head/>
+  <boolean>true</boolean>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-max-01.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-max-01.rq
new file mode 100644
index 0000000000000000000000000000000000000000..d1634d8d9ddc7b3cdcf3de23c685470864dca1d5
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-max-01.rq
@@ -0,0 +1,5 @@
+PREFIX : <http://www.example.org/>
+SELECT (MAX(?o) AS ?max)
+WHERE {
+	?s ?p ?o
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-max-01.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-max-01.srx
new file mode 100644
index 0000000000000000000000000000000000000000..1be7e475a8ef66d86cb726d9c132aae8fb640712
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-max-01.srx
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="max"/>
+  </head>
+  <results>
+    <result>
+      <binding name="max">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#double">3.0E4</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-max-02.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-max-02.rq
new file mode 100644
index 0000000000000000000000000000000000000000..fdf516da2a4eb6c59ac119557ef71636009fd68f
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-max-02.rq
@@ -0,0 +1,6 @@
+PREFIX : <http://www.example.org/>
+SELECT ?s (MAX(?o) AS ?max)
+WHERE {
+	?s ?p ?o
+}
+GROUP BY ?s
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-max-02.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-max-02.srx
new file mode 100644
index 0000000000000000000000000000000000000000..795dc13553863bed3d1cd7bd45a9e0e6821002a2
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-max-02.srx
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="s"/>
+    <variable name="max"/>
+  </head>
+  <results>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/ints</uri>
+      </binding>
+      <binding name="max">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">3</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/decimals</uri>
+      </binding>
+      <binding name="max">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#decimal">3.5</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/doubles</uri>
+      </binding>
+      <binding name="max">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#double">3.0E4</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/mixed1</uri>
+      </binding>
+      <binding name="max">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#decimal">2.2</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/mixed2</uri>
+      </binding>
+      <binding name="max">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#decimal">2.2</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-min-01.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-min-01.rq
new file mode 100644
index 0000000000000000000000000000000000000000..f9e5033dd714d402b0b1c1af313861093e2fd1ca
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-min-01.rq
@@ -0,0 +1,5 @@
+PREFIX : <http://www.example.org/>
+SELECT (MIN(?o) AS ?min)
+WHERE {
+	?s :dec ?o
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-min-01.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-min-01.srx
new file mode 100644
index 0000000000000000000000000000000000000000..102efe42c3f8536813562efcb72c6917bdc50862
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-min-01.srx
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="min"/>
+  </head>
+  <results>
+    <result>
+      <binding name="min">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#decimal">1.0</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-min-02.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-min-02.rq
new file mode 100644
index 0000000000000000000000000000000000000000..3ae3ea4fc26914a0adebbe1675439ddd7fe4e3cf
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-min-02.rq
@@ -0,0 +1,6 @@
+PREFIX : <http://www.example.org/>
+SELECT ?s (MIN(?o) AS ?min)
+WHERE {
+	?s ?p ?o
+}
+GROUP BY ?s
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-min-02.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-min-02.srx
new file mode 100644
index 0000000000000000000000000000000000000000..fc9786291472e69c4929874e3d3bf034c4202c63
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-min-02.srx
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="s"/>
+    <variable name="min"/>
+  </head>
+  <results>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/ints</uri>
+      </binding>
+      <binding name="min">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/decimals</uri>
+      </binding>
+      <binding name="min">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#decimal">1.0</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/doubles</uri>
+      </binding>
+      <binding name="min">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#double">1.0E2</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/mixed1</uri>
+      </binding>
+      <binding name="min">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/mixed2</uri>
+      </binding>
+      <binding name="min">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#double">2.0E-1</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-numeric.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-numeric.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..61099a4d1aa5a3ef195143700ed27525844270ff
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-numeric.ttl
@@ -0,0 +1,8 @@
+@prefix : <http://www.example.org/> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+:ints :int 1, 2, 3 .
+:decimals :dec 1.0, 2.2, 3.5 .
+:doubles :double 1.0E2, 2.0E3, 3.0E4 .
+:mixed1 :int 1 ; :dec 2.2 .
+:mixed2 :double 2E-1 ; :dec 2.2 .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-numeric2.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-numeric2.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..bda35c3166c6044fc4a5a608ce289b8af8961dda
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-numeric2.ttl
@@ -0,0 +1,8 @@
+@prefix : <http://www.example.org/> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+:ints :int 1, 2, 3 .
+:decimals :dec 1.0, 2.2, 3.5 .
+:doubles :double 1.0E2, 2.0E3, 3.0E4 .
+:mixed1 :int 1 ; :dec 2.2 .
+:mixed2 :double 2E-1 ; :dec 0.2 .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sample-01.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sample-01.rq
new file mode 100644
index 0000000000000000000000000000000000000000..7e7162c8fbabb997ab0d385c3cf63859c7638d02
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sample-01.rq
@@ -0,0 +1,10 @@
+PREFIX : <http://www.example.org/>
+ASK {
+	{
+		SELECT (SAMPLE(?o) AS ?sample)
+		WHERE {
+			?s :dec ?o
+		}
+	}
+	FILTER(?sample = 1.0 || ?sample = 2.2 || ?sample = 3.5)
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sample-01.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sample-01.srx
new file mode 100644
index 0000000000000000000000000000000000000000..3b6bc6d93f6a0d16500d3896829982e31a737e4b
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sample-01.srx
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head/>
+  <boolean>true</boolean>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sum-01.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sum-01.rq
new file mode 100644
index 0000000000000000000000000000000000000000..57e45ca1119c7dffd4bacbbd2c5a33234cca0218
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sum-01.rq
@@ -0,0 +1,5 @@
+PREFIX : <http://www.example.org/>
+SELECT (SUM(?o) AS ?sum)
+WHERE {
+	?s :dec ?o
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sum-01.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sum-01.srx
new file mode 100644
index 0000000000000000000000000000000000000000..6cbe0d63af42aa151acbde6e67c331c730d35ea9
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sum-01.srx
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="sum"/>
+  </head>
+  <results>
+    <result>
+      <binding name="sum">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#decimal">11.1</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sum-02.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sum-02.rq
new file mode 100644
index 0000000000000000000000000000000000000000..b9cced93178ce197fa292ce7a69bec64db5f844a
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sum-02.rq
@@ -0,0 +1,6 @@
+PREFIX : <http://www.example.org/>
+SELECT ?s (SUM(?o) AS ?sum)
+WHERE {
+	?s ?p ?o
+}
+GROUP BY ?s
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sum-02.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sum-02.srx
new file mode 100644
index 0000000000000000000000000000000000000000..dd85281f91cadd0cc3fc6e44e131169cdf750953
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg-sum-02.srx
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="s"/>
+    <variable name="sum"/>
+  </head>
+  <results>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/ints</uri>
+      </binding>
+      <binding name="sum">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">6</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/decimals</uri>
+      </binding>
+      <binding name="sum">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#decimal">6.7</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/doubles</uri>
+      </binding>
+      <binding name="sum">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#double">3.21E4</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/mixed1</uri>
+      </binding>
+      <binding name="sum">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#decimal">3.2</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="s">
+        <uri>http://www.example.org/mixed2</uri>
+      </binding>
+      <binding name="sum">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#double">4.0E-1</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg01.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg01.rq
new file mode 100644
index 0000000000000000000000000000000000000000..06976420b96ef48f892372fcc9f11fdc0d5741aa
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg01.rq
@@ -0,0 +1,4 @@
+PREFIX : <http://www.example.org>
+
+SELECT (COUNT(?O) AS ?C)
+WHERE { ?S ?P ?O }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg01.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg01.srx
new file mode 100644
index 0000000000000000000000000000000000000000..9e13305a6438035d44de90563967b51360c58c06
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg01.srx
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="C"/>
+  </head>
+  <results>
+    <result>
+      <binding name="C">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">5</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg01.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg01.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..5d8f4c5870c760dd56ba7e76a843bfa03ba4886d
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg01.ttl
@@ -0,0 +1,4 @@
+@prefix : <http://www.example.org/> .
+
+:s :p1 :o1, :o2, :o3.
+:s :p2 :o1, :o2.
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg02.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg02.rq
new file mode 100644
index 0000000000000000000000000000000000000000..f5fa6b23295408bc674e832857945122da916841
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg02.rq
@@ -0,0 +1,5 @@
+PREFIX : <http://www.example.org>
+
+SELECT ?P (COUNT(?O) AS ?C)
+WHERE { ?S ?P ?O }
+GROUP BY ?P
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg02.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg02.srx
new file mode 100644
index 0000000000000000000000000000000000000000..dff443c562b993ddcc52f6d49325b30ac5bda26c
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg02.srx
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="P"/>
+    <variable name="C"/>
+  </head>
+  <results>
+    <result>
+      <binding name="P">
+        <uri>http://www.example.org/p1</uri>
+      </binding>
+      <binding name="C">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">3</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="P">
+        <uri>http://www.example.org/p2</uri>
+      </binding>
+      <binding name="C">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg03.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg03.rq
new file mode 100644
index 0000000000000000000000000000000000000000..9c39780c8a75f609a66083c8bf77c25221bc02aa
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg03.rq
@@ -0,0 +1,6 @@
+PREFIX : <http://www.example.org>
+
+SELECT ?P (COUNT(?O) AS ?C)
+WHERE { ?S ?P ?O }
+GROUP BY ?P
+HAVING (COUNT(?O) > 2 )
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg03.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg03.srx
new file mode 100644
index 0000000000000000000000000000000000000000..a257426a05684f5e44f4e1f0a161bcdcb1bbaaaa
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg03.srx
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="P"/>
+    <variable name="C"/>
+  </head>
+  <results>
+    <result>
+      <binding name="P">
+        <uri>http://www.example.org/p1</uri>
+      </binding>
+      <binding name="C">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">3</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg04.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg04.rq
new file mode 100644
index 0000000000000000000000000000000000000000..6b873bd4346833cc6002832f78f3445f31bd025c
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg04.rq
@@ -0,0 +1,4 @@
+PREFIX : <http://www.example.org>
+
+SELECT (COUNT(*) AS ?C)
+WHERE { ?S ?P ?O }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg04.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg04.srx
new file mode 100644
index 0000000000000000000000000000000000000000..9e13305a6438035d44de90563967b51360c58c06
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg04.srx
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="C"/>
+  </head>
+  <results>
+    <result>
+      <binding name="C">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">5</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg05.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg05.rq
new file mode 100644
index 0000000000000000000000000000000000000000..839eada7cdb1cafbca3fa98af4c0d7a046215d49
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg05.rq
@@ -0,0 +1,5 @@
+PREFIX : <http://www.example.org>
+
+SELECT ?P (COUNT(*) AS ?C)
+WHERE { ?S ?P ?O }
+GROUP BY ?P
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg05.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg05.srx
new file mode 100644
index 0000000000000000000000000000000000000000..dff443c562b993ddcc52f6d49325b30ac5bda26c
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg05.srx
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="P"/>
+    <variable name="C"/>
+  </head>
+  <results>
+    <result>
+      <binding name="P">
+        <uri>http://www.example.org/p1</uri>
+      </binding>
+      <binding name="C">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">3</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="P">
+        <uri>http://www.example.org/p2</uri>
+      </binding>
+      <binding name="C">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg06.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg06.rq
new file mode 100644
index 0000000000000000000000000000000000000000..051d8f740ceda19f8884d99beb50f9227c0792a9
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg06.rq
@@ -0,0 +1,5 @@
+PREFIX : <http://www.example.org>
+
+SELECT (COUNT(*) AS ?C)
+WHERE { ?S ?P ?O }
+HAVING (COUNT(*) > 0 )
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg06.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg06.srx
new file mode 100644
index 0000000000000000000000000000000000000000..9e13305a6438035d44de90563967b51360c58c06
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg06.srx
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="C"/>
+  </head>
+  <results>
+    <result>
+      <binding name="C">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">5</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg07.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg07.rq
new file mode 100644
index 0000000000000000000000000000000000000000..de31f26740e8ef70304ea7f7d7e5455e68faf67e
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg07.rq
@@ -0,0 +1,6 @@
+PREFIX : <http://www.example.org>
+
+SELECT ?P (COUNT(*) AS ?C)
+WHERE { ?S ?P ?O }
+GROUP BY ?P
+HAVING ( COUNT(*) > 2 )
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg07.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg07.srx
new file mode 100644
index 0000000000000000000000000000000000000000..a257426a05684f5e44f4e1f0a161bcdcb1bbaaaa
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg07.srx
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="P"/>
+    <variable name="C"/>
+  </head>
+  <results>
+    <result>
+      <binding name="P">
+        <uri>http://www.example.org/p1</uri>
+      </binding>
+      <binding name="C">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">3</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg08.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg08.rq
new file mode 100644
index 0000000000000000000000000000000000000000..70a3bbbc86f219a141d8e3b0d14c5ad061164ef3
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg08.rq
@@ -0,0 +1,5 @@
+PREFIX : <http://www.example.org/>
+
+SELECT ((?O1 + ?O2) AS ?O12) (COUNT(?O1) AS ?C)
+WHERE { ?S :p ?O1; :q ?O2 } GROUP BY (?O1 + ?O2)
+ORDER BY ?O12
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg08.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg08.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..a450c221631c4c8f34814a14cf886f90369e4dee
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg08.ttl
@@ -0,0 +1,4 @@
+@prefix : <http://www.example.org/> .
+
+:s :p 0,1,2 .
+:s :q 0,1,2 .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg08b.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg08b.rq
new file mode 100644
index 0000000000000000000000000000000000000000..2e4314830e85fa27a92818f9f3ecb043ec3d18cd
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg08b.rq
@@ -0,0 +1,5 @@
+PREFIX : <http://www.example.org/>
+
+   SELECT ?O12 (COUNT(?O1) AS ?C)
+   WHERE { ?S :p ?O1; :q ?O2 } GROUP BY ((?O1 + ?O2) AS ?O12)
+   ORDER BY ?O12
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg08b.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg08b.srx
new file mode 100644
index 0000000000000000000000000000000000000000..e5bec044308a5cd859a5668a3e4fb715afa2e3b9
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg08b.srx
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="O12"/>
+    <variable name="C"/>
+  </head>
+  <results>
+    <result>
+      <binding name="O12">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">0</literal>
+      </binding>
+      <binding name="C">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="O12">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
+      </binding>
+      <binding name="C">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="O12">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
+      </binding>
+      <binding name="C">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">3</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="O12">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">3</literal>
+      </binding>
+      <binding name="C">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
+      </binding>
+    </result>
+    <result>
+      <binding name="O12">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">4</literal>
+      </binding>
+      <binding name="C">
+        <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
+      </binding>
+    </result>
+  </results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg09.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg09.rq
new file mode 100644
index 0000000000000000000000000000000000000000..922f5600f031f207c442015a043f1ebc035d5a96
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg09.rq
@@ -0,0 +1,4 @@
+PREFIX : <http://www.example.org/>
+
+SELECT ?P (COUNT(?O) AS ?C)
+WHERE { ?S ?P ?O } GROUP BY ?S
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg10.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg10.rq
new file mode 100644
index 0000000000000000000000000000000000000000..899a18b54d1f8dd38fc52e25fc5779eec1a5ee0b
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg10.rq
@@ -0,0 +1,4 @@
+PREFIX : <http://www.example.org/>
+
+SELECT ?P (COUNT(?O) AS ?C)
+WHERE { ?S ?P ?O }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg11.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg11.rq
new file mode 100644
index 0000000000000000000000000000000000000000..fb227416166d56aa9ce752375d321f4ecf0a6bbe
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg11.rq
@@ -0,0 +1,4 @@
+PREFIX : <http://www.example.org/>
+
+SELECT ((?O1 + ?O2) AS ?O12) (COUNT(?O1) AS ?C)
+WHERE { ?S :p ?O1; :q ?O2 } GROUP BY (?S)
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg12.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg12.rq
new file mode 100644
index 0000000000000000000000000000000000000000..3a5ad970cfcca96646f5a19b53c537efbeeb8892
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/agg12.rq
@@ -0,0 +1,4 @@
+PREFIX : <http://www.example.org/>
+
+SELECT ?O1 (COUNT(?O2) AS ?C)
+WHERE { ?S :p ?O1; :q ?O2 } GROUP BY (?O1 + ?O2)
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/empty.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/empty.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..4cedc2d2342e7356f7c9b4777a2d769f7ef103c9
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/empty.ttl
@@ -0,0 +1 @@
+@prefix ex: <http://example.com/> .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/manifest.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/manifest.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..eedcfe05f69870d8c2342f00a1ab96c2c892d286
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/aggregates/manifest.ttl
@@ -0,0 +1,347 @@
+@prefix rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix : <http://www.w3.org/2009/sparql/docs/tests/data-sparql11/aggregates/manifest#> .
+@prefix rdfs:	<http://www.w3.org/2000/01/rdf-schema#> .
+@prefix mf:     <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+@prefix qt:     <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
+@prefix dawgt:   <http://www.w3.org/2001/sw/DataAccess/tests/test-dawg#> .
+@prefix sparql:  <http://www.w3.org/ns/sparql#> .
+
+<>  rdf:type mf:Manifest ;
+    rdfs:label "Aggregates" ;
+    mf:entries
+    ( 
+    :agg01
+    :agg02
+    :agg03
+    :agg04
+    :agg05
+    :agg06
+    :agg07
+    :agg08
+    :agg08b
+    :agg09
+    :agg10
+    :agg11
+    :agg12
+    :agg-groupconcat-01
+    :agg-groupconcat-02
+    :agg-groupconcat-03
+    :agg-sum-01
+    :agg-sum-02
+    :agg-avg-01
+    :agg-avg-02
+    :agg-min-01
+    :agg-min-02
+    :agg-max-01
+    :agg-max-02
+    :agg-sample-01 
+    :agg-err-01
+    :agg-err-02
+    :agg-empty-group
+) .
+
+
+:agg01 rdf:type mf:QueryEvaluationTest ;
+    mf:name "COUNT 1";
+	mf:feature sparql:count ;
+    rdfs:comment    "Simple count" ;
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-01-31#resolution_3> ;
+    mf:action
+         [ qt:query  <agg01.rq> ;
+           qt:data   <agg01.ttl> ] ;
+    mf:result  <agg01.srx>
+    .
+
+:agg02 rdf:type mf:QueryEvaluationTest ;
+    mf:name "COUNT 2";
+	mf:feature sparql:count ;
+    rdfs:comment    "Count with grouping" ;
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-01-31#resolution_3> ;
+    mf:action
+         [ qt:query  <agg02.rq> ;
+           qt:data   <agg01.ttl> ] ;
+    mf:result  <agg02.srx>
+    .
+
+:agg03 rdf:type mf:QueryEvaluationTest ;
+    mf:name "COUNT 3";
+	mf:feature sparql:count ;
+    rdfs:comment    "Count with grouping and HAVING clause" ;
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-01-31#resolution_3> ;
+    mf:action
+         [ qt:query  <agg03.rq> ;
+           qt:data   <agg01.ttl> ] ;
+    mf:result  <agg03.srx>
+    .
+
+
+:agg04 rdf:type mf:QueryEvaluationTest ;
+    mf:name "COUNT 4";
+	mf:feature sparql:count ;
+    rdfs:comment    "Count(*)" ;
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-01-31#resolution_3> ;
+    mf:action
+         [ qt:query  <agg04.rq> ;
+           qt:data   <agg01.ttl> ] ;
+    mf:result  <agg04.srx>
+    .
+
+:agg05 rdf:type mf:QueryEvaluationTest ;
+    mf:name "COUNT 5";
+	mf:feature sparql:count ;
+    rdfs:comment    "Count(*) with grouping" ;
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-01-31#resolution_3> ;
+    mf:action
+         [ qt:query  <agg05.rq> ;
+           qt:data   <agg01.ttl> ] ;
+    mf:result  <agg05.srx>
+    .
+
+:agg06 rdf:type mf:QueryEvaluationTest ;
+    mf:name "COUNT 6";
+	mf:feature sparql:count ;
+    rdfs:comment    "Count(*) with HAVING Count(*)" ;
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-01-31#resolution_3> ;
+    mf:action
+         [ qt:query  <agg06.rq> ;
+           qt:data   <agg01.ttl> ] ;
+    mf:result  <agg06.srx>
+    .
+
+:agg07 rdf:type mf:QueryEvaluationTest;
+    mf:name "COUNT 7";
+	mf:feature sparql:count ;
+    rdfs:comment    "Count(*) with grouping and HAVING Count(*)" ;
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-01-31#resolution_3> ;
+    mf:action
+         [ qt:query  <agg07.rq> ;
+           qt:data   <agg01.ttl> ] ;
+    mf:result  <agg07.srx>
+    .
+
+:agg08 rdf:type  mf:NegativeSyntaxTest11;
+    mf:name    "COUNT 8" ;
+	mf:feature sparql:count ;
+    rdfs:comment "grouping by expression, done wrong";
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-01-31#resolution_3> ;
+    mf:action  <agg08.rq> .
+
+:agg08b rdf:type  mf:QueryEvaluationTest;
+    mf:name    "COUNT 8b" ;
+	mf:feature sparql:count ;
+    rdfs:comment "grouping by expression, done correctly";
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-01-31#resolution_3> ;
+    mf:action
+         [ qt:query  <agg08b.rq> ;
+           qt:data   <agg08.ttl> ] ;
+    mf:result  <agg08b.srx> .
+
+:agg09 rdf:type  mf:NegativeSyntaxTest11;
+    mf:name    "COUNT 9" ;
+	mf:feature sparql:count ;
+    rdfs:comment "Projection of an ungrouped variable (not appearing in the GROUP BY expression)";
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-01-31#resolution_3> ;
+    mf:action  <agg09.rq> .
+
+:agg10 rdf:type  mf:NegativeSyntaxTest11;
+    mf:name    "COUNT 10" ;
+	mf:feature sparql:count ;
+    rdfs:comment "Projection of an ungrouped variable (no GROUP BY expression at all)";
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-01-31#resolution_3> ;
+    mf:action  <agg10.rq> .
+
+:agg11 rdf:type  mf:NegativeSyntaxTest11;
+    mf:name    "COUNT 11" ;
+	mf:feature sparql:count ;
+    rdfs:comment "Use of an ungrouped variable in a project expression";
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-01-31#resolution_3> ;
+    mf:action  <agg11.rq> .
+
+:agg12 rdf:type  mf:NegativeSyntaxTest11;
+    mf:name    "COUNT 12" ;
+	mf:feature sparql:count ;
+    rdfs:comment "Use of an ungrouped variable in a project expression, where the variable appears in a GROUP BY expression";
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-01-31#resolution_3> ;
+    mf:action  <agg12.rq> .
+
+:agg-groupconcat-01 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "GROUP_CONCAT 1" ;
+	mf:feature sparql:group_concat ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2010-09-07#resolution_2> ;
+    mf:action
+         [ qt:query  <agg-groupconcat-1.rq> ;
+           qt:data   <agg-groupconcat-1.ttl> ] ;
+    mf:result  <agg-groupconcat-1.srx>
+    .
+
+:agg-groupconcat-02 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "GROUP_CONCAT 2" ;
+	mf:feature sparql:group_concat ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2010-09-07#resolution_2> ;
+    mf:action
+         [ qt:query  <agg-groupconcat-2.rq> ;
+           qt:data   <agg-groupconcat-1.ttl> ] ;
+    mf:result  <agg-groupconcat-2.srx>
+    .
+
+:agg-groupconcat-03 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "GROUP_CONCAT with SEPARATOR" ;
+	mf:feature sparql:group_concat ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2010-09-07#resolution_2> ;
+    mf:action
+         [ qt:query  <agg-groupconcat-3.rq> ;
+           qt:data   <agg-groupconcat-1.ttl> ] ;
+    mf:result  <agg-groupconcat-3.srx>
+    .
+
+:agg-avg-01 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "AVG" ;
+	mf:feature sparql:avg ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2010-09-07#resolution_2> ;
+    mf:action
+         [ qt:query  <agg-avg-01.rq> ;
+           qt:data   <agg-numeric.ttl> ] ;
+    mf:result  <agg-avg-01.srx>
+    .
+
+:agg-avg-02 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "AVG with GROUP BY" ;
+	mf:feature sparql:avg ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2010-09-07#resolution_2> ;
+    mf:action
+         [ qt:query  <agg-avg-02.rq> ;
+           qt:data   <agg-numeric2.ttl> ] ;
+    mf:result  <agg-avg-02.srx>
+    .
+
+:agg-min-01 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "MIN" ;
+	mf:feature sparql:min ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2010-09-07#resolution_2> ;
+    mf:action
+         [ qt:query  <agg-min-01.rq> ;
+           qt:data   <agg-numeric.ttl> ] ;
+    mf:result  <agg-min-01.srx>
+    .
+
+:agg-min-02 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "MIN with GROUP BY" ;
+	mf:feature sparql:min ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2010-09-07#resolution_2> ;
+    mf:action
+         [ qt:query  <agg-min-02.rq> ;
+           qt:data   <agg-numeric.ttl> ] ;
+    mf:result  <agg-min-02.srx>
+    .
+
+:agg-max-01 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "MAX" ;
+	mf:feature sparql:max ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2010-09-07#resolution_2> ;
+    mf:action
+         [ qt:query  <agg-max-01.rq> ;
+           qt:data   <agg-numeric.ttl> ] ;
+    mf:result  <agg-max-01.srx>
+    .
+
+:agg-max-02 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "MAX with GROUP BY" ;
+	mf:feature sparql:max ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2010-09-07#resolution_2> ;
+    mf:action
+         [ qt:query  <agg-max-02.rq> ;
+           qt:data   <agg-numeric.ttl> ] ;
+    mf:result  <agg-max-02.srx>
+    .
+
+:agg-sum-01 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "SUM" ;
+	mf:feature sparql:sum ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2010-09-07#resolution_2> ;
+    mf:action
+         [ qt:query  <agg-sum-01.rq> ;
+           qt:data   <agg-numeric.ttl> ] ;
+    mf:result  <agg-sum-01.srx>
+    .
+
+:agg-sum-02 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "SUM with GROUP BY" ;
+	mf:feature sparql:sum ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2010-09-07#resolution_2> ;
+    mf:action
+         [ qt:query  <agg-sum-02.rq> ;
+           qt:data   <agg-numeric2.ttl> ] ;
+    mf:result  <agg-sum-02.srx>
+    .
+
+:agg-sample-01 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "SAMPLE" ;
+	mf:feature sparql:sample ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2010-09-07#resolution_2> ;
+    mf:action
+         [ qt:query  <agg-sample-01.rq> ;
+           qt:data   <agg-numeric.ttl> ] ;
+    mf:result  <agg-sample-01.srx>
+    .
+
+:agg-err-01 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "Error in AVG" ;
+	mf:feature sparql:aggregate ;
+	rdfs:comment "Error in AVG return no binding";
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2010-09-07#resolution_2> ;
+    mf:action
+         [ qt:query  <agg-err-01.rq> ;
+           qt:data   <agg-err-01.ttl> ] ;
+    mf:result  <agg-err-01.srx>
+    .
+    
+:agg-err-02 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "Protect from error in AVG" ;
+	mf:feature sparql:aggregate ;
+	rdfs:comment "Protect from error in AVG using IF and COALESCE";
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2010-09-07#resolution_2> ;
+    mf:action
+         [ qt:query  <agg-err-02.rq> ;
+           qt:data   <agg-err-02.ttl> ] ;
+    mf:result  <agg-err-02.srx>
+    .    
+
+:agg-empty-group rdf:type mf:QueryEvaluationTest ;
+	mf:name "agg empty group" ;
+    mf:name "Aggregate over empty group resulting in a row with unbound variables" ;
+	mf:feature sparql:aggregate ;
+	rdfs:seeAlso <http://answers.semanticweb.com/questions/17410/semantics-of-sparql-aggregates> ;
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-08-07#resolution_2> ;
+    mf:action
+         [ qt:query  <agg-empty-group.rq> ;
+           qt:data   <empty.ttl> ] ;
+    mf:result  <agg-empty-group.srx>
+    .    
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere01.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere01.rq
new file mode 100644
index 0000000000000000000000000000000000000000..34e007ddd569814a57e2412982f83e5054a27059
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere01.rq
@@ -0,0 +1,3 @@
+PREFIX : <http://example.org/>
+
+CONSTRUCT WHERE { ?s ?p ?o}
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere01result.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere01result.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..bd2bd7ee2ba494c48a2b5cd343a54a876b89f45c
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere01result.ttl
@@ -0,0 +1,8 @@
+@prefix :        <http://example.org/> .
+
+:s2   :p            :o1 ;
+      :p            :o2 .
+
+:s1   :p            :o1 .
+
+:s3   :p            :o3 .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere02.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere02.rq
new file mode 100644
index 0000000000000000000000000000000000000000..e97615c3787eabbff5ecba374803d2fa81526a66
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere02.rq
@@ -0,0 +1,3 @@
+PREFIX : <http://example.org/>
+
+CONSTRUCT WHERE { :s1 :p ?o . ?s2 :p ?o }
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere02result.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere02result.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..d508000a082d4f7c49d0a2c7c1340a7e9db0c25a
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere02result.ttl
@@ -0,0 +1,5 @@
+@prefix :        <http://example.org/> .
+
+:s2   :p            :o1 .
+
+:s1   :p            :o1 .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere03.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere03.rq
new file mode 100644
index 0000000000000000000000000000000000000000..ae3919c44599f8ae8c27964fc0ee20671eea9e65
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere03.rq
@@ -0,0 +1,3 @@
+PREFIX : <http://example.org/>
+
+CONSTRUCT WHERE { :s2 :p ?o1, ?o2 }
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere03result.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere03result.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..ffbaff814b1ec775888ecac9692a43656325808a
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere03result.ttl
@@ -0,0 +1,4 @@
+@prefix :        <http://example.org/> .
+
+:s2   :p            :o1 ;
+      :p            :o2 .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere04.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere04.rq
new file mode 100644
index 0000000000000000000000000000000000000000..2429a5e40b67a26f334657d3673f7c558935bfd0
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere04.rq
@@ -0,0 +1,5 @@
+PREFIX : <http://example.org/>
+
+CONSTRUCT 
+FROM <data.ttl>
+WHERE { ?s ?p ?o }
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere04result.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere04result.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..bd2bd7ee2ba494c48a2b5cd343a54a876b89f45c
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere04result.ttl
@@ -0,0 +1,8 @@
+@prefix :        <http://example.org/> .
+
+:s2   :p            :o1 ;
+      :p            :o2 .
+
+:s1   :p            :o1 .
+
+:s3   :p            :o3 .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere05.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere05.rq
new file mode 100644
index 0000000000000000000000000000000000000000..f56edf876d7c6c978c45fa924f47302600c8bc27
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere05.rq
@@ -0,0 +1,4 @@
+PREFIX : <http://example.org/>
+
+CONSTRUCT 
+WHERE { ?s ?p ?o FILTER ( ?o = :o1) }
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere06.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere06.rq
new file mode 100644
index 0000000000000000000000000000000000000000..3628b1ed33032033c2b4f52b01740113fbf0f95f
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/constructwhere06.rq
@@ -0,0 +1,2 @@
+CONSTRUCT 
+WHERE { GRAPH <data.ttl> { ?s ?p ?o } }
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/data.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/data.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..633812c279fdd5c233ec2aa63eaa296e4f61ccda
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/data.ttl
@@ -0,0 +1,6 @@
+@prefix : <http://example.org/> .
+
+:s1 :p :o1 .
+:s2 :p :o1 .
+:s2 :p :o2 .
+:s3 :p :o3 .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/manifest.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/manifest.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..6bf5d1c8a60256398b53321ffc4b504213a2754d
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/construct/manifest.ttl
@@ -0,0 +1,74 @@
+@prefix rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix : <http://www.w3.org/2009/sparql/docs/tests/data-sparql11/construct/manifest#> .
+@prefix rdfs:	<http://www.w3.org/2000/01/rdf-schema#> .
+@prefix mf:     <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+@prefix qt:     <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
+@prefix dawgt:   <http://www.w3.org/2001/sw/DataAccess/tests/test-dawg#> .
+
+<>  rdf:type mf:Manifest ;
+    rdfs:label "CONSTRUCT" ;
+    mf:entries
+    ( 
+    :constructwhere01
+    :constructwhere02
+    :constructwhere03
+    :constructwhere04
+    :constructwhere05
+    :constructwhere06
+    ) .
+
+:constructwhere01 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "constructwhere01 - CONSTRUCT WHERE" ;
+    rdfs:comment "CONSTRUCT WHERE { ?S ?P ?O }";
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-02-01#resolution_3> ;
+    mf:action
+         [ qt:query  <constructwhere01.rq> ;
+           qt:data   <data.ttl> ] ;
+    mf:result  <constructwhere01result.ttl>
+    .
+
+:constructwhere02 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "constructwhere02 - CONSTRUCT WHERE" ;
+    rdfs:comment "CONSTRUCT WHERE  with join";
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-02-01#resolution_3> ;
+    mf:action
+         [ qt:query  <constructwhere02.rq> ;
+           qt:data   <data.ttl> ] ;
+    mf:result  <constructwhere02result.ttl>
+    .
+
+:constructwhere03 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "constructwhere03 - CONSTRUCT WHERE" ;
+    rdfs:comment "CONSTRUCT WHERE  with join, using shortcut notation";
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-02-01#resolution_3> ;
+    mf:action
+         [ qt:query  <constructwhere03.rq> ;
+           qt:data   <data.ttl> ] ;
+    mf:result  <constructwhere03result.ttl>
+    .
+:constructwhere04 rdf:type mf:QueryEvaluationTest ;
+    mf:name    "constructwhere04 - CONSTRUCT WHERE" ;
+    rdfs:comment "CONSTRUCT WHERE  with DatasetClause";
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-02-01#resolution_3> ;
+    mf:action
+         [ qt:query  <constructwhere04.rq> ] ;
+    mf:result  <constructwhere04result.ttl>
+    .
+
+:constructwhere05 rdf:type mf:NegativeSyntaxTest11 ;
+    mf:name    "constructwhere05 - CONSTRUCT WHERE" ;
+    rdfs:comment "CONSTRUCT WHERE  with FILTER";
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-02-01#resolution_3> ;
+    mf:action <constructwhere05.rq> .
+
+:constructwhere06 rdf:type mf:NegativeSyntaxTest11 ;
+    mf:name    "constructwhere06 - CONSTRUCT WHERE" ;
+    mf:description "CONSTRUCT WHERE  with GRAPH";
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-02-01#resolution_3> ;
+    mf:action <constructwhere06.rq> .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-01.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-01.ru
new file mode 100644
index 0000000000000000000000000000000000000000..1c8b98c299e86461302fdbee425fe60643b4bb7c
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-01.ru
@@ -0,0 +1,12 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+DELETE 
+{
+  ?s ?p ?o .
+}
+WHERE
+{
+  :a foaf:knows ?s .
+  ?s ?p ?o
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-02.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-02.ru
new file mode 100644
index 0000000000000000000000000000000000000000..35439e5beffaa1373455c830f3686bf6eb2a4092
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-02.ru
@@ -0,0 +1,12 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+DELETE 
+{
+  GRAPH <http://example.org/g1> { ?s ?p ?o }
+}
+WHERE 
+{
+  GRAPH <http://example.org/g1> { :a foaf:knows ?s .
+                                  ?s ?p ?o }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-03.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-03.ru
new file mode 100644
index 0000000000000000000000000000000000000000..0af1f8d80151133054a5903ddd09a27665f86548
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-03.ru
@@ -0,0 +1,12 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+DELETE 
+{
+  ?s ?p ?o .
+}
+WHERE 
+{
+  ?s foaf:knows :c .
+  ?s ?p ?o 
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-04.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-04.ru
new file mode 100644
index 0000000000000000000000000000000000000000..6ce29f934a3028bbbb2158c9523860d1b9cd2b04
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-04.ru
@@ -0,0 +1,12 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+DELETE 
+{
+  GRAPH <http://example.org/g1> { ?s ?p ?o }
+}
+WHERE
+{
+  GRAPH <http://example.org/g1> { ?s foaf:knows :c .
+                                  ?s ?p ?o }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-05.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-05.ru
new file mode 100644
index 0000000000000000000000000000000000000000..681cd5758f388e8032da44f1ae582385ba4e3d11
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-05.ru
@@ -0,0 +1,12 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+DELETE 
+{
+  ?s ?p ?o .
+}
+WHERE 
+{ 
+  :a foaf:knows ?s .
+  ?s ?p ?o
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-06.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-06.ru
new file mode 100644
index 0000000000000000000000000000000000000000..70825c1c5045c537da325e6a19ba230fd24cedf6
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-06.ru
@@ -0,0 +1,12 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+DELETE 
+{
+  GRAPH <http://example.org/g2> { ?s ?p ?o }
+}
+WHERE 
+{
+  GRAPH <http://example.org/g2> { ?s foaf:name "Chris" .
+                                  ?s ?p ?o }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-07.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-07.ru
new file mode 100644
index 0000000000000000000000000000000000000000..6e189c4affed62970ee5bea41be97fad92c99e2c
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-07.ru
@@ -0,0 +1,11 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+DELETE 
+{
+  ?s ?p ?o .
+}
+WHERE
+{
+  :a foaf:knows ?s .
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-01f.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-01f.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..3a121606a03527437f23a7d4cb67d8fb32b80bc3
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-01f.ttl
@@ -0,0 +1,9 @@
+@prefix : <http://example.org/> .
+@prefix foaf:       <http://xmlns.com/foaf/0.1/> .
+
+:a foaf:name "Alan" .
+:a foaf:mbox "alan@example.org" .
+:b foaf:name "Bob" .
+:b foaf:mbox "bob@example.org" .
+:a foaf:knows :b .
+
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-01s.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-01s.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..f2161b6eb02bd7e265d6924e3464f9621a5abce2
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-01s.ttl
@@ -0,0 +1,6 @@
+@prefix : <http://example.org/> .
+@prefix foaf:       <http://xmlns.com/foaf/0.1/> .
+
+:a foaf:name "Alan" .
+:a foaf:mbox "alan@example.org" .
+:a foaf:knows :b .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-01s2.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-01s2.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..3c6e735a01cd7f01627ef1d9b6b0e8b208d3e2ec
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-01s2.ttl
@@ -0,0 +1,5 @@
+@prefix : <http://example.org/> .
+@prefix foaf:       <http://xmlns.com/foaf/0.1/> .
+
+:b foaf:name "Bob" .
+:b foaf:mbox "bob@example.org" .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-02f.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-02f.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..b623497c97614c2943065250613eefed095aff29
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-02f.ttl
@@ -0,0 +1,9 @@
+@prefix : <http://example.org/> .
+@prefix foaf:       <http://xmlns.com/foaf/0.1/> .
+
+:a foaf:knows :b .
+:b foaf:name "Bob" .
+:b foaf:mbox "bob@example.org" .
+:c foaf:name "Chris" .
+:c foaf:mbox "chris@example.org" .
+:b foaf:knows :c .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-02s.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-02s.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..d3666f39ac0540818c4d7806a993bb0fb6187345
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-02s.ttl
@@ -0,0 +1,7 @@
+@prefix : <http://example.org/> .
+@prefix foaf:       <http://xmlns.com/foaf/0.1/> .
+
+:a foaf:knows :b .
+:b foaf:name "Bob" .
+:b foaf:mbox "bob@example.org" .
+:b foaf:knows :c .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-03f.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-03f.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..3d796337c43de2e1960db31076b637bafe2103b4
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-post-03f.ttl
@@ -0,0 +1,8 @@
+@prefix :           <http://example.org/> .
+@prefix foaf:       <http://xmlns.com/foaf/0.1/> .
+
+:c foaf:name "Chris" .
+:c foaf:mbox "chris@example.org" .
+:d foaf:name "Dan" .
+:d foaf:mbox "dan@example.org" .
+:c foaf:knows :d .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-pre-01.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-pre-01.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..3a121606a03527437f23a7d4cb67d8fb32b80bc3
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-pre-01.ttl
@@ -0,0 +1,9 @@
+@prefix : <http://example.org/> .
+@prefix foaf:       <http://xmlns.com/foaf/0.1/> .
+
+:a foaf:name "Alan" .
+:a foaf:mbox "alan@example.org" .
+:b foaf:name "Bob" .
+:b foaf:mbox "bob@example.org" .
+:a foaf:knows :b .
+
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-pre-02.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-pre-02.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..b623497c97614c2943065250613eefed095aff29
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-pre-02.ttl
@@ -0,0 +1,9 @@
+@prefix : <http://example.org/> .
+@prefix foaf:       <http://xmlns.com/foaf/0.1/> .
+
+:a foaf:knows :b .
+:b foaf:name "Bob" .
+:b foaf:mbox "bob@example.org" .
+:c foaf:name "Chris" .
+:c foaf:mbox "chris@example.org" .
+:b foaf:knows :c .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-pre-03.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-pre-03.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..3d796337c43de2e1960db31076b637bafe2103b4
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-pre-03.ttl
@@ -0,0 +1,8 @@
+@prefix :           <http://example.org/> .
+@prefix foaf:       <http://xmlns.com/foaf/0.1/> .
+
+:c foaf:name "Chris" .
+:c foaf:mbox "chris@example.org" .
+:d foaf:name "Dan" .
+:d foaf:mbox "dan@example.org" .
+:c foaf:knows :d .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-01.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-01.ru
new file mode 100644
index 0000000000000000000000000000000000000000..f9706ccd5834b462550e739d5ac98c1e8df8af31
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-01.ru
@@ -0,0 +1,13 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+DELETE 
+{
+  ?s ?p ?o .
+}
+USING <http://example.org/g2>
+WHERE
+{
+  :a foaf:knows ?s .
+  ?s ?p ?o 
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-02.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-02.ru
new file mode 100644
index 0000000000000000000000000000000000000000..3be3eb12b345f0feaf0a22a4a6167cc49a9aa70a
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-02.ru
@@ -0,0 +1,13 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+DELETE 
+{
+  ?s ?p ?o .
+}
+USING <http://example.org/g3>
+WHERE 
+{
+  GRAPH <http://example.org/g2> { :a foaf:knows ?s .
+                                  ?s ?p ?o }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-03.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-03.ru
new file mode 100644
index 0000000000000000000000000000000000000000..d88426a0aa10d879dd6b4e295eea10f9894b0a65
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-03.ru
@@ -0,0 +1,13 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+DELETE 
+{
+  ?s ?p ?o .
+}
+USING <http://example.org/g2>
+WHERE 
+{
+  ?s foaf:knows :d .
+  ?s ?p ?o 
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-04.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-04.ru
new file mode 100644
index 0000000000000000000000000000000000000000..b31ff3ad4bd479055c9fe8a34b0e4bcbcfb084d2
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-04.ru
@@ -0,0 +1,13 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+DELETE 
+{
+  ?s ?p ?o .
+}
+USING <http://example.org/g3>
+WHERE
+{
+  GRAPH <http://example.org/g2> { ?s foaf:knows :d .
+                                  ?s ?p ?o }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-05.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-05.ru
new file mode 100644
index 0000000000000000000000000000000000000000..0e1fc3ec985b784933406564e509ee6e82032581
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-05.ru
@@ -0,0 +1,13 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+DELETE 
+{
+  GRAPH <http://example.org/g1> { ?s ?p ?o }
+}
+USING <http://example.org/g1>
+WHERE 
+{ 
+  ?s foaf:knows :b .
+  ?s ?p ?o 
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-06.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-06.ru
new file mode 100644
index 0000000000000000000000000000000000000000..5b002306ba427055c2709b993dd63ba5cd45a17a
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-using-06.ru
@@ -0,0 +1,13 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+DELETE 
+{
+  GRAPH <http://example.org/g2> { ?s ?p ?o }
+}
+USING <http://example.org/g3>
+WHERE 
+{
+  GRAPH <http://example.org/g2> { ?s foaf:name "Chris" .
+                                  ?s ?p ?o }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-01.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-01.ru
new file mode 100644
index 0000000000000000000000000000000000000000..ddf32e359f157227b3d53ef446e1bfb3c4bb1276
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-01.ru
@@ -0,0 +1,13 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+WITH <http://example.org/g1>
+DELETE 
+{
+  ?s ?p ?o .
+}
+WHERE
+{
+  :a foaf:knows ?s .
+  ?s ?p ?o
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-02.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-02.ru
new file mode 100644
index 0000000000000000000000000000000000000000..a119fa1b22170807a1b19747fadadf5fb75e0f41
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-02.ru
@@ -0,0 +1,13 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+WITH <http://example.org/g2>
+DELETE 
+{
+  GRAPH <http://example.org/g1> { ?s ?p ?o }
+}
+WHERE 
+{
+  GRAPH <http://example.org/g1> { :a foaf:knows ?s .
+                                  ?s ?p ?o }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-03.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-03.ru
new file mode 100644
index 0000000000000000000000000000000000000000..86c86855ee8c6d6b7009f138f36e426329c1bad2
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-03.ru
@@ -0,0 +1,13 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+WITH <http://example.org/g1>
+DELETE 
+{
+  ?s ?p ?o .
+}
+WHERE 
+{
+  ?s foaf:knows :c .
+  ?s ?p ?o
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-04.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-04.ru
new file mode 100644
index 0000000000000000000000000000000000000000..49c8072e2cfb70b55be752584a31d5317ca6640c
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-04.ru
@@ -0,0 +1,13 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+WITH <http://example.org/g2>
+DELETE 
+{
+  GRAPH <http://example.org/g1> { ?s ?p ?o }
+}
+WHERE
+{
+  GRAPH <http://example.org/g1> { ?s foaf:knows :c .
+                                  ?s ?p ?o }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-05.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-05.ru
new file mode 100644
index 0000000000000000000000000000000000000000..ee14ce9edf39946d3a3d3158dc5780faf109164f
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-05.ru
@@ -0,0 +1,13 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+WITH <http://example.org/g1>
+DELETE 
+{
+  ?s ?p ?o .
+}
+WHERE 
+{ 
+  ?s foaf:knows :b .
+  ?s ?p ?o 
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-06.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-06.ru
new file mode 100644
index 0000000000000000000000000000000000000000..e1f88291f2b1c6e7d09e9a958af91e1171ce3f49
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/delete-with-06.ru
@@ -0,0 +1,13 @@
+PREFIX     : <http://example.org/> 
+PREFIX foaf: <http://xmlns.com/foaf/0.1/> 
+
+WITH <http://example.org/g3>
+DELETE 
+{
+  GRAPH <http://example.org/g2> { ?s ?p ?o }
+}
+WHERE 
+{
+  GRAPH <http://example.org/g2> { ?s foaf:name "Chris" .
+                                  ?s ?p ?o }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/manifest.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/manifest.ttl
new file mode 100755
index 0000000000000000000000000000000000000000..3954b17f32dbc36d0c055895f0841dcf8dd0aaf5
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/delete/manifest.ttl
@@ -0,0 +1,343 @@
+@prefix rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix : <http://www.w3.org/2009/sparql/docs/tests/data-sparql11/delete/manifest#> .
+@prefix rdfs:	<http://www.w3.org/2000/01/rdf-schema#> .
+@prefix dawgt:  <http://www.w3.org/2001/sw/DataAccess/tests/test-dawg#> .
+@prefix mf:     <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+@prefix qt:     <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
+@prefix ut:     <http://www.w3.org/2009/sparql/tests/test-update#> .
+
+<>  rdf:type mf:Manifest ;
+    rdfs:comment "Tests for SPARQL UPDATE" ;
+    mf:entries
+    (
+ 	:dawg-delete-01
+	:dawg-delete-02
+	:dawg-delete-03
+	:dawg-delete-04
+	:dawg-delete-05
+	:dawg-delete-06
+	:dawg-delete-07
+	:dawg-delete-with-01
+	:dawg-delete-with-02
+	:dawg-delete-with-03
+	:dawg-delete-with-04
+	:dawg-delete-with-05
+	:dawg-delete-with-06
+	:dawg-delete-using-01
+	:dawg-delete-using-02a
+	:dawg-delete-using-03
+	:dawg-delete-using-04
+	:dawg-delete-using-05
+    :dawg-delete-using-06a
+   ).
+
+:dawg-delete-01 a mf:UpdateEvaluationTest ;
+    mf:name    "Simple DELETE 1" ;
+    rdfs:comment "This is a simple delete of an existing triple from the default graph" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-01.ru> ; 
+                ut:data <delete-pre-01.ttl>
+              ] ;
+    mf:result [ ut:data <delete-post-01s.ttl>
+              ] .
+
+:dawg-delete-02 a mf:UpdateEvaluationTest ;
+    mf:name    "Simple DELETE 2" ;
+    rdfs:comment "This is a simple delete of an existing triple from a named graph" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-02.ru> ; 
+                ut:graphData [ ut:graph <delete-pre-01.ttl> ;
+                               rdfs:label "http://example.org/g1" ] 
+              ] ;
+    mf:result [ ut:graphData [ ut:graph <delete-post-01s.ttl> ;
+                               rdfs:label "http://example.org/g1" ]
+              ] .
+
+:dawg-delete-03 a mf:UpdateEvaluationTest ;
+    mf:name    "Simple DELETE 3" ;
+    rdfs:comment "This is a simple delete of a non-existing triple from the default graph" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-03.ru> ; 
+                ut:data <delete-pre-01.ttl>
+              ] ;
+    mf:result [ ut:data <delete-post-01f.ttl>
+              ] .
+
+:dawg-delete-04 a mf:UpdateEvaluationTest ;
+    mf:name    "Simple DELETE 4" ;
+    rdfs:comment "This is a simple delete of a non-existing triple from a named graph" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-04.ru> ; 
+                ut:graphData [ ut:graph <delete-pre-01.ttl> ;
+                               rdfs:label "http://example.org/g1" ] 
+              ] ;
+    mf:result [ ut:graphData [ ut:graph <delete-post-01f.ttl> ;
+                               rdfs:label "http://example.org/g1" ]
+              ] .
+
+:dawg-delete-05 a mf:UpdateEvaluationTest ;
+    mf:name    "Graph-specific DELETE 1" ;
+    rdfs:comment "Test 1 for DELETE only modifying the desired graph" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-05.ru> ; 
+                ut:data <delete-pre-01.ttl> ;
+                ut:graphData [ ut:graph <delete-pre-02.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-pre-03.ttl> ;
+                               rdfs:label "http://example.org/g3" ] 
+              ] ;
+    mf:result [ ut:data <delete-post-01s.ttl> ;
+                ut:graphData [ ut:graph <delete-post-02f.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-post-03f.ttl> ;
+                               rdfs:label "http://example.org/g3" ] 
+              ] .
+
+:dawg-delete-06 a mf:UpdateEvaluationTest ;
+    mf:name    "Graph-specific DELETE 2" ;
+    rdfs:comment "Test 2 for DELETE only modifying the desired graph" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-06.ru> ; 
+                ut:data <delete-pre-01.ttl> ;
+                ut:graphData [ ut:graph <delete-pre-02.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-pre-03.ttl> ;
+                               rdfs:label "http://example.org/g3" ] 
+              ] ;
+    mf:result [ ut:data <delete-post-01f.ttl> ;
+                ut:graphData [ ut:graph <delete-post-02s.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-post-03f.ttl> ;
+                               rdfs:label "http://example.org/g3" ] 
+              ] .
+
+:dawg-delete-07 a mf:UpdateEvaluationTest ;
+    mf:name    "Simple DELETE 7" ;
+    rdfs:comment "This is a simple delete to test that unbound variables in the DELETE clause do not act as wildcards" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-07.ru> ; 
+                ut:data <delete-pre-01.ttl>
+              ] ;
+    mf:result [ ut:data <delete-post-01f.ttl>
+              ] .
+
+:dawg-delete-with-01 a mf:UpdateEvaluationTest ;
+    mf:name    "Simple DELETE 1 (WITH)" ;
+    rdfs:comment "This is a simple delete using a WITH clause to identify the active graph" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-with-01.ru> ; 
+                ut:graphData [ ut:graph <delete-pre-01.ttl> ;
+                               rdfs:label "http://example.org/g1" ] 
+              ] ;
+    mf:result [ ut:graphData [ ut:graph <delete-post-01s.ttl> ;
+                               rdfs:label "http://example.org/g1" ] 
+              ] .
+
+:dawg-delete-with-02 a mf:UpdateEvaluationTest ;
+    mf:name    "Simple DELETE 2 (WITH)" ;
+    rdfs:comment "This is a simple test to make sure the GRAPH clause overrides the WITH clause" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-with-02.ru> ; 
+                ut:graphData [ut:graph <delete-pre-01.ttl> ;
+                              rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ut:graph <delete-pre-02.ttl> ;
+                              rdfs:label "http://example.org/g2" ]
+              ] ;
+    mf:result [ ut:graphData [ ut:graph <delete-post-01s.ttl> ;
+                               rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ ut:graph <delete-post-02f.ttl> ;
+                               rdfs:label "http://example.org/g2" ] 
+              ] .
+
+:dawg-delete-with-03 a mf:UpdateEvaluationTest ;
+    mf:name    "Simple DELETE 3 (WITH)" ;
+    rdfs:comment "This is a simple delete of a non-existing triple using a WITH clause to identify the active graph" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-with-03.ru> ; 
+                ut:graphData [ut:graph <delete-pre-01.ttl> ;
+                              rdfs:label "http://example.org/g1" ] 
+              ] ;
+    mf:result [ ut:result ut:Success ; 
+                ut:graphData [ ut:graph <delete-post-01f.ttl> ;
+                               rdfs:label "http://example.org/g1" ] 
+              ] .
+
+:dawg-delete-with-04 a mf:UpdateEvaluationTest ;
+    mf:name    "Simple DELETE 4 (WITH)" ;
+    rdfs:comment "This is a simple delete of a non-existing triple making sure that the GRAPH clause overrides the WITH clause" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-with-04.ru> ; 
+                ut:graphData [ ut:graph <delete-pre-01.ttl> ;
+                               rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ ut:graph <delete-pre-02.ttl> ;
+                               rdfs:label "http://example.org/g2" ]
+              ] ;
+    mf:result [ ut:graphData [ ut:graph <delete-post-01f.ttl> ;
+                               rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ ut:graph <delete-post-02f.ttl> ;
+                               rdfs:label "http://example.org/g2" ] 
+              ] .
+
+:dawg-delete-with-05 a mf:UpdateEvaluationTest ;
+    mf:name    "Graph-specific DELETE 1 (WITH)" ;
+    rdfs:comment "Test 1 for DELETE only modifying the desired graph using a WITH clause to specify the active graph" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-with-05.ru> ; 
+                ut:graphData [ ut:graph <delete-pre-01.ttl> ;
+                               rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ ut:graph <delete-pre-02.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-pre-03.ttl> ;
+                               rdfs:label "http://example.org/g3" ]
+              ] ;
+    mf:result [ ut:graphData [ ut:graph <delete-post-01s2.ttl> ;
+                               rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ ut:graph <delete-post-02f.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-post-03f.ttl> ;
+                               rdfs:label "http://example.org/g3" ]
+              ] .
+
+:dawg-delete-with-06 a mf:UpdateEvaluationTest ;
+    mf:name    "Graph-specific DELETE 2 (WITH)" ;
+    rdfs:comment "Test 2 for DELETE only modifying the desired graph making sure the GRAPH clause overrides the WITH clause" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-with-06.ru> ; 
+                ut:data <delete-pre-01.ttl> ;
+                ut:graphData [ ut:graph <delete-pre-02.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-pre-03.ttl> ;
+                               rdfs:label "http://example.org/g3" ]
+              ] ;
+    mf:result [ ut:data <delete-post-01f.ttl> ;
+                ut:graphData [ ut:graph <delete-post-02s.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-post-03f.ttl> ;
+                               rdfs:label "http://example.org/g3" ] 
+              ] .
+
+:dawg-delete-using-01 a mf:UpdateEvaluationTest ;
+    mf:name    "Simple DELETE 1 (USING)" ;
+    rdfs:comment "This is a simple delete using a USING clause to identify the active graph" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-using-01.ru> ; 
+                ut:data <delete-pre-01.ttl> ;
+                ut:graphData [ ut:graph <delete-pre-02.ttl> ;
+                               rdfs:label "http://example.org/g2" ]
+              ] ;
+    mf:result [ ut:data <delete-post-01s.ttl> ;
+                ut:graphData [ ut:graph <delete-post-02f.ttl> ;
+                               rdfs:label "http://example.org/g2" ]
+              ] .
+
+:dawg-delete-using-02a a mf:UpdateEvaluationTest ;
+    mf:name    "Simple DELETE 2 (USING)" ;
+    rdfs:comment "This is a simple test to make sure the GRAPH clause does not override the USING clause" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-09-25#resolution_3> ;
+    mf:action [ ut:request <delete-using-02.ru> ; 
+                ut:data <delete-pre-01.ttl> ;
+                ut:graphData [ ut:graph <delete-pre-02.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-pre-03.ttl> ;
+                               rdfs:label "http://example.org/g3" ]
+              ] ;
+    mf:result [ ut:data <delete-post-01f.ttl> ;
+                ut:graphData [ ut:graph <delete-post-02f.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-post-03f.ttl> ;
+                               rdfs:label "http://example.org/g3" ]
+              ] .
+
+
+:dawg-delete-using-03 a mf:UpdateEvaluationTest ;
+    mf:name    "Simple DELETE 3 (USING)" ;
+    rdfs:comment "This is a simple delete of a non-existing triple using a USING clause to identify the active graph" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-using-03.ru> ; 
+                ut:data <delete-pre-01.ttl> ;
+                ut:graphData [ ut:graph <delete-pre-02.ttl> ;
+                               rdfs:label "http://example.org/g2" ]
+              ] ;
+    mf:result [ ut:data <delete-post-01f.ttl> ;
+                ut:graphData [ ut:graph <delete-post-02f.ttl> ;
+                               rdfs:label "http://example.org/g2" ]
+              ] .
+
+:dawg-delete-using-04 a mf:UpdateEvaluationTest ;
+    mf:name    "Simple DELETE 4 (USING)" ;
+    rdfs:comment "This is a simple delete of a non-existing triple making sure that the GRAPH clause overrides the USING clause" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-using-04.ru> ; 
+                ut:data <delete-pre-03.ttl> ;
+                ut:graphData [ ut:graph <delete-pre-02.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-pre-03.ttl> ;
+                               rdfs:label "http://example.org/g3" ]
+              ] ;
+    mf:result [ ut:data <delete-post-03f.ttl> ;
+                ut:graphData [ ut:graph <delete-post-02f.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-post-03f.ttl> ;
+                               rdfs:label "http://example.org/g3" ]
+              ] .
+
+:dawg-delete-using-05 a mf:UpdateEvaluationTest ;
+    mf:name    "Graph-specific DELETE 1 (USING)" ;
+    rdfs:comment "Test 1 for DELETE only modifying the desired graph using a USING clause to specify the active graph" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [ ut:request <delete-using-05.ru> ; 
+                ut:graphData [ ut:graph <delete-pre-01.ttl> ;
+                               rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ ut:graph <delete-pre-02.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-pre-03.ttl> ;
+                               rdfs:label "http://example.org/g3" ] 
+              ] ;
+    mf:result [ ut:graphData [ ut:graph <delete-post-01s2.ttl> ;
+                               rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ ut:graph <delete-post-02f.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-post-03f.ttl> ;
+                               rdfs:label "http://example.org/g3" ]
+              ] .
+
+:dawg-delete-using-06a a mf:UpdateEvaluationTest ;
+    mf:name    "Graph-specific DELETE 2 (USING)" ;
+    rdfs:comment "Test 2 for DELETE only modifying the desired graph making sure the GRAPH clause does not override the USING clause" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-09-25#resolution_3> ;
+    mf:action [ ut:request <delete-using-06.ru> ; 
+                ut:graphData [ ut:graph <delete-pre-01.ttl> ;
+                               rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ ut:graph <delete-pre-02.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-pre-03.ttl> ;
+                               rdfs:label "http://example.org/g3" ]
+              ] ;
+    mf:result [ ut:graphData [ ut:graph <delete-post-01f.ttl> ;
+                               rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ ut:graph <delete-post-02f.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+                ut:graphData [ ut:graph <delete-post-03f.ttl> ;
+                               rdfs:label "http://example.org/g3" ]
+              ] .
+
+
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-all-01.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-all-01.ru
new file mode 100644
index 0000000000000000000000000000000000000000..1d9f433d8da0849312280a51b838035c2a6f4ac6
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-all-01.ru
@@ -0,0 +1,4 @@
+PREFIX     : <http://example.org/> 
+
+DROP ALL
+
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-default-01.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-default-01.ru
new file mode 100644
index 0000000000000000000000000000000000000000..65d5fd04cbe75fdce9b995cdb81c2217f9db5aee
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-default-01.ru
@@ -0,0 +1,4 @@
+PREFIX     : <http://example.org/> 
+
+DROP DEFAULT
+
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-default.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-default.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..0f1f9441223942126f00556543fc5b3d2bf3390c
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-default.ttl
@@ -0,0 +1,3 @@
+@prefix : <http://example.org/> .
+
+<> :name "Default Graph" .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-g1.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-g1.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..cf26e8ff2be0e11867f707aaa58ea5f46aa96714
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-g1.ttl
@@ -0,0 +1,5 @@
+@prefix : <http://example.org/> .
+
+:g1 :name "G1" ;
+	:description "Graph 1" ;
+	.
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-g2.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-g2.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..afb0160c34d9bb304b59aef25f9467d7276adfc8
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-g2.ttl
@@ -0,0 +1,4 @@
+@prefix : <http://example.org/> .
+
+:g2 :name "G2" ;
+	.
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-graph-01.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-graph-01.ru
new file mode 100644
index 0000000000000000000000000000000000000000..1a008325f0958992f711dfd7cbbede96b49d3d82
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-graph-01.ru
@@ -0,0 +1,3 @@
+PREFIX     : <http://example.org/> 
+
+DROP GRAPH :g1
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-named-01.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-named-01.ru
new file mode 100644
index 0000000000000000000000000000000000000000..a38420c1b2a53aae12a45218c7734e567a6cbcbb
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/drop-named-01.ru
@@ -0,0 +1,3 @@
+PREFIX     : <http://example.org/> 
+
+DROP NAMED
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/manifest.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/manifest.ttl
new file mode 100755
index 0000000000000000000000000000000000000000..509c54625f8e4ec9af67718b075dbc93a84727bf
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/drop/manifest.ttl
@@ -0,0 +1,93 @@
+@prefix rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix : <http://www.w3.org/2009/sparql/docs/tests/data-sparql11/drop/manifest#> .
+@prefix rdfs:	<http://www.w3.org/2000/01/rdf-schema#> .
+@prefix dawgt:  <http://www.w3.org/2001/sw/DataAccess/tests/test-dawg#> .
+@prefix mf:     <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+@prefix qt:     <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
+@prefix ut:     <http://www.w3.org/2009/sparql/tests/test-update#> .
+
+<>  rdf:type mf:Manifest ;
+    rdfs:comment "Tests for SPARQL UPDATE" ;
+    mf:entries
+    (
+	:dawg-drop-default-01
+	:dawg-drop-graph-01
+	:dawg-drop-named-01
+	:dawg-drop-all-01
+   ).
+
+:dawg-drop-default-01 a mf:UpdateEvaluationTest ;
+    mf:name    "DROP DEFAULT" ;
+    rdfs:comment "This is a DROP of the default graph" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [
+    			ut:request <drop-default-01.ru> ; 
+                ut:data <drop-default.ttl> ;
+                ut:graphData [ ut:graph <drop-g1.ttl> ;
+                               rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ ut:graph <drop-g2.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+              ] ;
+    mf:result [
+                ut:graphData [ ut:graph <drop-g1.ttl> ;
+                               rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ ut:graph <drop-g2.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+              ] ;
+    .
+
+:dawg-drop-graph-01 a mf:UpdateEvaluationTest ;
+    mf:name    "DROP GRAPH" ;
+    rdfs:comment "This is a DROP of an existing named graph" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [
+    			ut:request <drop-graph-01.ru> ; 
+                ut:data <drop-default.ttl> ;
+                ut:graphData [ ut:graph <drop-g1.ttl> ;
+                               rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ ut:graph <drop-g2.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+              ] ;
+    mf:result [
+    			ut:data <drop-default.ttl> ;
+                ut:graphData [ ut:graph <drop-g2.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+              ] ;
+    .
+
+:dawg-drop-named-01 a mf:UpdateEvaluationTest ;
+    mf:name    "DROP NAMED" ;
+    rdfs:comment "This is a DROP of all the named graphs" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [
+    			ut:request <drop-named-01.ru> ; 
+                ut:data <drop-default.ttl> ;
+                ut:graphData [ ut:graph <drop-g1.ttl> ;
+                               rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ ut:graph <drop-g2.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+              ] ;
+    mf:result [
+    			ut:data <drop-default.ttl> ;
+              ] ;
+    .
+
+:dawg-drop-all-01 a mf:UpdateEvaluationTest ;
+    mf:name    "DROP ALL" ;
+    rdfs:comment "This is a DROP of all graphs (default and named)" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_3> ;
+    mf:action [
+    			ut:request <drop-all-01.ru> ; 
+                ut:data <drop-default.ttl> ;
+                ut:graphData [ ut:graph <drop-g1.ttl> ;
+                               rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ ut:graph <drop-g2.ttl> ;
+                               rdfs:label "http://example.org/g2" ] ;
+              ] ;
+    mf:result [] ;
+    .
+
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists01.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists01.rq
new file mode 100644
index 0000000000000000000000000000000000000000..47c16a3bf15200332d0f78ecb7192d1d8e393858
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists01.rq
@@ -0,0 +1,6 @@
+prefix ex: <http://www.example.org/>
+
+select * where {
+?s ?p ?o
+filter exists {?s ?p ex:o}
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists01.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists01.srx
new file mode 100644
index 0000000000000000000000000000000000000000..41b3e0cc9a63233a0f1abb79284ff2ecad350a97
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists01.srx
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<sparql xmlns='http://www.w3.org/2005/sparql-results#'>
+<head>
+<variable name='s'/>
+<variable name='o'/>
+<variable name='p'/>
+</head>
+<results>
+<result>
+<binding name='s'><uri>http://www.example.org/s</uri></binding>
+<binding name='o'><uri>http://www.example.org/o</uri></binding>
+<binding name='p'><uri>http://www.example.org/p</uri></binding>
+</result>
+<result>
+<binding name='s'><uri>http://www.example.org/s</uri></binding>
+<binding name='o'><uri>http://www.example.org/o1</uri></binding>
+<binding name='p'><uri>http://www.example.org/p</uri></binding>
+</result>
+<result>
+<binding name='s'><uri>http://www.example.org/s</uri></binding>
+<binding name='o'><uri>http://www.example.org/o2</uri></binding>
+<binding name='p'><uri>http://www.example.org/p</uri></binding>
+</result>
+</results>
+</sparql>
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists01.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists01.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..39dc3bbf6465dd133dc53fe5361adf7d9d27d164
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists01.ttl
@@ -0,0 +1,4 @@
+@prefix : <http://www.example.org/> .
+
+:s :p :o, :o1, :o2.
+:t :p :o1, :o2.
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists02.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists02.rq
new file mode 100644
index 0000000000000000000000000000000000000000..1a81e3d23853452d81c40162cea31c20e880018f
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists02.rq
@@ -0,0 +1,6 @@
+prefix ex: <http://www.example.org/>
+
+select * where {
+?s ?p ex:o2
+filter exists {ex:s ex:p ex:o}
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists02.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists02.srx
new file mode 100644
index 0000000000000000000000000000000000000000..5ff350a1257036f6ecbb39425d0c464358dac57c
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists02.srx
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<sparql xmlns='http://www.w3.org/2005/sparql-results#'>
+<head>
+<variable name='s'/>
+<variable name='p'/>
+</head>
+<results>
+<result>
+<binding name='s'><uri>http://www.example.org/s</uri></binding>
+<binding name='p'><uri>http://www.example.org/p</uri></binding>
+</result>
+<result>
+<binding name='s'><uri>http://www.example.org/t</uri></binding>
+<binding name='p'><uri>http://www.example.org/p</uri></binding>
+</result>
+</results>
+</sparql>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists02.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists02.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..3f4a81ac4d2ef364e190c91ceaa5da9b738830d4
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists02.ttl
@@ -0,0 +1,4 @@
+@prefix : <http://www.example.org/> .
+
+:a :p :o1.
+:b :p :o1, :o2.
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists03.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists03.rq
new file mode 100644
index 0000000000000000000000000000000000000000..5c17acb36ccd4e7375f448c66d28dec96cf6fc00
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists03.rq
@@ -0,0 +1,9 @@
+prefix ex: <http://www.example.org/>
+
+select * where {
+graph <exists02.ttl> { 
+  ?s ?p ex:o1
+  filter exists { ?s ?p ex:o2 } 
+}
+
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists03.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists03.srx
new file mode 100644
index 0000000000000000000000000000000000000000..94d8b3992aebcc0ddc88364ee9b34017fd4a02ab
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists03.srx
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<sparql xmlns='http://www.w3.org/2005/sparql-results#'>
+<head>
+<variable name='s'/>
+<variable name='p'/>
+</head>
+<results>
+<result>
+<binding name='s'><uri>http://www.example.org/b</uri></binding>
+<binding name='p'><uri>http://www.example.org/p</uri></binding>
+</result>
+</results>
+</sparql>
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists04.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists04.rq
new file mode 100644
index 0000000000000000000000000000000000000000..8577d399671320824ecd500c2646b372741dc5ef
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists04.rq
@@ -0,0 +1,6 @@
+prefix ex: <http://www.example.org/>
+
+select * where {
+  ?s ?p ex:o
+  filter exists { ?s ?p ex:o1  filter exists { ?s ?p ex:o2 } } 
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists04.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists04.srx
new file mode 100644
index 0000000000000000000000000000000000000000..f6544d49e937ac6f971c14a7f17eebc83b989be1
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists04.srx
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<sparql xmlns='http://www.w3.org/2005/sparql-results#'>
+<head>
+<variable name='s'/>
+<variable name='p'/>
+</head>
+<results>
+<result>
+<binding name='s'><uri>http://www.example.org/s</uri></binding>
+<binding name='p'><uri>http://www.example.org/p</uri></binding>
+</result>
+</results>
+</sparql>
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists05.rq b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists05.rq
new file mode 100644
index 0000000000000000000000000000000000000000..0d698ff7eabc88f179b9d7f7219bc2db5bbb78c8
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists05.rq
@@ -0,0 +1,6 @@
+prefix ex: <http://www.example.org/>
+
+select * where {
+  ?s ?p ex:o
+  filter exists { ?s ?p ex:o1  filter not exists { ?s ?p ex:o2 } } 
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists05.srx b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists05.srx
new file mode 100644
index 0000000000000000000000000000000000000000..0674113e9ae43bd072ae2ee64e28ac7d50cc1fc7
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/exists05.srx
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<sparql xmlns='http://www.w3.org/2005/sparql-results#'>
+<head>
+<variable name='s'/>
+<variable name='p'/>
+</head>
+<results>
+</results>
+</sparql>
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/manifest.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/manifest.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..f4addfcc310d78851484baf190c50eb4f04afd5e
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/exists/manifest.ttl
@@ -0,0 +1,82 @@
+@prefix rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix : <http://www.w3.org/2009/sparql/docs/tests/data-sparql11/exists/manifest#> .
+@prefix rdfs:	<http://www.w3.org/2000/01/rdf-schema#> .
+@prefix mf:     <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+@prefix qt:     <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
+@prefix dawgt:   <http://www.w3.org/2001/sw/DataAccess/tests/test-dawg#> .
+@prefix sparql:  <http://www.w3.org/ns/sparql#> .
+
+<>  rdf:type mf:Manifest ;
+    rdfs:label "Positive Exists" ;
+    mf:entries
+    ( 
+    :exists01
+    :exists02
+    :exists03
+    :exists04
+    :exists05
+  ).
+
+
+:exists01 rdf:type mf:QueryEvaluationTest ;
+    mf:name "Exists with one constant";
+	mf:feature sparql:exists ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_2> ;
+    mf:action
+         [ qt:query  <exists01.rq> ;
+           qt:data   <exists01.ttl> ] ;
+    mf:result  <exists01.srx>
+    .
+    
+    
+:exists02 rdf:type mf:QueryEvaluationTest ;
+    mf:name "Exists with ground triple";
+	mf:feature sparql:exists ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_2> ;
+    mf:action
+         [ qt:query  <exists02.rq> ;
+           qt:data   <exists01.ttl> ] ;
+    mf:result  <exists02.srx>  
+    .
+    
+:exists03 rdf:type mf:QueryEvaluationTest ;
+    mf:name "Exists within graph pattern";
+	mf:feature sparql:exists ;
+    rdfs:comment    "Checks that exists is interpreted within named graph" ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_2> ;
+    mf:action
+         [ qt:query  <exists03.rq> ;
+           qt:data   <exists01.ttl> ;
+           qt:graphData   <exists02.ttl> 
+          ] ;
+    mf:result  <exists03.srx>  
+    .    
+   
+    
+ :exists04 rdf:type mf:QueryEvaluationTest ;
+    mf:name "Nested positive exists";
+	mf:feature sparql:exists ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_2> ;
+    mf:action
+         [ qt:query  <exists04.rq> ;
+           qt:data   <exists01.ttl> ;
+          ] ;
+    mf:result  <exists04.srx>  
+    .       
+    
+:exists05 rdf:type mf:QueryEvaluationTest ;
+    mf:name "Nested negative exists in positive exists";
+	mf:feature sparql:exists ;
+    dawgt:approval dawgt:Approved;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-02-07#resolution_2> ;
+    mf:action
+         [ qt:query  <exists05.rq> ;
+           qt:data   <exists01.ttl> ;
+          ] ;
+    mf:result  <exists05.srx>  
+    .           
+    
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/manifest.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/manifest.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..815a4babbc2368564b9e9867c183b27521ea0d94
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/manifest.ttl
@@ -0,0 +1,105 @@
+@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix :      <http://www.w3.org/2009/sparql/docs/tests/data-sparql11/move/manifest#> .
+@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix mf:    <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+@prefix qt:    <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
+@prefix ut:    <http://www.w3.org/2009/sparql/tests/test-update#> .
+@prefix dawgt: <http://www.w3.org/2001/sw/DataAccess/tests/test-dawg#> .
+
+<>  rdf:type mf:Manifest ;
+    rdfs:label "Move" ;
+    mf:entries
+    ( 
+    :move01
+    :move02
+    :move03
+    :move04
+    :move06
+    :move07
+    ) .
+
+:move01 rdf:type mf:UpdateEvaluationTest ;
+    mf:name "MOVE 1" ;
+    rdfs:comment "Move the default graph to an existing graph" ;
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-05-22#resolution_2> ;
+    mf:action [ ut:request <move-01.ru> ;
+                ut:data <move-default.ttl> ;
+                ut:graphData [ ut:graph <move-01.ttl> ;
+                               rdfs:label "http://example.org/g1" ]
+              ] ;
+    mf:result [ ut:graphData [ ut:graph <move-default.ttl> ;
+                               rdfs:label "http://example.org/g1" ]
+              ] .
+
+:move02 rdf:type mf:UpdateEvaluationTest ;
+    mf:name "MOVE 2" ;
+    rdfs:comment "Move the default graph to a non-existing graph" ;
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-05-22#resolution_2> ;
+    mf:action [ ut:request <move-01.ru> ;
+                ut:data <move-default.ttl> ;
+              ] ;
+    mf:result [ ut:graphData [ ut:graph <move-default.ttl> ;
+                               rdfs:label "http://example.org/g1" ]
+              ] .
+
+:move03 rdf:type mf:UpdateEvaluationTest ;
+    mf:name "MOVE 3" ;
+    rdfs:comment "Move a named graph to an existing graph" ;
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-05-22#resolution_2> ;
+    mf:action [ ut:request <move-03.ru> ;
+                ut:data <move-default.ttl> ;
+                ut:graphData [ ut:graph <move-01.ttl> ;
+                               rdfs:label "http://example.org/g1" ] ;
+                ut:graphData [ ut:graph <move-02.ttl> ;
+                               rdfs:label "http://example.org/g2" ]
+              ] ;
+    mf:result [ ut:data <move-default.ttl> ;
+                ut:graphData [ ut:graph <move-01.ttl> ;
+                               rdfs:label "http://example.org/g2" ]
+              ] .
+
+:move04 rdf:type mf:UpdateEvaluationTest ;
+    mf:name "MOVE 4" ;
+    rdfs:comment "Move a named graph to a non-existing graph" ;
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-05-22#resolution_2> ;
+    mf:action [ ut:request <move-03.ru> ;
+                ut:data <move-default.ttl> ;
+                ut:graphData [ ut:graph <move-01.ttl> ;
+                               rdfs:label "http://example.org/g1" ]
+              ] ;
+    mf:result [ ut:data <move-default.ttl> ;
+                ut:graphData [ ut:graph <move-01.ttl> ;
+                               rdfs:label "http://example.org/g2" ]
+              ] .
+
+:move06 rdf:type mf:UpdateEvaluationTest ;
+    mf:name "MOVE 6" ;
+    rdfs:comment "Move an existing graph to the default graph" ;
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-05-22#resolution_2> ;
+    mf:action [ ut:request <move-06.ru> ;
+                ut:data <move-default.ttl> ;
+                ut:graphData [ ut:graph <move-01.ttl> ;
+                               rdfs:label "http://example.org/g1" ]
+              ] ;
+    mf:result [ ut:data <move-01.ttl> ;
+              ] .
+
+:move07 rdf:type mf:UpdateEvaluationTest ;
+    mf:name "MOVE 7" ;
+    rdfs:comment "Move a graph to itself" ;
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-05-22#resolution_2> ;
+    mf:action [ ut:request <move-07.ru> ;
+                ut:data <move-default.ttl> ;
+                ut:graphData [ ut:graph <move-01.ttl> ;
+                               rdfs:label "http://example.org/g1" ]
+              ] ;
+    mf:result [ ut:data <move-default.ttl> ;
+                ut:graphData [ ut:graph <move-01.ttl> ;
+                               rdfs:label "http://example.org/g1" ]
+              ] .
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-01.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-01.ru
new file mode 100644
index 0000000000000000000000000000000000000000..9b531cb2c85f7243fd1c16fc92def61d81894987
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-01.ru
@@ -0,0 +1,2 @@
+PREFIX : <http://example.org/>
+MOVE DEFAULT TO :g1
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-01.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-01.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..66f37628dfe70b1df3e5a3b74b7c628388ce8e40
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-01.ttl
@@ -0,0 +1,6 @@
+@prefix foaf:  <http://xmlns.com/foaf/0.1/> .
+@prefix :      <http://example.org/> .
+
+:jerry a foaf:Person .
+:jerry foaf:givenName "Jerry" .
+:jerry foaf:mbox  <mailto:jerry@example.org> .
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-02.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-02.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..b6254f8358bcb394ec84658c7e54080f8eea95b5
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-02.ttl
@@ -0,0 +1,6 @@
+@prefix foaf:  <http://xmlns.com/foaf/0.1/> .
+@prefix :      <http://example.org/> .
+
+:mickey a foaf:Person .
+:mickey foaf:givenName "Mickey" .
+:mickey foaf:mbox  <mailto:mickey@example.org> .
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-03.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-03.ru
new file mode 100644
index 0000000000000000000000000000000000000000..e23ecf92f58164f98be2b4519ee47828111f5feb
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-03.ru
@@ -0,0 +1,2 @@
+PREFIX : <http://example.org/>
+MOVE :g1 TO :g2
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-06.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-06.ru
new file mode 100644
index 0000000000000000000000000000000000000000..7f79e81c63f671f61cde9b7f19e34970dd18ed8d
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-06.ru
@@ -0,0 +1,2 @@
+PREFIX : <http://example.org/>
+MOVE :g1 TO DEFAULT
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-07.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-07.ru
new file mode 100644
index 0000000000000000000000000000000000000000..993e07fb4df37d5e4a583085217a47362537603f
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-07.ru
@@ -0,0 +1,2 @@
+PREFIX : <http://example.org/>
+MOVE :g1 TO :g1
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-default.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-default.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..ade3e4c609cf7d164b6dac24ee02b8a4a837da99
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/move/move-default.ttl
@@ -0,0 +1,6 @@
+@prefix foaf:  <http://xmlns.com/foaf/0.1/> .
+@prefix :      <http://example.org/> .
+
+:tom a foaf:Person .
+:tom foaf:givenName "Tom" .
+:tom foaf:mbox  <mailto:tom@example.org> .
\ No newline at end of file
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/manifest.ttl b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/manifest.ttl
new file mode 100644
index 0000000000000000000000000000000000000000..ec6aa5c99e3d03ee6cce6307605ae560c13e2f5d
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/manifest.ttl
@@ -0,0 +1,392 @@
+@prefix :       <http://www.w3.org/2009/sparql/docs/tests/data-sparql11/syntax-update-1/manifest#> .
+@prefix rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs:	<http://www.w3.org/2000/01/rdf-schema#> .
+@prefix mf:     <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+@prefix mfx:    <http://jena.hpl.hp.com/2005/05/test-manifest-extra#> .
+@prefix qt:     <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
+@prefix dawgt:  <http://www.w3.org/2001/sw/DataAccess/tests/test-dawg#> .
+
+<>  rdf:type mf:Manifest ;
+    rdfs:comment "Syntax tests Syntax SPARQL Update" ;
+    mf:entries
+    ( 
+
+:test_1
+:test_2
+:test_3
+:test_4
+:test_5
+:test_6
+:test_7
+:test_8
+:test_9
+:test_10
+:test_11
+:test_12
+:test_13
+:test_14
+:test_15
+:test_16
+:test_17
+:test_18
+:test_19
+:test_20
+:test_21
+:test_22
+:test_23
+:test_24
+:test_25
+:test_26
+:test_27
+:test_28
+:test_29
+:test_30
+:test_31
+:test_32
+:test_33
+:test_34
+:test_35
+:test_36
+:test_37
+:test_38
+:test_39
+:test_40
+:test_41
+:test_42
+:test_43
+:test_44
+:test_45
+:test_46
+:test_47
+:test_48
+:test_49
+:test_50
+:test_51
+:test_52
+:test_53
+:test_54
+) .
+
+:test_1 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-01.ru" ;
+   mf:action  <syntax-update-01.ru> ;.
+
+:test_2 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-02.ru" ;
+   mf:action  <syntax-update-02.ru> ;.
+
+:test_3 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-03.ru" ;
+   mf:action  <syntax-update-03.ru> ;.
+
+:test_4 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-04.ru" ;
+   mf:action  <syntax-update-04.ru> ;.
+
+:test_5 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-05.ru" ;
+   mf:action  <syntax-update-05.ru> ;.
+
+:test_6 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-06.ru" ;
+   mf:action  <syntax-update-06.ru> ;.
+
+:test_7 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-07.ru" ;
+   mf:action  <syntax-update-07.ru> ;.
+
+:test_8 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-08.ru" ;
+   mf:action  <syntax-update-08.ru> ;.
+
+:test_9 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-09.ru" ;
+   mf:action  <syntax-update-09.ru> ;.
+
+:test_10 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-10.ru" ;
+   mf:action  <syntax-update-10.ru> ;.
+
+:test_11 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-11.ru" ;
+   mf:action  <syntax-update-11.ru> ;.
+
+:test_12 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-12.ru" ;
+   mf:action  <syntax-update-12.ru> ;.
+
+:test_13 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-13.ru" ;
+   mf:action  <syntax-update-13.ru> ;.
+
+:test_14 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-14.ru" ;
+   mf:action  <syntax-update-14.ru> ;.
+
+:test_15 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-15.ru" ;
+   mf:action  <syntax-update-15.ru> ;.
+
+:test_16 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-16.ru" ;
+   mf:action  <syntax-update-16.ru> ;.
+
+:test_17 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-17.ru" ;
+   mf:action  <syntax-update-17.ru> ;.
+
+:test_18 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-18.ru" ;
+   mf:action  <syntax-update-18.ru> ;.
+
+:test_19 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-19.ru" ;
+   mf:action  <syntax-update-19.ru> ;.
+
+:test_20 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-20.ru" ;
+   mf:action  <syntax-update-20.ru> ;.
+
+:test_21 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-21.ru" ;
+   mf:action  <syntax-update-21.ru> ;.
+
+:test_22 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-22.ru" ;
+   mf:action  <syntax-update-22.ru> ;.
+
+:test_23 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-23.ru" ;
+   mf:action  <syntax-update-23.ru> ;.
+
+:test_24 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-24.ru" ;
+   mf:action  <syntax-update-24.ru> ;.
+
+:test_25 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-25.ru" ;
+   mf:action  <syntax-update-25.ru> ;.
+
+:test_26 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-26.ru" ;
+   mf:action  <syntax-update-26.ru> ;.
+
+:test_27 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-27.ru" ;
+   mf:action  <syntax-update-27.ru> ;.
+
+:test_28 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-28.ru" ;
+   mf:action  <syntax-update-28.ru> ;.
+
+:test_29 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-29.ru" ;
+   mf:action  <syntax-update-29.ru> ;.
+
+:test_30 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-30.ru" ;
+   mf:action  <syntax-update-30.ru> ;.
+
+:test_31 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-31.ru" ;
+   mf:action  <syntax-update-31.ru> ;.
+
+:test_32 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-32.ru" ;
+   mf:action  <syntax-update-32.ru> ;.
+
+:test_33 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-33.ru" ;
+   mf:action  <syntax-update-33.ru> ;.
+
+:test_34 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-34.ru" ;
+   mf:action  <syntax-update-34.ru> ;.
+
+:test_35 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-35.ru" ;
+   mf:action  <syntax-update-35.ru> ;.
+
+:test_36 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-36.ru" ;
+   mf:action  <syntax-update-36.ru> ;.
+
+:test_37 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-37.ru" ;
+   mf:action  <syntax-update-37.ru> ;.
+
+:test_38 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-38.ru" ;
+   mf:action  <syntax-update-38.ru> ;.
+
+:test_39 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-39.ru" ;
+   mf:action  <syntax-update-39.ru> ;.
+
+:test_40 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-40.ru" ;
+   mf:action  <syntax-update-40.ru> ;.
+
+:test_41 rdf:type   mf:NegativeUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-bad-01.ru" ;
+   mf:action  <syntax-update-bad-01.ru> ;.
+
+:test_42 rdf:type   mf:NegativeUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-bad-02.ru" ;
+   mf:action  <syntax-update-bad-02.ru> ;.
+
+:test_43 rdf:type   mf:NegativeUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-bad-03.ru" ;
+   mf:action  <syntax-update-bad-03.ru> ;.
+
+:test_44 rdf:type   mf:NegativeUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-bad-04.ru" ;
+   mf:action  <syntax-update-bad-04.ru> ;.
+
+:test_45 rdf:type   mf:NegativeUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-bad-05.ru" ;
+   mf:action  <syntax-update-bad-05.ru> ;.
+
+:test_46 rdf:type   mf:NegativeUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-bad-06.ru" ;
+   mf:action  <syntax-update-bad-06.ru> ;.
+
+:test_47 rdf:type   mf:NegativeUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-bad-07.ru" ;
+   mf:action  <syntax-update-bad-07.ru> ;.
+
+:test_48 rdf:type   mf:NegativeUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-bad-08.ru" ;
+   mf:action  <syntax-update-bad-08.ru> ;.
+
+:test_49 rdf:type   mf:NegativeUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-bad-09.ru" ;
+   mf:action  <syntax-update-bad-09.ru> ;.
+
+:test_50 rdf:type   mf:NegativeUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-bad-10.ru" ;
+   mf:action  <syntax-update-bad-10.ru> ;.
+
+:test_51 rdf:type   mf:NegativeUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-bad-11.ru" ;
+   mf:action  <syntax-update-bad-11.ru> ;.
+
+:test_52 rdf:type   mf:NegativeUpdateSyntaxTest11 ;
+   dawgt:approval dawgt:Approved ;
+   dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2011-04-05#resolution_2> ;
+   mf:name    "syntax-update-bad-12.ru" ;
+   mf:action  <syntax-update-bad-12.ru> ;.
+
+:test_53 rdf:type   mf:PositiveUpdateSyntaxTest11 ;
+    dawgt:approval dawgt:Approved ;
+    dawgt:approvedBy <http://www.w3.org/2009/sparql/meeting/2012-08-07#resolution_3> ;
+   mf:name    "syntax-update-53.ru" ;
+   mf:action  <syntax-update-53.ru> ;.
+
+:test_54 rdf:type   mf:NegativeUpdateSyntaxTest11 ;
+    dawgt:approval  dawgt:NotClassified ;
+    # Reuse of bNode label across operations.  
+    mf:name    "syntax-update-54.ru" ;
+    mf:action  <syntax-update-54.ru> ;.
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-01.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-01.ru
new file mode 100644
index 0000000000000000000000000000000000000000..a1706e2cb37c59da0445d0472de04f701d8cc718
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-01.ru
@@ -0,0 +1,3 @@
+BASE <http://example/base#>
+PREFIX : <http://example/>
+LOAD <http://example.org/faraway>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-02.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-02.ru
new file mode 100644
index 0000000000000000000000000000000000000000..8050bd665f08238d6f040ef4e12398db625acad7
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-02.ru
@@ -0,0 +1,7 @@
+# Comment
+BASE <http://example/base#>
+# Comment
+PREFIX : <http://example/>
+# Comment
+LOAD <http://example.org/faraway>
+# Comment
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-03.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-03.ru
new file mode 100644
index 0000000000000000000000000000000000000000..514a649ddafba0bdd947590752e512dbcc4fce3f
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-03.ru
@@ -0,0 +1 @@
+LOAD <http://example.org/faraway> ;
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-04.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-04.ru
new file mode 100644
index 0000000000000000000000000000000000000000..077764275f95d8c8e7fb0438bc5bdc68d098ec24
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-04.ru
@@ -0,0 +1 @@
+LOAD <http://example.org/faraway> INTO GRAPH <localCopy>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-05.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-05.ru
new file mode 100644
index 0000000000000000000000000000000000000000..b3f4b87af134459b9ed79e937ef6de7aca17c977
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-05.ru
@@ -0,0 +1 @@
+DROP NAMED
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-06.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-06.ru
new file mode 100644
index 0000000000000000000000000000000000000000..ef60445c867c427ca9db782111ec59d7491697db
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-06.ru
@@ -0,0 +1 @@
+DROP DEFAULT
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-07.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-07.ru
new file mode 100644
index 0000000000000000000000000000000000000000..61a404f7c59d30a761831096988323098a063acb
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-07.ru
@@ -0,0 +1 @@
+DROP ALL
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-08.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-08.ru
new file mode 100644
index 0000000000000000000000000000000000000000..ddd3a13c80f08c835ea2de75f488e7671bea2e14
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-08.ru
@@ -0,0 +1 @@
+DROP GRAPH <graph>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-09.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-09.ru
new file mode 100644
index 0000000000000000000000000000000000000000..aff3357fbfe99e38aa80ef207d9afe9317a3790c
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-09.ru
@@ -0,0 +1 @@
+DROP SILENT NAMED
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-10.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-10.ru
new file mode 100644
index 0000000000000000000000000000000000000000..a2595a7cf67eda1e75b84099ed065576082372fd
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-10.ru
@@ -0,0 +1 @@
+DROP SILENT DEFAULT
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-11.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-11.ru
new file mode 100644
index 0000000000000000000000000000000000000000..e7a4b1068db0a8835920e0616fe75e3c4918ee32
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-11.ru
@@ -0,0 +1 @@
+DROP SILENT ALL
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-12.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-12.ru
new file mode 100644
index 0000000000000000000000000000000000000000..2d02e08a2f52c7cb43f093111183a2770477e89c
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-12.ru
@@ -0,0 +1 @@
+DROP SILENT GRAPH <graph>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-13.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-13.ru
new file mode 100644
index 0000000000000000000000000000000000000000..66d7177f280bbf67614315c88303aec7c5ad57f5
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-13.ru
@@ -0,0 +1 @@
+CREATE GRAPH <graph>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-14.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-14.ru
new file mode 100644
index 0000000000000000000000000000000000000000..ba3709b8a08a3166b028a1b0b78bae50802d50b1
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-14.ru
@@ -0,0 +1 @@
+CREATE SILENT GRAPH <graph>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-15.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-15.ru
new file mode 100644
index 0000000000000000000000000000000000000000..cea7a88f1ae2f178ce861ecc80510f68f4e2030a
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-15.ru
@@ -0,0 +1 @@
+CLEAR NAMED
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-16.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-16.ru
new file mode 100644
index 0000000000000000000000000000000000000000..dd8f2b6c0bf59bfa2021d92922bf75a19e8dc645
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-16.ru
@@ -0,0 +1 @@
+CLEAR DEFAULT
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-17.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-17.ru
new file mode 100644
index 0000000000000000000000000000000000000000..1074b88d40877bd9d1a9835422c152cc5bdbdd7b
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-17.ru
@@ -0,0 +1 @@
+CLEAR ALL
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-18.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-18.ru
new file mode 100644
index 0000000000000000000000000000000000000000..7391e48d8bdcc32a9a6a86fbb1319ea2ae447179
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-18.ru
@@ -0,0 +1 @@
+CLEAR GRAPH <graph>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-19.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-19.ru
new file mode 100644
index 0000000000000000000000000000000000000000..9b7e0fb3f755cee19682f9de0cf1ae5298715db4
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-19.ru
@@ -0,0 +1 @@
+CLEAR SILENT NAMED
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-20.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-20.ru
new file mode 100644
index 0000000000000000000000000000000000000000..9370f0bb4350f712cd4ec5283891adf6c856e824
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-20.ru
@@ -0,0 +1 @@
+CLEAR SILENT DEFAULT
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-21.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-21.ru
new file mode 100644
index 0000000000000000000000000000000000000000..7bcc9450c96572c02451f8a2055df2aaf18a8ef1
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-21.ru
@@ -0,0 +1 @@
+CLEAR SILENT ALL
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-22.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-22.ru
new file mode 100644
index 0000000000000000000000000000000000000000..761d6da62ad58e6914cb532e424572cb9d34e4ff
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-22.ru
@@ -0,0 +1 @@
+CLEAR SILENT GRAPH <graph>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-23.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-23.ru
new file mode 100644
index 0000000000000000000000000000000000000000..ebc8b60476e9da8e76ba6e3dd5c574ddfd746784
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-23.ru
@@ -0,0 +1 @@
+INSERT DATA { <s> <p> 'o1', 'o2', 'o3' }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-24.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-24.ru
new file mode 100644
index 0000000000000000000000000000000000000000..e30391fccc065337610cdc9701ce5e421e4ed2bc
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-24.ru
@@ -0,0 +1 @@
+INSERT DATA { GRAPH <G> { <s> <p> 'o1', 'o2', 'o3' } }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-25.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-25.ru
new file mode 100644
index 0000000000000000000000000000000000000000..2d04d109ea71ca93d2548ba1503b5db98943939b
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-25.ru
@@ -0,0 +1,6 @@
+INSERT DATA { 
+  <s1> <p1> <o1>
+  GRAPH <G> { <s> <p1> 'o1'; <p2> <o2> } 
+  GRAPH <G1> { <s> <p1> 'o1'; <p2> <o2> } 
+  <s1> <p1> <o1>
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-26.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-26.ru
new file mode 100644
index 0000000000000000000000000000000000000000..c7b4b39a13ab0e9a776885a3246010bc4753157b
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-26.ru
@@ -0,0 +1,3 @@
+INSERT 
+# Comment
+DATA { GRAPH <G> { <s> <p> 'o1', 'o2', 'o3' } }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-27.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-27.ru
new file mode 100644
index 0000000000000000000000000000000000000000..a202410ae916185da2568dd7cf82d8abc56751bc
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-27.ru
@@ -0,0 +1,2 @@
+INSERT 
+DATA { }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-28.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-28.ru
new file mode 100644
index 0000000000000000000000000000000000000000..06d836eb708756d806f02c726763e85c0d079851
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-28.ru
@@ -0,0 +1,2 @@
+INSERT 
+DATA {  GRAPH <G>{} }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-29.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-29.ru
new file mode 100644
index 0000000000000000000000000000000000000000..e24468efd2be25718b4f5b590f6c6e732e8ee469
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-29.ru
@@ -0,0 +1 @@
+DELETE DATA { <s> <p> 'o1', 'o2', 'o3' }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-30.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-30.ru
new file mode 100644
index 0000000000000000000000000000000000000000..c9159e513c890d915731d63ffe45a7b22d27e8df
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-30.ru
@@ -0,0 +1 @@
+DELETE DATA { GRAPH <G> { <s> <p> 'o1', 'o2', 'o3' } }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-31.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-31.ru
new file mode 100644
index 0000000000000000000000000000000000000000..73da0841dffe7ea1e1de88fb3578a81ca4978d25
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-31.ru
@@ -0,0 +1,6 @@
+DELETE DATA { 
+  <s1> <p1> <o1>
+  GRAPH <G> { <s> <p1> 'o1'; <p2> <o2> } 
+  GRAPH <G1> { <s> <p1> 'o1'; <p2> <o2> } 
+  <s1> <p1> <o1>
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-32.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-32.ru
new file mode 100644
index 0000000000000000000000000000000000000000..1624bc37579d839747dd1d643591563632830241
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-32.ru
@@ -0,0 +1,16 @@
+BASE    <base:>
+PREFIX  :     <http://example/>
+
+WITH :g
+DELETE {
+  <s> ?p ?o .
+}
+INSERT {
+  ?s ?p <#o> .
+}
+USING <base:g1>
+USING <base:g2>
+USING NAMED :gn1
+USING NAMED :gn2
+WHERE
+  { ?s ?p ?o }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-33.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-33.ru
new file mode 100644
index 0000000000000000000000000000000000000000..56244f9ae951f28412368c68e0394e41dfa4519a
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-33.ru
@@ -0,0 +1,7 @@
+PREFIX  :     <http://example/>
+WITH :g
+DELETE {
+  <base:s> ?p ?o .
+}
+WHERE
+  { ?s ?p ?o }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-34.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-34.ru
new file mode 100644
index 0000000000000000000000000000000000000000..15480a9ad89b82ec02d7850e41f157aa1abeb484
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-34.ru
@@ -0,0 +1,7 @@
+PREFIX  :     <http://example/>
+WITH :g
+INSERT {
+  <base:s> ?p ?o .
+}
+WHERE
+  { ?s ?p ?o }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-35.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-35.ru
new file mode 100644
index 0000000000000000000000000000000000000000..0fdbd76b71e69997bdb9ab43caaf2b2b099634bc
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-35.ru
@@ -0,0 +1 @@
+DELETE WHERE { ?s ?p ?o }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-36.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-36.ru
new file mode 100644
index 0000000000000000000000000000000000000000..34a383454b89fd03ad8f44d747699478a9644f2b
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-36.ru
@@ -0,0 +1,6 @@
+# Comment
+DELETE 
+# Comment
+WHERE 
+# Comment
+{ GRAPH <G> { <s> <p> 123 ; <q> 4567.0 . } }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-37.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-37.ru
new file mode 100644
index 0000000000000000000000000000000000000000..cbaa918124f14237ee03ca57fb80a2180cbe218e
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-37.ru
@@ -0,0 +1,2 @@
+CREATE GRAPH <g> ;
+LOAD <remote> INTO GRAPH <g> ;
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-38.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-38.ru
new file mode 100644
index 0000000000000000000000000000000000000000..b7db25411d06ab75b08bbd4a12922545f89ad22a
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-38.ru
@@ -0,0 +1 @@
+# Empty
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-39.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-39.ru
new file mode 100644
index 0000000000000000000000000000000000000000..d0be85ff797b8fe089c7f4055eea4e6ae4abb175
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-39.ru
@@ -0,0 +1,2 @@
+BASE <http://example/>
+# Otherwise empty
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-40.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-40.ru
new file mode 100644
index 0000000000000000000000000000000000000000..a494d59bd3796cd98ad25ae1bfbc4ba612a07c77
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-40.ru
@@ -0,0 +1,2 @@
+PREFIX : <http://example/>
+# Otherwise empty
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-53.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-53.ru
new file mode 100644
index 0000000000000000000000000000000000000000..15b57c0952461d47ac3b55329a77874df70ce3bc
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-53.ru
@@ -0,0 +1,6 @@
+PREFIX : <http://www.example.org/>
+
+INSERT DATA { 
+              GRAPH<g1> { _:b1 :p :o } 
+              GRAPH<g2> { _:b1 :p :o } 
+            }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-54.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-54.ru
new file mode 100644
index 0000000000000000000000000000000000000000..39b4c542e32b98eb58d1e480b4af89e7bf71e0f0
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-54.ru
@@ -0,0 +1,5 @@
+PREFIX : <http://www.example.org/>
+
+INSERT DATA { _:b1 :p :o }
+;
+INSERT DATA { _:b1 :p :o } 
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-01.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-01.ru
new file mode 100644
index 0000000000000000000000000000000000000000..1268c0b3cf23b99427367fc3273ae8f29add7937
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-01.ru
@@ -0,0 +1,2 @@
+# No URL
+LOAD ;
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-02.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-02.ru
new file mode 100644
index 0000000000000000000000000000000000000000..305a246aa67841c1e120da3c67576f763b4b15ad
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-02.ru
@@ -0,0 +1,2 @@
+# Typo in keyword.
+CREATE DEAFULT
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-03.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-03.ru
new file mode 100644
index 0000000000000000000000000000000000000000..360944864e5f653c30a8cf5427a4059736a8e84e
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-03.ru
@@ -0,0 +1,2 @@
+# Variable in data.
+DELETE DATA { ?s <p> <o> }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-04.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-04.ru
new file mode 100644
index 0000000000000000000000000000000000000000..9aa3973589e4f16213311415b5715a608ca37592
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-04.ru
@@ -0,0 +1,2 @@
+# Variable in data.
+INSERT DATA { GRAPH ?g {<s> <p> <o> } }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-05.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-05.ru
new file mode 100644
index 0000000000000000000000000000000000000000..590f83014c8ed26c9aad4c44115e7b177cf8c535
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-05.ru
@@ -0,0 +1,7 @@
+# Nested GRAPH
+DELETE DATA { 
+  GRAPH <G> { 
+    <s> <p> <o> .
+    GRAPH <G1> { <s> <p1> 'o1' }
+  }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-06.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-06.ru
new file mode 100644
index 0000000000000000000000000000000000000000..1339cc1ab3b850ba003c6ac5ff97e4d943b4c505
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-06.ru
@@ -0,0 +1,2 @@
+# Missing template
+INSERT WHERE { ?s ?p ?o }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-07.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-07.ru
new file mode 100644
index 0000000000000000000000000000000000000000..640fc539bbf5942fb9d7837825912f593b37c50c
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-07.ru
@@ -0,0 +1,3 @@
+# No separator
+CREATE GRAPH <g>
+LOAD <remote> INTO GRAPH <g>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-08.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-08.ru
new file mode 100644
index 0000000000000000000000000000000000000000..3fb2b1edf5a08b344f876a4899cf643aa53670e5
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-08.ru
@@ -0,0 +1,4 @@
+# Too many separators
+CREATE GRAPH <g>
+;;
+LOAD <remote> INTO GRAPH <g>
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-09.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-09.ru
new file mode 100644
index 0000000000000000000000000000000000000000..9a2c4b8979dfc3a86a04d9f4aad62d1c4206b120
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-09.ru
@@ -0,0 +1,4 @@
+CREATE GRAPH <g>
+;
+LOAD <remote> INTO GRAPH <g>
+;;
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-10.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-10.ru
new file mode 100644
index 0000000000000000000000000000000000000000..5a638fe419e423b634db5d75260584b82a78322c
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-10.ru
@@ -0,0 +1,2 @@
+# BNode in DELETE WHERE
+DELETE WHERE { _:a <p> <o> }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-11.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-11.ru
new file mode 100644
index 0000000000000000000000000000000000000000..1d2f23adb3f1f2dfcb17f76cd5cfe3768bd67f06
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-11.ru
@@ -0,0 +1,2 @@
+# BNode in DELETE template
+DELETE { <s> <p> [] } WHERE { ?x <p> <o> }
diff --git a/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-12.ru b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-12.ru
new file mode 100644
index 0000000000000000000000000000000000000000..43e3a22b8ad2547afbd554b3ecce5f9a872a59f4
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/sparql_1_1_tests/w3c-tests/syntax-update-1/syntax-update-bad-12.ru
@@ -0,0 +1,2 @@
+# BNode in DELETE DATA
+DELETE DATA { _:a <p> <o> }
diff --git a/lib/arc2/tests/db_adapter_depended/src/ARC2/Store/Adapter/CachedPDOAdapterTest.php b/lib/arc2/tests/db_adapter_depended/src/ARC2/Store/Adapter/CachedPDOAdapterTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6265265b24319d863f435cea733da209d6cadf7c
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/src/ARC2/Store/Adapter/CachedPDOAdapterTest.php
@@ -0,0 +1,96 @@
+<?php
+
+namespace Tests\db_adapter_depended\src\ARC2\Store\Adapter;
+
+use ARC2\Store\Adapter\CachedPDOAdapter;
+use Tests\ARC2_TestCase;
+
+class CachedPDOAdapterTest extends ARC2_TestCase
+{
+    public function setUp(): void
+    {
+        // stop, if pdo_mysql is not available
+        if (false == \extension_loaded('pdo_mysql')) {
+            $this->markTestSkipped('Test skipped, because extension pdo_mysql is not installed.');
+        }
+
+        // stop, if pdo_db_protocol is not set in dbConfig
+        if (false == isset($this->dbConfig['db_pdo_protocol'])) {
+            $this->markTestSkipped(
+                'Test skipped, because db_pdo_protocol is not set. Its ok, if this happens in unit test environment.'
+            );
+        }
+
+        parent::setUp();
+
+        $this->dbConfig['cache_enabled'] = true;
+
+        $this->fixture = new CachedPDOAdapter($this->dbConfig);
+
+        // remove all tables
+        $tables = $this->fixture->fetchList('SHOW TABLES');
+        foreach($tables as $table) {
+            $this->fixture->simpleQuery('DROP TABLE '. $table['Tables_in_'.$this->dbConfig['db_name']]);
+        }
+    }
+
+    public function testFetchRow()
+    {
+        // create test data
+        $this->fixture->simpleQuery('CREATE TABLE users (id INT(6), name VARCHAR(30) NOT NULL)');
+        $this->fixture->simpleQuery('INSERT INTO users (id, name) VALUE (1, "foobar");');
+        $this->fixture->simpleQuery('INSERT INTO users (id, name) VALUE (2, "foobar2");');
+
+        $selectQuery = 'SELECT * FROM users WHERE id = 2';
+
+        // check that cache doesnt know $selectQuery yet.
+        $this->assertFalse($this->fixture->getCacheInstance()->has(hash('sha1', $selectQuery)));
+
+        $user = $this->fixture->fetchRow($selectQuery);
+
+        // check cache, that expected entry is available
+        $this->assertTrue($this->fixture->getCacheInstance()->has(hash('sha1', $selectQuery)));
+
+        // check if $users is equal to the cached version
+        $this->assertEquals($user, $this->fixture->fetchRow($selectQuery));
+    }
+
+    public function testFetchList()
+    {
+        // create test data
+        $this->fixture->simpleQuery('CREATE TABLE users (id INT(6), name VARCHAR(30) NOT NULL)');
+        $this->fixture->simpleQuery('INSERT INTO users (id, name) VALUE (1, "foobar");');
+        $this->fixture->simpleQuery('INSERT INTO users (id, name) VALUE (2, "foobar2");');
+
+        $selectQuery = 'SELECT * FROM users';
+
+        // check that cache doesnt know $selectQuery yet.
+        $this->assertFalse($this->fixture->getCacheInstance()->has(hash('sha1', $selectQuery)));
+
+        $users = $this->fixture->fetchList($selectQuery);
+
+        // check cache, that expected entry is available
+        $this->assertTrue($this->fixture->getCacheInstance()->has(hash('sha1', $selectQuery)));
+
+        // check if $users is equal to the cached version
+        $this->assertEquals($users, $this->fixture->fetchList($selectQuery));
+    }
+
+    public function testCacheInvalidationIfDBChanges()
+    {
+        // create test data
+        $this->fixture->simpleQuery('CREATE TABLE users (id INT(6), name VARCHAR(30) NOT NULL)');
+        $this->fixture->simpleQuery('INSERT INTO users (id, name) VALUE (1, "foobar");');
+        $this->fixture->simpleQuery('INSERT INTO users (id, name) VALUE (2, "foobar2");');
+
+        $selectQuery = 'SELECT * FROM users';
+
+        $users = $this->fixture->fetchList($selectQuery);
+        $this->assertTrue($this->fixture->getCacheInstance()->has(hash('sha1', $selectQuery)));
+
+        // change table and therefore the DB => invalidation of the cache
+        $this->fixture->exec('DELETE FROM users WHERE id = 1');
+
+        $this->assertFalse($this->fixture->getCacheInstance()->has(hash('sha1', $selectQuery)));
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/store/ARC2_StoreAskQueryHandlerTest.php b/lib/arc2/tests/db_adapter_depended/store/ARC2_StoreAskQueryHandlerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0809dcc6e793e24404fccb0f6d1cd75adc9f43f2
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/store/ARC2_StoreAskQueryHandlerTest.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Tests\db_adapter_depended\store;
+
+use Tests\ARC2_TestCase;
+
+class ARC2_StoreAskQueryHandlerTest extends ARC2_TestCase
+{
+    protected $store;
+
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->store = \ARC2::getStore($this->dbConfig);
+        $this->store->drop();
+        $this->store->setup();
+
+        $this->fixture = new \ARC2_StoreAskQueryHandler($this->store->a, $this->store);
+    }
+
+    public function tearDown(): void
+    {
+        $this->store->closeDBCon();
+    }
+
+    /*
+     * Tests for __init
+     */
+
+    public function test__init()
+    {
+        $this->fixture = new \ARC2_StoreAskQueryHandler($this->store->a, $this->store);
+        $this->fixture->__init();
+        $this->assertEquals($this->store, $this->fixture->store);
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/store/ARC2_StoreInsertQueryHandlerTest.php b/lib/arc2/tests/db_adapter_depended/store/ARC2_StoreInsertQueryHandlerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ab533d7dd213f0d1ecc03110782f11cf3f8d0e95
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/store/ARC2_StoreInsertQueryHandlerTest.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Tests\db_adapter_depended\store;
+
+use Tests\ARC2_TestCase;
+
+class ARC2_StoreInsertQueryHandlerTest extends ARC2_TestCase
+{
+    protected $store;
+
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->store = \ARC2::getStore($this->dbConfig);
+        $this->store->drop();
+        $this->store->setup();
+
+        $this->fixture = new \ARC2_StoreInsertQueryHandler($this->store->a, $this->store);
+    }
+
+    public function tearDown(): void
+    {
+        $this->store->closeDBCon();
+    }
+
+    /*
+     * Tests for __init
+     */
+
+    public function test__init()
+    {
+        $this->fixture = new \ARC2_StoreInsertQueryHandler($this->store->a, $this->store);
+        $this->fixture->__init();
+        $this->assertEquals($this->store, $this->fixture->store);
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/store/ARC2_StoreTest.php b/lib/arc2/tests/db_adapter_depended/store/ARC2_StoreTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2a70e4918f988ad702690300f962827292c9cdfb
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/store/ARC2_StoreTest.php
@@ -0,0 +1,785 @@
+<?php
+
+namespace Tests\db_adapter_depended\store;
+
+use Tests\ARC2_TestCase;
+
+class ARC2_StoreTest extends ARC2_TestCase
+{
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->fixture = \ARC2::getStore($this->dbConfig);
+        $this->fixture->createDBCon();
+
+        // remove all tables
+        $tables = $this->fixture->getDBObject()->fetchList('SHOW TABLES');
+        foreach($tables as $table) {
+            $this->fixture->getDBObject()->simpleQuery('DROP TABLE '. $table['Tables_in_'.$this->dbConfig['db_name']]);
+        }
+
+        // fresh setup of ARC2
+        $this->fixture->setup();
+    }
+
+    public function tearDown(): void
+    {
+        $this->fixture->closeDBCon();
+    }
+
+    /**
+     * Returns a list of all available graph URIs of the store. It can also respect access control,
+     * to only returned available graphs in the current context. But that depends on the implementation
+     * and can differ.
+     *
+     * @return array simple array of key-value-pairs, which consists of graph URIs as key and NamedNode
+     *               instance as value
+     */
+    protected function getGraphs()
+    {
+        // g2t table
+        if (isset($this->dbConfig['db_table_prefix'])) {
+            $g2t = $this->dbConfig['db_table_prefix'] . '_';
+        } else {
+            $g2t = '';
+        }
+        if (isset($this->dbConfig['store_name'])) {
+            $g2t .= $this->dbConfig['store_name'] . '_';
+        }
+        $g2t .= 'g2t';
+
+        // id2val table
+        if (isset($this->dbConfig['db_table_prefix'])) {
+            $id2val = $this->dbConfig['db_table_prefix'] . '_';
+        } else {
+            $id2val = '';
+        }
+        if (isset($this->dbConfig['store_name'])) {
+            $id2val .= $this->dbConfig['store_name'] . '_';
+        }
+        $id2val .= 'id2val';
+
+        // collects all values which have an ID (column g) in the g2t table.
+        $query = 'SELECT id2val.val AS graphUri
+            FROM '.$g2t.' g2t
+            LEFT JOIN '.$id2val.' id2val ON g2t.g = id2val.id
+            GROUP BY g';
+
+        // send SQL query
+        $list = $this->fixture->getDBObject()->fetchList($query);
+        $graphs = [];
+
+        // collect graph URI's
+        foreach($list as $row) {
+            $graphs[] = $row['graphUri'];
+        }
+
+        return $graphs;
+    }
+
+    /**
+     * @doesNotPerformAssertions
+     */
+    public function testSetup()
+    {
+        $this->fixture->reset();
+
+        $this->fixture->setup();
+    }
+
+    /*
+     * Tests for caching behavior
+     */
+
+    public function testCaching()
+    {
+        if (false == $this->fixture->cacheEnabled()) {
+            $this->markTestSkipped('Skip tests of ARC2_Store caching, because cache is not enabled.');
+        }
+
+        // add test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+        }');
+
+        $selectQuery = 'SELECT * FROM <http://example.com/> {?s ?p ?o.}';
+
+        // check that query is not known in cache
+        $this->assertFalse($this->dbConfig['cache_instance']->has(\hash('sha1', $selectQuery)));
+
+        $result = $this->fixture->query($selectQuery);
+        unset($result['query_time']);
+        $this->assertEquals(1, \count($result['result']['rows']));
+
+        $this->assertTrue($this->dbConfig['cache_instance']->has(\hash('sha1', $selectQuery)));
+
+        // compare cached and raw result
+        $cachedResult = $this->fixture->query($selectQuery);
+        unset($cachedResult['query_time']);
+        $this->assertEquals($result, $cachedResult);
+    }
+
+    /*
+     * Tests for changeNamespaceURI
+     */
+
+    public function testChangeNamespaceURIEmptyStore()
+    {
+        $res = $this->fixture->changeNamespaceURI(
+            'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
+            'urn:rdf'
+        );
+
+        $this->assertEquals(
+            [
+                'id_replacements' => 0,
+                'triple_updates' => 0,
+            ],
+            $res
+        );
+    }
+
+    public function testChangeNamespaceURIFilledStore()
+    {
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://pref/s> <http://pref/p1> "baz" .
+        }');
+
+        $res = $this->fixture->changeNamespaceURI(
+            'http://pref/',
+            'urn:rdf'
+        );
+
+        $this->assertEquals(
+            [
+                'id_replacements' => 2,
+                'triple_updates' => 0,
+            ],
+            $res
+        );
+    }
+
+    /*
+     * Tests for countDBProcesses
+     */
+
+    public function testCountDBProcesses()
+    {
+        $this->assertTrue(is_integer($this->fixture->countDBProcesses()));
+    }
+
+    /*
+     * Tests for createBackup
+     */
+
+    public function testCreateBackup()
+    {
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+        }');
+
+        $this->fixture->createBackup('/tmp/backup.txt');
+
+        $expectedXML = <<<XML
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="s"/>
+    <variable name="p"/>
+    <variable name="o"/>
+    <variable name="g"/>
+  </head>
+  <results>
+    <result>
+      <binding name="s">
+        <uri>http://s</uri>
+      </binding>
+      <binding name="p">
+        <uri>http://p1</uri>
+      </binding>
+      <binding name="o">
+        <literal>baz</literal>
+      </binding>
+      <binding name="g">
+        <uri>http://example.com/</uri>
+      </binding>
+    </result>
+  </results>
+</sparql>
+
+XML;
+        $this->assertEquals(file_get_contents('/tmp/backup.txt'), $expectedXML);
+    }
+
+    /*
+     * Tests for closeDBCon
+     */
+
+    public function testCloseDBCon()
+    {
+        $this->assertTrue(isset($this->fixture->a['db_object']));
+
+        $this->fixture->closeDBCon();
+
+        $this->assertFalse(isset($this->fixture->a['db_object']));
+    }
+
+    /*
+     * Tests for delete
+     */
+
+    public function testDelete()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+            <http://s> <http://xmlns.com/foaf/0.1/name> "label1" .
+        }');
+
+        $res = $this->fixture->query('SELECT * WHERE {?s ?p ?o.}');
+        $this->assertEquals(2, \count($res['result']['rows']));
+
+        // remove graph
+        $this->fixture->delete(false, 'http://example.com/');
+
+        $res = $this->fixture->query('SELECT * WHERE {?s ?p ?o.}');
+        $this->assertEquals(0, \count($res['result']['rows']));
+    }
+
+    /*
+     * Tests for drop
+     */
+
+    public function testDrop()
+    {
+        // make sure all tables were created
+        $this->fixture->setup();
+        $tables = $this->fixture->getDBObject()->fetchList('SHOW TABLES');
+        $this->assertEquals(6, \count($tables));
+
+        // remove all tables
+        $this->fixture->drop();
+
+        // check that all tables were removed
+        $tables = $this->fixture->getDBObject()->fetchList('SHOW TABLES');
+        $this->assertEquals(0, \count($tables));
+    }
+
+    /*
+     * Tests for dump
+     */
+
+    public function testDump()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+        }');
+
+        // fixed dump call using error_reporting to avoid
+        // Cannot modify header information - headers already sent by (output started at
+        // ./vendor/phpunit/phpunit/src/Util/Printer.php:110)
+        // thanks to https://github.com/sebastianbergmann/phpunit/issues/720#issuecomment-364024753
+        error_reporting(0);
+        ob_start();
+        $this->fixture->dump();
+        $dumpContent = ob_get_clean();
+        error_reporting(E_ALL);
+
+        $expectedXML = <<<XML
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="s"/>
+    <variable name="p"/>
+    <variable name="o"/>
+    <variable name="g"/>
+  </head>
+  <results>
+    <result>
+      <binding name="s">
+        <uri>http://s</uri>
+      </binding>
+      <binding name="p">
+        <uri>http://p1</uri>
+      </binding>
+      <binding name="o">
+        <literal>baz</literal>
+      </binding>
+      <binding name="g">
+        <uri>http://example.com/</uri>
+      </binding>
+    </result>
+  </results>
+</sparql>
+
+XML;
+        $this->assertEquals($expectedXML, $dumpContent);
+    }
+
+    /*
+     * Tests for enableFulltextSearch
+     */
+
+    public function testEnableFulltextSearch()
+    {
+        $res1 = $this->fixture->enableFulltextSearch();
+        $res2 = $this->fixture->disableFulltextSearch();
+
+        $this->assertNull($res1);
+        $this->assertEquals(1, $res2);
+
+        $this->assertEquals(0, $this->fixture->a['db_object']->getErrorCode());
+        $this->assertEquals('', $this->fixture->a['db_object']->getErrorMessage());
+    }
+
+    /*
+     * Tests for getDBVersion
+     */
+
+    // just check pattern
+    public function testGetDBVersion()
+    {
+        $result = preg_match('/[0-9]{2}-[0-9]{2}-[0-9]{2}/', $this->fixture->getDBVersion(), $match);
+        $this->assertEquals(1, $result);
+    }
+
+    /*
+     * Tests for getDBCon
+     */
+
+    public function testGetDBCon()
+    {
+        // TODO use a different check, if mariadb or mysql is used
+        $this->assertTrue(false !== $this->fixture->getDBCon());
+    }
+
+    /*
+     * Tests for getSetting and setSetting
+     */
+
+    public function testGetAndSetSetting()
+    {
+        $this->assertEquals(0, $this->fixture->getSetting('foo'));
+
+        $this->fixture->setSetting('foo', 'bar');
+
+        $this->assertEquals('bar', $this->fixture->getSetting('foo'));
+    }
+
+    public function testGetAndSetSettingUseDefault()
+    {
+        $this->assertEquals('no-entry', $this->fixture->getSetting('not-available-'.time(), 'no-entry'));
+    }
+
+    public function testGetAndSetSettingExistingSetting()
+    {
+        $this->assertEquals(0, $this->fixture->getSetting('foo'));
+
+        $this->fixture->setSetting('foo', 'bar');
+        $this->fixture->setSetting('foo', 'bar2'); // overrides existing setting
+
+        $this->assertEquals('bar2', $this->fixture->getSetting('foo'));
+    }
+
+    /*
+     * Tests for getLabelProps
+     */
+
+    public function testGetLabelProps()
+    {
+        $this->assertEquals(
+            [
+                'http://www.w3.org/2000/01/rdf-schema#label',
+                'http://xmlns.com/foaf/0.1/name',
+                'http://purl.org/dc/elements/1.1/title',
+                'http://purl.org/rss/1.0/title',
+                'http://www.w3.org/2004/02/skos/core#prefLabel',
+                'http://xmlns.com/foaf/0.1/nick',
+            ],
+            $this->fixture->getLabelProps()
+        );
+    }
+
+    /*
+     * Tests for getResourceLabel
+     */
+
+    public function testGetResourceLabel()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+            <http://s> <http://xmlns.com/foaf/0.1/name> "label1" .
+        }');
+
+        $res = $this->fixture->getResourceLabel('http://s');
+
+        $this->assertEquals('label1', $res);
+    }
+
+    public function testGetResourceLabelNoData()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+        }');
+
+        $res = $this->fixture->getResourceLabel('http://s');
+
+        $this->assertEquals('s', $res);
+    }
+
+    /*
+     * Tests for getResourcePredicates
+     */
+
+    public function testGetResourcePredicates()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+            <http://s> <http://p2> "bar" .
+        }');
+
+        $res = $this->fixture->getResourcePredicates('http://s');
+
+        $this->assertEquals(
+            [
+                'http://p1' => [],
+                'http://p2' => [],
+            ],
+            $res
+        );
+    }
+
+    public function testGetResourcePredicatesMultipleGraphs()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+            <http://s> <http://p2> "bar" .
+        }');
+
+        $this->fixture->query('INSERT INTO <http://example.com/2> {
+            <http://s> <http://p3> "baz" .
+            <http://s> <http://p4> "bar" .
+        }');
+
+        $res = $this->fixture->getResourcePredicates('http://s');
+
+        $this->assertEquals(
+            [
+                'http://p1' => [],
+                'http://p2' => [],
+                'http://p3' => [],
+                'http://p4' => [],
+            ],
+            $res
+        );
+    }
+
+    /*
+     * Tests for getPredicateRange
+     */
+
+    public function testGetPredicateRange()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://p1> <http://www.w3.org/2000/01/rdf-schema#range> <http://foobar> .
+        }');
+
+        $res = $this->fixture->getPredicateRange('http://p1');
+
+        $this->assertEquals('http://foobar', $res);
+    }
+
+    public function testGetPredicateRangeNotFound()
+    {
+        $res = $this->fixture->getPredicateRange('http://not-available');
+
+        $this->assertEquals('', $res);
+    }
+
+    /*
+     * Tests for getIDValue
+     */
+
+    public function testGetIDValue()
+    {
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://p1> <http://www.w3.org/2000/01/rdf-schema#range> <http://foobar> .
+        }');
+
+        $res = $this->fixture->getIDValue(1);
+
+        $this->assertEquals('http://example.com/', $res);
+    }
+
+    public function testGetIDValueNoData()
+    {
+        $res = $this->fixture->getIDValue(1);
+
+        $this->assertEquals(0, $res);
+    }
+
+    /**
+     * Saft frameworks ARC2 addition fails to run with ARC2 2.4.
+     *
+     * https://github.com/SaftIng/Saft/tree/master/src/Saft/Addition/ARC2
+     */
+    public function testInsertSaftRegressionTest1()
+    {
+        $res = $this->fixture->query('SELECT * FROM <http://example.com/> WHERE { ?s ?p ?o. } ');
+        $this->assertEquals(0, count($res['result']['rows']));
+
+        $this->fixture->insert(
+            file_get_contents(__DIR__.'/../../data/nt/saft-arc2-addition-regression1.nt'),
+            'http://example.com/'
+        );
+
+        $res1 = $this->fixture->query('SELECT * FROM <http://example.com/> WHERE { ?s ?p ?o. } ');
+        $this->assertEquals(442, count($res1['result']['rows']));
+
+        $res2 = $this->fixture->query('SELECT * WHERE { ?s ?p ?o. } ');
+        $this->assertEquals(442, count($res2['result']['rows']));
+    }
+
+    /**
+     * Saft frameworks ARC2 addition fails to run with ARC2 2.4.
+     *
+     * https://github.com/SaftIng/Saft/tree/master/src/Saft/Addition/ARC2
+     *
+     * This tests checks gathering of freshly created resources.
+     */
+    public function testInsertSaftRegressionTest2()
+    {
+        $res = $this->fixture->query('INSERT INTO <http://localhost/Saft/TestGraph/> {<http://foo/1> <http://foo/2> <http://foo/3> . }');
+
+        $res1 = $this->fixture->query('SELECT * FROM <http://localhost/Saft/TestGraph/> WHERE {?s ?p ?o.}');
+        $this->assertEquals(1, count($res1['result']['rows']));
+
+        $res2 = $this->fixture->query('SELECT * WHERE {?s ?p ?o.}');
+        $this->assertEquals(1, count($res2['result']['rows']));
+
+        $res2 = $this->fixture->query('SELECT ?s ?p ?o WHERE {?s ?p ?o.}');
+        $this->assertEquals(1, count($res2['result']['rows']));
+    }
+
+    /**
+     * Saft frameworks ARC2 addition fails to run with ARC2 2.4.
+     *
+     * This test checks side effects of update operations on different graphs.
+     *
+     * We add 1 triple to 1 and another to another graph. Afterwards removing the first graph.
+     * In the end should the second graph still containg his triple.
+     */
+    public function testInsertSaftRegressionTest3()
+    {
+        $this->fixture->query(
+            'INSERT INTO <http://localhost/Saft/TestGraph/> {<http://localhost/Saft/TestGraph/> <http://localhost/Saft/TestGraph/> <http://localhost/Saft/TestGraph/> . }'
+        );
+        $this->fixture->query(
+            'INSERT INTO <http://second-graph/> {<http://second-graph/0> <http://second-graph/1> <http://second-graph/2> . }'
+        );
+        $this->fixture->query(
+            'DELETE FROM <http://localhost/Saft/TestGraph/>'
+        );
+
+        $res = $this->fixture->query('SELECT * FROM <http://second-graph/> WHERE {?s ?p ?o.}');
+        $this->assertEquals(1, count($res['result']['rows']));
+    }
+
+    public function testMultipleInsertQuerysInDifferentGraphs()
+    {
+        $this->markTestSkipped(
+            'Adding the same triple into two graphs does not work.'
+            . PHP_EOL . 'Bug report: https://github.com/semsol/arc2/issues/114'
+        );
+
+        /*
+         * the following checks will not go through because of the bug in #114
+         */
+
+        $this->fixture->query('INSERT INTO <http://graph1/> {<http://foo/1> <http://foo/2> <http://foo/3> . }');
+        $this->fixture->query('INSERT INTO <http://graph2/> {<http://foo/4> <http://foo/5> <http://foo/6> . }');
+        $this->fixture->query('INSERT INTO <http://graph2/> {<http://foo/a> <http://foo/b> <http://foo/c> . }');
+
+        $res = $this->fixture->query('SELECT * FROM <http://graph1/> WHERE {?s ?p ?o.}');
+        $this->assertEquals(1, count($res['result']['rows']));
+
+        $res = $this->fixture->query('SELECT * FROM <http://graph2/> WHERE {?s ?p ?o.}');
+        $this->assertEquals(2, count($res['result']['rows']));
+
+        $res = $this->fixture->query('SELECT * WHERE {?s ?p ?o.}');
+        $this->assertEquals(3, count($res['result']['rows']));
+    }
+
+    /*
+     * Tests for logQuery
+     */
+
+    public function testLogQuery()
+    {
+        $logFile = 'arc_query_log.txt';
+
+        $this->assertFalse(file_exists($logFile));
+
+        $this->fixture->logQuery('query1');
+
+        $this->assertTrue(file_exists($logFile));
+        unlink($logFile);
+    }
+
+    /*
+     * Tests for renameTo
+     */
+
+    public function testRenameTo()
+    {
+        /*
+         * remove all tables
+         */
+        $tables = $this->fixture->getDBObject()->fetchList('SHOW TABLES');
+        foreach($tables as $table) {
+            $this->fixture->getDBObject()->simpleQuery('DROP TABLE '. $table['Tables_in_'.$this->fixture->a['db_name']]);
+        }
+
+        /*
+         * create fresh store and check tables
+         */
+        $this->fixture->setup();
+
+        $tables = $this->fixture->getDBObject()->fetchList('SHOW TABLES');
+        foreach($tables as $table) {
+            $this->assertTrue(
+                false !== strpos($table['Tables_in_'.$this->fixture->a['db_name']], $this->dbConfig['db_table_prefix'].'_')
+            );
+        }
+
+        /*
+         * rename store
+         */
+        $prefix = 'new_store';
+        $this->fixture->renameTo($prefix);
+
+        /*
+         * check for new prefixes
+         */
+        $tables = $this->fixture->getDBObject()->fetchList('SHOW TABLES');
+        foreach($tables as $table) {
+            $this->assertTrue(
+                false !== strpos($table['Tables_in_'.$this->fixture->a['db_name']], $prefix)
+            );
+        }
+    }
+
+    /*
+     * Tests for replace
+     */
+
+    public function testReplace()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://original/> {
+            <http://s> <http://p1> "baz" .
+            <http://s> <http://xmlns.com/foaf/0.1/name> "label1" .
+        }');
+
+        $res = $this->fixture->query('SELECT * WHERE {?s ?p ?o.}');
+        $this->assertEquals(2, \count($res['result']['rows']));
+
+        $this->assertEquals(
+            [
+                'http://original/'
+            ],
+            $this->getGraphs()
+        );
+
+        // replace graph
+        $returnVal = $this->fixture->replace(false, 'http://original/', 'http://replacement/');
+
+        // check triples
+        $res = $this->fixture->query('SELECT * FROM <http://original/> WHERE {?s ?p ?o.}');
+        $this->assertEquals(0, \count($res['result']['rows']));
+
+        // get available graphs
+        $this->assertEquals(0, \count($this->getGraphs()));
+
+        $res = $this->fixture->query('SELECT * FROM <http://replacement/> WHERE {?s ?p ?o.}');
+        // TODO this does not makes sense, why are there no triples?
+        $this->assertEquals(0, \count($res['result']['rows']));
+
+        $res = $this->fixture->query('SELECT * WHERE {?s ?p ?o.}');
+        // TODO this does not makes sense, why are there no triples?
+        $this->assertEquals(0, \count($res['result']['rows']));
+
+        // check return value
+        $this->assertEquals(
+            [
+                [
+                    't_count' => 2,
+                    'delete_time' => $returnVal[0]['delete_time'],
+                    'index_update_time' => $returnVal[0]['index_update_time']
+                ],
+                false
+            ],
+            $returnVal
+        );
+    }
+
+    /*
+     * Tests for replicateTo
+     */
+
+    public function testReplicateTo()
+    {
+        if ('05-06' == substr($this->fixture->getDBVersion(), 0, 5)) {
+            $this->markTestSkipped('With MySQL 5.6 ARC2_Store::replicateTo does not work. Tables keep their names.');
+        }
+
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "2009-05-28T18:03:38+09:00" .
+            <http://s> <http://p1> "2009-05-28T18:03:38+09:00GMT" .
+            <http://s> <http://p1> "21 August 2007" .
+        }');
+
+        // replicate
+        $this->fixture->replicateTo('replicate');
+
+        /*
+         * check for new prefixes
+         */
+        $tables = $this->fixture->getDBObject()->fetchList('SHOW TABLES');
+        $foundArcPrefix = $foundReplicatePrefix = false;
+        foreach($tables as $table) {
+            // check for original table
+            if (false !== strpos($table['Tables_in_'.$this->dbConfig['db_name']], $this->dbConfig['store_name'].'_')) {
+                $foundArcPrefix = true;
+            // check for replicated table
+            } elseif (false !== strpos($table['Tables_in_'.$this->dbConfig['db_name']], 'replicate_')) {
+                $foundReplicatePrefix = true;
+            }
+        }
+
+        $this->assertTrue($foundArcPrefix);
+        $this->assertTrue($foundReplicatePrefix);
+    }
+
+    /*
+     * Tests for reset
+     */
+
+    public function testResetKeepSettings()
+    {
+        $this->fixture->setSetting('foo', 'bar');
+        $this->assertEquals(1, $this->fixture->hasSetting('foo'));
+
+        $this->fixture->reset(1);
+
+        $this->assertEquals(1, $this->fixture->hasSetting('foo'));
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/store/query/AskQueryTest.php b/lib/arc2/tests/db_adapter_depended/store/query/AskQueryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..cfa29b9ce23a159c764e656ec109d2ea522f0aab
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/store/query/AskQueryTest.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace Tests\db_adapter_depended\store\query;
+
+use Tests\ARC2_TestCase;
+
+/**
+ * Tests for query method - focus on ASK queries
+ */
+class AskQueryTest extends ARC2_TestCase
+{
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->fixture = \ARC2::getStore($this->dbConfig);
+        $this->fixture->drop();
+        $this->fixture->setup();
+    }
+
+    public function tearDown(): void
+    {
+        $this->fixture->closeDBCon();
+    }
+
+    public function testAskDefaultGraph()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+        }');
+
+        $res = $this->fixture->query('ASK {<http://s> <http://p1> ?o.}');
+        $this->assertEquals(
+            [
+                'query_type' => 'ask',
+                'result' => true,
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    public function testAskGraphSpecified()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+        }');
+
+        $res = $this->fixture->query('ASK FROM <http://example.com/> {<http://s> <http://p1> ?o.}');
+        $this->assertEquals(
+            [
+                'query_type' => 'ask',
+                'result' => true,
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/store/query/DeleteQueryTest.php b/lib/arc2/tests/db_adapter_depended/store/query/DeleteQueryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c6a8d2e6ae3e29236bc1ea356828f3c69f4643ff
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/store/query/DeleteQueryTest.php
@@ -0,0 +1,142 @@
+<?php
+
+namespace Tests\db_adapter_depended\store\query;
+
+use Tests\ARC2_TestCase;
+
+/**
+ * Tests for query method - focus on DELETE queries
+ */
+class DeleteQueryTest extends ARC2_TestCase
+{
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->fixture = \ARC2::getStore($this->dbConfig);
+        $this->fixture->drop();
+        $this->fixture->setup();
+    }
+
+    public function tearDown(): void
+    {
+        $this->fixture->closeDBCon();
+    }
+
+    protected function runSPOQuery($g = null)
+    {
+        return null == $g
+            ? $this->fixture->query('SELECT * WHERE {?s ?p ?o.}')
+            : $this->fixture->query('SELECT * FROM <'.$g.'> WHERE {?s ?p ?o.}');
+    }
+
+    public function testDelete()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/1> {
+            <http://s> <http://p1> "baz" .
+        }');
+        $this->fixture->query('INSERT INTO <http://example.com/2> {
+            <http://s> <http://p1> "bar" .
+        }');
+
+        $this->assertEquals(2, \count($this->runSPOQuery()['result']['rows']));
+
+        $this->fixture->query('DELETE {<http://s> ?p ?o .}');
+
+        $this->assertEquals(0, \count($this->runSPOQuery()['result']['rows']));
+    }
+
+    public function testDelete2()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/1> {
+            <http://s> <http://p1> "baz" .
+        }');
+        $this->fixture->query('INSERT INTO <http://example.com/2> {
+            <http://s> <http://p2> "bar" .
+        }');
+
+        $this->assertEquals(2, \count($this->runSPOQuery()['result']['rows']));
+
+        $this->fixture->query('DELETE {<http://s> <http://p1> ?o .}');
+
+        $this->assertEquals(1, \count($this->runSPOQuery()['result']['rows']));
+    }
+
+    public function testDeleteAGraph()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/1> {
+            <http://s> <http://p1> "baz" .
+        }');
+
+        $this->assertEquals(1, \count($this->runSPOQuery()['result']['rows']));
+
+        $this->fixture->query('DELETE FROM <http://example.com/1>');
+
+        $this->assertEquals(0, \count($this->runSPOQuery()['result']['rows']));
+    }
+
+    public function testDeleteWhere()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/1> {
+            <http://s> <http://to-delete> 1, 2 .
+            <http://s> <http://to-check> 1, 2 .
+            <http://s> rdf:type <http://Test> .
+        }');
+
+        $this->assertEquals(5, \count($this->runSPOQuery()['result']['rows']));
+
+        $this->fixture->query('DELETE {
+            <http://s> <http://to-delete> 1, 2 .
+        } WHERE {
+            <http://s> <http://to-check> 1, 2 .
+        }');
+
+        $this->assertEquals(3, \count($this->runSPOQuery()['result']['rows']));
+    }
+
+    public function testDeleteWhereWithBlankNode()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/1> {
+            _:a <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://Person> ;
+                <http://foo> <http://bar > .
+        }');
+
+        $this->assertEquals(2, \count($this->runSPOQuery()['result']['rows']));
+
+        $this->fixture->query('DELETE {
+            _:a ?p ?o .
+        } WHERE {
+            _:a <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://Person> .
+        }');
+
+        // first we check the expected behavior and afterwards skip to notice the
+        // developer about it.
+        $this->assertEquals(2, \count($this->runSPOQuery()['result']['rows']));
+        $this->markTestSkipped('DELETE queries with blank nodes are not working.');
+    }
+
+    public function testDeleteFromWhere()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/1> {
+            <http://s> <http://to-delete> 1, 2 .
+            <http://s> <http://to-check> 1, 2 .
+            <http://s> rdf:type <http://Test> .
+        }');
+
+        $this->assertEquals(5, \count($this->runSPOQuery('http://example.com/1')['result']['rows']));
+
+        $this->fixture->query('DELETE FROM <http://example.com/1> {
+            <http://s> <http://to-delete> 1, 2 .
+        } WHERE {
+            <http://s> <http://to-check> 1, 2 .
+        }');
+
+        $this->assertEquals(3, \count($this->runSPOQuery('http://example.com/1')['result']['rows']));
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/store/query/DescribeQueryTest.php b/lib/arc2/tests/db_adapter_depended/store/query/DescribeQueryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..433669aec59da9f633776a7e283f9444db1ef1a2
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/store/query/DescribeQueryTest.php
@@ -0,0 +1,106 @@
+<?php
+
+namespace Tests\db_adapter_depended\store\query;
+
+use Tests\ARC2_TestCase;
+
+/**
+ * Tests for query method - focus on DESCRIBE queries
+ */
+class DescribeQueryTest extends ARC2_TestCase
+{
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->fixture = \ARC2::getStore($this->dbConfig);
+        $this->fixture->drop();
+        $this->fixture->setup();
+    }
+
+    public function tearDown(): void
+    {
+        $this->fixture->closeDBCon();
+    }
+
+    public function testDescribeDefaultGraph()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+        }');
+
+        $res = $this->fixture->query('DESCRIBE <http://s>');
+        $this->assertEquals(
+            [
+                'query_type' => 'describe',
+                'result' => [
+                    'http://s' => [
+                        'http://p1' => [
+                            [
+                                'value' => 'baz',
+                                'type' => 'literal'
+                            ]
+                        ]
+                    ]
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    public function testDescribeWhereDefaultGraph()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+        }');
+
+        $res = $this->fixture->query('DESCRIBE ?s WHERE {?s ?p "baz".}');
+        $this->assertEquals(
+            [
+                'query_type' => 'describe',
+                'result' => [
+                    'http://s' => [
+                        'http://p1' => [
+                            [
+                                'value' => 'baz',
+                                'type' => 'literal'
+                            ]
+                        ]
+                    ]
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    public function testDescribeWhereDefaultGraph2()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+        }');
+
+        $res = $this->fixture->query('DESCRIBE * WHERE {?s ?p "baz".}');
+        $this->assertEquals(
+            [
+                'query_type' => 'describe',
+                'result' => [
+                    'http://s' => [
+                        'http://p1' => [
+                            [
+                                'value' => 'baz',
+                                'type' => 'literal'
+                            ]
+                        ]
+                    ]
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/store/query/ErrorHandlingInQueriesTest.php b/lib/arc2/tests/db_adapter_depended/store/query/ErrorHandlingInQueriesTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6c9eaab47303f7dd21190ecbd1ff162649cf6e50
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/store/query/ErrorHandlingInQueriesTest.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace Tests\db_adapter_depended\store\query;
+
+use Tests\ARC2_TestCase;
+
+/**
+ * Tests for query method - focus on how the system reacts, when errors occur.
+ */
+class ErrorHandlingInQueriesTest extends ARC2_TestCase
+{
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->fixture = \ARC2::getStore($this->dbConfig);
+        $this->fixture->drop();
+        $this->fixture->setup();
+    }
+
+    public function tearDown(): void
+    {
+        $this->fixture->closeDBCon();
+    }
+
+    /**
+     * What if a result variable is not used in query.
+     */
+    public function testResultVariableNotUsedInQuery()
+    {
+        $res = $this->fixture->query('
+            SELECT ?not_used_in_query ?s WHERE {
+                ?s ?p ?o .
+            }
+        ');
+
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        'not_used_in_query', 's'
+                    ],
+                    'rows' => [
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+
+        $this->assertTrue(2 <= count($this->fixture->errors));
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/store/query/InsertIntoQueryTest.php b/lib/arc2/tests/db_adapter_depended/store/query/InsertIntoQueryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..84c7704fbb352bc1a4393267ac261af07b50f571
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/store/query/InsertIntoQueryTest.php
@@ -0,0 +1,387 @@
+<?php
+
+namespace Tests\db_adapter_depended\store\query;
+
+use Tests\ARC2_TestCase;
+
+/**
+ * Tests for query method - focus on INSERT INTO queries
+ */
+class InsertIntoQueryTest extends ARC2_TestCase
+{
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->fixture = \ARC2::getStore($this->dbConfig);
+        $this->fixture->drop();
+        $this->fixture->setup();
+    }
+
+    public function tearDown(): void
+    {
+        $this->fixture->closeDBCon();
+    }
+
+    public function testInsertInto()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+        }');
+
+        $res = $this->fixture->query('SELECT * FROM <http://example.com/> {?s ?p ?o.}');
+        $this->assertEquals(1, \count($res['result']['rows']));
+    }
+
+    public function testInsertIntoAllKindsOfTriples()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> <http://o> .
+            <#make> <#me> <#happy> .
+            <http://s2> rdf:type <http://Person> .
+            <http://s2> <http://foo> 1 .
+            <http://s2> <http://foo> 2.0 .
+            <http://s2> <http://foo> "3" .
+            <http://s2> <http://foo> "4"^^xsd:integer .
+            <http://s2> <http://foo> "5"@en .
+            _:foo <http://foo> "6" .
+        }');
+
+        $res = $this->fixture->query('SELECT * FROM <http://example.com/> {?s ?p ?o.}');
+
+        // using <#foo> in query makes ARC2 using the phpunit path as prefix
+        // e.g. file:///var/www/html/pier-and-peer/ARC2/vendor/phpunit/phpunit/phpunit#
+        // therefore we build this prefix manually to check later
+        $filePrefix = 'file://'.str_replace('tests/db_adapter_depended/store/query', '', __DIR__);
+        $filePrefix .= 'vendor/phpunit/phpunit/phpunit#';
+
+        $this->assertEquals(
+            [
+                [
+                    's' => 'http://s',
+                    's type' => 'uri',
+                    'p' => 'http://p1',
+                    'p type' => 'uri',
+                    'o' => 'http://o',
+                    'o type' => 'uri',
+                ],
+                [
+                    's' => $filePrefix.'make',
+                    's type' => 'uri',
+                    'p' => $filePrefix.'me',
+                    'p type' => 'uri',
+                    'o' => $filePrefix.'happy',
+                    'o type' => 'uri',
+                ],
+                [
+                    's' => 'http://s2',
+                    's type' => 'uri',
+                    'p' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
+                    'p type' => 'uri',
+                    'o' => 'http://Person',
+                    'o type' => 'uri',
+                ],
+                [
+                    's' => 'http://s2',
+                    's type' => 'uri',
+                    'p' => 'http://foo',
+                    'p type' => 'uri',
+                    'o' => '1',
+                    'o type' => 'literal',
+                    'o datatype' => 'http://www.w3.org/2001/XMLSchema#integer',
+                ],
+                [
+                    's' => 'http://s2',
+                    's type' => 'uri',
+                    'p' => 'http://foo',
+                    'p type' => 'uri',
+                    'o' => '2.0',
+                    'o type' => 'literal',
+                    'o datatype' => 'http://www.w3.org/2001/XMLSchema#decimal',
+                ],
+                [
+                    's' => 'http://s2',
+                    's type' => 'uri',
+                    'p' => 'http://foo',
+                    'p type' => 'uri',
+                    'o' => '3',
+                    'o type' => 'literal',
+                ],
+                [
+                    's' => 'http://s2',
+                    's type' => 'uri',
+                    'p' => 'http://foo',
+                    'p type' => 'uri',
+                    'o' => '4',
+                    'o type' => 'literal',
+                    'o datatype' => 'http://www.w3.org/2001/XMLSchema#integer',
+                ],
+                [
+                    's' => 'http://s2',
+                    's type' => 'uri',
+                    'p' => 'http://foo',
+                    'p type' => 'uri',
+                    'o' => '5',
+                    'o type' => 'literal',
+                    'o lang' => 'en',
+                ],
+                [
+                    's' => $res['result']['rows'][8]['s'],
+                    's type' => 'bnode',
+                    'p' => 'http://foo',
+                    'p type' => 'uri',
+                    'o' => '6',
+                    'o type' => 'literal',
+                ],
+            ],
+            $res['result']['rows']
+        );
+    }
+
+    public function testInsertIntoBlankNode()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> [
+                <http://foo> <http://bar>
+            ] .
+        }');
+
+        $res = $this->fixture->query('SELECT * FROM <http://example.com/> {?s ?p ?o.}');
+
+        // because bnode ID is random, we check only its structure
+        $this->assertTrue(isset($res['result']['rows'][0]));
+        $this->assertEquals(1, preg_match('/_:[a-z0-9]+_[a-z0-9]+/', $res['result']['rows'][0]['o']));
+
+        $this->assertEquals(
+            [
+                [
+                    's' => 'http://s',
+                    's type' => 'uri',
+                    'p' => 'http://p1',
+                    'p type' => 'uri',
+                    'o' => $res['result']['rows'][0]['o'],
+                    'o type' => 'bnode',
+                ],
+                [
+                    's' => $res['result']['rows'][0]['o'],
+                    's type' => 'bnode',
+                    'p' => 'http://foo',
+                    'p type' => 'uri',
+                    'o' => 'http://bar',
+                    'o type' => 'uri',
+                ],
+            ],
+            $res['result']['rows']
+        );
+    }
+
+    public function testInsertIntoDate()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "2009-05-28T18:03:38+09:00" .
+            <http://s> <http://p1> "2009-05-28T18:03:38+09:00GMT" .
+            <http://s> <http://p1> "21 August 2007" .
+        }');
+
+        $res = $this->fixture->query('SELECT * FROM <http://example.com/> {?s ?p ?o.}');
+
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => ['s', 'p', 'o'],
+                    'rows' => [
+                        [
+                            's' => 'http://s',
+                            's type' => 'uri',
+                            'p' => 'http://p1',
+                            'p type' => 'uri',
+                            'o' => '2009-05-28T18:03:38+09:00',
+                            'o type' => 'literal',
+                        ],
+                        [
+                            's' => 'http://s',
+                            's type' => 'uri',
+                            'p' => 'http://p1',
+                            'p type' => 'uri',
+                            'o' => '2009-05-28T18:03:38+09:00GMT',
+                            'o type' => 'literal',
+                        ],
+                        [
+                            's' => 'http://s',
+                            's type' => 'uri',
+                            'p' => 'http://p1',
+                            'p type' => 'uri',
+                            'o' => '21 August 2007',
+                            'o type' => 'literal',
+                        ],
+                    ]
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    public function testInsertIntoList()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> 1, 2, 3 .
+        }');
+
+        $res = $this->fixture->query('SELECT * FROM <http://example.com/> {?s ?p ?o.}');
+
+        $this->assertEquals(
+            [
+                [
+                    's' => 'http://s',
+                    's type' => 'uri',
+                    'p' => 'http://p1',
+                    'p type' => 'uri',
+                    'o' => '1',
+                    'o type' => 'literal',
+                    'o datatype' => 'http://www.w3.org/2001/XMLSchema#integer',
+                ],
+                [
+                    's' => 'http://s',
+                    's type' => 'uri',
+                    'p' => 'http://p1',
+                    'p type' => 'uri',
+                    'o' => '2',
+                    'o type' => 'literal',
+                    'o datatype' => 'http://www.w3.org/2001/XMLSchema#integer',
+                ],
+                [
+                    's' => 'http://s',
+                    's type' => 'uri',
+                    'p' => 'http://p1',
+                    'p type' => 'uri',
+                    'o' => '3',
+                    'o type' => 'literal',
+                    'o datatype' => 'http://www.w3.org/2001/XMLSchema#integer',
+                ],
+            ],
+            $res['result']['rows']
+        );
+    }
+
+    // show that ARC2 can't store long values
+    public function testInsertIntoLongValue()
+    {
+        // create long URI (ca. 250 chars)
+        $longURI = 'http://'.hash('sha512', 'long')
+            .hash('sha512', 'URI');
+
+        // test data
+        $this->fixture->query('INSERT INTO <http://graph> {
+            <'.$longURI.'/s> <'.$longURI.'/p> <'.$longURI.'/o> ;
+                             <'.$longURI.'/p2> <'.$longURI.'/o2> .
+        ');
+
+        $res = $this->fixture->query('SELECT * {?s ?p ?o.}');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => ['s', 'p', 'o'],
+                    'rows' => []
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+
+        $this->markTestSkipped('ARC2 can not store long values, e.g. URIs with around 250 chars.');
+    }
+
+    public function testInsertIntoListMoreComplex()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            _:b0  rdf:first  1 ;
+                  rdf:rest   _:b1 .
+            _:b1  rdf:first  ?x ;
+                  rdf:rest   _:b2 .
+            _:b2  rdf:first  3 ;
+                  rdf:rest   rdf:nil .
+        }');
+
+        $res = $this->fixture->query('SELECT * FROM <http://example.com/> {?s ?p ?o.}');
+
+        $this->assertEquals(
+            [
+                [
+                    's' => $res['result']['rows'][0]['s'],
+                    's type' => 'bnode',
+                    'p' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first',
+                    'p type' => 'uri',
+                    'o' => '1',
+                    'o type' => 'literal',
+                    'o datatype' => 'http://www.w3.org/2001/XMLSchema#integer',
+                ],
+                [
+                    's' => $res['result']['rows'][1]['s'],
+                    's type' => 'bnode',
+                    'p' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest',
+                    'p type' => 'uri',
+                    'o' => $res['result']['rows'][1]['o'],
+                    'o type' => 'bnode',
+                ],
+                [
+                    's' => $res['result']['rows'][2]['s'],
+                    's type' => 'bnode',
+                    'p' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest',
+                    'p type' => 'uri',
+                    'o' => $res['result']['rows'][2]['o'],
+                    'o type' => 'bnode',
+                ],
+                [
+                    's' => $res['result']['rows'][3]['s'],
+                    's type' => 'bnode',
+                    'p' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first',
+                    'p type' => 'uri',
+                    'o' => '3',
+                    'o type' => 'literal',
+                    'o datatype' => 'http://www.w3.org/2001/XMLSchema#integer',
+                ],
+                [
+                    's' => $res['result']['rows'][4]['s'],
+                    's type' => 'bnode',
+                    'p' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest',
+                    'p type' => 'uri',
+                    'o' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil',
+                    'o type' => 'uri',
+                ],
+            ],
+            $res['result']['rows']
+        );
+    }
+
+    public function testInsertIntoWhere()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> CONSTRUCT {
+            <http://baz> <http://location> "Leipzig" .
+            <http://baz2> <http://location> "Grimma" .
+        } WHERE {
+            ?s <http://location> "Leipzig" .
+        }');
+
+        // we expect that 1 element gets added to the store, because of the WHERE clause.
+        // but ARC2 added none.
+        $res = $this->fixture->query('SELECT * FROM <http://example.com/> {?s ?p ?o.}');
+        $this->assertEquals(0, \count($res['result']['rows']));
+
+        $this->markTestSkipped(
+            'ARC2 does not check the WHERE clause when inserting data. No data added at all.'
+            .PHP_EOL
+            .PHP_EOL.'FYI: https://www.w3.org/Submission/SPARQL-Update/#sec_examples and '
+            .PHP_EOL.'https://github.com/semsol/arc2/wiki/SPARQL-#insert-example'
+        );
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/store/query/KnownNotWorkingSparqlQueriesTest.php b/lib/arc2/tests/db_adapter_depended/store/query/KnownNotWorkingSparqlQueriesTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6a11942011faf9469568396636a1a2ff9e47ecd7
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/store/query/KnownNotWorkingSparqlQueriesTest.php
@@ -0,0 +1,175 @@
+<?php
+
+namespace Tests\db_adapter_depended\store\query;
+
+use Tests\ARC2_TestCase;
+
+/**
+ * Tests for query method - focus on queries which are known to fail.
+ */
+class KnownNotWorkingSparqlQueriesTest extends ARC2_TestCase
+{
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->fixture = \ARC2::getStore($this->dbConfig);
+        $this->fixture->drop();
+        $this->fixture->setup();
+    }
+
+    public function tearDown(): void
+    {
+        $this->fixture->closeDBCon();
+    }
+
+    /**
+     * Variable alias
+     */
+    public function testSelectAlias()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT (?s AS ?s_alias) ?o FROM <http://example.com/> WHERE {?s <http://p1> ?o.}
+        ');
+
+        $this->assertEquals(0, $res);
+    }
+
+    /**
+     * FILTER: langMatches with *
+     *
+     * Based on the specification (https://www.w3.org/TR/rdf-sparql-query/#func-langMatches)
+     * langMatches with * has to return all entries with no language set.
+     */
+    public function testSelectFilterLangMatchesWithStar()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "foo" .
+            <http://s> <http://p1> "in de"@de .
+            <http://s> <http://p1> "in en"@en .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER langMatches (lang(?o), "*")
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => [],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    /**
+     * sameTerm
+     */
+    public function testSelectSameTerm()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://container1> <http://weight> "100" .
+            <http://container2> <http://weight> "100" .
+        }');
+
+        $res = $this->fixture->query('SELECT ?c1 ?c2 WHERE {
+            ?c1 ?weight ?w1.
+
+            ?c2 ?weight ?w2.
+
+            FILTER (sameTerm(?w1, ?w2))
+        }');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        'c1', 'c2'
+                    ],
+                    'rows' => [
+                        [
+                            'c1' => 'http://container1',
+                            'c1 type' => 'uri',
+                            'c2' => 'http://container1',
+                            'c2 type' => 'uri',
+                        ],
+                        [
+                            'c1' => 'http://container2',
+                            'c1 type' => 'uri',
+                            'c2' => 'http://container1',
+                            'c2 type' => 'uri',
+                        ],
+                        [
+                            'c1' => 'http://container1',
+                            'c1 type' => 'uri',
+                            'c2' => 'http://container2',
+                            'c2 type' => 'uri',
+                        ],
+                        [
+                            'c1' => 'http://container2',
+                            'c1 type' => 'uri',
+                            'c2' => 'http://container2',
+                            'c2 type' => 'uri',
+                        ],
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res,
+            '',
+            0,
+            10,
+            true
+        );
+
+        $this->markTestSkipped(
+            'ARC2: solving sameterm does not work properly. The result contains elements multiple times. '
+            . PHP_EOL . 'Expected behavior is described here: https://www.w3.org/TR/rdf-sparql-query/#func-sameTerm'
+        );
+    }
+
+    /**
+     * Sub Select
+     */
+    public function testSelectSubSelect()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://person1> <http://id> "1" .
+            <http://person3> <http://id> "3" .
+            <http://person2> <http://id> "2" .
+
+            <http://person1> <http://knows> <http://person2> .
+            <http://person2> <http://knows> <http://person3> .
+            <http://person3> <http://knows> <http://person2> .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT * WHERE {
+                {
+                    SELECT ?p WHERE {
+                        ?p <http://id> "1" .
+                    }
+                }
+                ?p <http://knows> ?who .
+            }
+        ');
+
+        $this->assertEquals(0, $res);
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/store/query/LoadQueryTest.php b/lib/arc2/tests/db_adapter_depended/store/query/LoadQueryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0ac34d138803fd20e7825eeb3409cea911954bbb
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/store/query/LoadQueryTest.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Tests\db_adapter_depended\store\query;
+
+use Tests\ARC2_TestCase;
+
+/**
+ * Tests for query method - focus on LOAD queries
+ */
+class LoadQueryTest extends ARC2_TestCase
+{
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->fixture = \ARC2::getStore($this->dbConfig);
+        $this->fixture->drop();
+        $this->fixture->setup();
+    }
+
+    public function tearDown(): void
+    {
+        $this->fixture->closeDBCon();
+    }
+
+    public function testLoad()
+    {
+        // check that store is empty
+        $res = $this->fixture->query('SELECT * WHERE {?s ?p ?o.}');
+        $this->assertEquals(0, count($res['result']['rows']));
+
+        $filepath = 'https://raw.githubusercontent.com/semsol/arc2/'
+            .'master/tests/data/turtle/manifest.ttl';
+        $this->fixture->query('LOAD <'.$filepath.'>');
+
+        // check that triples were inserted
+        $res = $this->fixture->query('
+            SELECT *
+            FROM <https://raw.githubusercontent.com/semsol/arc2/'
+                    .'master/tests/data/turtle/manifest.ttl>
+            WHERE {?s ?p ?o.}
+        ');
+        $this->assertEquals(1860, count($res['result']['rows']));
+    }
+
+    public function testLoadInto()
+    {
+        // check that store is empty
+        $res = $this->fixture->query('SELECT * FROM <http://load-example> WHERE {?s ?p ?o.}');
+        $this->assertEquals(0, count($res['result']['rows']));
+
+        $filepath = 'https://raw.githubusercontent.com/semsol/arc2/'
+            .'master/tests/data/turtle/manifest.ttl';
+        $this->fixture->query('LOAD <'.$filepath.'> INTO <http://load-example>');
+
+        // check that triples were inserted
+        $res = $this->fixture->query('SELECT * FROM <http://load-example> WHERE {?s ?p ?o.}');
+        $this->assertEquals(1860, count($res['result']['rows']));
+    }
+}
diff --git a/lib/arc2/tests/db_adapter_depended/store/query/SelectQueryTest.php b/lib/arc2/tests/db_adapter_depended/store/query/SelectQueryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..f4ba702a063fa5ccb0338c0219a006a8b7c37d31
--- /dev/null
+++ b/lib/arc2/tests/db_adapter_depended/store/query/SelectQueryTest.php
@@ -0,0 +1,1423 @@
+<?php
+
+namespace Tests\db_adapter_depended\store\query;
+
+use Tests\ARC2_TestCase;
+
+/**
+ * Tests for query method - focus on SELECT queries
+ */
+class SelectQueryTest extends ARC2_TestCase
+{
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->fixture = \ARC2::getStore($this->dbConfig);
+        $this->fixture->drop();
+        $this->fixture->setup();
+    }
+
+    public function tearDown(): void
+    {
+        $this->fixture->closeDBCon();
+    }
+
+    public function testSelectDefaultGraph()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+        }');
+
+        $res = $this->fixture->query('SELECT * WHERE {<http://s> <http://p1> ?o.}');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        'o'
+                    ],
+                    'rows' => [
+                        [
+                            'o' => 'baz',
+                            'o type' => 'literal'
+                        ]
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    public function testSelectGraphSpecified()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+        }');
+
+        $res = $this->fixture->query('SELECT * FROM <http://example.com/> WHERE {<http://s> <http://p1> ?o.}');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        'o'
+                    ],
+                    'rows' => [
+                        [
+                            'o' => 'baz',
+                            'o type' => 'literal'
+                        ]
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // simulate a LEFT JOIN using OPTIONAL
+    public function testSelectLeftJoinUsingOptional()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s1> <http://p1> <http://s2> .
+            <http://s1> <http://p1> <http://s3> .
+
+            <http://s2> <http://p1> <http://s3> .
+            <http://s2> <http://p1> <http://s4> .
+
+            <http://s3> <http://p1> <http://s1> .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT * WHERE {
+                ?s <http://p1> ?o .
+                OPTIONAL {
+                    ?o <http://p1> ?o2 .
+                }
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o', 'o2'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://s3',
+                            's type' => 'uri',
+                            'o' => 'http://s1',
+                            'o type' => 'uri',
+                            'o2' => 'http://s2',
+                            'o2 type' => 'uri'
+                        ],
+                        [
+                            's' => 'http://s3',
+                            's type' => 'uri',
+                            'o' => 'http://s1',
+                            'o type' => 'uri',
+                            'o2' => 'http://s3',
+                            'o2 type' => 'uri'
+                        ],
+                        [
+                            's' => 'http://s1',
+                            's type' => 'uri',
+                            'o' => 'http://s2',
+                            'o type' => 'uri',
+                            'o2' => 'http://s3',
+                            'o2 type' => 'uri'
+                        ],
+                        [
+                            's' => 'http://s1',
+                            's type' => 'uri',
+                            'o' => 'http://s2',
+                            'o type' => 'uri',
+                            'o2' => 'http://s4',
+                            'o2 type' => 'uri'
+                        ],
+                        [
+                            's' => 'http://s1',
+                            's type' => 'uri',
+                            'o' => 'http://s3',
+                            'o type' => 'uri',
+                            'o2' => 'http://s1',
+                            'o2 type' => 'uri'
+                        ],
+                        [
+                            's' => 'http://s2',
+                            's type' => 'uri',
+                            'o' => 'http://s3',
+                            'o type' => 'uri',
+                            'o2' => 'http://s1',
+                            'o2 type' => 'uri'
+                        ],
+                        [
+                            's' => 'http://s2',
+                            's type' => 'uri',
+                            'o' => 'http://s4',
+                            'o type' => 'uri'
+                        ],
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // OPTIONAL, artifical query to extend coverage for store code. (ARC2_StoreSelectQueryHandler::sameOptional)
+    public function testSelectOptional()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s1> <http://p1> <http://s2> .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT * WHERE {
+                ?s <http://p1> ?o .
+                OPTIONAL {
+                    ?o <http://p1> ?o2 .
+                }
+                OPTIONAL {
+                    ?o <http://p1> ?o2 .
+                }
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o', 'o2'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://s1',
+                            's type' => 'uri',
+                            'o' => 'http://s2',
+                            'o type' => 'uri',
+                        ],
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    public function testSelectNoWhereClause()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "baz" .
+        }');
+
+        $res = $this->fixture->query('SELECT * FROM <http://example.com/> {<http://s> <http://p1> ?o.}');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        'o'
+                    ],
+                    'rows' => [
+                        [
+                            'o' => 'baz',
+                            'o type' => 'literal'
+                        ]
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    /*
+     * FILTER
+     */
+
+    // bound: is variable set?
+    public function testSelectFilterBoundNotBounding()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "foo" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p2> ?o .
+                FILTER (bound(?o))
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => []
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // bound: is variable set?
+    public function testSelectFilterBoundVariableBounded()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "foo" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER (bound(?o))
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://s',
+                            's type' => 'uri',
+                            'o' => 'foo',
+                            'o type' => 'literal',
+                        ]
+                    ]
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // datatype
+    public function testSelectFilterDatatype()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> 3 .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER (datatype(?o) = xsd:integer)
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://s',
+                            's type' => 'uri',
+                            'o' => '3',
+                            'o type' => 'literal',
+                            'o datatype' => 'http://www.w3.org/2001/XMLSchema#integer',
+                        ]
+                    ]
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // isBlank
+    public function testSelectFilterIsBlankFound()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> _:foo .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER (isBlank(?o))
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://s',
+                            's type' => 'uri',
+                            'o' => $res['result']['rows'][0]['o'],
+                            'o type' => 'bnode',
+                        ]
+                    ]
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // isBlank
+    public function testSelectFilterIsBlankNotFound()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> <http://foo> .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER (isBlank(?o))
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => []
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // isIri
+    public function testSelectFilterIsIriFound()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> <urn:id> .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER (isIri(?o))
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://s',
+                            's type' => 'uri',
+                            'o' => 'urn:id',
+                            'o type' => 'uri',
+                        ]
+                    ]
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // isIri
+    public function testSelectFilterIsIriNotFound()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "foo" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER (isIri(?o))
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => []
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // isLiteral
+    public function testSelectFilterIsLiteralFound()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "foo" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER (isLiteral(?o))
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://s',
+                            's type' => 'uri',
+                            'o' => 'foo',
+                            'o type' => 'literal',
+                        ]
+                    ]
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // isLiteral
+    public function testSelectFilterIsLiteralNotFound()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> <http://foo> .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER (isLiteral(?o))
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => []
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // isUri
+    public function testSelectFilterIsUriFound()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> <urn:id> .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER (isUri(?o))
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://s',
+                            's type' => 'uri',
+                            'o' => 'urn:id',
+                            'o type' => 'uri',
+                        ]
+                    ]
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // isUri
+    public function testSelectFilterIsUriNotFound()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "foo" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER (isUri(?o))
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => []
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // lang: test behavior when using a language
+    public function testSelectFilterLang()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "foo" .
+            <http://s> <http://p1> "in de"@de .
+            <http://s> <http://p1> "in en"@en .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER (lang(?o) = "en")
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://s',
+                            's type' => 'uri',
+                            'o' => 'in en',
+                            'o type' => 'literal',
+                            'o lang' => 'en'
+                        ]
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // langMatches
+    public function testSelectFilterLangMatches()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "foo" .
+            <http://s> <http://p1> "in de"@de .
+            <http://s> <http://p1> "in en"@en .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER langMatches (lang(?o), "en")
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://s',
+                            's type' => 'uri',
+                            'o' => 'in en',
+                            'o type' => 'literal',
+                            'o lang' => 'en'
+                        ]
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // regex
+    public function testSelectFilterRegex()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "Alice".
+            <http://s2> <http://p1> "Bob" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER regex (?o, "^Ali")
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://s',
+                            's type' => 'uri',
+                            'o' => 'Alice',
+                            'o type' => 'literal'
+                        ]
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // regex
+    public function testSelectFilterRegexWithModifier()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "Alice".
+            <http://s2> <http://p1> "Bob" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER regex (?o, "^ali", "i")
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://s',
+                            's type' => 'uri',
+                            'o' => 'Alice',
+                            'o type' => 'literal'
+                        ]
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // str
+    public function testSelectFilterStr()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "foo" .
+            <http://s> <http://p1> "in de"@de .
+            <http://s> <http://p1> "in en"@en .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER (str(?o) = "in en")
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://s',
+                            's type' => 'uri',
+                            'o' => 'in en',
+                            'o type' => 'literal',
+                            'o lang' => 'en'
+                        ]
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // str
+    public function testSelectFilterStrNotFound()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://s> <http://p1> "foo" .
+            <http://s> <http://p1> "in de"@de .
+            <http://s> <http://p1> "in en"@en .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT ?s ?o WHERE {
+                ?s <http://p1> ?o .
+                FILTER (str(?o) = "in it")
+            }
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'o'
+                    ],
+                    'rows' => [],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // >
+    public function testSelectFilterRelationalGreatThan()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://container1> <http://weight> "150" .
+            <http://container2> <http://weight> "50" .
+        }');
+
+        $res = $this->fixture->query('SELECT ?c WHERE {
+            ?c <http://weight> ?w .
+
+            FILTER (?w > 100)
+        }');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        'c'
+                    ],
+                    'rows' => [
+                        [
+                            'c' => 'http://container1',
+                            'c type' => 'uri',
+                        ],
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // <
+    public function testSelectFilterRelationalSmallerThan()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://container1> <http://weight> "150" .
+            <http://container2> <http://weight> "50" .
+        }');
+
+        $res = $this->fixture->query('SELECT ?c WHERE {
+            ?c <http://weight> ?w .
+
+            FILTER (?w < 100)
+        }');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        'c'
+                    ],
+                    'rows' => [
+                        [
+                            'c' => 'http://container2',
+                            'c type' => 'uri',
+                        ],
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // =
+    public function testSelectFilterRelationalEqual()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://container1> <http://weight> "150" .
+            <http://container2> <http://weight> "50" .
+        }');
+
+        $res = $this->fixture->query('SELECT ?c WHERE {
+            ?c <http://weight> ?w .
+
+            FILTER (?w = 150)
+        }');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        'c'
+                    ],
+                    'rows' => [
+                        [
+                            'c' => 'http://container1',
+                            'c type' => 'uri',
+                        ],
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    // !=
+    public function testSelectFilterRelationalNotEqual()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://container1> <http://weight> "150" .
+            <http://container2> <http://weight> "50" .
+        }');
+
+        $res = $this->fixture->query('SELECT ?c WHERE {
+            ?c <http://weight> ?w .
+
+            FILTER (?w != 150)
+        }');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        'c'
+                    ],
+                    'rows' => [
+                        [
+                            'c' => 'http://container2',
+                            'c type' => 'uri',
+                        ],
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    /*
+     * SELECT COUNT
+     */
+
+    public function testSelectCount()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://person1> <http://name> "baz" .
+            <http://person2> <http://name> "baz" .
+            <http://person3> <http://name> "baz" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT COUNT(?s) AS ?count WHERE {
+                ?s <http://name> "baz" .
+            }
+            ORDER BY DESC(?count)
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        'count'
+                    ],
+                    'rows' => [
+                        [
+                            'count' => '3',
+                            'count type' => 'literal',
+                        ]
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    /*
+     * GROUP BY
+     */
+
+    public function testSelectGroupBy()
+    {
+        $query = 'SELECT ?who COUNT(?person) as ?persons WHERE {
+                ?who <http://knows> ?person .
+            }
+            GROUP BY ?who
+        ';
+
+        // mark skipped, if we have a certain MySQL version running
+        // TODO make that more flexible, currently its tight to MySQL
+        $serverVersion = $this->fixture->a['db_object']->getServerVersion();
+        if ('05-07' == substr($serverVersion, 0, 5)) {
+            $this->markTestSkipped(
+                '[mysql 5.7] Result set is empty for query: '
+                .$query
+            );
+        }
+
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://person1> <http://knows> <http://person2>, <http://person3> .
+            <http://person2> <http://knows> <http://person3> .
+        }');
+
+        $res = $this->fixture->query($query);
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        'who',
+                        'persons'
+                    ],
+                    'rows' => [
+                        [
+                            'who' => 'http://person1',
+                            'who type' => 'uri',
+                            'persons' => '2',
+                            'persons type' => 'literal',
+                        ],
+                        [
+                            'who' => 'http://person2',
+                            'who type' => 'uri',
+                            'persons' => '1',
+                            'persons type' => 'literal',
+                        ],
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    /*
+     * OFFSET and LIMIT
+     */
+
+    public function testSelectOffset()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://person1> <http://id> "1" .
+            <http://person3> <http://id> "3" .
+            <http://person2> <http://id> "2" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT * WHERE { ?s ?p ?o . }
+            OFFSET 1
+        ');
+
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'p', 'o'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://person3',
+                            's type' => 'uri',
+                            'p' => 'http://id',
+                            'p type' => 'uri',
+                            'o' => '3',
+                            'o type' => 'literal',
+                        ],
+                        [
+                            's' => 'http://person2',
+                            's type' => 'uri',
+                            'p' => 'http://id',
+                            'p type' => 'uri',
+                            'o' => '2',
+                            'o type' => 'literal',
+                        ],
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    public function testSelectOffsetLimit()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://person1> <http://id> "1" .
+            <http://person3> <http://id> "3" .
+            <http://person2> <http://id> "2" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT * WHERE { ?s ?p ?o . }
+            OFFSET 1 LIMIT 2
+        ');
+
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'p', 'o'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://person3',
+                            's type' => 'uri',
+                            'p' => 'http://id',
+                            'p type' => 'uri',
+                            'o' => '3',
+                            'o type' => 'literal',
+                        ],
+                        [
+                            's' => 'http://person2',
+                            's type' => 'uri',
+                            'p' => 'http://id',
+                            'p type' => 'uri',
+                            'o' => '2',
+                            'o type' => 'literal',
+                        ],
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    public function testSelectLimit()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://person1> <http://id> "1" .
+            <http://person3> <http://id> "3" .
+            <http://person2> <http://id> "2" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT * WHERE { ?s ?p ?o . }
+            LIMIT 2
+        ');
+
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's', 'p', 'o'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://person1',
+                            's type' => 'uri',
+                            'p' => 'http://id',
+                            'p type' => 'uri',
+                            'o' => '1',
+                            'o type' => 'literal',
+                        ],
+                        [
+                            's' => 'http://person3',
+                            's type' => 'uri',
+                            'p' => 'http://id',
+                            'p type' => 'uri',
+                            'o' => '3',
+                            'o type' => 'literal',
+                        ],
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    /*
+     * ORDER BY
+     */
+
+    public function testSelectOrderByAsc()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://person1> <http://id> "1" .
+            <http://person3> <http://id> "3" .
+            <http://person2> <http://id> "2" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT * WHERE {
+                ?s <http://id> ?id .
+            }
+            ORDER BY ASC(?id)
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's',
+                        'id'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://person1',
+                            's type' => 'uri',
+                            'id' => '1',
+                            'id type' => 'literal',
+                        ],
+                        [
+                            's' => 'http://person2',
+                            's type' => 'uri',
+                            'id' => '2',
+                            'id type' => 'literal',
+                        ],
+                        [
+                            's' => 'http://person3',
+                            's type' => 'uri',
+                            'id' => '3',
+                            'id type' => 'literal',
+                        ],
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    public function testSelectOrderByDesc()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://person1> <http://id> "1" .
+            <http://person3> <http://id> "3" .
+            <http://person2> <http://id> "2" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT * WHERE {
+                ?s <http://id> ?id .
+            }
+            ORDER BY DESC(?id)
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's',
+                        'id'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://person3',
+                            's type' => 'uri',
+                            'id' => '3',
+                            'id type' => 'literal',
+                        ],
+                        [
+                            's' => 'http://person2',
+                            's type' => 'uri',
+                            'id' => '2',
+                            'id type' => 'literal',
+                        ],
+                        [
+                            's' => 'http://person1',
+                            's type' => 'uri',
+                            'id' => '1',
+                            'id type' => 'literal',
+                        ]
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    public function testSelectOrderByWithoutContent()
+    {
+        $res = $this->fixture->query('
+            SELECT * WHERE {
+                ?s <http://id> ?id .
+            }
+            ORDER BY
+        ');
+
+        // query false, therefore 0 as result
+        $this->assertEquals(0, $res);
+    }
+
+    /*
+     * UNION
+     */
+
+    public function testSelectUnion()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://person1> <http://id> "1" .
+            <http://person3> <http://id> "3" .
+            <http://person2> <http://id> "2" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT * WHERE {
+                {
+                    ?p <http://id> "1" .
+                } UNION {
+                    ?p <http://id> "3" .
+                }
+            }
+        ');
+
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        'p'
+                    ],
+                    'rows' => [
+                        [
+                            'p' => 'http://person1',
+                            'p type' => 'uri',
+                        ],
+                        [
+                            'p' => 'http://person3',
+                            'p type' => 'uri',
+                        ],
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+
+    /*
+     * Tests using certain queries with SELECT FROM WHERE and not just SELECT WHERE
+     */
+
+    public function testSelectOrderByAscWithFromClause()
+    {
+        // test data
+        $this->fixture->query('INSERT INTO <http://example.com/> {
+            <http://person1> <http://id> "1" .
+            <http://person3> <http://id> "3" .
+            <http://person2> <http://id> "2" .
+        }');
+
+        $res = $this->fixture->query('
+            SELECT * FROM <http://example.com/> WHERE {
+                ?s <http://id> ?id .
+            }
+            ORDER BY ASC(?id)
+        ');
+        $this->assertEquals(
+            [
+                'query_type' => 'select',
+                'result' => [
+                    'variables' => [
+                        's',
+                        'id'
+                    ],
+                    'rows' => [
+                        [
+                            's' => 'http://person1',
+                            's type' => 'uri',
+                            'id' => '1',
+                            'id type' => 'literal',
+                        ],
+                        [
+                            's' => 'http://person2',
+                            's type' => 'uri',
+                            'id' => '2',
+                            'id type' => 'literal',
+                        ],
+                        [
+                            's' => 'http://person3',
+                            's type' => 'uri',
+                            'id' => '3',
+                            'id type' => 'literal',
+                        ],
+                    ],
+                ],
+                'query_time' => $res['query_time']
+            ],
+            $res
+        );
+    }
+}
diff --git a/lib/arc2/tests/unit/ARC2_ClassTest.php b/lib/arc2/tests/unit/ARC2_ClassTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..502b5bb4da95a1b847665d2fc95f925730ff3cab
--- /dev/null
+++ b/lib/arc2/tests/unit/ARC2_ClassTest.php
@@ -0,0 +1,67 @@
+<?php
+
+class ARC2_ClassTest extends PHPUnit\Framework\TestCase {
+
+    public function setUp(): void {
+        $array = array();
+        $stdClass = new stdClass;
+        $this->arc2 = new ARC2_Class($array, $stdClass);
+    }
+
+    public function testCamelCase() {
+         $this->assertSame("Fish", $this->arc2->camelCase("fish"));
+         $this->assertSame("fish", $this->arc2->camelCase("fish", true));
+         $this->assertSame("fish", $this->arc2->camelCase("fish", true, true));
+
+         $this->assertSame("FishHeads", $this->arc2->camelCase("fish_heads"));
+         $this->assertSame("fishHeads", $this->arc2->camelCase("fish_heads", true));
+         $this->assertSame("fishHeads", $this->arc2->camelCase("fish_heads", true, true));
+
+         $this->assertSame("ALLCAPITALS", $this->arc2->camelCase("ALL_CAPITALS"));
+    }
+
+    public function testDeCamelCase() {
+         $this->assertSame("fish", $this->arc2->deCamelCase("fish"));
+         $this->assertSame("Fish", $this->arc2->deCamelCase("fish", true));
+
+         $this->assertSame("fish heads", $this->arc2->deCamelCase("fish_heads"));
+         $this->assertSame("Fish heads", $this->arc2->deCamelCase("fish_heads", true));
+
+         $this->assertSame("ALL CAPITALS", $this->arc2->deCamelCase("ALL_CAPITALS"));
+    }
+
+
+    public function testV() {
+        $this->assertSame(false, $this->arc2->v(null));
+        $this->assertSame(false, $this->arc2->v("cats", false, array()));
+        $this->assertSame(true, $this->arc2->v("cats", false, array("cats" => true)));
+
+        $o = new stdclass;
+        $o->cats = true;
+        $this->assertSame(true, $this->arc2->v("cats", false, $o));
+    }
+
+    public function testV1() {
+        $this->assertSame(false, $this->arc2->v1(null));
+        $this->assertSame(false, $this->arc2->v1("cats", false, array()));
+        $this->assertSame(true, $this->arc2->v1("cats", false, array("cats" => true)));
+        $this->assertSame("blackjack", $this->arc2->v1("cats", "blackjack", array("cats" => null)));
+
+        $o = new stdclass;
+        $o->cats = true;
+        $this->assertSame(true, $this->arc2->v1("cats", false, $o));
+
+        $o = new stdclass;
+        $o->cats = 0;
+        $this->assertSame("blackjack", $this->arc2->v1("cats", "blackjack", $o));
+    }
+
+    public function testExtractTermLabel() {
+        $this->assertSame("bar", $this->arc2->extractTermLabel('http://example.com/foo#bar'));
+        $this->assertSame("bar cats", $this->arc2->extractTermLabel('http://example.com/foo#bar?cats'));
+        $this->assertSame("bar", $this->arc2->extractTermLabel('#bar'));
+        $this->assertSame("bar", $this->arc2->extractTermLabel('http://example.com/bar'));
+        $this->assertSame("bar", $this->arc2->extractTermLabel('http://example.com/bar/'));
+    }
+
+}
diff --git a/lib/arc2/tests/unit/ARC2_GraphTest.php b/lib/arc2/tests/unit/ARC2_GraphTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e68dd4b2f0643cb0a15e73ea327cc1faa3f475d5
--- /dev/null
+++ b/lib/arc2/tests/unit/ARC2_GraphTest.php
@@ -0,0 +1,213 @@
+<?php
+
+namespace Tests\unit;
+
+use Tests\ARC2_TestCase;
+
+class ARC2_GraphTest extends ARC2_TestCase {
+
+	public function setUp(): void
+	{
+		parent::setUp();
+
+		$this->obj = \ARC2::getGraph();
+		$this->res1 = array(
+			'http://example.com/s1' => array(
+				'http://example.com/p1' => array(
+					array('value' => 'o1', 'type' => 'literal'),
+					array('value' => 'http://example.com/o1', 'type' => 'uri'),
+				),
+			),
+		);
+		$this->res2 = array(
+			'http://example.com/s2' => array(
+				'http://example.com/p2' => array(
+					array('value' => 'o2', 'type' => 'literal'),
+					array('value' => 'http://example.com/o2', 'type' => 'uri'),
+				),
+			),
+		);
+		$this->res3 = array(
+			'http://example.com/s1' => array(
+				'http://example.com/p3' => array(
+					array('value' => 'o3', 'type' => 'literal'),
+				),
+			),
+		);
+	}
+
+	public function testSetIndex() {
+		$actual = $this->obj->setIndex($this->res1);
+		$this->assertSame($this->obj, $actual);
+
+		$actual = $this->obj->getIndex();
+		$this->assertEquals($this->res1, $actual);
+	}
+
+	public function testGetIndex() {
+		$actual = $this->obj->getIndex();
+		$this->assertTrue(is_array($actual), 'should return array');
+	}
+
+	public function testAddIndex() {
+		$actual = $this->obj->addIndex($this->res1);
+		$this->assertSame($this->obj, $actual);
+
+		$actual = $this->obj->getIndex();
+		$this->assertEquals($this->res1, $actual);
+
+		$this->obj->addIndex($this->res1);
+		$actual = $this->obj->getIndex();
+		$this->assertEquals($this->res1, $actual);
+
+		$this->obj->addIndex($this->res2);
+		$actual = $this->obj->getIndex();
+		$this->assertEquals(array_merge($this->res1, $this->res2), $actual);
+
+		$this->obj->addIndex($this->res3);
+		$actual = $this->obj->getIndex();
+		$this->assertEquals(2, count(array_keys($actual['http://example.com/s1'])));
+		$this->assertEquals(1, count(array_keys($actual['http://example.com/s2'])));
+	}
+
+	public function testAddGraph() {
+		$this->obj->addIndex($this->res1);
+		$g2 = \ARC2::getGraph()->addIndex($this->res2);
+
+		$actual = $this->obj->addGraph($g2);
+		$this->assertSame($this->obj, $actual);
+
+		$actual = $this->obj->getIndex();
+		$this->assertEquals(array_merge($this->res1, $this->res2), $actual);
+	}
+
+	public function testAddGraphWithNamespaces() {
+		$g2 = \ARC2::getGraph()->setPrefix('ex', 'http://example.com/');
+
+		$actual = $this->obj->addGraph($g2);
+		$this->assertArrayHasKey('ex', $actual->ns);
+	}
+
+	public function testAddRdf() {
+		$rdf = $this->obj->toTurtle($this->res1);
+		$this->obj->addRdf($rdf, 'turtle');
+		$actual = $this->obj->getIndex();
+		$this->assertEquals($this->res1, $actual);
+
+		$rdf = json_encode($this->res2);
+		$this->obj->addRdf($rdf, 'json');
+		$actual = $this->obj->getIndex();
+		$this->assertEquals(array_merge($this->res1, $this->res2), $actual);
+	}
+
+	public function testHasSubject() {
+		$actual = $this->obj->setIndex($this->res1);
+		$this->assertTrue($actual->hasSubject('http://example.com/s1'));
+		$this->assertFalse($actual->hasSubject('http://example.com/s2'));
+	}
+
+	public function testHasTriple() {
+		$actual = $this->obj->setIndex($this->res1);
+		$this->assertTrue($actual->hasTriple('http://example.com/s1', 'http://example.com/p1', 'o1'));
+		$this->assertFalse($actual->hasTriple('http://example.com/s1', 'http://example.com/p1', 'o2'));
+		$this->assertTrue($actual->hasTriple('http://example.com/s1', 'http://example.com/p1', array('value' => 'o1', 'type' => 'literal')));
+		$this->assertFalse($actual->hasTriple('http://example.com/s1', 'http://example.com/p1', array('value' => 'o1', 'type' => 'uri')));
+	}
+
+	public function testHasLiteralTriple() {
+		$actual = $this->obj->setIndex($this->res2);
+		$this->assertTrue($actual->hasLiteralTriple('http://example.com/s2', 'http://example.com/p2', 'o2'));
+		$this->assertFalse($actual->hasLiteralTriple('http://example.com/s1', 'http://example.com/p1', 'o2'));
+	}
+
+	public function testHasLinkTriple() {
+		$actual = $this->obj->setIndex($this->res2);
+		$this->assertTrue($actual->hasLinkTriple('http://example.com/s2', 'http://example.com/p2', 'http://example.com/o2'));
+		$this->assertFalse($actual->hasLinkTriple('http://example.com/s2', 'http://example.com/p2', 'o2'));
+	}
+
+	public function testAddTriple() {
+		$actual = $this->obj->addTriple('_:s1', '_:p1', 'o1');
+		$this->assertTrue($actual->hasLiteralTriple('_:s1', '_:p1', 'o1'));
+
+		$actual = $this->obj->addTriple('_:s1', '_:p1', 'o1', 'bnode');
+		$this->assertTrue($actual->hasLinkTriple('_:s1', '_:p1', 'o1'));
+	}
+
+	public function testGetSubjects() {
+		$g = $this->obj->setIndex($this->res1);
+
+		$actual = $g->getSubjects();
+		$this->assertEquals(array('http://example.com/s1'), $actual);
+
+		$actual = $g->getSubjects('p');
+		$this->assertEquals(array(), $actual);
+
+		$actual = $g->getSubjects('http://example.com/p1');
+		$this->assertEquals(array('http://example.com/s1'), $actual);
+
+		$actual = $g->getSubjects(null, 'o');
+		$this->assertEquals(array(), $actual);
+
+		$actual = $g->getSubjects(null, 'o1');
+		$this->assertEquals(array('http://example.com/s1'), $actual);
+
+		$actual = $g->getSubjects(null, array('value' => 'http://example.com/o1', 'type' => 'uri'));
+		$this->assertEquals(array('http://example.com/s1'), $actual);
+
+		$actual = $g->getSubjects('http://example.com/p1', 'o');
+		$this->assertEquals(array(), $actual);
+
+		$actual = $g->getSubjects('http://example.com/p1', 'o1');
+		$this->assertEquals(array('http://example.com/s1'), $actual);
+
+	}
+
+	public function testGetPredicates() {
+		$g = $this->obj->setIndex($this->res1)->addIndex($this->res2);
+
+		$actual = $g->getPredicates();
+		$this->assertEquals(array('http://example.com/p1', 'http://example.com/p2'), $actual);
+
+		$actual = $g->getPredicates('http://example.com/s2');
+		$this->assertEquals(array('http://example.com/p2'), $actual);
+	}
+
+	public function testGetObjects() {
+		$actual = $this->obj->setIndex($this->res1)->getObjects('http://example.com/s1', 'http://example.com/p1', true);
+		$this->assertEmpty(array_diff(array('http://example.com/o1', 'o1'), $actual));
+		$this->assertEmpty(array_diff($actual, array('http://example.com/o1', 'o1')));
+
+		$actual = $this->obj->setIndex($this->res3)->getObjects('http://example.com/s1', 'http://example.com/p3');
+		$this->assertEquals(array(array('value' => 'o3', 'type' => 'literal')), $actual);
+	}
+
+	public function testGetObject() {
+		$actual = $this->obj->setIndex($this->res1)->getObject('http://example.com/s1', 'http://example.com/p1', true);
+		$this->assertEquals('o1', $actual);
+
+		$actual = $this->obj->setIndex($this->res3)->getObject('http://example.com/s1', 'http://example.com/p3');
+		$this->assertEquals(array('value' => 'o3', 'type' => 'literal'), $actual);
+	}
+
+	public function testGetNtriples() {
+		$actual = $this->obj->setIndex($this->res3)->getNTriples();
+		$this->assertStringContainsString('<http://example.com/s1> <http://example.com/p3> "o3"', $actual);
+	}
+
+	public function testGetTurtle() {
+		$actual = $this->obj->setIndex($this->res3)->setPrefix('ex', 'http://example.com/')->getTurtle();
+		$this->assertStringContainsString('<http://example.com/s1> ex:p3 "o3"', $actual);
+	}
+
+	public function testGetRDFXML() {
+		$actual = $this->obj->setIndex($this->res3)->getRDFXML();
+		$this->assertStringContainsString('<rdf:Description rdf:about="http://example.com/s1">', $actual);
+	}
+
+	public function testGetJSON() {
+		$actual = $this->obj->setIndex($this->res3)->getJSON();
+		$this->assertStringContainsString('{"http:\/\/example.com\/s1":', $actual);
+	}
+
+}
diff --git a/lib/arc2/tests/unit/ARC2_ReaderTest.php b/lib/arc2/tests/unit/ARC2_ReaderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..72e3d2e508f36b9fe65f2e02dae97f1e0f3d6934
--- /dev/null
+++ b/lib/arc2/tests/unit/ARC2_ReaderTest.php
@@ -0,0 +1,60 @@
+<?php
+
+
+namespace Tests\unit;
+use Tests\ARC2_TestCase;
+
+class ARC2_ReaderTest extends ARC2_TestCase {
+
+	public function setUp(): void
+	{
+		parent::setUp();
+
+		$this->reader = \ARC2::getReader();
+		$this->reader->__init();
+	}
+
+	public function testFullQualifiedURIIgnoresPreviousParts() {
+
+		$parts_of_previous_uri = array("port" => 8081, "scheme" => "https", "host" => "foo.bar", "path"=>"/baz");
+		$uri_parts = $this->reader->getURIPartsFromURIAndPreviousURIParts("http://google.com:80/urlpath", $parts_of_previous_uri);
+
+        	$this->assertEquals("http", $uri_parts['scheme']);
+        	$this->assertEquals("80", $uri_parts['port']);
+        	$this->assertEquals("google.com", $uri_parts['host']);
+        	$this->assertEquals("/urlpath", $uri_parts['path']);
+	}
+
+	public function testWhenARelativeURIIsPassedSchemeHostAndPortAreInferredFromPreviousParts() {
+
+		$parts_of_previous_uri = array("port" => 8081, "scheme" => "https", "host" => "foo.bar", "path"=>"/baz");
+		$uri_parts = $this->reader->getURIPartsFromURIAndPreviousURIParts("/urlbits/andbobs", $parts_of_previous_uri);
+
+        	$this->assertEquals("https", $uri_parts['scheme']);
+        	$this->assertEquals("8081", $uri_parts['port']);
+        	$this->assertEquals("foo.bar", $uri_parts['host']);
+        	$this->assertEquals("/urlbits/andbobs", $uri_parts['path']);
+	}
+
+	public function testWhenTheSchemeChangesButPortIsNotExplicitThePortIsInferredFromTheSchemeNotThePreviousParts() {
+
+		$parts_of_previous_uri = array("port" => 8081, "scheme" => "https", "host" => "foo.bar", "path"=>"/baz");
+		$uri_parts = $this->reader->getURIPartsFromURIAndPreviousURIParts("http://bbc.co.uk/news", $parts_of_previous_uri);
+
+        	$this->assertEquals("http", $uri_parts['scheme']);
+        	$this->assertEquals("80", $uri_parts['port']);
+        	$this->assertEquals("bbc.co.uk", $uri_parts['host']);
+        	$this->assertEquals("/news", $uri_parts['path']);
+	}
+
+	public function testWhenTheSchemeHasNotChangedAndPortIsNotExplicitThePortIsInferredFromThePreviousParts() {
+		/* not totally convinced this is actually the right behaviour. Possibly if there is a scheme but no port then the scheme should always set the port */
+		$parts_of_previous_uri = array("port" => 8081, "scheme" => "https", "host" => "foo.bar", "path"=>"/baz");
+		$uri_parts = $this->reader->getURIPartsFromURIAndPreviousURIParts("https://bbc.co.uk/news", $parts_of_previous_uri);
+
+        	$this->assertEquals("https", $uri_parts['scheme']);
+        	$this->assertEquals("8081", $uri_parts['port']);
+        	$this->assertEquals("bbc.co.uk", $uri_parts['host']);
+        	$this->assertEquals("/news", $uri_parts['path']);
+	}
+}
diff --git a/lib/arc2/tests/unit/ARC2_Test.php b/lib/arc2/tests/unit/ARC2_Test.php
new file mode 100644
index 0000000000000000000000000000000000000000..8467f1a964aa2b537d6cd123d77d90de8982926e
--- /dev/null
+++ b/lib/arc2/tests/unit/ARC2_Test.php
@@ -0,0 +1,126 @@
+<?php
+
+namespace Tests\unit;
+
+use Tests\ARC2_TestCase;
+
+class ARC2_Test extends ARC2_TestCase {
+
+	public function testGetVersion() {
+		$actual = \ARC2::getVersion();
+		$this->assertRegExp('/^[0-9]{4}-[0-9]{2}-[0-9]{2}/', $actual, "should start with date");
+	}
+
+	public function testGetIncPath() {
+		$actual = \ARC2::getIncPath('RDFParser');
+		$this->assertStringEndsWith('parsers/', $actual, 'should create correct path');
+		$this->assertTrue(is_dir($actual), 'should create correct pointer');
+	}
+
+	public function testGetScriptURI() {
+		$tmp = $_SERVER;
+		unset($_SERVER);
+		$actual = \ARC2::getScriptURI();
+		$this->assertEquals('http://localhost/unknown_path', $actual);
+		$_SERVER = $tmp;
+
+		$_SERVER = array(
+			'SERVER_PROTOCOL' => 'http',
+			'SERVER_PORT' => 443,
+			'HTTP_HOST' => 'example.com',
+			'SCRIPT_NAME' => '/foo'
+		);
+		$actual = \ARC2::getScriptURI();
+		$this->assertEquals('https://example.com/foo', $actual);
+		$_SERVER = $tmp;
+
+		unset($_SERVER['HTTP_HOST']);
+		unset($_SERVER['SERVER_NAME']);
+		$_SERVER['SCRIPT_FILENAME'] = __FILE__;
+		$actual = \ARC2::getScriptURI();
+		$this->assertEquals('file://' . __FILE__, $actual);
+		$_SERVER = $tmp;
+	}
+
+	public function testGetRequestURI() {
+		$tmp = $_SERVER;
+		unset($_SERVER);
+		$actual = \ARC2::getRequestURI();
+		$this->assertEquals(\ARC2::getScriptURI(), $actual);
+		$_SERVER = $tmp;
+
+		$_SERVER = array(
+			'SERVER_PROTOCOL' => 'http',
+			'SERVER_PORT' => 1234,
+			'HTTP_HOST' => 'example.com',
+			'REQUEST_URI' => '/foo'
+		);
+		$actual = \ARC2::getRequestURI();
+		$this->assertEquals('http://example.com:1234/foo', $actual);
+		$_SERVER = $tmp;
+	}
+
+	public function testInc() {
+		$actual = \ARC2::inc('Class');
+		$this->assertNotEquals(0, $actual);
+
+		$actual = \ARC2::inc('RDFParser');
+		$this->assertNotEquals(0, $actual);
+
+		$actual = \ARC2::inc('ARC2_RDFParser');
+		$this->assertNotEquals(0, $actual);
+
+		$actual = \ARC2::inc('Foo');
+		$this->assertEquals(0, $actual);
+
+		$actual = \ARC2::inc('Vendor_Foo');
+		$this->assertEquals(0, $actual);
+	}
+
+	public function testMtime() {
+		$actual = \ARC2::mtime();
+		$this->assertTrue(is_float($actual));
+	}
+
+	public function testX() {
+		$actual = \ARC2::x('foo', '  foobar');
+		$this->assertEquals('bar', $actual[1]);
+	}
+
+	public function testToUTF8() {
+		$actual = \ARC2::toUTF8('foo');
+		$this->assertEquals('foo', $actual);
+
+		$actual = \ARC2::toUTF8(utf8_encode('Iñtërnâtiônàlizætiøn'));
+		$this->assertEquals('Iñtërnâtiônàlizætiøn', $actual);
+	}
+
+	public function testSplitURI() {
+		$actual = \ARC2::splitURI('http://www.w3.org/XML/1998/namespacefoo');
+		$this->assertEquals(array('http://www.w3.org/XML/1998/namespace', 'foo'), $actual);
+
+		$actual = \ARC2::splitURI('http://www.w3.org/2005/Atomfoo');
+		$this->assertEquals(array('http://www.w3.org/2005/Atom', 'foo'), $actual);
+
+		$actual = \ARC2::splitURI('http://www.w3.org/2005/Atom#foo');
+		$this->assertEquals(array('http://www.w3.org/2005/Atom#', 'foo'), $actual);
+
+		$actual = \ARC2::splitURI('http://www.w3.org/1999/xhtmlfoo');
+		$this->assertEquals(array('http://www.w3.org/1999/xhtml', 'foo'), $actual);
+
+		$actual = \ARC2::splitURI('http://www.w3.org/1999/02/22-rdf-syntax-ns#foo');
+		$this->assertEquals(array('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'foo'), $actual);
+
+		$actual = \ARC2::splitURI('http://example.com/foo');
+		$this->assertEquals(array('http://example.com/', 'foo'), $actual);
+
+		$actual = \ARC2::splitURI('http://example.com/foo/bar');
+		$this->assertEquals(array('http://example.com/foo/', 'bar'), $actual);
+
+		$actual = \ARC2::splitURI('http://example.com/foo#bar');
+		$this->assertEquals(array('http://example.com/foo#', 'bar'), $actual);
+
+	}
+
+
+}
diff --git a/lib/arc2/tests/unit/ARC2_getFormatTest.php b/lib/arc2/tests/unit/ARC2_getFormatTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3ea27fe1f17ffb70682bf3289205f0340eacf34a
--- /dev/null
+++ b/lib/arc2/tests/unit/ARC2_getFormatTest.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace Tests\unit;
+
+use Tests\ARC2_TestCase;
+
+define('TESTS_FOLDER_PATH', __DIR__ .'/../');
+
+class ARC2_getFormatTest extends ARC2_TestCase {
+
+	public function testGetFormatWithAtom() {
+		$data = file_get_contents(TESTS_FOLDER_PATH . 'data/atom/feed.atom');
+
+		$actual = \ARC2::getFormat($data, 'application/atom+xml');
+		$this->assertEquals('atom', $actual);
+
+		$actual = \ARC2::getFormat($data);
+		$this->assertEquals('atom', $actual);
+	}
+
+	public function testGetFormatWithRdfXml() {
+		$data = file_get_contents(TESTS_FOLDER_PATH . 'data/rdfxml/planetrdf-bloggers.rdf');
+
+		$actual = \ARC2::getFormat($data, 'application/rdf+xml');
+		$this->assertEquals('rdfxml', $actual);
+
+		$actual = \ARC2::getFormat($data);
+		$this->assertEquals('rdfxml', $actual);
+	}
+
+	public function testGetFormatWithTurtle() {
+		$data = file_get_contents(TESTS_FOLDER_PATH . 'data/turtle/manifest.ttl');
+
+		$actual = \ARC2::getFormat($data, 'text/turtle');
+		$this->assertEquals('turtle', $actual);
+
+		$actual = \ARC2::getFormat($data);
+		$this->assertEquals('turtle', $actual);
+	}
+
+	public function testGetFormatWithJson() {
+		$data = file_get_contents(TESTS_FOLDER_PATH . 'data/json/sparql-select-result.json');
+
+		$actual = \ARC2::getFormat($data, 'application/json');
+		$this->assertEquals('json', $actual);
+
+		$actual = \ARC2::getFormat($data);
+		$this->assertEquals('json', $actual);
+
+		$data = file_get_contents(TESTS_FOLDER_PATH . 'data/json/crunchbase-facebook.js');
+
+		$actual = \ARC2::getFormat($data);
+		$this->assertEquals('cbjson', $actual);
+
+	}
+
+	public function testGetFormatWithN3() {
+		$data = file_get_contents(TESTS_FOLDER_PATH . 'data/nt/test.nt');
+
+		$actual = \ARC2::getFormat($data, 'application/rdf+n3');
+		$this->assertEquals('n3', $actual);
+
+		$actual = \ARC2::getFormat($data, '', 'n3');
+		$this->assertEquals('n3', $actual);
+	}
+
+	public function testGetFormatWithNTriples() {
+		$data = file_get_contents(TESTS_FOLDER_PATH . 'data/nt/test.nt');
+
+		$actual = \ARC2::getFormat($data);
+		$this->assertEquals('ntriples', $actual);
+
+		$actual = \ARC2::getFormat($data, '', 'nt');
+		$this->assertEquals('ntriples', $actual);
+	}
+
+}
diff --git a/lib/arc2/tests/unit/ARC2_getPreferredFormatTest.php b/lib/arc2/tests/unit/ARC2_getPreferredFormatTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3752c6fe9bf7a0ce04dcee90f5662be0046b520e
--- /dev/null
+++ b/lib/arc2/tests/unit/ARC2_getPreferredFormatTest.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Tests\unit;
+
+use Tests\ARC2_TestCase;
+
+class ARC2_getPreferredFormatTest extends ARC2_TestCase {
+
+	public function setUp(): void
+	{
+        // fix warning about unset SCRIPT_NAME index in PHPUnit
+        // Notice: Undefined index: SCRIPT_NAME in /var/www/html/ARC2/vendor/phpunit/phpunit/src/Util/Filter.php on line 27
+        $_SERVER['SCRIPT_NAME'] = '';
+	}
+
+	public function testGetPreferredFormat() {
+		$_SERVER['HTTP_ACCEPT'] = '';
+		$actual = \ARC2::getPreferredFormat('xml');
+		$this->assertEquals('XML', $actual);
+
+		$actual = \ARC2::getPreferredFormat('foo');
+		$this->assertEquals(null, $actual);
+
+		$_SERVER['HTTP_ACCEPT'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
+		$actual = \ARC2::getPreferredFormat();
+		$this->assertEquals('HTML', $actual);
+
+		$_SERVER['HTTP_ACCEPT'] = 'application/rdf+xml,text/html;q=0.9,*/*;q=0.8';
+		$actual = \ARC2::getPreferredFormat();
+		$this->assertEquals('RDFXML', $actual);
+	}
+
+}
diff --git a/lib/arc2/tests/unit/src/ARC2/Store/Adapter/AbstractAdapterTest.php b/lib/arc2/tests/unit/src/ARC2/Store/Adapter/AbstractAdapterTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2a553931f048d17c799adf19e584eca57c8a34cb
--- /dev/null
+++ b/lib/arc2/tests/unit/src/ARC2/Store/Adapter/AbstractAdapterTest.php
@@ -0,0 +1,264 @@
+<?php
+
+namespace Tests\unit\src\ARC2\Store\Adapter;
+
+use Tests\ARC2_TestCase;
+
+abstract class AbstractAdapterTest extends ARC2_TestCase
+{
+    abstract protected function checkAdapterRequirements();
+    abstract protected function getAdapterInstance($config);
+    abstract public function testConnectUseGivenConnection();
+    abstract public function testEscape();
+    abstract public function testGetAdapterName();
+    abstract public function testGetConnection();
+    abstract public function testGetNumberOfRowsInvalidQuery();
+
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->checkAdapterRequirements();
+
+        $this->fixture = $this->getAdapterInstance($this->dbConfig);
+        $result = $this->fixture->connect();
+
+        // remove all tables
+        $tables = $this->fixture->fetchList('SHOW TABLES');
+        foreach($tables as $table) {
+            $this->fixture->simpleQuery('DROP TABLE '. $table['Tables_in_'.$this->dbConfig['db_name']]);
+        }
+    }
+
+    public function tearDown(): void
+    {
+        if (null !== $this->fixture) {
+            $this->fixture->disconnect();
+        }
+    }
+
+    protected function dropAllTables()
+    {
+        // remove all tables
+        $tables = $this->fixture->fetchList('SHOW TABLES');
+        foreach($tables as $table) {
+            $this->fixture->simpleQuery('DROP TABLE '. $table['Tables_in_'.$this->dbConfig['db_name']]);
+        }
+    }
+
+    /*
+     * Tests for connect
+     */
+
+    public function testConnectCreateNewConnection()
+    {
+        $this->fixture->disconnect();
+
+        // do explicit reconnect
+        $this->fixture = $this->getAdapterInstance($this->dbConfig);
+        $this->fixture->connect();
+
+        $tables = $this->fixture->fetchList('SHOW TABLES');
+        $this->assertTrue(is_array($tables));
+    }
+
+    /*
+     * Tests for exec
+     */
+
+    public function testExec()
+    {
+        $this->fixture->simpleQuery('CREATE TABLE users (id INT(6), name VARCHAR(30) NOT NULL)');
+        $this->fixture->simpleQuery('INSERT INTO users (id, name) VALUE (1, "foobar");');
+        $this->fixture->simpleQuery('INSERT INTO users (id, name) VALUE (2, "foobar2");');
+
+        $this->assertEquals(2, $this->fixture->exec('DELETE FROM users;'));
+    }
+
+    /*
+     * Tests for fetchRow
+     */
+
+    public function testFetchRow()
+    {
+        // valid query
+        $sql = 'CREATE TABLE users (
+            id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
+            name VARCHAR(30) NOT NULL
+        )';
+        $this->fixture->simpleQuery($sql);
+        $this->assertEquals(null, $this->fixture->fetchRow('SELECT * FROM users'));
+
+        // add data
+        $this->fixture->simpleQuery('INSERT INTO users (id, name) VALUE (1, "foobar");');
+        $this->assertEquals(
+            [
+                'id' => 1,
+                'name' => 'foobar',
+            ],
+            $this->fixture->fetchRow('SELECT * FROM users WHERE id = 1;')
+        );
+    }
+
+    /*
+     * Tests for fetchList
+     */
+
+    public function testFetchList()
+    {
+        // valid query
+        $sql = 'CREATE TABLE users (
+            id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
+            name VARCHAR(30) NOT NULL
+        )';
+        $this->fixture->simpleQuery($sql);
+        $this->assertEquals([], $this->fixture->fetchList('SELECT * FROM users'));
+
+        // add data
+        $this->fixture->simpleQuery('INSERT INTO users (id, name) VALUE (1, "foobar");');
+        $this->assertEquals(
+            [
+                [
+                    'id' => 1,
+                    'name' => 'foobar',
+                ]
+            ],
+            $this->fixture->fetchList('SELECT * FROM users')
+        );
+    }
+
+    /*
+     * Tests for getCollation
+     */
+
+    public function testGetCollation()
+    {
+        // g2t table
+        if (isset($this->dbConfig['db_table_prefix'])) {
+            $table = $this->dbConfig['db_table_prefix'] . '_';
+        } else {
+            $table = '';
+        }
+        if (isset($this->dbConfig['store_name'])) {
+            $table .= $this->dbConfig['store_name'] . '_';
+        }
+        $table .= 'setting';
+
+        // create setting table which is used to determine collation
+        $sql = 'CREATE TABLE '.$table.' (
+          k char(32) NOT NULL,
+          val text NOT NULL,
+          UNIQUE KEY (k)
+        ) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_unicode_ci DELAY_KEY_WRITE = 1';
+        $this->fixture->simpleQuery($sql);
+
+        $this->assertEquals('utf8_unicode_ci', $this->fixture->getCollation());
+    }
+
+    // setting table not there
+    public function testGetCollationNoReferenceTable()
+    {
+        $this->assertEquals('', $this->fixture->getCollation());
+    }
+
+    /*
+     * Tests for getDBSName
+     */
+
+    public function testGetDBSName()
+    {
+        // connect and check
+        $this->fixture->connect();
+        $this->assertTrue(in_array($this->fixture->getDBSName(), array('mariadb', 'mysql')));
+    }
+
+    public function testGetDBSNameNoConnection()
+    {
+        // disconnect current connection
+        $this->fixture->disconnect();
+
+        // create new instance, but dont connect
+        $db = $this->getAdapterInstance($this->dbConfig);
+
+        $this->assertNull($db->getDBSName());
+    }
+
+    /*
+     * Tests for getNumberOfRows
+     */
+
+    public function testGetNumberOfRows()
+    {
+        // create test table
+        $this->fixture->simpleQuery('
+            CREATE TABLE pet (name VARCHAR(20));
+        ');
+
+        $this->assertEquals(1, $this->fixture->getNumberOfRows('SHOW TABLES'));
+    }
+
+    /*
+     * Tests for query
+     */
+
+    public function testQuery()
+    {
+        // valid query
+        $sql = 'CREATE TABLE MyGuests (id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY)';
+        $this->fixture->simpleQuery($sql);
+
+        $foundTable = false;
+        foreach ($this->fixture->fetchList('SHOW TABLES') as $entry) {
+            if ('MyGuests' == $entry['Tables_in_'.$this->dbConfig['db_name']]) {
+                $foundTable = true;
+                break;
+            }
+        }
+        $this->assertTrue($foundTable, 'Expected table not found.');
+    }
+
+    /*
+     * Tests for getServerVersion
+     */
+
+    public function testGetServerVersion()
+    {
+        // check that server version looks like 05-00-05
+        $this->assertEquals(1, preg_match('/\d\d-\d\d-\d\d/', $this->fixture->getServerVersion()));
+    }
+
+    /*
+     * Tests for getStoreName
+     */
+
+    public function testGetStoreName()
+    {
+        $this->assertEquals($this->dbConfig['store_name'], $this->fixture->getStoreName());
+    }
+
+    public function testGetStoreNameNotDefined()
+    {
+        $this->fixture->disconnect();
+
+        $copyOfDbConfig = $this->dbConfig;
+        unset($copyOfDbConfig['store_name']);
+
+        $db = $this->getAdapterInstance($copyOfDbConfig);
+
+        $this->assertEquals('arc', $db->getStoreName());
+    }
+
+    /*
+     * Tests for simpleQuery
+     */
+
+    public function testSimpleQueryNoConnection()
+    {
+        // test, that it creates a connection itself, when calling simpleQuery
+        $this->fixture->disconnect();
+
+        $db = $this->getAdapterInstance($this->dbConfig);
+        $sql = 'CREATE TABLE MyGuests (id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY)';
+        $this->assertTrue($db->simpleQuery($sql));
+    }
+}
diff --git a/lib/arc2/tests/unit/src/ARC2/Store/Adapter/AdapterFactoryTest.php b/lib/arc2/tests/unit/src/ARC2/Store/Adapter/AdapterFactoryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ebcbffceb854f469bc9936db788339d1a823e057
--- /dev/null
+++ b/lib/arc2/tests/unit/src/ARC2/Store/Adapter/AdapterFactoryTest.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Tests\unit\src\ARC2\Store\Adapter;
+
+use ARC2\Store\Adapter\AbstractAdapter;
+use ARC2\Store\Adapter\AdapterFactory;
+use Tests\ARC2_TestCase;
+
+class AdapterFactoryTest extends ARC2_TestCase
+{
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->fixture = new AdapterFactory();
+    }
+
+    /*
+     * Tests for getInstanceFor
+     */
+
+    public function testGetInstanceFor()
+    {
+        $this->assertTrue($this->fixture->getInstanceFor('mysqli') instanceof AbstractAdapter);
+    }
+
+    public function testGetInstanceForInvalidAdapterName()
+    {
+        $this->expectException('Exception');
+        $this->expectExceptionMessage('Unknown adapter name given. Currently supported are: mysqli, pdo');
+
+        $this->fixture->getInstanceFor('invalid');
+    }
+
+    /*
+     * Tests for getSupportedAdapters
+     */
+
+    public function testGetSupportedAdapters()
+    {
+        $this->assertEquals(array('mysqli', 'pdo'), $this->fixture->getSupportedAdapters());
+    }
+}
diff --git a/lib/arc2/tests/unit/src/ARC2/Store/Adapter/CachedPDOAdapterTest.php b/lib/arc2/tests/unit/src/ARC2/Store/Adapter/CachedPDOAdapterTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..90e4df11ba897f83b71ec8f36360036ff08ad92c
--- /dev/null
+++ b/lib/arc2/tests/unit/src/ARC2/Store/Adapter/CachedPDOAdapterTest.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Tests\unit\src\ARC2\Store\Adapter;
+
+use ARC2\Store\Adapter\CachedPDOAdapter;
+
+class CachedPDOAdapterTest extends PDOAdapterTest
+{
+    public function setUp(): void
+    {
+        global $dbConfig;
+
+        if (false == isset($dbConfig['cache_enabled'])
+            || (
+                isset($dbConfig['cache_enabled']) && false == $dbConfig['cache_enabled']
+            )) {
+            $this->markTestSkipped('Cache not enabled, therefore skipped.');
+        }
+
+        parent::setUp();
+    }
+
+    protected function getAdapterInstance($configuration)
+    {
+        return new CachedPDOAdapter($configuration);
+    }
+
+    public function testExceptionIfCacheIsNotEnabled()
+    {
+        $this->expectException('Exception');
+        $this->expectExceptionMessage('Cache not enabled, therefore CachedPDOAdapter can not be used.');
+
+        $cfg = $this->dbConfig;
+        unset($cfg['cache_enabled']);
+        unset($cfg['cache_instance']);
+
+        new CachedPDOAdapter($cfg);
+    }
+}
diff --git a/lib/arc2/tests/unit/src/ARC2/Store/Adapter/PDOAdapterTest.php b/lib/arc2/tests/unit/src/ARC2/Store/Adapter/PDOAdapterTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e936c1e484424e864bd3239fb55e08cd17ec52e3
--- /dev/null
+++ b/lib/arc2/tests/unit/src/ARC2/Store/Adapter/PDOAdapterTest.php
@@ -0,0 +1,108 @@
+<?php
+
+namespace Tests\unit\src\ARC2\Store\Adapter;
+
+use ARC2\Store\Adapter\PDOAdapter;
+
+class PDOAdapterTest extends AbstractAdapterTest
+{
+    protected function checkAdapterRequirements()
+    {
+        // stop, if pdo_mysql is not available
+        if (false == \extension_loaded('pdo_mysql')) {
+            $this->markTestSkipped('Test skipped, because extension pdo_mysql is not installed.');
+        }
+
+        // stop, if pdo_db_protocol is not set in dbConfig
+        if (false == isset($this->dbConfig['db_pdo_protocol'])) {
+            $this->markTestSkipped(
+                'Test skipped, because db_pdo_protocol is not set. Its ok, if this happens in unit test environment.'
+            );
+        }
+    }
+
+    protected function getAdapterInstance($configuration)
+    {
+        return new PDOAdapter($configuration);
+    }
+
+    public function testConnectUseGivenConnection()
+    {
+        $this->fixture->disconnect();
+
+        // create connection outside of the instance
+        $dsn = $this->dbConfig['db_pdo_protocol'].':host='. $this->dbConfig['db_host'];
+        $dsn .= ';dbname='.$this->dbConfig['db_name'];
+        $dsn .= ';charset=utf8mb4';
+        $connection = new \PDO(
+            $dsn,
+            $this->dbConfig['db_user'],
+            $this->dbConfig['db_pwd']
+        );
+
+        $connection->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
+        $connection->setAttribute(\PDO::ERRMODE_EXCEPTION, true);
+        $connection->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_BOTH);
+        $connection->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
+
+        $this->fixture = $this->getAdapterInstance($this->dbConfig);
+
+        // use existing connection
+        $this->fixture->connect($connection);
+
+        // if not the same origin, the connection ID differs
+        $connectionId = $connection->query('SELECT CONNECTION_ID()')->fetch(\PDO::FETCH_ASSOC);
+        $this->assertEquals($this->fixture->getConnectionId(), $connectionId);
+
+        /*
+         * simple test query to check that its working
+         */
+        $sql = 'CREATE TABLE MyGuests (id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY)';
+        $this->fixture->simpleQuery($sql);
+
+        $tables = $this->fixture->fetchList('SHOW TABLES');
+        $this->assertTrue(is_array($tables) && 0 < count($tables));
+    }
+
+    public function testEscape()
+    {
+        $this->assertEquals('\"hallo\"', $this->fixture->escape('"hallo"'));
+    }
+
+    public function testGetAdapterName()
+    {
+        $this->assertEquals('pdo', $this->fixture->getAdapterName());
+    }
+
+    public function testGetConnection()
+    {
+        $this->assertTrue($this->fixture->getConnection() instanceof \PDO);
+    }
+
+    public function testGetNumberOfRowsInvalidQuery()
+    {
+        $this->expectException('Exception');
+
+        $dbs = 'mysql' == $this->fixture->getDBSName() ? 'MySQL' : 'MariaDB';
+
+        $this->expectExceptionMessage(
+            "SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your $dbs server version for the right syntax to use near 'of x' at line 1"
+        );
+
+        $this->fixture->getNumberOfRows('SHOW TABLES of x');
+    }
+
+    public function testQueryInvalid()
+    {
+        $this->expectException('Exception');
+
+        $dbs = 'mysql' == $this->fixture->getDBSName() ? 'MySQL' : 'MariaDB';
+
+        $this->expectExceptionMessage(
+            "SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your $dbs server version for the right syntax to use near 'invalid query' at line 1"
+        );
+
+        // invalid query
+        $this->assertFalse($this->fixture->simpleQuery('invalid query'));
+    }
+}
diff --git a/lib/arc2/tests/unit/src/ARC2/Store/Adapter/mysqliAdapterTest.php b/lib/arc2/tests/unit/src/ARC2/Store/Adapter/mysqliAdapterTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..5268472129edb47ffe334434f0bbc428cba29712
--- /dev/null
+++ b/lib/arc2/tests/unit/src/ARC2/Store/Adapter/mysqliAdapterTest.php
@@ -0,0 +1,102 @@
+<?php
+
+namespace Tests\unit\src\ARC2\Store\Adapter;
+
+use ARC2\Store\Adapter\mysqliAdapter;
+
+class mysqliAdapterTest extends AbstractAdapterTest
+{
+    protected function checkAdapterRequirements()
+    {
+        // stop, if mysqli is not available
+        if (false == \extension_loaded('mysqli') || false == \function_exists('mysqli_connect')) {
+            $this->markTestSkipped('Test skipped, because extension mysqli is not installed.');
+        }
+    }
+
+    protected function getAdapterInstance($configuration)
+    {
+        return new mysqliAdapter($configuration);
+    }
+
+    public function testConnectUseGivenConnection()
+    {
+        $this->fixture->disconnect();
+
+        // create connection outside of the instance
+        $connection = mysqli_connect(
+            $this->dbConfig['db_host'],
+            $this->dbConfig['db_user'],
+            $this->dbConfig['db_pwd'],
+            $this->dbConfig['db_name']
+        );
+
+        $this->fixture = new mysqliAdapter();
+
+        // use existing connection
+        $this->fixture->connect($connection);
+
+        // if not the same origin, the connection ID differs
+        $this->assertEquals($this->fixture->getConnectionId(), mysqli_thread_id($connection));
+
+        // simple test query to check that its working
+        $result = $this->fixture->simpleQuery('SHOW TABLES');
+        $this->assertTrue($result);
+    }
+
+    public function testEscape()
+    {
+        $this->assertEquals('\"hallo\"', $this->fixture->escape('"hallo"'));
+    }
+
+    public function testGetAdapterName()
+    {
+        $this->assertEquals('mysqli', $this->fixture->getAdapterName());
+    }
+
+    public function testGetConnection()
+    {
+        $this->assertTrue($this->fixture->getConnection() instanceof \mysqli);
+    }
+
+    /*
+     * Tests for getErrorMessage and getErrorCode
+     */
+
+    public function testGetErrorMessageAndGetErrorCode()
+    {
+        // invalid query
+        $result = $this->fixture->simpleQuery('SHOW TABLES of x');
+        $this->assertFalse($result);
+        $errorMsg = $this->fixture->getErrorMessage();
+        $errorCode = $this->fixture->getErrorCode();
+
+        $dbs = 'mariadb' == $this->fixture->getDBSName() ? 'MariaDB' : 'MySQL';
+
+        $this->assertEquals(
+            "You have an error in your SQL syntax; check the manual that corresponds to your $dbs server "
+            ."version for the right syntax to use near 'of x' at line 1",
+            $errorMsg
+        );
+
+        $this->assertTrue(0 < $errorCode);
+    }
+
+    public function testGetNumberOfRowsInvalidQuery()
+    {
+        // run with invalid query
+        $this->assertEquals(0, $this->fixture->getNumberOfRows('SHOW TABLES of x'));
+    }
+
+    public function testMysqliQuery()
+    {
+        $res = $this->fixture->mysqliQuery('SHOW TABLES');
+        $this->assertTrue($res instanceof \mysqli_result);
+    }
+
+    public function testQueryInvalid()
+    {
+        // invalid query
+        $this->assertFalse($this->fixture->simpleQuery('invalid query'));
+    }
+}
diff --git a/lib/arc2/tests/unit/store/ARC2_StoreEndpointTest.php b/lib/arc2/tests/unit/store/ARC2_StoreEndpointTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..471199d47dbedb3799844b7073fd8f4867b038a5
--- /dev/null
+++ b/lib/arc2/tests/unit/store/ARC2_StoreEndpointTest.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace Tests\unit\store;
+
+use Tests\ARC2_TestCase;
+
+
+//Tests ARC2_StoreEndpoint functions  
+class ARC2_StoreEndpointTest extends ARC2_TestCase
+{
+
+    public function setUp(): void
+    {
+        parent::setUp();
+        $this->endpoint = \ARC2::getStoreEndpoint($this->dbConfig);
+        $this->endpoint->createDBCon();
+    }
+    public function testJSON()
+    {
+
+        $data = array(
+            'result' => array(
+                'variables' => array(
+                    'a',
+                    'b',
+                    'c'
+                ),
+                'rows' => array(
+                    array(
+                        'a' => 'http://de.dbpedia.org/resource/Johann_von_Pont',
+                        'a type' => 'uri',
+                        'b' => 'http://dbpedia.org/ontology/deathPlace',
+                        'b type' => 'uri',
+                        'c' => 'http://de.dbpedia.org/resource/Aachen',
+                        'c type' => 'uri'
+                    ),
+                    array(
+                        'a' => 'http://de.dbpedia.org/resource/Aachen',
+                        'a type' => 'uri',
+                        'b' => 'http://dbpedia.org/ontology/elevation',
+                        'b type' => 'uri',
+                        'c' => '173.0',
+                        'c type' => 'literal',
+                        'c datatype' => 'http://www.w3.org/2001/XMLSchema#double'
+                    ),
+                    array(
+                        'a' => 'http://de.dbpedia.org/resource/Aachen',
+                        'a type' => 'uri',
+                        'b' => 'http://dbpedia.org/ontology/leaderTitle',
+                        'b type' => 'uri',
+                        'c' => 'Oberbürgermeister',
+                        'c type' => 'literal',
+                        'c lang' => 'de'
+                    )
+                )
+            ),
+            'query_time' => 1
+        );
+        $res  = json_decode($this->endpoint->getSPARQLJSONSelectResultDoc($data), true);
+        $this->assertArrayHasKey('head', $res);
+        $this->assertArrayHasKey('results', $res);
+        $this->assertEquals($res['head']['vars'][0], 'a');
+        $this->assertEquals($res['results']['bindings'][0]['a']['value'], 'http://de.dbpedia.org/resource/Johann_von_Pont');
+        $this->assertEquals($res['results']['bindings'][1]['c']['type'], 'typed-literal');
+        $this->assertEquals($res['results']['bindings'][2]['c']['type'], 'literal');
+    }
+}
diff --git a/lib/arc2/tests/unit/store/ARC2_StoreLoadQueryHandlerTest.php b/lib/arc2/tests/unit/store/ARC2_StoreLoadQueryHandlerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..7bbcc19a5bd71ac2d4d3c530df7a7d0bb33f46a6
--- /dev/null
+++ b/lib/arc2/tests/unit/store/ARC2_StoreLoadQueryHandlerTest.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Tests\unit\store;
+
+use ARC2_StoreLoadQueryHandler;
+use Tests\ARC2_TestCase;
+
+class ARC2_StoreLoadQueryHandlerTest extends ARC2_TestCase
+{
+    protected $store;
+
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->store = \ARC2::getStore($this->dbConfig);
+        $this->store->createDBCon();
+
+        $this->fixture = new ARC2_StoreLoadQueryHandler($this->store, $this);
+
+        // remove all tables
+        $tables = $this->store->getDBObject()->fetchList('SHOW TABLES');
+        foreach($tables as $table) {
+            $this->store->getDBObject()->simpleQuery('DROP TABLE '. $table['Tables_in_'.$this->dbConfig['db_name']]);
+        }
+
+        // fresh setup of ARC2
+        $this->store->setup();
+    }
+
+    public function tearDown(): void
+    {
+        $this->store->closeDBCon();
+    }
+
+    /*
+     * Tests for getOComp
+     */
+
+    /**
+     * Tests to behavior, if a datetime string was given.
+     */
+    public function testGetOComp()
+    {
+        // case with +hourse
+        $string = '2009-05-28T18:03:38+09:00';
+        $this->assertEquals('2009-05-28T09:03:38Z', $this->fixture->getOComp($string));
+
+        // GMT case
+        $string = '2009-05-28T18:03:38GMT';
+        $this->assertEquals('2009-05-28T18:03:38Z', $this->fixture->getOComp($string));
+    }
+}
diff --git a/lib/arc2/tests/unit/store/ARC2_StoreTest.php b/lib/arc2/tests/unit/store/ARC2_StoreTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..4bcb562aacaca8768f5a5feb9d89983258b0cc5a
--- /dev/null
+++ b/lib/arc2/tests/unit/store/ARC2_StoreTest.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Tests\unit\store;
+
+use Tests\ARC2_TestCase;
+
+class ARC2_StoreTest extends ARC2_TestCase
+{
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->fixture = \ARC2::getStore($this->dbConfig);
+        $this->fixture->createDBCon();
+
+        // remove all tables
+        $tables = $this->fixture->getDBObject()->fetchList('SHOW TABLES');
+        foreach($tables as $table) {
+            $this->fixture->getDBObject()->simpleQuery('DROP TABLE '. $table['Tables_in_'.$this->dbConfig['db_name']]);
+        }
+
+        // fresh setup of ARC2
+        $this->fixture->setup();
+    }
+
+    public function tearDown(): void
+    {
+        $this->fixture->closeDBCon();
+    }
+
+    public function testCacheEnabled()
+    {
+        $cacheEnabled = isset($this->dbConfig['cache_enabled'])
+            && $this->dbConfig['cache_enabled']
+            && 'pdo' == $this->dbConfig['db_adapter'];
+        $this->assertEquals($cacheEnabled, $this->fixture->cacheEnabled());
+    }
+}