(function() {


  if(typeof(console)=='undefined') {
     console = {};
     console.log = function(e){};
  }
  
  window.process = {};
  process.nextTick = function(f) {
    setTimeout(f,0);
  };
var Utils = {};



Utils['extends'] = function(supertype, descendant) {
    descendant.prototype = new supertype();
};


Utils.stackCounterLimit = 1000;
Utils.stackCounter = 0;

Utils.recur = function(c){
    if(Utils.stackCounter === Utils.stackCounterLimit) {
        Utils.stackCounter = 0;
        setTimeout(c, 0);
    } else {
        Utils.stackCounter++;
        c();
    } 
};

Utils.clone = function(o) {
    return JSON.parse(JSON.stringify(o));
};

Utils.shuffle = function(o){ //v1.0
    for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x){};
    return o;
};

Utils.include = function(a,v) {
    var cmp = arguments[2];

    for(var i=(a.length-1); i>=0; i--) {
        var res = false;
        if(cmp == null) {
            res = (a[i] === v);
        } else {
            res = (cmp(a[i],v) === 0);
        }

        if(res === true) {
            return true;
        }
    }

    return false;
};

Utils.remove = function(a,v) {
    var acum = [];
    for(var i=0; i<a.length; i++) {
        if(a[i] !== v) {
            acum.push(a[i]);
        }
    }

    return acum;
};

Utils.repeat = function(c,max,floop,fend,env) {
    if(arguments.length===4) { env = {}; }
    if(c<max) {
        env._i = c;
        floop(function(floop,env){
            // avoid stack overflow
            // deadly hack
            Utils.recur(function(){ Utils.repeat(c+1, max, floop, fend, env); });
        },env);
    } else {
        fend(env);
    }
};


Utils.meanwhile = function(c,floop,fend,env) {
    if(arguments.length===3) { env = {}; }

    if(env['_stack_counter'] == null) {
        env['_stack_counter'] = 0;
    }

    if(c===true) {
        floop(function(c,floop,env){
            if(env['_stack_counter'] % 40 == 39) {
                env['_stack_counter'] = env['_stack_counter'] + 1;
                setTimeout(function(){ Utils.neanwhile(c, floop, fend, env); }, 0);
            } else {
                env['_stack_counter'] = env['_stack_counter'] + 1;
                Utils.meanwhile(c, floop, fend, env);
            }
        },env);
    } else {
        fend(env);
    }
};

Utils.seq = function() {
    var fs = arguments;
    return function(callback) {
        Utils.repeat(0, fs.length, function(k,env){
            var floop = arguments.callee;
            fs[env._i](function(){
                k(floop, env);
            });
        }, function(){
            callback();
        });
    };
};


Utils.partition = function(c, n) {
    var rem = c.length % n;
    var currentGroup = [];
    for(var i=0; i<rem; i++) {
        currentGroup.push(null);
    }
    
    var groups = [];
    for(var i=0; i<c.length; i++) {
        currentGroup.push(c[i]);
        if(currentGroup.length % n == 0) {
            groups.push(currentGroup);
            currentGroup = [];
        }
    }
    return groups;
};

Utils.keys = function(obj) {
    var variables = [];
    for(var variable in obj) {
        variables.push(variable);
    }

    return variables;
};

Utils.iso8601 = function(date) {
    function pad(n){
        return n<10 ? '0'+n : n;
    }    
    return date.getUTCFullYear()+'-'
        + pad(date.getUTCMonth()+1)+'-'
        + pad(date.getUTCDate())+'T'
        + pad(date.getUTCHours())+':'
        + pad(date.getUTCMinutes())+':'
        + pad(date.getUTCSeconds())+'Z';
};


Utils.parseStrictISO8601 = function (str) {
    var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
        "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
        "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
    var d = str.match(new RegExp(regexp));

    var offset = 0;
    var date = new Date(d[1], 0, 1);

    if (d[3]) {
        date.setMonth(d[3] - 1);
    } else {
        throw "missing ISO8061 component"
    }
    if (d[5]) {
        date.setDate(d[5]);
    } else {
        throw "missing ISO8061 component"
    }
    if (d[7]) {
        date.setHours(d[7]);
    } else {
        throw "missing ISO8061 component"
    }
    if (d[8]) {
        date.setMinutes(d[8]);
    } else {
        throw "missing ISO8061 component"
    }
    if (d[10]) {
        date.setSeconds(d[10]);
    } else {
        throw "missing ISO8061 component"
    }
    if (d[12]) {
        date.setMilliseconds(Number("0." + d[12]) * 1000);
    }
    if (d[14]) {
        offset = (Number(d[16]) * 60) + Number(d[17]);
        offset *= ((d[15] == '-') ? 1 : -1);
    }

    offset -= date.getTimezoneOffset();
    var time = (Number(date) + (offset * 60 * 1000));
    var toReturn = new Date();
    toReturn.setTime(Number(time));
    return toReturn;
};


Utils.parseISO8601 = function (str) {
    var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
        "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
        "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
    var d = str.match(new RegExp(regexp));

    var offset = 0;
    var date = new Date(d[1], 0, 1);

    if (d[3]) { date.setMonth(d[3] - 1); }
    if (d[5]) { date.setDate(d[5]);  }
    if (d[7]) { date.setHours(d[7]);  }
    if (d[8]) { date.setMinutes(d[8]);  }
    if (d[10]) { date.setSeconds(d[10]);  }
    if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
    if (d[14]) {
        offset = (Number(d[16]) * 60) + Number(d[17]);
        offset *= ((d[15] == '-') ? 1 : -1);
    }

    offset -= date.getTimezoneOffset();
    var time = (Number(date) + (offset * 60 * 1000));
    var toReturn = new Date();
    toReturn.setTime(Number(time));
    return toReturn;
};

Utils.parseISO8601Components = function (str) {
    var regexp = "([0-9]{4})(-([0-9]{2}))(-([0-9]{2}))(T([0-9]{2}):([0-9]{2})(:([0-9]{2}))?(\.([0-9]+))?)?(Z|([-+])([0-9]{2})(:([0-9]{2}))?)?";
    var d = str.match(new RegExp(regexp));
    var year, month, date, hours, minutes, seconds, millisecs, timezone;
    year = Number(d[1]);
    month = d[3] - 1;
    date  = Number(d[5]);
    hours = Number(d[7]);
    minutes = Number(d[8]);
    seconds = Number(d[10]);

    if(d[12]) { millisecs = Number("0." + d[12]) * 1000; }

    if(d[13]==="Z") {
        timezone = 0;
    } else if (d[14]) {
        timezone = 0;
        if(d[17]) {
            timezone = Number(d[17]);
        }
        timezone = timezone+(Number(d[15]) * 60);
        timezone *= ((d[14] == '-') ? -1 : +1);
    } else if(d[14]==null && d[11]) {
        timezone = Number(d[12])*60;
    }    

    return {'year': isNaN(year) ? null : year,
            'month': isNaN(month) ? null : month,
            'date': isNaN(date) ? null : date,
            'hours': isNaN(hours) ? null : hours,
            'minutes': isNaN(minutes) ? null : minutes,
            'seconds': isNaN(seconds) ? null : seconds,
            'millisecs':isNaN(millisecs) ? null : millisecs,
            'timezone': isNaN(timezone) ? null : timezone};
};

Utils.compareDateComponents = function(stra,strb) {
    var a = Utils.parseISO8601Components(stra);
    var b = Utils.parseISO8601Components(strb);

    if((a.timezone == null && b.timezone == null) ||
       (a.timezone != null && b.timezone != null)) {        
        var da = Utils.parseISO8601(stra);
        var db = Utils.parseISO8601(strb);
        
        if(da.getTime() == db.getTime()) {
            return 0;
        } else if(da.getTime() < db.getTime()){
            return -1;
        } else {
            return 1;
        }
    } else if (a.timezone != null && b.timezone == null){
        da = Utils.parseISO8601(stra);
        db = Utils.parseISO8601(strb);
        var ta = da.getTime();
        var tb = db.getTime();

        var offset = 14*60*60;

        if(ta < tb && ta < (tb + offset)) {
            return -1;
        } else if(ta > tb && ta > (tb - offset)) {
            return 1;
        } else {
        return null;
        }
    } else {
        da = Utils.parseISO8601(stra);
        db = Utils.parseISO8601(strb);
        ta = da.getTime();
        tb = db.getTime();

        var offset = 14*60*60;
        if(ta < tb && (ta + offset)  < tb) {
            return -1;
        } else if(ta > tb && (ta + offset) > tb) {
            return 1;
        } else {
        return null;
        }
    }
};

// RDF utils
Utils.lexicalFormLiteral = function(term, env) {
    var value = term.value;
    var lang = term.lang;
    var type = term.type;

    var indexedValue = null;
    if(value != null && type != null && typeof(type) != 'string') {
        var typeValue = type.value;

        if(typeValue == null) {
            var typePrefix = type.prefix;
            var typeSuffix = type.suffix;

            var resolvedPrefix = env.namespaces[typePrefix];
            term.type = resolvedPrefix+typeSuffix;
	    typeValue = resolvedPrefix+typeSuffix;
        }
	// normalization
	if(typeValue.indexOf('hexBinary') != -1) {
            indexedValue = '"' + term.value.toLowerCase() + '"^^<' + typeValue + '>';
	} else {
            indexedValue = '"' + term.value + '"^^<' + typeValue + '>';
	}
    } else {
        if(lang == null && type == null) {
            indexedValue = '"' + value + '"';
        } else if(type == null) {
            indexedValue = '"' + value + '"' + "@" + lang;        
        } else {
	    // normalization
	    if(type.indexOf('hexBinary') != -1) {
		indexedValue = '"' + term.value.toLowerCase() + '"^^<'+type+'>';
	    } else {
		indexedValue = '"' + term.value + '"^^<'+type+'>';
	    }
        }
    }
    return indexedValue;
};

Utils.lexicalFormBaseUri = function(term, env) {
    var uri = null;
    env = env || {};
    //console.log("*** normalizing URI token:");
    //console.log(term);
    if(term.value == null) {
        //console.log(" - URI has prefix and suffix");
        //console.log(" - prefix:"+term.prefix);
        //console.log(" - suffixx:"+term.suffix);
        var prefix = term.prefix;
        var suffix = term.suffix;
        var resolvedPrefix = env.namespaces[prefix];
        if(resolvedPrefix != null) {            
            uri = resolvedPrefix+suffix;
        } else {
            uri = prefix+":"+suffix;
        }
    } else {
        //console.log(" - URI is not prefixed");
        uri = term.value;
    }

    if(uri===null) {
        return null;
    } else {
        //console.log(" - resolved URI is "+uri);
        if(uri.indexOf(":") == -1) {
            //console.log(" - URI is partial");
            uri = (env.base||"") + uri; // applyBaseUri
        } else {
            //console.log(" - URI is complete");
        }
        //console.log(" -> FINAL URI: "+uri);
    }

    return uri;
};


Utils.lexicalFormTerm = function(term, ns) {
    if(term.token === 'uri') {
        return {'uri': Utils.lexicalFormBaseUri(term, ns)};
    } else if(term.token === 'literal') {
        return {'literal': Utils.lexicalFormLiteral(term, ns)};
    } else if(term.token === 'blank') {
        var label = '_:'+term.value;
        return {'blank': label};
    } else {
	throw "Error, cannot get lexical form of unknown token: "+term.token;
    }
};

Utils.normalizeUnicodeLiterals = function (string) {
    var escapedUnicode = string.match(/\\u[0-9abcdefABCDEF]{4,4}/g) || [];
    var dups = {};
    for (var i = 0; i < escapedUnicode.length; i++) {
        if (dups[escapedUnicode[i]] == null) {
            dups[escapedUnicode[i]] = true;
            string = string.replace(new RegExp("\\" + escapedUnicode[i], "g"), eval("'" + escapedUnicode[i] + "'"));
        }
    }

    return string;
};

Utils.hashTerm = function(term) {
    try {
      if(term == null) {
          return "";
      } if(term.token==='uri') {
          return "u"+term.value;
      } else if(term.token === 'blank') {
          return "b"+term.value;
      } else if(term.token === 'literal') {
          var l = "l"+term.value;
          l = l + (term.type || "");
          l = l + (term.lang || "");        
   
          return l;
      }
    } catch(e) {
        if(typeof(term) === 'object') {
            var key = "";
            for(p in term) {
                key = key + p + term[p];
            }

            return key;
        }
        return term;
    }
};

// end of ./src/js-trees/src/utils.js 
// exports
var InMemoryBTree = {};

var left = -1;
var right = 1;


/**
 * @doc
 * Implementation based on <http://www.gossamer-threads.com/lists/linux/kernel/667935>
 *
 */

/**
 * Tree
 *
 * Implements the interface of BinarySearchTree.Tree
 *
 * An implementation of an in memory B-Tree.
 */

InMemoryBTree.Tree = function(order) {
    if(arguments.length != 0) {
        this.order = order;
        this.root = this._allocateNode();
        this.root.isLeaf = true;
        this.root.level = 0;
        this._diskWrite(this.root);
        this._updateRootNode(this.root);

        this.comparator = function(a,b) {
            if(a < b) {
                return -1;
            } else if(a > b){
                return 1;
            } else {
                return 0;
            }
        };
        this.merger = null;
    }
};

/**
 * Creates the new node.
 *
 * This class can be overwritten by different versions of
 * the tree t select the right kind of node to be used
 *
 * @returns the new alloacted node
 */
InMemoryBTree.Tree.prototype._allocateNode = function () {
    return new InMemoryBTree.Node();
};

/**
 * _diskWrite
 *
 * Persists the node to secondary memory.
 */
InMemoryBTree.Tree.prototype._diskWrite= function(node) {
    // dummy implementation;
    // no-op
};


/**
 * _diskRead
 *
 * Retrieves a node from secondary memory using the provided
 * pointer
 */
InMemoryBTree.Tree.prototype._diskRead = function(pointer) {
    // dummy implementation;
    // no-op
    return pointer;
};


InMemoryBTree.Tree.prototype._diskDelete= function(node) {
    // dummy implmentation
    // no-op
};

/**
 * _updateRootNode
 *
 * Updates the pointer to the root node stored in disk.
 */
InMemoryBTree.Tree.prototype._updateRootNode = function(node) {
    // dummy implementation;
    // no-op
    return node;
};

InMemoryBTree.Tree.prototype.clear = function() {
        this.root = this._allocateNode();
        this.root.isLeaf = true;
        this.root.level = 0;
        this._updateRootNode(this.root);
};

/**
 * search
 *
 * Retrieves the node matching the given value.
 * If no node is found, null is returned.
 */
InMemoryBTree.Tree.prototype.search = function(key, checkExists) {
    var searching = true;
    var node = this.root;

    while(searching) {
        var idx = 0;
        while(idx < node.numberActives && this.comparator(key, node.keys[idx].key) === 1) {
            idx++;
        }

        if(idx < node.numberActives && this.comparator(node.keys[idx].key,key) === 0) {
            if(checkExists != null && checkExists == true) {
                return true;
            } else {
                return node.keys[idx].data;
            }
        } else {
            if(node.isLeaf === true) {
                searching = false;
            } else {
                node = this._diskRead(node.children[idx]);
            }
        }
    }

    return null;
};


/**
 * walk
 * Applies a function to all the nodes key and data in the the
 * tree in key order.
 */
InMemoryBTree.Tree.prototype.walk = function(f) {
    this._walk(f,this.root);
};

InMemoryBTree.Tree.prototype._walk = function(f,node) {
    if(node.isLeaf) {
        for(var i=0; i<node.numberActives; i++) {
            f(node.keys[i]);
        }
    } else {
        for(var i=0; i<node.numberActives; i++) {
            this._walk(f,this._diskRead(node.children[i]));
            f(node.keys[i]);
        }
        this._walk(f,this._diskRead(node.children[node.numberActives]));
    }
};

/**
 * walkNodes
 * Applies a function to all the nodes in the the
 * tree in key order.
 */
InMemoryBTree.Tree.prototype.walkNodes = function(f) {
    this._walkNodes(f,this.root);
};

InMemoryBTree.Tree.prototype._walkNodes = function(f,node) {
    if(node.isLeaf) {
        f(node);
    } else {
        f(node);
        for(var i=0; i<node.numberActives; i++) {
            this._walkNodes(f,this._diskRead(node.children[i]));
        }
        this._walkNodes(f,this._diskRead(node.children[node.numberActives]));
    }
};

/**
 * _splitChild
 *
 * Split the child node and adjusts the parent.
 */
InMemoryBTree.Tree.prototype._splitChild = function(parent, index, child) {
    var newChild = this._allocateNode();
    newChild.isLeaf = child.isLeaf;
    newChild.level = child.level;
    newChild.numberActives = this.order - 1;

    // Copy the higher order keys to the new child
    var newParentChild = child.keys[this.order-1];
    child.keys[this.order-1] = null;

    for(var i=0; i< this.order-1; i++) {
	newChild.keys[i]=child.keys[i+this.order];
	child.keys[i+this.order] = null;
	if(!child.isLeaf) {
	    newChild.children[i] = child.children[i+this.order];
            child.children[i+this.order] = null;
	}
    }

    // Copy the last child pointer
    if(!child.isLeaf) {
	newChild.children[i] = child.children[i+this.order];
        child.children[i+this.order] = null;
    }

    child.numberActives = this.order - 1;


    for(i = parent.numberActives + 1; i>index+1; i--) {
	parent.children[i] = parent.children[i-1];
    }

    parent.children[index+1] = newChild;

    for(i = parent.numberActives; i>index; i--) {
	parent.keys[i] = parent.keys[i-1];
    }

    parent.keys[index] = newParentChild;
    parent.numberActives++;

    this._diskWrite(newChild);
    this._diskWrite(parent);
    this._diskWrite(child);
};

/**
 * insert
 *
 * Creates a new node with value key and data and inserts it
 * into the tree.
 */
InMemoryBTree.Tree.prototype.insert = function(key,data) {
    if(this.root.numberActives === (2 * this.order - 1)) {
        var newRoot = this._allocateNode();
        newRoot.isLeaf = false;
        newRoot.level = this.root.level + 1;
        newRoot.numberActives = 0;
        newRoot.children[0] = this.root;

        this._splitChild(newRoot, 0, this.root);
        this.root = newRoot;
        this._updateRootNode(this.root);
        this._insertNonFull(newRoot, key, data);
    } else {
        this._insertNonFull(this.root, key, data);
    }
};

/**
 * _insertNonFull
 *
 * Recursive function that tries to insert the new key in
 * in the prvided node, or splits it and go deeper
 * in the BTree hierarchy.
 */
InMemoryBTree.Tree.prototype._insertNonFull = function(node,key,data) {
    var idx = node.numberActives - 1;

    while(!node.isLeaf) {
        while(idx>=0 && this.comparator(key,node.keys[idx].key) === -1) {
            idx--;
        }
        idx++;
        var child = this._diskRead(node.children[idx]);

        if(child.numberActives === 2*this.order -1) {
            this._splitChild(node,idx,child);
            if(this.comparator(key, node.keys[idx].key)===1) {
                idx++;
            }
        }
        node = this._diskRead(node.children[idx]);
        idx = node.numberActives -1;
    }

    while(idx>=0 && this.comparator(key,node.keys[idx].key) === -1) {
        node.keys[idx+1] = node.keys[idx];
        idx--;
    }

    node.keys[idx + 1] = {key:key, data:data};
    node.numberActives++;
    this._diskWrite(node);
};

/**
 * delete
 *
 * Deletes the key from the BTree.
 * If the key is not found, an exception is thrown.
 *
 * @param key the key to be deleted
 * @returns true if the key is deleted false otherwise
 */
InMemoryBTree.Tree.prototype['delete'] = function(key) {
    var node = this.root;
    var parent = null;
    var searching = true;
    var idx = null;
    var lsibling = null;
    var rsibling = null;
    var shouldContinue = true;

    while(shouldContinue === true) {
        shouldContinue = false;

        while(searching === true) {
            i = 0;

            if(node.numberActives === 0) {
                return false;
            }

            while(i<node.numberActives && this.comparator(key, node.keys[i].key) === 1) {
                i++;
            }

            idx = i;

            if(i<node.numberActives && this.comparator(key, node.keys[i].key) === 0) {
                searching = false;
            }

            if(searching === true) {

                if(node.isLeaf === true) {
                    return false;
                }

                parent = node;
                node = this._diskRead(node.children[i]);

                if(node===null) {
                    return false;
                }

                if(idx === parent.numberActives) {
                    lsibling = this._diskRead(parent.children[idx-1]);
                    rsibling = null;
                } else if(idx === 0) {
                    lsibling = null;
                    rsibling = this._diskRead(parent.children[1]);
                } else {
                    lsibling = this._diskRead(parent.children[idx-1]);
                    rsibling = this._diskRead(parent.children[idx+1]);
                }


                if(node.numberActives === (this.order-1) && parent != null) {
                    if(rsibling != null && rsibling.numberActives > (this.order-1)) {
                        // The current node has (t - 1) keys but the right sibling has > (t - 1) keys
                        this._moveKey(parent,i,left);
                    } else if(lsibling != null && lsibling.numberActives > (this.order-1)) {
                        // The current node has (t - 1) keys but the left sibling has > (t - 1) keys
                        this._moveKey(parent,i,right);
                    } else if(lsibling != null && lsibling.numberActives === (this.order-1)) {
                        // The current node has (t - 1) keys but the left sibling has (t - 1) keys
                        node = this._mergeSiblings(parent,i,left);
                    } else if(rsibling != null && rsibling.numberActives === (this.order-1)){
                        // The current node has (t - 1) keys but the left sibling has (t - 1) keys
                        node = this._mergeSiblings(parent,i,right);
                    }
                }
            }
        }


        //Case 1 : The node containing the key is found and is the leaf node.
        //Also the leaf node has keys greater than the minimum required.
        //Simply remove the key
        if(node.isLeaf && (node.numberActives > (this.order-1))) {
            this._deleteKeyFromNode(node,idx);
            return true;
        }


        //If the leaf node is the root permit deletion even if the number of keys is
        //less than (t - 1)
        if(node.isLeaf && (node === this.root)) {
            this._deleteKeyFromNode(node,idx);
            return true;
        }


        //Case 2: The node containing the key is found and is an internal node
        if(node.isLeaf === false) {
            var tmpNode = null;
            var tmpNode2 = null;
            if((tmpNode=this._diskRead(node.children[idx])).numberActives > (this.order-1)) {
                var subNodeIdx = this._getMaxKeyPos(tmpNode);
                key = subNodeIdx.node.keys[subNodeIdx.index];

                node.keys[idx] = key;

                //this._delete(node.children[idx],key.key);
                this._diskWrite(node);
                node = tmpNode;
                key = key.key;
                shouldContinue = true;
                searching = true;
            } else if ((tmpNode = this._diskRead(node.children[idx+1])).numberActives >(this.order-1)) {
                var subNodeIdx = this._getMinKeyPos(tmpNode);
                key = subNodeIdx.node.keys[subNodeIdx.index];

                node.keys[idx] = key;

                //this._delete(node.children[idx+1],key.key);
                this._diskWrite(node);
                node = tmpNode;
                key = key.key;
                shouldContinue = true;
                searching = true;
            } else if((tmpNode = this._diskRead(node.children[idx])).numberActives === (this.order-1) &&
                      (tmpNode2 = this._diskRead(node.children[idx+1])).numberActives === (this.order-1)) {

                var combNode = this._mergeNodes(tmpNode, node.keys[idx], tmpNode2);
                node.children[idx] = combNode;

                idx++;
                for(var i=idx; i<node.numberActives; i++) {
          	    node.children[i] = node.children[i+1];
          	    node.keys[i-1] = node.keys[i];
                }
                // freeing unused references
                node.children[i] = null;
                node.keys[i-1] = null;

                node.numberActives--;
                if (node.numberActives === 0 && this.root === node) {
                    this.root = combNode;
                }

                this._diskWrite(node);

                node = combNode;
                shouldContinue = true;
                searching = true;
            }
        }


        // Case 3:
	// In this case start from the top of the tree and continue
	// moving to the leaf node making sure that each node that
	// we encounter on the way has atleast 't' (order of the tree)
	// keys
	if(node.isLeaf && (node.numberActives > this.order - 1) && searching===false) {
            this._deleteKeyFromNode(node,idx);
	}

        if(shouldContinue === false) {
            return true;
        }
    }
};

/**
 * _moveKey
 *
 * Move key situated at position i of the parent node
 * to the left or right child at positions i-1 and i+1
 * according to the provided position
 *
 * @param parent the node whose is going to be moved to a child
 * @param i Index of the key in the parent
 * @param position left, or right
 */
InMemoryBTree.Tree.prototype._moveKey = function (parent, i, position) {

    if (position === right) {
        i--;
    }

    //var lchild = parent.children[i-1];
    var lchild = this._diskRead(parent.children[i]);
    var rchild = this._diskRead(parent.children[i + 1]);


    if (position == left) {
        lchild.keys[lchild.numberActives] = parent.keys[i];
        lchild.children[lchild.numberActives + 1] = rchild.children[0];
        rchild.children[0] = null;
        lchild.numberActives++;

        parent.keys[i] = rchild.keys[0];

        for (var _i = 1; _i < rchild.numberActives; _i++) {
            rchild.keys[_i - 1] = rchild.keys[_i];
            rchild.children[_i - 1] = rchild.children[_i];
        }
        rchild.children[rchild.numberActives - 1] = rchild.children[rchild.numberActives];
        rchild.numberActives--;
    } else {
        rchild.children[rchild.numberActives + 1] = rchild.children[rchild.numberActives];
        for (var _i = rchild.numberActives; _i > 0; _i--) {
            rchild.children[_i] = rchild.children[_i - 1];
            rchild.keys[_i] = rchild.keys[_i - 1];
        }
        rchild.keys[0] = null;
        rchild.children[0] = null;

        rchild.children[0] = lchild.children[lchild.numberActives];
        rchild.keys[0] = parent.keys[i];
        rchild.numberActives++;

        lchild.children[lchild.numberActives] = null;
        parent.keys[i] = lchild.keys[lchild.numberActives - 1];
        lchild.keys[lchild.numberActives - 1] = null;
        lchild.numberActives--;
    }

    this._diskWrite(lchild);
    this._diskWrite(rchild);
    this._diskWrite(parent);
};

/**
 * _mergeSiblings
 *
 * Merges two nodes at the left and right of the provided
 * index in the parent node.
 *
 * @param parent the node whose children will be merged
 * @param i Index of the key in the parent pointing to the nodes to merge
 */
InMemoryBTree.Tree.prototype._mergeSiblings = function (parent, index, pos) {
    var i, j;
    var n1, n2;

    if (index === (parent.numberActives)) {
        index--;
        n1 = this._diskRead(parent.children[parent.numberActives - 1]);
        n2 = this._diskRead(parent.children[parent.numberActives]);
    } else {
        n1 = this._diskRead(parent.children[index]);
        n2 = this._diskRead(parent.children[index + 1]);
    }

    //Merge the current node with the left node
    var newNode = this._allocateNode();
    newNode.isLeaf = n1.isLeaf;
    newNode.level = n1.level;

    for (j = 0; j < this.order - 1; j++) {
        newNode.keys[j] = n1.keys[j];
        newNode.children[j] = n1.children[j];
    }

    newNode.keys[this.order - 1] = parent.keys[index];
    newNode.children[this.order - 1] = n1.children[this.order - 1];

    for (j = 0; j < this.order - 1; j++) {
        newNode.keys[j + this.order] = n2.keys[j];
        newNode.children[j + this.order] = n2.children[j];
    }
    newNode.children[2 * this.order - 1] = n2.children[this.order - 1];

    parent.children[index] = newNode;

    for (j = index; j < parent.numberActives; j++) {
        parent.keys[j] = parent.keys[j + 1];
        parent.children[j + 1] = parent.children[j + 2];
    }

    newNode.numberActives = n1.numberActives + n2.numberActives + 1;
    parent.numberActives--;

    for (i = parent.numberActives; i < 2 * this.order - 1; i++) {
        parent.keys[i] = null;
    }

    if (parent.numberActives === 0 && this.root === parent) {
        this.root = newNode;
        if (newNode.level) {
            newNode.isLeaf = false;
        } else {
            newNode.isLeaf = true;
        }
    }

    this._diskWrite(newNode);
    if (this.root === newNode) {
        this._updateRootNode(this.root);
    }
    this._diskWrite(parent);
    this._diskDelete(n1);
    this._diskDelete(n2);

    return newNode;
};

/**
 * _deleteKeyFromNode
 *
 * Deletes the key at position index from the provided node.
 *
 * @param node The node where the key will be deleted.
 * @param index The index of the key that will be deletd.
 * @return true if the key can be deleted, false otherwise
 */
InMemoryBTree.Tree.prototype._deleteKeyFromNode = function (node, index) {
    var keysMax = (2 * this.order) - 1;
    if (node.numberActives < keysMax) {
        keysMax = node.numberActives;
    }
    ;

    var i;

    if (node.isLeaf === false) {
        return false;
    }

    var key = node.keys[index];

    for (i = index; i < keysMax - 1; i++) {
        node.keys[i] = node.keys[i + 1];
    }

    // cleaning invalid reference
    node.keys.pop();

    node.numberActives--;

    this._diskWrite(node);

    return true;
};

InMemoryBTree.Tree.prototype._mergeNodes = function (n1, key, n2) {
    var newNode;
    var i;

    newNode = this._allocateNode();
    newNode.isLeaf = true;

    for (i = 0; i < n1.numberActives; i++) {
        newNode.keys[i] = n1.keys[i];
        newNode.children[i] = n1.children[i];
    }
    newNode.children[n1.numberActives] = n1.children[n1.numberActives];
    newNode.keys[n1.numberActives] = key;

    for (i = 0; i < n2.numberActives; i++) {
        newNode.keys[i + n1.numberActives + 1] = n2.keys[i];
        newNode.children[i + n1.numberActives + 1] = n2.children[i];
    }
    newNode.children[(2 * this.order) - 1] = n2.children[n2.numberActives];

    newNode.numberActives = n1.numberActives + n2.numberActives + 1;
    newNode.isLeaf = n1.isLeaf;
    newNode.level = n1.level;


    this._diskWrite(newNode);
    // @todo
    // delte old nodes from disk
    return newNode;
};

/**
 * audit
 *
 * Checks that the tree data structure is
 * valid.
 */
InMemoryBTree.Tree.prototype.audit = function (showOutput) {
    var errors = [];
    var alreadySeen = [];
    var that = this;

    var foundInArray = function (data) {
        for (var i = 0; i < alreadySeen.length; i++) {
            if (that.comparator(alreadySeen[i], data) === 0) {
                var error = " !!! duplicated key " + data;
                if (showOutput === true) {
                    console.log(error);
                }
                errors.push(error);
            }
        }
    };

    var length = null;
    var that = this;
    this.walkNodes(function (n) {
        if (showOutput === true) {
            console.log("--- Node at " + n.level + " level");
            console.log(" - leaf? " + n.isLeaf);
            console.log(" - num actives? " + n.numberActives);
            console.log(" - keys: ");
        }
        for (var i = n.numberActives; i < n.keys.length; i++) {
            if (n.keys[i] != null) {
                if (showOutput === true) {
                    console.log(" * warning : redundant key data");
                    errors.push(" * warning : redundant key data");
                }
            }
        }

        for (var i = n.numberActives + 1; i < n.children.length; i++) {
            if (n.children[i] != null) {
                if (showOutput === true) {
                    console.log(" * warning : redundant children data");
                    errors.push(" * warning : redundant key data");
                }
            }
        }


        if (n.isLeaf === false) {
            for (var i = 0; i < n.numberActives; i++) {
                var maxLeft = that._diskRead(n.children[i]).keys[that._diskRead(n.children[i]).numberActives - 1 ].key;
                var minRight = that._diskRead(n.children[i + 1]).keys[0].key;
                if (showOutput === true) {
                    console.log("   " + n.keys[i].key + "(" + maxLeft + "," + minRight + ")");
                }
                if (that.comparator(n.keys[i].key, maxLeft) === -1) {
                    var error = " !!! value max left " + maxLeft + " > key " + n.keys[i].key;
                    if (showOutput === true) {
                        console.log(error);
                    }
                    errors.push(error);
                }
                if (that.comparator(n.keys[i].key, minRight) === 1) {
                    var error = " !!! value min right " + minRight + " < key " + n.keys[i].key;
                    if (showOutput === true) {
                        console.log(error);
                    }
                    errors.push(error);
                }

                foundInArray(n.keys[i].key);
                alreadySeen.push(n.keys[i].key);
            }
        } else {
            if (length === null) {
                length = n.level;
            } else {
                if (length != n.level) {
                    var error = " !!! Leaf node with wrong level value";
                    if (showOutput === true) {
                        console.log(error);
                    }
                    errors.push(error);
                }
            }
            for (var i = 0; i < n.numberActives; i++) {
                if (showOutput === true) {
                    console.log(" " + n.keys[i].key);
                }
                foundInArray(n.keys[i].key);
                alreadySeen.push(n.keys[i].key);

            }
        }

        if (n != that.root) {
            if (n.numberActives > ((2 * that.order) - 1)) {
                if (showOutput === true) {
                    var error = " !!!! MAX num keys restriction violated ";
                }
                console.log(error);
                errors.push(error);
            }
            if (n.numberActives < (that.order - 1)) {
                if (showOutput === true) {
                    var error = " !!!! MIN num keys restriction violated ";
                }
                console.log(error);
                errors.push(error);
            }

        }
    });

    return errors;
};

/**
 *  _getMaxKeyPos
 *
 *  Used to get the position of the MAX key within the subtree
 *  @return An object containing the key and position of the key
 */
InMemoryBTree.Tree.prototype._getMaxKeyPos = function (node) {
    var node_pos = {};

    while (true) {
        if (node === null) {
            break;
        }

        if (node.isLeaf === true) {
            node_pos.node = node;
            node_pos.index = node.numberActives - 1;
            return node_pos;
        } else {
            node_pos.node = node;
            node_pos.index = node.numberActives - 1;
            node = this._diskRead(node.children[node.numberActives]);
        }
    }

    return node_pos;
};

/**
 *  _getMinKeyPos
 *
 *  Used to get the position of the MAX key within the subtree
 *  @return An object containing the key and position of the key
 */
InMemoryBTree.Tree.prototype._getMinKeyPos = function (node) {
    var node_pos = {};

    while (true) {
        if (node === null) {
            break;
        }

        if (node.isLeaf === true) {
            node_pos.node = node;
            node_pos.index = 0;
            return node_pos;
        } else {
            node_pos.node = node;
            node_pos.index = 0;
            node = this._diskRead(node.children[0]);
        }
    }

    return node_pos;
};


/**
 * Node
 *
 * Implements the interface of BinarySearchTree.Node
 *
 * A Tree node augmented with BTree
 * node structures
 */
InMemoryBTree.Node = function() {
    this.numberActives = 0;
    this.isLeaf = null;
    this.keys = [];
    this.children = [];
    this.level = 0;
};

// end of ./src/js-trees/src/in_memory_b_tree.js 
// exports
var QuadIndexCommon = {};

/**
 * NodeKey
 *
 * Implements the interface of BinarySearchTree.Node
 *
 * A Tree node augmented with BPlusTree
 * node structures
 */
QuadIndexCommon.NodeKey = function(components, order) {
    this.subject = components.subject;
    this.predicate = components.predicate;
    this.object = components.object;
    this.graph = components.graph;
    this.order = order;
};

QuadIndexCommon.NodeKey.prototype.comparator = function(keyPattern) {
    for(var i=0; i<this.order.length; i++) {
        var component = this.order[i];
        if(keyPattern[component] == null) {
            return 0;
        } else {
            if(this[component] < keyPattern[component] ) {
                return -1
            } else if(this[component] > keyPattern[component]) {
                return 1
            }
        }
    }

    return 0;
};

/**
 * Pattern
 *
 * A pattern with some variable components
 */
QuadIndexCommon.Pattern = function (components) {
    this.subject = components.subject;
    this.predicate = components.predicate;
    this.object = components.object;
    this.graph = components.graph;
    this.indexKey = [];

    this.keyComponents = {};

    var order = [];
    var indif = [];
    var components = ['subject', 'predicate', 'object', 'graph'];

    // components must have been already normalized and
    // inserted in the lexicon.
    // OIDs retrieved from the lexicon *are* numbers so
    // they can be told apart from variables (strings)
    for (var i = 0; i < components.length; i++) {
        if (typeof(this[components[i]]) === 'string') {
            indif.push(components[i]);
            this.keyComponents[components[i]] = null;
        } else {
            order.push(components[i]);
            this.keyComponents[components[i]] = this[components[i]];
            this.indexKey.push(components[i]);
        }
    }

    this.order = order.concat(indif);
    this.key = new QuadIndexCommon.NodeKey(this.keyComponents, this.order);
};

// end of ./src/js-rdf-persistence/src/quad_index_common.js 
// exports
var QuadIndex = {};

// imports
var BaseTree = InMemoryBTree;

QuadIndex.Tree = function(params,callback) {
    if(arguments != 0) {
        this.componentOrder = params.componentOrder;


        // @todo change this if using the file backed implementation
        BaseTree.Tree.call(this, params.order, params['name'], params['persistent'], params['cacheMaxSize']);

        this.comparator = function (a, b) {
            for (var i = 0; i < this.componentOrder.length; i++) {
                var component = this.componentOrder[i];
                var vala = a[component];
                var valb = b[component];
                if (vala < valb) {
                    return -1;
                } else if (vala > valb) {
                    return 1;
                }
            }
            return 0;
        };

        this.rangeComparator = function (a, b) {
            for (var i = 0; i < this.componentOrder.length; i++) {
                var component = this.componentOrder[i];
                if (b[component] == null || a[component] == null) {
                    return 0;
                } else {
                    if (a[component] < b[component]) {
                        return -1
                    } else if (a[component] > b[component]) {
                        return 1
                    }
                }
            }

            return 0;
        };

        if(callback!=null) {
            callback(this);
        }
    }
};

Utils['extends'](BaseTree.Tree, QuadIndex.Tree);

QuadIndex.Tree.prototype.insert = function(quad, callback) {
    BaseTree.Tree.prototype.insert.call(this, quad, null);
    if(callback)
        callback(true);

    return true
};

QuadIndex.Tree.prototype.search = function(quad, callback) {
    var result = BaseTree.Tree.prototype.search.call(this, quad, true); // true -> check exists : not present in all the b-tree implementations, check first.
    if(callback)
        callback(result);

    return result;
};

QuadIndex.Tree.prototype.range = function (pattern, callback) {
    var result = null;
    if (typeof(this.root) === 'string') {
        result = this._rangeTraverse(this, this._diskRead(this.root), pattern);
    } else {
        result = this._rangeTraverse(this, this.root, pattern);
    }

    if (callback)
        callback(result);

    return result;
};

QuadIndex.Tree.prototype._rangeTraverse = function(tree,node, pattern) {
    var patternKey  = pattern.key;
    var acum = [];
    var pendingNodes = [node];
    var node, idxMin, idxMax;
    while(pendingNodes.length > 0) {
        node = pendingNodes.shift();
        idxMin = 0;

        while(idxMin < node.numberActives && tree.rangeComparator(node.keys[idxMin].key,patternKey) === -1) {
            idxMin++;
        }
        if(node.isLeaf === true) {
            idxMax = idxMin;

            while(idxMax < node.numberActives && tree.rangeComparator(node.keys[idxMax].key,patternKey) === 0) {
                acum.push(node.keys[idxMax].key);
                idxMax++;
            }

        } else {
            var pointer = node.children[idxMin];
            var childNode = tree._diskRead(pointer);
            pendingNodes.push(childNode);

            var idxMax = idxMin;
            while(true) {
                if(idxMax < node.numberActives && tree.rangeComparator(node.keys[idxMax].key,patternKey) === 0) {
                    acum.push(node.keys[idxMax].key);
                    idxMax++;
                    childNode = tree._diskRead(node.children[idxMax]);
                    pendingNodes.push(childNode);
                } else {
                    break;
                }
            }
        }
    }
    return acum;
};

// end of ./src/js-rdf-persistence/src/quad_index.js 
// exports
var QuadBackend = {};


// imports


/*
 * "perfect" indices for RDF indexing
 *
 * SPOG (?, ?, ?, ?), (s, ?, ?, ?), (s, p, ?, ?), (s, p, o, ?), (s, p, o, g)
 * GP   (?, ?, ?, g), (?, p, ?, g)
 * OGS  (?, ?, o, ?), (?, ?, o, g), (s, ?, o, g)
 * POG  (?, p, ?, ?), (?, p, o, ?), (?, p, o, g)
 * GSP  (s, ?, ?, g), (s, p, ?, g)
 * OS   (s, ?, o, ?)
 */
QuadBackend.QuadBackend = function (configuration, callback) {
    if (arguments != 0) {
        this.indexMap = {};
        this.treeOrder = configuration['treeOrder'];
        this.indices = ['SPOG', 'GP', 'OGS', 'POG', 'GSP', 'OS'];
        this.componentOrders = {
            SPOG:['subject', 'predicate', 'object', 'graph'],
            GP:['graph', 'predicate', 'subject', 'object'],
            OGS:['object', 'graph', 'subject', 'predicate'],
            POG:['predicate', 'object', 'graph', 'subject'],
            GSP:['graph', 'subject', 'predicate', 'object'],
            OS:['object', 'subject', 'predicate', 'graph']
        };

        for (var i = 0; i < this.indices.length; i++) {
            var indexKey = this.indices[i];
            this.indexMap[indexKey] = new QuadIndex.Tree({order:this.treeOrder,
                componentOrder:this.componentOrders[indexKey],
                persistent:configuration['persistent'],
                name:(configuration['name'] || "") + indexKey,
                cacheMaxSize:configuration['cacheMaxSize']});
        }

        if (callback)
            callback(this);
    }
};

QuadBackend.QuadBackend.prototype.clear = function() {
        for(var i=0; i<this.indices.length; i++) {
            var indexKey = this.indices[i];
            this.indexMap[indexKey].clear();
        }
};

QuadBackend.QuadBackend.prototype._indexForPattern = function (pattern) {
    var indexKey = pattern.indexKey;
    var matchingIndices = this.indices;

    for (var i = 0; i < matchingIndices.length; i++) {
        var index = matchingIndices[i];
        var indexComponents = this.componentOrders[index];
        for (var j = 0; j < indexComponents.length; j++) {
            if (Utils.include(indexKey, indexComponents[j]) === false) {
                break;
            }
            if (j == indexKey.length - 1) {
                return index;
            }
        }
    }

    return 'SPOG'; // If no other match, we erturn the more generic index
};


QuadBackend.QuadBackend.prototype.index = function (quad, callback) {
    for (var i = 0; i < this.indices.length; i++) {
        var indexKey = this.indices[i];
        var index = this.indexMap[indexKey];

        index.insert(quad);
    }

    if (callback)
        callback(true);

    return true;
};

QuadBackend.QuadBackend.prototype.range = function (pattern, callback) {
    var indexKey = this._indexForPattern(pattern);
    var index = this.indexMap[indexKey];
    var quads = index.range(pattern);
    if (callback)
        callback(quads);

    return quads;
};

QuadBackend.QuadBackend.prototype.search = function (quad, callback) {
    var indexKey = this.indices[0];
    var index = this.indexMap[indexKey];
    var result = index.search(quad);

    if (callback)
        callback(result != null);

    return (result != null)
};


QuadBackend.QuadBackend.prototype['delete'] = function (quad, callback) {
    var indexKey, index;
    for (var i = 0; i < this.indices.length; i++) {
        indexKey = this.indices[i];
        index = this.indexMap[indexKey];

        index['delete'](quad);
    }

    if (callback)
        callback(true);

    return true;
};

// end of ./src/js-rdf-persistence/src/quad_backend.js 
// exports
var Lexicon = {};

// imports

/**
 * Temporal implementation of the lexicon
 */


Lexicon.Lexicon = function(callback){
    this.uriToOID = {};
    this.OIDToUri = {};

    this.literalToOID = {};
    this.OIDToLiteral = {};

    this.blankToOID = {};
    this.OIDToBlank = {};

    this.defaultGraphOid = 0;

    this.defaultGraphUri = "https://github.com/antoniogarrote/rdfstore-js#default_graph";
    this.defaultGraphUriTerm = {"token": "uri", "prefix": null, "suffix": null, "value": this.defaultGraphUri, "oid": this.defaultGraphOid};
    this.oidCounter = 1;

    this.knownGraphs = {};
    
    if(callback != null) {
        callback(this);
    }
};

Lexicon.Lexicon.prototype.registerGraph = function(oid){
    if(oid != this.defaultGraphOid) {
        this.knownGraphs[oid] = true;
    }
    return true
};

Lexicon.Lexicon.prototype.registeredGraphs = function(shouldReturnUris) {
    var acum = [];

    for(var g in this.knownGraphs) {
        if(shouldReturnUris === true) {
            acum.push(this.OIDToUri['u'+g]);
        } else {
            acum.push(g);
        }
    }
    return acum;
};

Lexicon.Lexicon.prototype.registerUri = function(uri) {
    if(uri === this.defaultGraphUri) {
        return(this.defaultGraphOid);
    } else if(this.uriToOID[uri] == null){
        var oid = this.oidCounter;
        var oidStr = 'u'+oid;
        this.oidCounter++;

        this.uriToOID[uri] =[oid, 0];
        this.OIDToUri[oidStr] = uri;

        return(oid);
    } else {
        var oidCounter = this.uriToOID[uri];
        var oid = oidCounter[0];
        var counter = oidCounter[1] + 1;
        this.uriToOID[uri] = [oid, counter];
        return(oid);
    }
};

Lexicon.Lexicon.prototype.resolveUri = function(uri) {
    if(uri === this.defaultGraphUri) {
        return(this.defaultGraphOid);
    } else {
        var oidCounter = this.uriToOID[uri];
        if(oidCounter != null) {
            return(oidCounter[0]);
        } else {
            return(-1);
        }
    }
};

Lexicon.Lexicon.prototype.resolveUriCost = function(uri) {
    if(uri === this.defaultGraphUri) {
        return(this.defaultGraphOid);
    } else {
        var oidCounter = this.uriToOID[uri];
        if(oidCounter != null) {
            return(oidCounter[1]);
        } else {
            return(-1);
        }
    }
};

Lexicon.Lexicon.prototype.registerBlank = function(label) {
    var oid = this.oidCounter;
    this.oidCounter++;
    var oidStr = ""+oid;
    this.OIDToBlank[oidStr] = true;
    return(oidStr);
};

Lexicon.Lexicon.prototype.resolveBlank = function(label) {
//    @todo
//    this is failing with unicode tests... e.g. kanji2

//    var id = label.split(":")[1];
//    callback(id);

    var oid = this.oidCounter;
    this.oidCounter++;
    return(""+oid);
};

Lexicon.Lexicon.prototype.resolveBlankCost = function(label) {
    return 0;
};

Lexicon.Lexicon.prototype.registerLiteral = function(literal) {
    if(this.literalToOID[literal] == null){
        var oid = this.oidCounter;
        var oidStr =  'l'+ oid;
        this.oidCounter++;

        this.literalToOID[literal] = [oid, 0];
        this.OIDToLiteral[oidStr] = literal;

        return(oid);
    } else {
        var oidCounter = this.literalToOID[literal];
        var oid = oidCounter[0];
        var counter = oidCounter[1] + 1;
        this.literalToOID[literal] = [oid, counter];
        return(oid);
    }
};

Lexicon.Lexicon.prototype.resolveLiteral = function (literal) {
    var oidCounter = this.literalToOID[literal];
    if (oidCounter != null) {
        return(oidCounter[0]);
    } else {
        return(-1);
    }
};

Lexicon.Lexicon.prototype.resolveLiteralCost = function (literal) {
    var oidCounter = this.literalToOID[literal];
    if (oidCounter != null) {
        return(oidCounter[1]);
    } else {
        return(0);
    }
};


Lexicon.Lexicon.prototype.parseLiteral = function(literalString) {
    var parts = literalString.lastIndexOf("@");
    if(parts!=-1 && literalString[parts-1]==='"' && literalString.substring(parts, literalString.length).match(/^@[a-zA-Z\-]+$/g)!=null) {
        var value = literalString.substring(1,parts-1);
        var lang = literalString.substring(parts+1, literalString.length);
        return {token: "literal", value:value, lang:lang};
    }

    var parts = literalString.lastIndexOf("^^");
    if(parts!=-1 && literalString[parts-1]==='"' && literalString[parts+2] === '<' && literalString[literalString.length-1] === '>') {
        var value = literalString.substring(1,parts-1);
        var type = literalString.substring(parts+3, literalString.length-1);

        return {token: "literal", value:value, type:type};
    }

    var value = literalString.substring(1,literalString.length-1);
    return {token:"literal", value:value};
};

Lexicon.Lexicon.prototype.parseUri = function(uriString) {
    return {token: "uri", value:uriString};
};

Lexicon.Lexicon.prototype.retrieve = function(oid) {
    try {
        if(oid === this.defaultGraphOid) {
            return({ token: "uri", 
                       value:this.defaultGraphUri,
                       prefix: null,
                       suffix: null,
                       defaultGraph: true });
        } else {
          var maybeUri = this.OIDToUri['u'+oid];
          if(maybeUri != null) {
              return(this.parseUri(maybeUri));
          } else {
              var maybeLiteral = this.OIDToLiteral['l'+oid];
              if(maybeLiteral != null) {
                  return(this.parseLiteral(maybeLiteral));
              } else {
                  var maybeBlank = this.OIDToBlank[""+oid];
                  if(maybeBlank != null) {
                      return({token:"blank", value:"_:"+oid});
                  } else {
                      throw("Null value for OID");
                  }
              }
          }
        }
    } catch(e) {
        console.log("error in lexicon retrieving OID:");
        console.log(oid);
        if(e.message || e.stack) {
            if(e.message) {
                console.log(e.message); 
            }
            if(e.stack) {
                console.log(e.stack);
            }
        } else {
            console.log(e);
        }
        throw new Error("Unknown retrieving OID in lexicon:"+oid);

    }
};

Lexicon.Lexicon.prototype.clear = function() {
    this.uriToOID = {};
    this.OIDToUri = {};

    this.literalToOID = {};
    this.OIDToLiteral = {};

    this.blankToOID = {};
    this.OIDToBlank = {};
};

Lexicon.Lexicon.prototype.unregister = function (quad, key) {
    try {
        this.unregisterTerm(quad.subject.token, key.subject);
        this.unregisterTerm(quad.predicate.token, key.predicate);
        this.unregisterTerm(quad.object.token, key.object);
        if (quad.graph != null) {
            this.unregisterTerm(quad.graph.token, key.graph);
        }
        return(true);
    } catch (e) {
        console.log("Error unregistering quad");
        console.log(e.message);
        return(false);
    }
};

Lexicon.Lexicon.prototype.unregisterTerm = function (kind, oid) {
    if (kind === 'uri') {
        if (oid != this.defaultGraphOid) {
            var oidStr = 'u' + oid;
            var uri = this.OIDToUri[oidStr];     // = uri;
            var oidCounter = this.uriToOID[uri]; // =[oid, 0];

            var counter = oidCounter[1];
            if ("" + oidCounter[0] === "" + oid) {
                if (counter === 0) {
                    delete this.OIDToUri[oidStr];
                    delete this.uriToOID[uri];
                    // delete the graph oid from known graphs
                    // in case this URI is a graph identifier
                    delete this.knownGraphs[oid];
                } else {
                    this.uriToOID[uri] = [oid, counter - 1];
                }
            } else {
                throw("Not matching OID : " + oid + " vs " + oidCounter[0]);
            }
        }
    } else if (kind === 'literal') {
        this.oidCounter++;
        var oidStr = 'l' + oid;
        var literal = this.OIDToLiteral[oidStr];  // = literal;
        var oidCounter = this.literalToOID[literal]; // = [oid, 0];

        var counter = oidCounter[1];
        if ("" + oidCounter[0] === "" + oid) {
            if (counter === 0) {
                delete this.OIDToLiteral[oidStr];
                delete this.literalToOID[literal];
            } else {
                this.literalToOID[literal] = [oid, counter - 1];
            }
        } else {
            throw("Not matching OID : " + oid + " vs " + oidCounter[0]);
        }

    } else if (kind === 'blank') {
        delete this.OIDToBlank["" + oid];
    }
};

// end of ./src/js-rdf-persistence/src/lexicon.js 
// exports
var NetworkTransport = {};

NetworkTransport.load = function (uri, accept, callback, redirect) {
    var transport = jQuery;

    transport.ajax({
        url:uri,
        headers:{"Accept":accept},

        success:function (data, status, xhr) {
            if (("" + xhr.status)[0] == '2') {
                var headers = xhr.getAllResponseHeaders().split("\n");
                var acum = {};
                for (var i = 0; i < headers.length; i++) {
                    var header = headers[i].split(":");
                    acum[header[0]] = header[1];
                }

                callback(true, {headers:acum,
                                data:data});
            }
        },

        error:function (xhr, textStatus, ex) {
            if (("" + xhr.status)[0] == '3') {
                if (redirection == 0) {
                    callback(false, 500);
                } else {
                    var location = (xhr.getAllResponseHeaders()["Location"] || xhr.getAllResponseHeaders()["location"]);
                    if (location != null) {
                        NetworkTransport.load(location, accept, callback, (redirection - 1));
                    } else {
                        callback(false, 500);
                    }
                }
            } else {
                callback(false, xhr.statusCode());
            }
        }
    });
};

// end of ./src/js-communication/src/ajax_transport.js 

/**
 * Javascript implementation of JSON-LD.
 *
 * @author Dave Longley
 *
 * Copyright (c) 2011 Digital Bazaar, Inc. All rights reserved.
 */

var jsonldParser = null;

(function()
{

// used by Exception
var _setMembers = function(self, obj)
{
   self.stack = '';
   for(var key in obj)
   {
      self[key] = obj[key];
   }
};

// define jsonld
if(typeof(window) !== 'undefined')
{
   var jsonld = window.jsonld = window.jsonld || {};
   Exception = function(obj)
   {
      _setMembers(this, obj);
   };

   // define js 1.8.5 Object.keys method unless present
   if(!Object.keys)
   {
      Object.keys = function(o)
      {  
         if(o !== Object(o))
         {
            throw new TypeError('Object.keys called on non-object');
         }
         var rval = [];
         for(var p in o)
         {
            if(Object.prototype.hasOwnProperty.call(o, p))
            {
               rval.push(p);
            }
         }
         return rval;
      };
   }

   if (!Array.prototype.filter)
   {
     Array.prototype.filter = function(fun /*, thisp */)
     {
       "use strict";
    
       if (this == null)
         throw new TypeError();
    
       var t = Object(this);
       var len = t.length >>> 0;
       if (typeof fun != "function")
         throw new TypeError();
    
       var res = [];
       var thisp = arguments[1];
       for (var i = 0; i < len; i++)
       {
         if (i in t)
         {
           var val = t[i]; // in case fun mutates this
           if (fun.call(thisp, val, i, t))
             res.push(val);
         }
       }
    
       return res;
     };
   }

}
// define node.js module
else if(typeof(module) !== 'undefined' && module.exports)
{
   var jsonld = {};
   //module.exports = jsonld;
   Exception = function(obj)
   {
      _setMembers(this, obj);
      this.stack = new Error().stack;
   };
}


jsonldParser = jsonld;

var defaultContext = { "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#",
                       "dcterms": "http://purl.org/dc/terms/",
                       "foaf": "http://xmlns.com/foaf/0.1/",
                       "cal": "http://www.w3.org/2002/12/cal/ical#",
                       "vcard": "http://www.w3.org/2006/vcard/ns# ",
                       "geo": "http://www.w3.org/2003/01/geo/wgs84_pos#",
                       "cc": "http://creativecommons.org/ns#",
                       "sioc": "http://rdfs.org/sioc/ns#",
                       "doap": "http://usefulinc.com/ns/doap#",
                       "com": "http://purl.org/commerce#",
                       "ps": "http://purl.org/payswarm#",
                       "gr": "http://purl.org/goodrelations/v1#",
                       "sig": "http://purl.org/signature#",
                       "ccard": "http://purl.org/commerce/creditcard#"
                     };

/*
 * Globals and helper functions.
 */
var ns =
{
   xsd: 'http://www.w3.org/2001/XMLSchema#'
};

var xsd =
{
   'boolean': ns.xsd + 'boolean',
   'double': ns.xsd + 'double',
   'integer': ns.xsd + 'integer'
};

/**
 * Sets a subject's property to the given object value. If a value already
 * exists, it will be appended to an array.
 *
 * @param s the subject.
 * @param p the property.
 * @param o the object.
 */
var _setProperty = function(s, p, o)
{
   if(p in s)
   {
      if(s[p].constructor === Array)
      {
         s[p].push(o);
      }
      else
      {
         s[p] = [s[p], o];
      }
   }
   else
   {
      s[p] = o;
   }
};

/**
 * Clones an object, array, or string/number. If cloning an object, the keys
 * will be sorted.
 * 
 * @param value the value to clone.
 * 
 * @return the cloned value.
 */
var _clone = function(value)
{
   var rval;
   
   if(value.constructor === Object)
   {
      rval = {};
      var keys = Object.keys(value).sort();
      for(var i in keys)
      {
         var key = keys[i];
         rval[key] = _clone(value[key]);
      }
   }
   else if(value.constructor === Array)
   {
      rval = [];
      for(var i in value)
      {
         rval[i] = _clone(value[i]);
      }
   }
   else
   {
      rval = value;
   }
   
   return rval;
};

/**
 * Gets the keywords from a context.
 * 
 * @param ctx the context.
 * 
 * @return the keywords.
 */
var _getKeywords = function(ctx)
{
   // TODO: reduce calls to this function by caching keywords in processor
   // state
   
   var rval =
   {
      '@id': '@id',
      '@language': '@language',
      '@literal': '@literal',
      '@type': '@type'
   };
   
   if(ctx)
   {
      // gather keyword aliases from context
      var keywords = {};
      for(var key in ctx)
      {
         if(ctx[key].constructor === String && ctx[key] in rval)
         {
            keywords[ctx[key]] = key;
         }
      }
      
      // overwrite keywords
      for(var key in keywords)
      {
         rval[key] = keywords[key];
      }
   }
   
   return rval;
};

/**
 * Gets the iri associated with a term.
 * 
 * @param ctx the context.
 * @param term the term.
 * 
 * @return the iri or NULL.
 */
var _getTermIri = function(ctx, term)
{
   var rval = null;
   if(term in ctx)
   {
      if(ctx[term].constructor === String)
      {
         rval = ctx[term];
      }
      else if(ctx[term].constructor === Object && '@id' in ctx[term])
      {
         rval = ctx[term]['@id'];
      }
   }
   return rval;
};

/**
 * Compacts an IRI into a term or prefix if it can be. IRIs will not be
 * compacted to relative IRIs if they match the given context's default
 * vocabulary.
 *
 * @param ctx the context to use.
 * @param iri the IRI to compact.
 * @param usedCtx a context to update if a value was used from "ctx".
 *
 * @return the compacted IRI as a term or prefix or the original IRI.
 */
var _compactIri = function(ctx, iri, usedCtx)
{
   var rval = null;
   
   // check the context for a term that could shorten the IRI
   // (give preference to terms over prefixes)
   for(var key in ctx)
   {
      // skip special context keys (start with '@')
      if(key.length > 0 && key[0] !== '@')
      {
         // compact to a term
         if(iri === _getTermIri(ctx, key))
         {
            rval = key;
            if(usedCtx !== null)
            {
               usedCtx[key] = _clone(ctx[key]);
            }
            break;
         }
      }
   }
   
   // term not found, if term is @type, use keyword
   if(rval === null && iri === '@type')
   {
      rval = _getKeywords(ctx)['@type'];
   }
   
   // term not found, check the context for a prefix
   if(rval === null)
   {
      for(var key in ctx)
      {
         // skip special context keys (start with '@')
         if(key.length > 0 && key[0] !== '@')
         {
            // see if IRI begins with the next IRI from the context
            var ctxIri = _getTermIri(ctx, key);
            if(ctxIri !== null)
            {
               var idx = iri.indexOf(ctxIri);
               
               // compact to a prefix
               if(idx === 0 && iri.length > ctxIri.length)
               {
                  rval = key + ':' + iri.substr(ctxIri.length);
                  if(usedCtx !== null)
                  {
                     usedCtx[key] = _clone(ctx[key]);
                  }
                  break;
               }
            }
         }
      }
   }

   // could not compact IRI
   if(rval === null)
   {
      rval = iri;
   }

   return rval;
};

/**
 * Expands a term into an absolute IRI. The term may be a regular term, a
 * prefix, a relative IRI, or an absolute IRI. In any case, the associated
 * absolute IRI will be returned.
 *
 * @param ctx the context to use.
 * @param term the term to expand.
 * @param usedCtx a context to update if a value was used from "ctx".
 *
 * @return the expanded term as an absolute IRI.
 */
var _expandTerm = function(ctx, term, usedCtx)
{
   var rval = term;
   
   // get JSON-LD keywords
   var keywords = _getKeywords(ctx);
   
   // 1. If the property has a colon, it is a prefix or an absolute IRI:
   var idx = term.indexOf(':');
   if(idx !== -1)
   {
      // get the potential prefix
      var prefix = term.substr(0, idx);

      // expand term if prefix is in context, otherwise leave it be
      if(prefix in ctx)
      {
         // prefix found, expand property to absolute IRI
         var iri = _getTermIri(ctx, prefix);
         rval = iri + term.substr(idx + 1);
         if(usedCtx !== null)
         {
            usedCtx[prefix] = _clone(ctx[prefix]);
         }
      }
   }
   // 2. If the property is in the context, then it's a term.
   else if(term in ctx)
   {
      rval = _getTermIri(ctx, term);
      if(usedCtx !== null)
      {
         usedCtx[term] = _clone(ctx[term]);
      }
   }
   // 3. The property is a keyword.
   else
   {
      for(var key in keywords)
      {
         if(term === keywords[key])
         {
            rval = key;
            break;
         }
      }
   }
   
   return rval;
};

/**
 * Sorts the keys in a context.
 * 
 * @param ctx the context to sort.
 * 
 * @return the sorted context.
 */
var _sortContextKeys = function(ctx)
{
   // sort keys
   var rval = {};
   var keys = Object.keys(ctx).sort();
   for(var k in keys)
   {
      var key = keys[k];
      rval[key] = ctx[key];
   }
   return rval;
};

/**
 * Gets whether or not a value is a reference to a subject (or a subject with
 * no properties).
 * 
 * @param value the value to check.
 * 
 * @return true if the value is a reference to a subject, false if not.
 */
var _isReference = function(value)
{
   // Note: A value is a reference to a subject if all of these hold true:
   // 1. It is an Object.
   // 2. It is has an @id key.
   // 3. It has only 1 key.
   return (value !== null &&
      value.constructor === Object &&
      '@id' in value &&
      Object.keys(value).length === 1);
};

/**
 * Gets whether or not a value is a subject with properties.
 * 
 * @param value the value to check.
 * 
 * @return true if the value is a subject with properties, false if not.
 */
var _isSubject = function(value)
{
   var rval = false;
   
   // Note: A value is a subject if all of these hold true:
   // 1. It is an Object.
   // 2. It is not a literal.
   // 3. It has more than 1 key OR any existing key is not '@id'.
   if(value !== null && value.constructor === Object && !('@literal' in value))
   {
      var keyCount = Object.keys(value).length;
      rval = (keyCount > 1 || !('@id' in value));
   }
   
   return rval;
};

/*
 * JSON-LD API.
 */

/**
 * Normalizes a JSON-LD object.
 *
 * @param input the JSON-LD object to normalize.
 * 
 * @return the normalized JSON-LD object.
 */
jsonld.normalize = function(input)
{
   return new Processor().normalize(input);
};

/**
 * Removes the context from a JSON-LD object, expanding it to full-form.
 *
 * @param input the JSON-LD object to remove the context from.
 * 
 * @return the context-neutral JSON-LD object.
 */
jsonld.expand = function(input)
{
   return new Processor().expand({}, null, input);
};

/**
 * Expands the given JSON-LD object and then compacts it using the
 * given context.
 *
 * @param ctx the new context to use.
 * @param input the input JSON-LD object.
 * 
 * @return the output JSON-LD object.
 */
jsonld.compact = function(ctx, input)
{
   var rval = null;
   
   // TODO: should context simplification be optional? (ie: remove context
   // entries that are not used in the output)

   if(input !== null)
   {
      // fully expand input
      input = jsonld.expand(input);
      
      var tmp;
      if(input.constructor === Array)
      {
         rval = [];
         tmp = input;
      }
      else
      {
         tmp = [input];
      }
      
      // merge context if it is an array
      if(ctx.constructor === Array)
      {
         ctx = jsonld.mergeContexts({}, ctx);
      }
      
      for(var i in tmp)
      {
         // setup output context
         var ctxOut = {};
         
         // compact
         var out = new Processor().compact(_clone(ctx), null, tmp[i], ctxOut);
         
         // add context if used
         if(Object.keys(ctxOut).length > 0)
         {
            // sort context keys
            ctxOut = _sortContextKeys(ctxOut);
            
            // sort keys
            var keys = Object.keys(out);
            keys.sort();
            
            // put @context first
            keys.unshift('@context');
            out['@context'] = ctxOut;
            
            // order keys in output
            var ordered = {};
            for(var k in keys)
            {
               var key = keys[k];
               ordered[key] = out[key];
            }
            out = ordered;
         }
         
         if(rval === null)
         {
            rval = out;
         }
         else
         {
            rval.push(out);
         }
      }
   }

   return rval;
};

/**
 * Merges one context with another.
 *
 * @param ctx1 the context to overwrite/append to.
 * @param ctx2 the new context to merge onto ctx1.
 *
 * @return the merged context.
 */
jsonld.mergeContexts = function(ctx1, ctx2)
{
   // merge first context if it is an array
   if(ctx1.constructor === Array)
   {
      ctx1 = jsonld.mergeContexts({}, ctx1);
   }
   
   // copy context to merged output
   var merged = _clone(ctx1);
   
   if(ctx2.constructor === Array)
   {
      // merge array of contexts in order
      for(var i in ctx2)
      {
         merged = jsonld.mergeContexts(merged, ctx2[i]);
      }
   }
   else
   {
      // if the new context contains any IRIs that are in the merged context,
      // remove them from the merged context, they will be overwritten
      for(var key in ctx2)
      {
         // ignore special keys starting with '@'
         if(key.indexOf('@') !== 0)
         {
            for(var mkey in merged)
            {
               if(merged[mkey] === ctx2[key])
               {
                  // FIXME: update related coerce rules
                  delete merged[mkey];
                  break;
               }
            }
         }
      }
   
      // merge contexts
      for(var key in ctx2)
      {
         merged[key] = _clone(ctx2[key]);
      }
   }

   return merged;
};

/**
 * Expands a term into an absolute IRI. The term may be a regular term, a
 * prefix, a relative IRI, or an absolute IRI. In any case, the associated
 * absolute IRI will be returned.
 *
 * @param ctx the context to use.
 * @param term the term to expand.
 *
 * @return the expanded term as an absolute IRI.
 */
jsonld.expandTerm = _expandTerm;

/**
 * Compacts an IRI into a term or prefix if it can be. IRIs will not be
 * compacted to relative IRIs if they match the given context's default
 * vocabulary.
 *
 * @param ctx the context to use.
 * @param iri the IRI to compact.
 *
 * @return the compacted IRI as a term or prefix or the original IRI.
 */
jsonld.compactIri = function(ctx, iri)
{
   return _compactIri(ctx, iri, null);
};

/**
 * Frames JSON-LD input.
 * 
 * @param input the JSON-LD input.
 * @param frame the frame to use.
 * @param options framing options to use.
 * 
 * @return the framed output.
 */
jsonld.frame = function(input, frame, options)
{
   return new Processor().frame(input, frame, options);
};

/**
 * Generates triples given a JSON-LD input. Each triple that is generated
 * results in a call to the given callback. The callback takes 3 parameters:
 * subject, property, and object. If the callback returns false then this
 * method will stop generating triples and return. If the callback is null,
 * then an array with triple objects containing "s", "p", "o" properties will
 * be returned.
 * 
 * The object or "o" property will be a JSON-LD formatted object.
 * 
 * @param input the JSON-LD input.
 * @param callback the triple callback.
 * 
 * @return an array of triple objects if callback is null, null otherwise.
 */
jsonld.toTriples = function(input, graph, callback)
{
   var rval = null;
   
   // normalize input
   var normalized = jsonld.normalize(input);
   
   // setup default callback
   callback = callback || null;
   if(callback === null)
   {
      rval = [];
      callback = function(s, p, o)
      {
         rval.push({'subject': Utils.lexicalFormTerm(s), 
                    'predicate': Utils.lexicalFormTerm(p), 
                    'object': Utils.lexicalFormTerm(o), 
                    'graph': graph});
      };
   }
   
   // generate triples
   var quit = false;
   for(var i1 in normalized)
   {
      var e = normalized[i1];
      var s = e['@id'];
       if(s[0] == "_") {
           s = {'token':'blank', 'value':s.split(":")[1]};
       } else {
           s = {'token':'uri', 'value':s};
       }

      for(var p in e)
      {
         if(p !== '@id')
         {
	     var obj = e[p];
             if(obj.constructor !== Array)
             {
		 obj = [obj];
             }
            for(var i2 in obj)
            {
                var obji2 = obj[i2];
		if(p === '@type' || p === 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type') {
		    p = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type';
                    obji2 = {'token':'uri', 'value':obji2};		    
                } else if(typeof(obji2) === 'string') {
                    obji2 = {'token': 'literal', 'value':obji2};
                } else if(obji2['@id'] != null) {
                    if(obji2['@id'][0] == "_") {
                        obji2 = {'token':'blank', 'value':obji2['@id'].split(":")[1]};
                    } else {
                        obji2 = {'token':'uri', 'value':obji2['@id']};
                    }
                } else if(obji2['@type'] != null) {
                    obji2 = {'token':'literal', 'value':obji2['@literal'], 'type':obji2['@type']};
                } else if(obji2['@language'] != null) {
                    obji2 = {'token':'literal', 'value':obji2['@literal'], 'lang':obji2['@language']};
                }

		quit = (callback(s, {'token':'uri', 'value':p}, obji2) === false);
		if(quit)
		{
                    break;
		}
            }
            if(quit)
            {
               break;
            }
         }
      }
      if(quit)
      {
         break;
      }
   }
   
   return rval;
};

/**
 * Resolves external @context URLs. Every @context URL in the given JSON-LD
 * object is resolved using the given URL-resolver function. Once all of
 * the @contexts have been resolved, the given result callback is invoked.
 * 
 * @param input the JSON-LD input object (or array).
 * @param resolver the resolver method that takes a URL and a callback that
 *           receives a JSON-LD serialized @context or null on error (with
 *           optional an error object as the second parameter).
 * @param callback the callback to be invoked with the fully-resolved
 *           JSON-LD output (object or array) or null on error (with an
 *           optional error array as the second parameter).
 */
jsonld.resolve = function(input, resolver, callback)
{
   // find all @context URLs
   var urls = {};
   var findUrls = function(input, replace)
   {
      if(input.constructor === Array)
      {
         for(var i in input)
         {
            findUrls(input[i]);
         }
      }
      else if(input.constructor === Object)
      {
         for(var key in input)
         {
            if(key === '@context')
            {
               // @context is an array that might contain URLs
               if(input[key].constructor === Array)
               {
                  var list = input[key];
                  for(var i in list)
                  {
                     if(list[i].constructor === String)
                     {
                        // replace w/resolved @context if appropriate
                        if(replace)
                        {
                           list[i] = urls[list[i]];
                        }
                        // unresolved @context found
                        else
                        {
                           urls[list[i]] = {};
                        }
                     }
                  }
               }
               else if(input[key].constructor === String)
               {
                  // replace w/resolved @context if appropriate
                  if(replace)
                  {
                     input[key] = urls[input[key]];
                  }
                  // unresolved @context found
                  else
                  {
                     urls[input[key]] = {};
                  }
               }
            }
         }
      }
   };
   findUrls(input, false);
   
   // state for resolving URLs
   var count = Object.keys(urls).length;
   var errors = null;
   
   if(count === 0)
   {
      callback(input, errors);
   }
   else
   {
      // resolve all URLs
      for(var url in urls)
      {
         resolver(url, function(result, error)
         {
            --count;
            
            if(result === null)
            {
               errors = errors || [];
               errors.push({ url: url, error: error });
            }
            else
            {
               try
               {
                  if(result.constructor === String)
                  {
                     urls[url] = JSON.parse(result)['@context'];
                  }
                  else
                  {
                     urls[url] = result['@context'];
                  }
               }
               catch(ex)
               {
                  errors = errors || [];
                  errors.push({ url: url, error: ex });
               }
            }
            
            if(count === 0)
            {
               if(errors === null)
               {
                  findUrls(input, true);
               }
               callback(input, errors);
            }
         });
      }
   }
};

// TODO: organizational rewrite

/**
 * Constructs a new JSON-LD processor.
 */
var Processor = function()
{
};

/**
 * Recursively compacts a value. This method will compact IRIs to prefixes or
 * terms and do reverse type coercion to compact a value.
 *
 * @param ctx the context to use.
 * @param property the property that points to the value, NULL for none.
 * @param value the value to compact.
 * @param usedCtx a context to update if a value was used from "ctx".
 *
 * @return the compacted value.
 */
Processor.prototype.compact = function(ctx, property, value, usedCtx)
{
   var rval;
   
   // get JSON-LD keywords
   var keywords = _getKeywords(ctx);
   
   if(value === null)
   {
      // return null, but check coerce type to add to usedCtx
      rval = null;
      this.getCoerceType(ctx, property, usedCtx);
   }
   else if(value.constructor === Array)
   {
      // recursively add compacted values to array
      rval = [];
      for(var i in value)
      {
         rval.push(this.compact(ctx, property, value[i], usedCtx));
      }
   }
   // graph literal/disjoint graph
   else if(
      value.constructor === Object &&
      '@id' in value && value['@id'].constructor === Array)
   {
      rval = {};
      rval[keywords['@id']] = this.compact(
         ctx, property, value['@id'], usedCtx);
   }
   // recurse if value is a subject
   else if(_isSubject(value))
   {
      // recursively handle sub-properties that aren't a sub-context
      rval = {};
      for(var key in value)
      {
         if(value[key] !== '@context')
         {
            // set object to compacted property, only overwrite existing
            // properties if the property actually compacted
            var p = _compactIri(ctx, key, usedCtx);
            if(p !== key || !(p in rval))
            {
               // FIXME: clean old values from the usedCtx here ... or just
               // change usedCtx to be built at the end of processing?
               rval[p] = this.compact(ctx, key, value[key], usedCtx);
            }
         }
      }
   }
   else
   {
      // get coerce type
      var coerce = this.getCoerceType(ctx, property, usedCtx);
      
      // get type from value, to ensure coercion is valid
      var type = null;
      if(value.constructor === Object)
      {
         // type coercion can only occur if language is not specified
         if(!('@language' in value))
         {
            // type must match coerce type if specified
            if('@type' in value)
            {
               type = value['@type'];
            }
            // type is ID (IRI)
            else if('@id' in value)
            {
               type = '@id';
            }
            // can be coerced to any type
            else
            {
               type = coerce;
            }
         }
      }
      // type can be coerced to anything
      else if(value.constructor === String)
      {
         type = coerce;
      }

      // types that can be auto-coerced from a JSON-builtin
      if(coerce === null &&
         (type === xsd['boolean'] || type === xsd['integer'] ||
         type === xsd['double']))
      {
         coerce = type;
      }

      // do reverse type-coercion
      if(coerce !== null)
      {
         // type is only null if a language was specified, which is an error
         // if type coercion is specified
         if(type === null)
         {
            throw {
               message: 'Cannot coerce type when a language is specified. ' +
                  'The language information would be lost.'
            };
         }
         // if the value type does not match the coerce type, it is an error
         else if(type !== coerce)
         {
            throw new Exception({
               message: 'Cannot coerce type because the type does ' +
                  'not match.',
               type: type,
               expected: coerce
            });
         }
         // do reverse type-coercion
         else
         {
            if(value.constructor === Object)
            {
               if('@id' in value)
               {
                  rval = value['@id'];
               }
               else if('@literal' in value)
               {
                  rval = value['@literal'];
               }
            }
            else
            {
               rval = value;
            }

            // do basic JSON types conversion
            if(coerce === xsd['boolean'])
            {
               rval = (rval === 'true' || rval != 0);
            }
            else if(coerce === xsd['double'])
            {
               rval = parseFloat(rval);
            }
            else if(coerce === xsd['integer'])
            {
               rval = parseInt(rval);
            }
         }
      }
      // no type-coercion, just change keywords/copy value
      else if(value.constructor === Object)
      {
         rval = {};
         for(var key in value)
         {
            rval[keywords[key]] = value[key];
         }
      }
      else
      {
         rval = _clone(value);
      }

      // compact IRI
      if(type === '@id')
      {
         if(rval.constructor === Object)
         {
            rval[keywords['@id']] = _compactIri(
               ctx, rval[keywords['@id']], usedCtx);
         }
         else
         {
            rval = _compactIri(ctx, rval, usedCtx);
         }
      }
   }

   return rval;
};

/**
 * Recursively expands a value using the given context. Any context in
 * the value will be removed.
 *
 * @param ctx the context.
 * @param property the property that points to the value, NULL for none.
 * @param value the value to expand.
 *
 * @return the expanded value.
 */
Processor.prototype.expand = function(ctx, property, value)
{
   var rval;
   
   // TODO: add data format error detection?
   
   // value is null, nothing to expand
   if(value === null)
   {
      rval = null;
   }
   // if no property is specified and the value is a string (this means the
   // value is a property itself), expand to an IRI
   else if(property === null && value.constructor === String)
   {
      rval = _expandTerm(ctx, value, null);
   }
   else if(value.constructor === Array)
   {
      // recursively add expanded values to array
      rval = [];
      for(var i in value)
      {
         rval.push(this.expand(ctx, property, value[i]));
      }
   }
   else if(value.constructor === Object)
   {
      // if value has a context, use it
      if('@context' in value)
      {
         ctx = jsonld.mergeContexts(ctx, value['@context']);
      }
      
      // recursively handle sub-properties that aren't a sub-context
      rval = {};
      for(var key in value)
      {
         // preserve frame keywords
         if(key === '@embed' || key === '@explicit' ||
            key === '@default' || key === '@omitDefault')
         {
            _setProperty(rval, key, _clone(value[key]));
         }
         else if(key !== '@context')
         {
            // set object to expanded property
            _setProperty(
               rval, _expandTerm(ctx, key, null),
               this.expand(ctx, key, value[key]));
         }
      }
   }
   else
   {
      // do type coercion
      var coerce = this.getCoerceType(ctx, property, null);

      // get JSON-LD keywords
      var keywords = _getKeywords(ctx);

      // automatic coercion for basic JSON types
      if(coerce === null &&
         (value.constructor === Number || value.constructor === Boolean))
      {
         if(value.constructor === Boolean)
         {
            coerce = xsd['boolean'];
         }
         else if(('' + value).indexOf('.') == -1)
         {
            coerce = xsd['integer'];
         }
         else
         {
            coerce = xsd['double'];
         }
      }
      
      // special-case expand @id and @type (skips '@id' expansion)
      if(property === keywords['@id'] || property === keywords['@type'])
      {
         rval = _expandTerm(ctx, value, null);
      }
      // coerce to appropriate type
      else if(coerce !== null)
      {
         rval = {};
         
         // expand ID (IRI)
         if(coerce === '@id')
         {
            rval['@id'] = _expandTerm(ctx, value, null);
         }
         // other type
         else
         {
            rval['@type'] = coerce;
            if(coerce === xsd['double'])
            {
               // do special JSON-LD double format
               value = value.toExponential(6).replace(
                  /(e(?:\+|-))([0-9])$/, '$10$2');
            }
            rval['@literal'] = '' + value;
         }
      }
      // nothing to coerce
      else
      {
         rval = '' + value;
      }
   }
   
   return rval;
};

/**
 * Normalizes a JSON-LD object.
 *
 * @param input the JSON-LD object to normalize.
 * 
 * @return the normalized JSON-LD object.
 */
Processor.prototype.normalize = function(input)
{
   var rval = [];

   // TODO: validate context
   
   if(input !== null)
   {
      // create name generator state
      this.ng =
      {
         tmp: null,
         c14n: null
      };
      
      // expand input
      var expanded = this.expand(defaultContext, null, input);
      
      // assign names to unnamed bnodes
      this.nameBlankNodes(expanded);
      
      // flatten
      var subjects = {};
      _flatten(null, null, expanded, subjects);

      // append subjects with sorted properties to array
      for(var key in subjects)
      {
         var s = subjects[key];
         var sorted = {};
         var keys = Object.keys(s).sort();
         for(var i in keys)
         {
            var k = keys[i];
            sorted[k] = s[k];
         }
         rval.push(sorted);
      }

      // canonicalize blank nodes
      this.canonicalizeBlankNodes(rval);

      // sort output
      rval.sort(function(a, b)
      {
         return _compare(a['@id'], b['@id']);
      });
   }

   return rval;
};

/**
 * Gets the coerce type for the given property.
 *
 * @param ctx the context to use.
 * @param property the property to get the coerced type for.
 * @param usedCtx a context to update if a value was used from "ctx".
 *
 * @return the coerce type, null for none.
 */
Processor.prototype.getCoerceType = function(ctx, property, usedCtx)
{
   var rval = null;

   // get expanded property
   var p = _expandTerm(ctx, property, null);
   
   // built-in type coercion JSON-LD-isms
   if(p === '@id' || p === '@type')
   {
      rval = '@id';
   }
   else
   {
      // look up compacted property for a coercion type
      p = _compactIri(ctx, p, null);
      if(p in ctx && ctx[p].constructor === Object && '@type' in ctx[p])
      {
         // property found, return expanded type
         var type = ctx[p]['@type'];
         rval = _expandTerm(ctx, type, usedCtx);
         if(usedCtx !== null)
         {
            usedCtx[p] = _clone(ctx[p]);
         }
      }
   }
   
   return rval;
};

var _isBlankNodeIri = function(v)
{
   return v.indexOf('_:') === 0;
};

var _isNamedBlankNode = function(v)
{
   // look for "_:" at the beginning of the subject
   return (
      v.constructor === Object && '@id' in v && _isBlankNodeIri(v['@id']));
};

var _isBlankNode = function(v)
{
   // look for a subject with no ID or a blank node ID
   return (_isSubject(v) && (!('@id' in v) || _isNamedBlankNode(v)));
};

/**
 * Compares two values.
 * 
 * @param v1 the first value.
 * @param v2 the second value.
 * 
 * @return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2.
 */
var _compare = function(v1, v2)
{
   var rval = 0;
   
   if(v1.constructor === Array && v2.constructor === Array)
   {
      for(var i = 0; i < v1.length && rval === 0; ++i)
      {
         rval = _compare(v1[i], v2[i]);
      }
   }
   else
   {
      rval = (v1 < v2 ? -1 : (v1 > v2 ? 1 : 0));
   }
   
   return rval;
};

/**
 * Compares two keys in an object. If the key exists in one object
 * and not the other, the object with the key is less. If the key exists in
 * both objects, then the one with the lesser value is less.
 * 
 * @param o1 the first object.
 * @param o2 the second object.
 * @param key the key.
 * 
 * @return -1 if o1 < o2, 0 if o1 == o2, 1 if o1 > o2.
 */
var _compareObjectKeys = function(o1, o2, key)
{
   var rval = 0;
   if(key in o1)
   {
      if(key in o2)
      {
         rval = _compare(o1[key], o2[key]);
      }
      else
      {
         rval = -1;
      }
   }
   else if(key in o2)
   {
      rval = 1;
   }
   return rval;
};

/**
 * Compares two object values.
 * 
 * @param o1 the first object.
 * @param o2 the second object.
 * 
 * @return -1 if o1 < o2, 0 if o1 == o2, 1 if o1 > o2.
 */
var _compareObjects = function(o1, o2)
{
   var rval = 0;
   
   if(o1.constructor === String)
   {
      if(o2.constructor !== String)
      {
         rval = -1;
      }
      else
      {
         rval = _compare(o1, o2);
      }
   }
   else if(o2.constructor === String)
   {
      rval = 1;
   }
   else
   {
      rval = _compareObjectKeys(o1, o2, '@literal');
      if(rval === 0)
      {
         if('@literal' in o1)
         {
            rval = _compareObjectKeys(o1, o2, '@type');
            if(rval === 0)
            {
               rval = _compareObjectKeys(o1, o2, '@language');
            }
         }
         // both are '@id' objects
         else
         {
            rval = _compare(o1['@id'], o2['@id']);
         }
      }
   }
   
   return rval;
};

/**
 * Compares the object values between two bnodes.
 * 
 * @param a the first bnode.
 * @param b the second bnode.
 * 
 * @return -1 if a < b, 0 if a == b, 1 if a > b.
 */
var _compareBlankNodeObjects = function(a, b)
{
   var rval = 0;
   
   /*
   3. For each property, compare sorted object values.
   3.1. The bnode with fewer objects is first.
   3.2. For each object value, compare only literals and non-bnodes.
   3.2.1. The bnode with fewer non-bnodes is first.
   3.2.2. The bnode with a string object is first.
   3.2.3. The bnode with the alphabetically-first string is first.
   3.2.4. The bnode with a @literal is first.
   3.2.5. The bnode with the alphabetically-first @literal is first.
   3.2.6. The bnode with the alphabetically-first @type is first.
   3.2.7. The bnode with a @language is first.
   3.2.8. The bnode with the alphabetically-first @language is first.
   3.2.9. The bnode with the alphabetically-first @id is first.
   */
   
   for(var p in a)
   {
      // skip IDs (IRIs)
      if(p !== '@id')
      {
         // step #3.1
         var lenA = (a[p].constructor === Array) ? a[p].length : 1;
         var lenB = (b[p].constructor === Array) ? b[p].length : 1;
         rval = _compare(lenA, lenB);

         // step #3.2.1
         if(rval === 0)
         {
            // normalize objects to an array
            var objsA = a[p];
            var objsB = b[p];
            if(objsA.constructor !== Array)
            {
               objsA = [objsA];
               objsB = [objsB];
            }
            
            // compare non-bnodes (remove bnodes from comparison)
            objsA = objsA.filter(function(e) {return !_isNamedBlankNode(e);});
            objsB = objsB.filter(function(e) {return !_isNamedBlankNode(e);});
            rval = _compare(objsA.length, objsB.length);
         }
         
         // steps #3.2.2-3.2.9
         if(rval === 0)
         {
            objsA.sort(_compareObjects);
            objsB.sort(_compareObjects);
            for(var i = 0; i < objsA.length && rval === 0; ++i)
            {
               rval = _compareObjects(objsA[i], objsB[i]);
            }
         }
         
         if(rval !== 0)
         {
            break;
         }
      }
   }
   
   return rval;
};

/**
 * Creates a blank node name generator using the given prefix for the
 * blank nodes. 
 * 
 * @param prefix the prefix to use.
 * 
 * @return the blank node name generator.
 */
var _createNameGenerator = function(prefix)
{
   var count = -1;
   var ng = {
      next: function()
      {
         ++count;
         return ng.current();
      },
      current: function()
      {
         return '_:' + prefix + count;
      },
      inNamespace: function(iri)
      {
         return iri.indexOf('_:' + prefix) === 0;
      }
   };
   return ng;
};

/**
 * Populates a map of all named subjects from the given input and an array
 * of all unnamed bnodes (includes embedded ones).
 * 
 * @param input the input (must be expanded, no context).
 * @param subjects the subjects map to populate.
 * @param bnodes the bnodes array to populate.
 */
var _collectSubjects = function(input, subjects, bnodes)
{
   if(input === null)
   {
      // nothing to collect
   }
   else if(input.constructor === Array)
   {
      for(var i in input)
      {
         _collectSubjects(input[i], subjects, bnodes);
      }
   }
   else if(input.constructor === Object)
   {
      if('@id' in input)
      {
         // graph literal/disjoint graph
         if(input['@id'].constructor == Array)
         {
            _collectSubjects(input['@id'], subjects, bnodes);
         }
         // named subject
         else if(_isSubject(input))
         {
            subjects[input['@id']] = input;
         }
      }
      // unnamed blank node
      else if(_isBlankNode(input))
      {
         bnodes.push(input);
      }
      
      // recurse through subject properties
      for(var key in input)
      {
         _collectSubjects(input[key], subjects, bnodes);
      }
   }
};

/**
 * Flattens the given value into a map of unique subjects. It is assumed that
 * all blank nodes have been uniquely named before this call. Array values for
 * properties will be sorted.
 *
 * @param parent the value's parent, NULL for none.
 * @param parentProperty the property relating the value to the parent.
 * @param value the value to flatten.
 * @param subjects the map of subjects to write to.
 */
var _flatten = function(parent, parentProperty, value, subjects)
{
   var flattened = null;
   
   if(value === null)
   {
      // drop null values
   }
   else if(value.constructor === Array)
   {
      // list of objects or a disjoint graph
      for(var i in value)
      {
         _flatten(parent, parentProperty, value[i], subjects);
      }
   }
   else if(value.constructor === Object)
   {
      // already-expanded value or special-case reference-only @type
      if('@literal' in value || parentProperty === '@type')
      {
         flattened = _clone(value);
      }
      // graph literal/disjoint graph
      else if(value['@id'].constructor === Array)
      {
         // cannot flatten embedded graph literals
         if(parent !== null)
         {
            throw {
               message: 'Embedded graph literals cannot be flattened.'
            };
         }
         
         // top-level graph literal
         for(var idx in value['@id'])
         {
            _flatten(parent, parentProperty, value['@id'][idx], subjects);
         }
      }
      // regular subject
      else
      {
         // create or fetch existing subject
         var subject;
         if(value['@id'] in subjects)
         {
            // FIXME: '@id' might be a graph literal (as {})
            subject = subjects[value['@id']];
         }
         else
         {
            // FIXME: '@id' might be a graph literal (as {})
            subject = {'@id': value['@id']};
            subjects[value['@id']] = subject;
         }
         flattened = {'@id': subject['@id']};

         // flatten embeds
         for(var key in value)
         {
            var v = value[key];
            
            // drop null values, skip @id (it is already set above)
            if(v !== null && key !== '@id')
            {
               if(key in subject)
               {
                  if(subject[key].constructor !== Array)
                  {
                     subject[key] = [subject[key]];
                  }
               }
               else
               {
                  subject[key] = [];
               }
               
               _flatten(subject[key], key, v, subjects);
               if(subject[key].length === 1)
               {
                  // convert subject[key] to object if it has only 1
                  subject[key] = subject[key][0];
               }
            }
         }
      }
   }
   // string value
   else
   {
      flattened = value;
   }

   // add flattened value to parent
   if(flattened !== null && parent !== null)
   {
      if(parent.constructor === Array)
      {
         // do not add duplicate IRIs for the same property
         var duplicate = false;
         if(flattened.constructor === Object && '@id' in flattened)
         {
            duplicate = (parent.filter(function(e)
            {
               return (e.constructor === Object && '@id' in e &&
                  e['@id'] === flattened['@id']);
            }).length > 0);
         }
         if(!duplicate)
         {
            parent.push(flattened);
         }
      }
      else
      {
         parent[parentProperty] = flattened;
      }
   }
};


/**
 * Assigns unique names to blank nodes that are unnamed in the given input.
 * 
 * @param input the input to assign names to.
 */
Processor.prototype.nameBlankNodes = function(input)
{
   // create temporary blank node name generator
   var ng = this.ng.tmp = _createNameGenerator('tmp');
   
   // collect subjects and unnamed bnodes
   var subjects = {};
   var bnodes = [];
   _collectSubjects(input, subjects, bnodes);
   
   // uniquely name all unnamed bnodes
   for(var i in bnodes)
   {
      var bnode = bnodes[i];
      if(!('@id' in bnode))
      {
         // generate names until one is unique
         while(ng.next() in subjects){}
         bnode['@id'] = ng.current();
         subjects[ng.current()] = bnode;
      }
   }
};

/**
 * Renames a blank node, changing its references, etc. The method assumes
 * that the given name is unique.
 * 
 * @param b the blank node to rename.
 * @param id the new name to use.
 */
Processor.prototype.renameBlankNode = function(b, id)
{
   var old = b['@id'];
   
   // update bnode IRI
   b['@id'] = id;
   
   // update subjects map
   var subjects = this.subjects;
   subjects[id] = subjects[old];
   delete subjects[old];
   
   // update reference and property lists
   this.edges.refs[id] = this.edges.refs[old];
   this.edges.props[id] = this.edges.props[old];
   delete this.edges.refs[old];
   delete this.edges.props[old];
   
   // update references to this bnode
   var refs = this.edges.refs[id].all;
   for(var i in refs)
   {
      var iri = refs[i].s;
      if(iri === old)
      {
         iri = id;
      }
      var ref = subjects[iri];
      var props = this.edges.props[iri].all;
      for(var i2 in props)
      {
         if(props[i2].s === old)
         {
            props[i2].s = id;
            
            // normalize property to array for single code-path
            var p = props[i2].p;
            var tmp = (ref[p].constructor === Object) ? [ref[p]] :
               (ref[p].constructor === Array) ? ref[p] : [];
            for(var n in tmp)
            {
               if(tmp[n].constructor === Object &&
                  '@id' in tmp[n] && tmp[n]['@id'] === old)
               {
                  tmp[n]['@id'] = id;
               }
            }
         }
      }
   }
   
   // update references from this bnode 
   var props = this.edges.props[id].all;
   for(var i in props)
   {
      var iri = props[i].s;
      refs = this.edges.refs[iri].all;
      for(var r in refs)
      {
         if(refs[r].s === old)
         {
            refs[r].s = id;
         }
      }
   }
};

/**
 * Canonically names blank nodes in the given input.
 * 
 * @param input the flat input graph to assign names to.
 */
Processor.prototype.canonicalizeBlankNodes = function(input)
{
   // create serialization state
   this.renamed = {};
   this.mappings = {};
   this.serializations = {};
   
   // collect subjects and bnodes from flat input graph
   var edges = this.edges =
   {
      refs: {},
      props: {}
   };
   var subjects = this.subjects = {};
   var bnodes = [];
   for(var i in input)
   {
      var iri = input[i]['@id'];
      subjects[iri] = input[i];
      edges.refs[iri] =
      {
         all: [],
         bnodes: []
      };
      edges.props[iri] =
      {
         all: [],
         bnodes: []
      };
      if(_isBlankNodeIri(iri))
      {
         bnodes.push(input[i]);
      }
   }
   
   // collect edges in the graph
   this.collectEdges();
   
   // create canonical blank node name generator
   var c14n = this.ng.c14n = _createNameGenerator('c14n');
   var ngTmp = this.ng.tmp;
   
   // rename all bnodes that happen to be in the c14n namespace
   // and initialize serializations
   for(var i in bnodes)
   {
      var bnode = bnodes[i];
      var iri = bnode['@id'];
      if(c14n.inNamespace(iri))
      {
         // generate names until one is unique
         while(ngTmp.next() in subjects){};
         this.renameBlankNode(bnode, ngTmp.current());
         iri = bnode['@id'];
      }
      this.serializations[iri] =
      {
         'props': null,
         'refs': null
      };
   }
   
   // keep sorting and naming blank nodes until they are all named
   var resort = true;
   var self = this;
   while(bnodes.length > 0)
   {
      if(resort)
      {
         resort = false;
         bnodes.sort(function(a, b)
         {
            return self.deepCompareBlankNodes(a, b);
         });
      }
      
      // name all bnodes according to the first bnode's relation mappings
      var bnode = bnodes.shift();
      var iri = bnode['@id'];
      var dirs = ['props', 'refs'];
      for(var d in dirs)
      {
         var dir = dirs[d];
         
         // if no serialization has been computed, name only the first node
         if(this.serializations[iri][dir] === null)
         {
            var mapping = {};
            mapping[iri] = 's1';
         }
         else
         {
            mapping = this.serializations[iri][dir].m;
         }
         
         // sort keys by value to name them in order
         var keys = Object.keys(mapping);
         keys.sort(function(a, b)
         {
            return _compare(mapping[a], mapping[b]);
         });
         
         // name bnodes in mapping
         var renamed = [];
         for(var i in keys)
         {
            var iriK = keys[i];
            if(!c14n.inNamespace(iri) && iriK in subjects)
            {
               this.renameBlankNode(subjects[iriK], c14n.next());
               renamed.push(iriK);
            }
         }
         
         // only keep non-canonically named bnodes
         var tmp = bnodes;
         bnodes = [];
         for(var i in tmp)
         {
            var b = tmp[i];
            var iriB = b['@id'];
            if(!c14n.inNamespace(iriB))
            {
               // mark serializations related to the named bnodes as dirty
               for(var i2 in renamed)
               {
                  if(this.markSerializationDirty(iriB, renamed[i2], dir))
                  {
                     // resort if a serialization was marked dirty
                     resort = true;
                  }
               }
               bnodes.push(b);
            }
         }
      }
   }
   
   // sort property lists that now have canonically-named bnodes
   for(var key in edges.props)
   {
      if(edges.props[key].bnodes.length > 0)
      {
         var bnode = subjects[key];
         for(var p in bnode)
         {
            if(p.indexOf('@') !== 0 && bnode[p].constructor === Array)
            {
               bnode[p].sort(_compareObjects);
            }
         }
      }
   }
};

/**
 * A MappingBuilder is used to build a mapping of existing blank node names
 * to a form for serialization. The serialization is used to compare blank
 * nodes against one another to determine a sort order.
 */
MappingBuilder = function()
{
   this.count = 1;
   this.processed = {};
   this.mapping = {};
   this.adj = {};
   this.keyStack = [{ keys: ['s1'], idx: 0 }];
   this.done = {};
   this.s = '';
};

/**
 * Copies this MappingBuilder.
 * 
 * @return the MappingBuilder copy.
 */
MappingBuilder.prototype.copy = function()
{
   var rval = new MappingBuilder();
   rval.count = this.count;
   rval.processed = _clone(this.processed);
   rval.mapping = _clone(this.mapping);
   rval.adj = _clone(this.adj);
   rval.keyStack = _clone(this.keyStack);
   rval.done = _clone(this.done);
   rval.s = this.s;
   return rval;
};

/**
 * Maps the next name to the given bnode IRI if the bnode IRI isn't already in
 * the mapping. If the given bnode IRI is canonical, then it will be given
 * a shortened form of the same name.
 * 
 * @param iri the blank node IRI to map the next name to.
 * 
 * @return the mapped name.
 */
MappingBuilder.prototype.mapNode = function(iri)
{
   if(!(iri in this.mapping))
   {
      if(iri.indexOf('_:c14n') === 0)
      {
         this.mapping[iri] = 'c' + iri.substr(6);
      }
      else
      {
         this.mapping[iri] = 's' + this.count++;
      }
   }
   return this.mapping[iri];
};

/**
 * Serializes the properties of the given bnode for its relation serialization.
 * 
 * @param b the blank node.
 * 
 * @return the serialized properties.
 */
var _serializeProperties = function(b)
{
   var rval = '';
   
   var first = true;
   for(var p in b)
   {
      if(p !== '@id')
      {
         if(first)
         {
            first = false;
         }
         else
         {
            rval += '|';
         }
         
         // property
         rval += '<' + p + '>';
         
         // object(s)
         var objs = (b[p].constructor === Array) ? b[p] : [b[p]];
         for(var oi in objs)
         {
            var o = objs[oi];
            if(o.constructor === Object)
            {
               // ID (IRI)
               if('@id' in o)
               {
                  if(_isBlankNodeIri(o['@id']))
                  {
                     rval += '_:';
                  }
                  else
                  {
                     rval += '<' + o['@id'] + '>';
                  }
               }
               // literal
               else
               {
                  rval += '"' + o['@literal'] + '"';
                  
                  // type literal
                  if('@type' in o)
                  {
                     rval += '^^<' + o['@type'] + '>';
                  }
                  // language literal
                  else if('@language' in o)
                  {
                     rval += '@' + o['@language'];
                  }
               }
            }
            // plain literal
            else
            {
               rval += '"' + o + '"';
            }
         }
      }
   }
   
   return rval;
};

/**
 * Recursively increments the relation serialization for a mapping.
 * 
 * @param subjects the subjects in the graph.
 * @param edges the edges in the graph.
 */
MappingBuilder.prototype.serialize = function(subjects, edges)
{
   if(this.keyStack.length > 0)
   {
      // continue from top of key stack
      var next = this.keyStack.pop();
      for(; next.idx < next.keys.length; ++next.idx)
      {
         var k = next.keys[next.idx];
         if(!(k in this.adj))
         {
            this.keyStack.push(next);
            break;
         }
         
         if(k in this.done)
         {
            // mark cycle
            this.s += '_' + k;
         }
         else
         {
            // mark key as serialized
            this.done[k] = true;
            
            // serialize top-level key and its details
            var s = k;
            var adj = this.adj[k];
            var iri = adj.i;
            if(iri in subjects)
            {
               var b = subjects[iri];
               
               // serialize properties
               s += '[' + _serializeProperties(b) + ']';
               
               // serialize references
               var first = true;
               s += '[';
               var refs = edges.refs[iri].all;
               for(var r in refs)
               {
                  if(first)
                  {
                     first = false;
                  }
                  else
                  {
                     s += '|';
                  }
                  s += '<' + refs[r].p + '>';
                  s += _isBlankNodeIri(refs[r].s) ?
                     '_:' : ('<' + refs[r].s + '>');
               }
               s += ']';
            }
            
            // serialize adjacent node keys
            s += adj.k.join('');
            this.s += s;
            this.keyStack.push({ keys: adj.k, idx: 0 });
            this.serialize(subjects, edges);
         }
      }
   }
};

/**
 * Marks a relation serialization as dirty if necessary.
 * 
 * @param iri the IRI of the bnode to check.
 * @param changed the old IRI of the bnode that changed.
 * @param dir the direction to check ('props' or 'refs').
 * 
 * @return true if marked dirty, false if not.
 */
Processor.prototype.markSerializationDirty = function(iri, changed, dir)
{
   var rval = false;
   
   var s = this.serializations[iri];
   if(s[dir] !== null && changed in s[dir].m)
   {
      s[dir] = null;
      rval = true;
   }
   
   return rval;
};

/**
 * Rotates the elements in an array one position.
 * 
 * @param a the array.
 */
var _rotate = function(a)
{
   a.unshift.apply(a, a.splice(1, a.length));
};

/**
 * Compares two serializations for the same blank node. If the two
 * serializations aren't complete enough to determine if they are equal (or if
 * they are actually equal), 0 is returned.
 * 
 * @param s1 the first serialization.
 * @param s2 the second serialization.
 * 
 * @return -1 if s1 < s2, 0 if s1 == s2 (or indeterminate), 1 if s1 > v2.
 */
var _compareSerializations = function(s1, s2)
{
   var rval = 0;
   
   if(s1.length == s2.length)
   {
      rval = _compare(s1, s2);
   }
   else if(s1.length > s2.length)
   {
      rval = _compare(s1.substr(0, s2.length), s2);
   }
   else
   {
      rval = _compare(s1, s2.substr(0, s1.length));
   }
   
   return rval;
};

/**
 * Recursively serializes adjacent bnode combinations for a bnode.
 * 
 * @param s the serialization to update.
 * @param iri the IRI of the bnode being serialized.
 * @param siri the serialization name for the bnode IRI.
 * @param mb the MappingBuilder to use.
 * @param dir the edge direction to use ('props' or 'refs').
 * @param mapped all of the already-mapped adjacent bnodes.
 * @param notMapped all of the not-yet mapped adjacent bnodes.
 */
Processor.prototype.serializeCombos = function(
   s, iri, siri, mb, dir, mapped, notMapped)
{
   // handle recursion
   if(notMapped.length > 0)
   {
      // copy mapped nodes
      mapped = _clone(mapped);
      
      // map first bnode in list
      mapped[mb.mapNode(notMapped[0].s)] = notMapped[0].s;
      
      // recurse into remaining possible combinations
      var original = mb.copy();
      notMapped = notMapped.slice(1);
      var rotations = Math.max(1, notMapped.length);
      for(var r = 0; r < rotations; ++r)
      {
         var m = (r === 0) ? mb : original.copy();
         this.serializeCombos(s, iri, siri, m, dir, mapped, notMapped);
         
         // rotate not-mapped for next combination
         _rotate(notMapped);
      }
   }
   // no more adjacent bnodes to map, update serialization
   else
   {
      var keys = Object.keys(mapped).sort();
      mb.adj[siri] = { i: iri, k: keys, m: mapped };
      mb.serialize(this.subjects, this.edges);
      
      // optimize away mappings that are already too large
      if(s[dir] === null || _compareSerializations(mb.s, s[dir].s) <= 0)
      {
         // recurse into adjacent values
         for(var i in keys)
         {
            var k = keys[i];
            this.serializeBlankNode(s, mapped[k], mb, dir);
         }
         
         // update least serialization if new one has been found
         mb.serialize(this.subjects, this.edges);
         if(s[dir] === null ||
            (_compareSerializations(mb.s, s[dir].s) <= 0 &&
            mb.s.length >= s[dir].s.length))
         {
            s[dir] = { s: mb.s, m: mb.mapping };
         }
      }
   }
};

/**
 * Computes the relation serialization for the given blank node IRI.
 * 
 * @param s the serialization to update.
 * @param iri the current bnode IRI to be mapped.
 * @param mb the MappingBuilder to use.
 * @param dir the edge direction to use ('props' or 'refs').
 */
Processor.prototype.serializeBlankNode = function(s, iri, mb, dir)
{
   // only do mapping if iri not already processed
   if(!(iri in mb.processed))
   {
      // iri now processed
      mb.processed[iri] = true;
      var siri = mb.mapNode(iri);
      
      // copy original mapping builder
      var original = mb.copy();
      
      // split adjacent bnodes on mapped and not-mapped
      var adj = this.edges[dir][iri].bnodes;
      var mapped = {};
      var notMapped = [];
      for(var i in adj)
      {
         if(adj[i].s in mb.mapping)
         {
            mapped[mb.mapping[adj[i].s]] = adj[i].s;
         }
         else
         {
            notMapped.push(adj[i]);
         }
      }
      
      /*
      // TODO: sort notMapped using ShallowCompare
      var self = this;
      notMapped.sort(function(a, b)
      {
         var rval = self.shallowCompareBlankNodes(
            self.subjects[a.s], self.subjects[b.s]);
         return rval;
      });
      
      var same = false;
      var prev = null;
      for(var i in notMapped)
      {
         var curr = this.subjects[notMapped[i].s];
         if(prev !== null)
         {
            if(this.shallowCompareBlankNodes(prev, curr) === 0)
            {
               same = true;
            }
            else
            {
               if(!same)
               {
                  mapped[mb.mapNode(prev['@id'])] = prev['@id'];
                  delete notMapped[i - 1];
               }
               if(i === notMapped.length - 1)
               {
                  mapped[mb.mapNode(curr['@id'])];
                  delete notMapped[i];
               }
               same = false;
            }
         }
         prev = curr;
      }*/
      
      // TODO: ensure this optimization does not alter canonical order
      
      // if the current bnode already has a serialization, reuse it
      /*var hint = (iri in this.serializations) ?
         this.serializations[iri][dir] : null;
      if(hint !== null)
      {
         var hm = hint.m;
         notMapped.sort(function(a, b)
         {
            return _compare(hm[a.s], hm[b.s]);
         });
         for(var i in notMapped)
         {
            mapped[mb.mapNode(notMapped[i].s)] = notMapped[i].s;
         }
         notMapped = [];
      }*/
      
      // loop over possible combinations
      var combos = Math.max(1, notMapped.length);
      for(var i = 0; i < combos; ++i)
      {
         var m = (i === 0) ? mb : original.copy();
         this.serializeCombos(s, iri, siri, m, dir, mapped, notMapped);         
      }
   }
};

/**
 * Compares two blank nodes for equivalence.
 * 
 * @param a the first blank node.
 * @param b the second blank node.
 * 
 * @return -1 if a < b, 0 if a == b, 1 if a > b.
 */
Processor.prototype.deepCompareBlankNodes = function(a, b)
{
   var rval = 0;
   
   // compare IRIs
   var iriA = a['@id'];
   var iriB = b['@id'];
   if(iriA === iriB)
   {
      rval = 0;
   }
   else
   {
      // do shallow compare first
      rval = this.shallowCompareBlankNodes(a, b);
      
      // deep comparison is necessary
      if(rval === 0)
      {
         // compare property edges and then reference edges
         var dirs = ['props', 'refs'];
         for(var i = 0; rval === 0 && i < dirs.length; ++i)
         {
            // recompute 'a' and 'b' serializations as necessary
            var dir = dirs[i];
            var sA = this.serializations[iriA];
            var sB = this.serializations[iriB];
            if(sA[dir] === null)
            {
               var mb = new MappingBuilder();
               if(dir === 'refs')
               {
                  // keep same mapping and count from 'props' serialization
                  mb.mapping = _clone(sA['props'].m);
                  mb.count = Object.keys(mb.mapping).length + 1;
               }
               this.serializeBlankNode(sA, iriA, mb, dir);
            }
            if(sB[dir] === null)
            {
               var mb = new MappingBuilder();
               if(dir === 'refs')
               {
                  // keep same mapping and count from 'props' serialization
                  mb.mapping = _clone(sB['props'].m);
                  mb.count = Object.keys(mb.mapping).length + 1;
               }
               this.serializeBlankNode(sB, iriB, mb, dir);
            }
            
            // compare serializations
            rval = _compare(sA[dir].s, sB[dir].s);
         }
      }
   }
   
   return rval;
};

/**
 * Performs a shallow sort comparison on the given bnodes.
 * 
 * @param a the first bnode.
 * @param b the second bnode.
 * 
 * @return -1 if a < b, 0 if a == b, 1 if a > b.
 */
Processor.prototype.shallowCompareBlankNodes = function(a, b)
{
   var rval = 0;
   
   /* ShallowSort Algorithm (when comparing two bnodes):
      1. Compare the number of properties.
      1.1. The bnode with fewer properties is first.
      2. Compare alphabetically sorted-properties.
      2.1. The bnode with the alphabetically-first property is first.
      3. For each property, compare object values.
      4. Compare the number of references.
      4.1. The bnode with fewer references is first.
      5. Compare sorted references.
      5.1. The bnode with the reference iri (vs. bnode) is first.
      5.2. The bnode with the alphabetically-first reference iri is first.
      5.3. The bnode with the alphabetically-first reference property is first.
    */
   var pA = Object.keys(a);
   var pB = Object.keys(b);
   
   // step #1
   rval = _compare(pA.length, pB.length);
   
   // step #2
   if(rval === 0)
   {
      rval = _compare(pA.sort(), pB.sort());
   }
   
   // step #3
   if(rval === 0)
   {
      rval = _compareBlankNodeObjects(a, b);
   }
   
   // step #4
   if(rval === 0)
   {
      var edgesA = this.edges.refs[a['@id']].all;
      var edgesB = this.edges.refs[b['@id']].all;
      rval = _compare(edgesA.length, edgesB.length);
   }
   
   // step #5
   if(rval === 0)
   {
      for(var i = 0; i < edgesA.length && rval === 0; ++i)
      {
         rval = this.compareEdges(edgesA[i], edgesB[i]);
      }
   }
   
   return rval;
};

/**
 * Compares two edges. Edges with an IRI (vs. a bnode ID) come first, then
 * alphabetically-first IRIs, then alphabetically-first properties. If a blank
 * node has been canonically named, then blank nodes will be compared after
 * properties (with a preference for canonically named over non-canonically
 * named), otherwise they won't be.
 * 
 * @param a the first edge.
 * @param b the second edge.
 * 
 * @return -1 if a < b, 0 if a == b, 1 if a > b.
 */
Processor.prototype.compareEdges = function(a, b)
{
   var rval = 0;
   
   var bnodeA = _isBlankNodeIri(a.s);
   var bnodeB = _isBlankNodeIri(b.s);
   var c14n = this.ng.c14n;
   
   // if not both bnodes, one that is a bnode is greater
   if(bnodeA != bnodeB)
   {
      rval = bnodeA ? 1 : -1;
   }
   else
   {
      if(!bnodeA)
      {
         rval = _compare(a.s, b.s);
      }
      if(rval === 0)
      {
         rval = _compare(a.p, b.p);
      }
      
      // do bnode IRI comparison if canonical naming has begun
      if(rval === 0 && c14n !== null)
      {
         var c14nA = c14n.inNamespace(a.s);
         var c14nB = c14n.inNamespace(b.s);
         if(c14nA != c14nB)
         {
            rval = c14nA ? 1 : -1;
         }
         else if(c14nA)
         {
            rval = _compare(a.s, b.s);
         }
      }
   }
   
   return rval;
};

/**
 * Populates the given reference map with all of the subject edges in the
 * graph. The references will be categorized by the direction of the edges,
 * where 'props' is for properties and 'refs' is for references to a subject as
 * an object. The edge direction categories for each IRI will be sorted into
 * groups 'all' and 'bnodes'.
 */
Processor.prototype.collectEdges = function()
{
   var refs = this.edges.refs;
   var props = this.edges.props;
   
   // collect all references and properties
   for(var iri in this.subjects)
   {
      var subject = this.subjects[iri];
      for(var key in subject)
      {
         if(key !== '@id')
         {
            // normalize to array for single codepath
            var object = subject[key];
            var tmp = (object.constructor !== Array) ? [object] : object;
            for(var i in tmp)
            {
               var o = tmp[i];
               if(o.constructor === Object && '@id' in o &&
                  o['@id'] in this.subjects)
               {
                  var objIri = o['@id'];
                  
                  // map object to this subject
                  refs[objIri].all.push({ s: iri, p: key });
                  
                  // map this subject to object
                  props[iri].all.push({ s: objIri, p: key });
               }
            }
         }
      }
   }
   
   // create sorted categories
   var self = this;
   for(var iri in refs)
   {
      refs[iri].all.sort(function(a, b) { return self.compareEdges(a, b); });
      refs[iri].bnodes = refs[iri].all.filter(function(edge) {
         return _isBlankNodeIri(edge.s);
      });
   }
   for(var iri in props)
   {
      props[iri].all.sort(function(a, b) { return self.compareEdges(a, b); });
      props[iri].bnodes = props[iri].all.filter(function(edge) {
         return _isBlankNodeIri(edge.s);
      });
   }
};

/**
 * Returns true if the given input is a subject and has one of the given types
 * in the given frame.
 * 
 * @param input the input.
 * @param frame the frame with types to look for.
 * 
 * @return true if the input has one of the given types.
 */
var _isType = function(input, frame)
{
   var rval = false;
   
   // check if type(s) are specified in frame and input
   var type = '@type';
   if('@type' in frame &&
      input.constructor === Object && type in input)
   {
      var tmp = (input[type].constructor === Array) ?
         input[type] : [input[type]];
      var types = (frame[type].constructor === Array) ?
         frame[type] : [frame[type]];
      for(var t = 0; t < types.length && !rval; ++t)
      {
         type = types[t];
         for(var i in tmp)
         {
            if(tmp[i] === type)
            {
               rval = true;
               break;
            }
         }
      }
   }
   
   return rval;
};

/**
 * Returns true if the given input matches the given frame via duck-typing.
 * 
 * @param input the input.
 * @param frame the frame to check against.
 * 
 * @return true if the input matches the frame.
 */
var _isDuckType = function(input, frame)
{
   var rval = false;
   
   // frame must not have a specific type
   var type = '@type';
   if(!(type in frame))
   {
      // get frame properties that must exist on input
      var props = Object.keys(frame).filter(function(e)
      {
         // filter non-keywords
         return e.indexOf('@') !== 0;
      });
      if(props.length === 0)
      {
         // input always matches if there are no properties
         rval = true;
      }
      // input must be a subject with all the given properties
      else if(input.constructor === Object && '@id' in input)
      {
         rval = true;
         for(var i in props)
         {
            if(!(props[i] in input))
            {
               rval = false;
               break;
            }
         }
      }
   }
   
   return rval;
};

/**
 * Subframes a value.
 * 
 * @param subjects a map of subjects in the graph.
 * @param value the value to subframe.
 * @param frame the frame to use.
 * @param embeds a map of previously embedded subjects, used to prevent cycles.
 * @param autoembed true if auto-embed is on, false if not.
 * @param parent the parent object.
 * @param parentKey the parent key.
 * @param options the framing options.
 * 
 * @return the framed input.
 */
var _subframe = function(
   subjects, value, frame, embeds, autoembed, parent, parentKey, options)
{
   // get existing embed entry
   var iri = value['@id'];
   var embed = (iri in embeds) ? embeds[iri] : null;
   
   // determine if value should be embedded or referenced,
   // embed is ON if:
   // 1. The frame OR default option specifies @embed as ON, AND
   // 2. There is no existing embed OR it is an autoembed, AND
   //    autoembed mode is off.
   var embedOn = (
      (('@embed' in frame && frame['@embed']) ||
      (!('@embed' in frame) && options.defaults.embedOn)) &&
      (embed === null || (embed.autoembed && !autoembed)));
   
   if(!embedOn)
   {
      // not embedding, so only use subject IRI as reference
      value = {'@id': value['@id']};
   }
   else
   {
      // create new embed entry
      if(embed === null)
      {
         embed = {};
         embeds[iri] = embed;
      }
      // replace the existing embed with a reference
      else if(embed.parent !== null)
      {
         if(embed.parent[embed.key].constructor === Array)
         {
            // find and replace embed in array
            var objs = embed.parent[embed.key];
            for(var i in objs)
            {
               if(objs[i].constructor === Object && '@id' in objs[i] &&
                  objs[i]['@id'] === iri)
               {
                  objs[i] = {'@id': value['@id']};
                  break;
               }
            }
         }
         else
         {
            embed.parent[embed.key] = {'@id': value['@id']};
         }
         
         // recursively remove any dependent dangling embeds
         var removeDependents = function(iri)
         {
            var iris = Object.keys(embeds);
            for(var i in iris)
            {
               i = iris[i];
               if(i in embeds && embeds[i].parent !== null &&
                  embeds[i].parent['@id'] === iri)
               {
                  delete embeds[i];
                  removeDependents(i);
               }
            }
         };
         removeDependents(iri);
      }
      
      // update embed entry
      embed.autoembed = autoembed;
      embed.parent = parent;
      embed.key = parentKey;
      
      // check explicit flag
      var explicitOn = (
         frame['@explicit'] === true || options.defaults.explicitOn);
      if(explicitOn)
      {
         // remove keys from the value that aren't in the frame
         for(key in value)
         {
            // do not remove @id or any frame key
            if(key !== '@id' && !(key in frame))
            {
               delete value[key];
            }
         }
      }
      
      // iterate over keys in value
      var keys = Object.keys(value);
      for(i in keys)
      {
         // skip keywords
         var key = keys[i];
         if(key.indexOf('@') !== 0)
         {
            // get the subframe if available
            if(key in frame)
            {
               var f = frame[key];
               var _autoembed = false;
            }
            // use a catch-all subframe to preserve data from graph
            else
            {
               var f = (value[key].constructor === Array) ? [] : {};
               var _autoembed = true;
            }
            
            // build input and do recursion
            var v = value[key];
            var input = (v.constructor === Array) ? v : [v];
            for(var n in input)
            {
               // replace reference to subject w/embedded subject
               if(input[n].constructor === Object &&
                  '@id' in input[n] &&
                  input[n]['@id'] in subjects)
               {
                  input[n] = subjects[input[n]['@id']];
               }
            }
            value[key] = _frame(
               subjects, input, f, embeds, _autoembed, value, key, options);
         }
      }
      
      // iterate over frame keys to add any missing values
      for(key in frame)
      {
         // skip keywords and non-null keys in value
         if(key.indexOf('@') !== 0 && (!(key in value) || value[key] === null))
         {
            var f = frame[key];
            
            // add empty array to value
            if(f.constructor === Array)
            {
               value[key] = [];
            }
            // add default value to value
            else
            {
               // use first subframe if frame is an array
               if(f.constructor === Array)
               {
                  f = (f.length > 0) ? f[0] : {};
               }
               
               // determine if omit default is on
               var omitOn = (
                  f['@omitDefault'] === true || options.defaults.omitDefaultOn);
               if(!omitOn)
               {
                  if('@default' in f)
                  {
                     // use specified default value
                     value[key] = f['@default'];
                  }
                  else
                  {
                     // built-in default value is: null
                     value[key] = null;
                  }
               }
            }
         }
      }
   }
   
   return value;
};

/**
 * Recursively frames the given input according to the given frame.
 * 
 * @param subjects a map of subjects in the graph.
 * @param input the input to frame.
 * @param frame the frame to use.
 * @param embeds a map of previously embedded subjects, used to prevent cycles.
 * @param autoembed true if auto-embed is on, false if not.
 * @param parent the parent object (for subframing), null for none.
 * @param parentKey the parent key (for subframing), null for none.
 * @param options the framing options.
 * 
 * @return the framed input.
 */
var _frame = function(
   subjects, input, frame, embeds, autoembed, parent, parentKey, options)
{
   var rval = null;
   
   // prepare output, set limit, get array of frames
   var limit = -1;
   var frames;
   if(frame.constructor === Array)
   {
      rval = [];
      frames = frame;
      if(frames.length === 0)
      {
         frames.push({});
      }
   }
   else
   {
      frames = [frame];
      limit = 1;
   }
   
   // iterate over frames adding input matches to list
   var values = [];
   for(var i = 0; i < frames.length && limit !== 0; ++i)
   {
      // get next frame
      frame = frames[i];
      if(frame.constructor !== Object)
      {
         throw {
            message: 'Invalid JSON-LD frame. ' +
               'Frame must be an object or an array.',
            frame: frame
         };
      }
      
      // create array of values for each frame
      values[i] = [];
      for(var n = 0; n < input.length && limit !== 0; ++n)
      {
         // add input to list if it matches frame specific type or duck-type
         var next = input[n];
         if(_isType(next, frame) || _isDuckType(next, frame))
         {
            values[i].push(next);
            --limit;
         }
      }
   }
   
   // for each matching value, add it to the output
   for(var i1 in values)
   {
      for(var i2 in values[i1])
      {
         frame = frames[i1];
         var value = values[i1][i2];
         
         // if value is a subject, do subframing
         if(_isSubject(value))
         {
            value = _subframe(
               subjects, value, frame, embeds, autoembed,
               parent, parentKey, options);
         }
         
         // add value to output
         if(rval === null)
         {
            rval = value;
         }
         else
         {
            // determine if value is a reference to an embed
            var isRef = (_isReference(value) && value['@id'] in embeds);
            
            // push any value that isn't a parentless reference
            if(!(parent === null && isRef))
            {
               rval.push(value);
            }
         }
      }
   }
   
   return rval;
};

/**
 * Frames JSON-LD input.
 * 
 * @param input the JSON-LD input.
 * @param frame the frame to use.
 * @param options framing options to use.
 * 
 * @return the framed output.
 */
Processor.prototype.frame = function(input, frame, options)
{
   var rval;
   
   // normalize input
   input = jsonld.normalize(input);
   
   // save frame context
   var ctx = null;
   if('@context' in frame)
   {
      ctx = _clone(frame['@context']);
      
      // remove context from frame
      frame = jsonld.expand(frame);
   }
   else if(frame.constructor === Array)
   {
      // save first context in the array
      if(frame.length > 0 && '@context' in frame[0])
      {
         ctx = _clone(frame[0]['@context']);
      }
      
      // expand all elements in the array
      var tmp = [];
      for(var i in frame)
      {
         tmp.push(jsonld.expand(frame[i]));
      }
      frame = tmp;
   }
   
   // create framing options
   // TODO: merge in options from function parameter
   options =
   {
      defaults:
      {
         embedOn: true,
         explicitOn: false,
         omitDefaultOn: false
      }
   };
   
   // build map of all subjects
   var subjects = {};
   for(var i in input)
   {
      subjects[input[i]['@id']] = input[i];
   }
   
   // frame input
   rval = _frame(subjects, input, frame, {}, false, null, null, options);
   
   // apply context
   if(ctx !== null && rval !== null)
   {
      rval = jsonld.compact(ctx, rval);
   }
   
   return rval;
};

})();


// exports
var JSONLDParser = {};

JSONLDParser.parser = {};
JSONLDParser.parser.parse = function(data, graph) {
    if(typeof(data) === 'string') {
        data = JSON.parse(data);
    }
    return jsonldParser.toTriples(data, graph);
};


// end of ./src/js-communication/src/jsonld_parser.js 
// This code is taking from the N3 project from Ruben Verborgh licensed under the MIT license. See https://github.com/RubenVerborgh/node-n3/blob/master/LICENSE.md

// **N3Lexer** tokenizes N3 documents.
// ## Regular expressions
var patterns = {
  _explicituri: /^<((?:[^\x00-\x20<>\\"\{\}\|\^\`]|\\[uU])*)>/,
  _string: /^"[^"\\]*(?:\\.[^"\\]*)*"(?=[^"\\])|^'[^'\\]*(?:\\.[^'\\]*)*'(?=[^'\\])/,
  _tripleQuotedString: /^""("[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*")""|^''('[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*')''/,
  _langcode: /^@([a-z]+(?:-[a-z0-9]+)*)(?=[^a-z0-9\-])/i,
  _prefix: /^((?:[A-Za-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:[\.\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)?:(?=\s)/,
  _qname:  /^((?:[A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:[\.\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)?:((?:(?:[0-:A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~])(?:(?:[\.\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~])*(?:[\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~]))?)?)(?=[\s\.;,)#])/,
  _number: /^[\-+]?(?:\d+\.?\d*([eE](?:[\-\+])?\d+)|\d+\.\d+|\.\d+|\d+)(?=\s*[\s\.;,)#])/,
  _boolean: /^(?:true|false)(?=[\s#,;.])/,
  _punctuation: /^\.(?!\d)|^;|^,|^\[|^\]|^\(|^\)/, // If a digit follows a dot, it is a number, not punctuation.
  _fastString: /^"[^"\\]+"(?=[^"\\])/,
  _keyword: /^(?:@[a-z]+|[Pp][Rr][Ee][Ff][Ii][Xx]|[Bb][Aa][Ss][Ee])(?=\s)/,
  _type: /^\^\^(?:<([^>]*)>|([A-Z_a-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c-\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd][\-0-9A-Z_a-z\u00b7\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u037d\u037f-\u1fff\u200c-\u200d\u203f-\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]*)?:([A-Z_a-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c-\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd][\-0-9A-Z_a-z\u00b7\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u037d\u037f-\u1fff\u200c-\u200d\u203f-\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]*)(?=[\s\.;,)#]))/,
  _shortPredicates: /^a(?=\s+|<)/,
  _newline: /^[ \t]*(?:#[^\n\r]*)?(?:\r\n|\n|\r)[ \t]*/,
  _whitespace: /^[ \t]+/,
  _nonwhitespace: /^\S*/,
  _endOfFile: /^(?:#[^\n\r]*)?$/
};

// Regular expression and replacement string to escape N3 strings.
// Note how we catch invalid unicode sequences separately (they will trigger an error).
var escapeSequence = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{8})|\\[uU]|\\(.)/g;
var escapeReplacements = { '\\': '\\', "'": "'", '"': '"',
                           'n': '\n', 'r': '\r', 't': '\t', 'f': '\f', 'b': '\b',
                           '_': '_', '~': '~', '.': '.', '-': '-', '!': '!', '$': '$', '&': '&',
                           '(': '(', ')': ')', '*': '*', '+': '+', ',': ',', ';': ';', '=': '=',
                           '/': '/', '?': '?', '#': '#', '@': '@', '%': '%' };
var illegalUrlChars = /[\x00-\x20<>\\"\{\}\|\^\`]/;

// Different punctuation types.
var punctuationTypes = { '.': 'dot', ';': 'semicolon', ',': 'comma',
                         '[': 'bracketopen', ']': 'bracketclose',
                         '(': 'liststart', ')': 'listend' };
var fullPredicates = { 'a': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' };

// ## Constructor
function N3Lexer() {
  if (!(this instanceof N3Lexer))
    return new N3Lexer();

  // Local copies of the patterns perform slightly better.
  for (var name in patterns)
    this[name] = patterns[name];
}

N3Lexer.prototype = {
  // ## Private methods

  // ### `_next` fires the callback with the next token.
  // Returns a boolean indicating whether a token has been emitted.
  _next: function (callback) {
    // Only emit tokens if there's still input left.
    if (this._input === undefined)
      return false;

    // Count and skip newlines.
    var match;
    while (match = this._newline.exec(this._input)) {
      this._line++;
      this._input = this._input.substr(match[0].length);
    }

    // Skip whitespace.
    if (match = this._whitespace.exec(this._input)) {
      this._input = this._input.substr(match[0].length);
    }

    // Create token skeleton.
    // We initialize all possible properties as strings, so the engine uses one runtime type for all tokens.
    var token = { line: this._line,
                  type: '',
                  value: '',
                  prefix: ''
                };
    var unescaped;

    // Emit the EOF token if we're at the end and reading is complete.
    if (this._endOfFile.test(this._input)) {
      // If we're streaming, don't emit EOF yet.
      if (!this._inputComplete)
        return false;
      // Free the input.
      delete this._input;
      // Emit EOF.
      token.type = 'eof';
      callback(null, token);
      return true;
    }

    // Try to find an `explicituri`.
    if (match = this._explicituri.exec(this._input)) {
      unescaped = this._unescape(match[1]);
      if (unescaped === null || illegalUrlChars.test(unescaped))
        return reportSyntaxError(this);
      token.type = 'explicituri';
      token.value = unescaped;
    }
    // Try to find a dot.
    else if (match = this._punctuation.exec(this._input)) {
      token.type = punctuationTypes[match[0]];
    }
    // Try to find a language code.
    else if (this._prevTokenType === 'literal' && (match = this._langcode.exec(this._input))) {
      token.type = 'langcode';
      token.value = match[1];
    }
    // Try to find a string literal the fast way.
    // This only includes non-empty simple quoted literals without escapes.
    // If streaming, make sure the input is long enough so we don't miss language codes or string types.
    else if (match = this._fastString.exec(this._input)) {
      token.type = 'literal';
      token.value = match[0];
    }
    // Try to find any other string literal wrapped in a pair of quotes.
    else if (match = this._string.exec(this._input)) {
      unescaped = this._unescape(match[0]);
      if (unescaped === null)
        return reportSyntaxError(this);
      token.type = 'literal';
      token.value = unescaped.replace(/^'|'$/g, '"');
    }
    // Try to find a string literal wrapped in a pair of triple quotes.
    else if (match = this._tripleQuotedString.exec(this._input)) {
      unescaped = match[1] || match[2];
      // Count the newlines and advance line counter.
      this._line += unescaped.split(/\r\n|\r|\n/).length - 1;
      unescaped = this._unescape(unescaped);
      if (unescaped === null)
        return reportSyntaxError(this);
      token.type = 'literal';
      token.value = unescaped.replace(/^'|'$/g, '"');
    }
    // Try to find a number.
    else if (match = this._number.exec(this._input)) {
      token.type = 'literal';
      token.value = '"' + match[0] + '"^^<http://www.w3.org/2001/XMLSchema#' +
                    (match[1] ? 'double>' : (/^[+\-]?\d+$/.test(match[0]) ? 'integer>' : 'decimal>'));
    }
    // Try to match a boolean.
    else if (match = this._boolean.exec(this._input)) {
      token.type = 'literal';
      token.value = '"' + match[0] + '"^^<http://www.w3.org/2001/XMLSchema#boolean>';
    }
    // Try to find a type.
    else if (this._prevTokenType === 'literal' && (match = this._type.exec(this._input))) {
      token.type = 'type';
      if (!match[2]) {
        token.value = match[1];
      }
      else {
        token.prefix = match[2];
        token.value = match[3];
      }
    }
    // Try to find a keyword.
    else if (match = this._keyword.exec(this._input)) {
      var keyword = match[0];
      token.type = keyword[0] === '@' ? keyword : keyword.toUpperCase();
    }
    // Try to find a prefix.
    else if ((this._prevTokenType === '@prefix' || this._prevTokenType === 'PREFIX') &&
             (match = this._prefix.exec(this._input))) {
      token.type = 'prefix';
      token.value = match[1] || '';
    }
    // Try to find a qname.
    else if (match = this._qname.exec(this._input)) {
      unescaped = this._unescape(match[2]);
      if (unescaped === null)
        return reportSyntaxError(this);
      token.type = 'qname';
      token.prefix = match[1] || '';
      token.value = unescaped;
    }
    // Try to find an abbreviated predicate.
    else if (match = this._shortPredicates.exec(this._input)) {
      token.type = 'abbreviation';
      token.value = fullPredicates[match[0]];
    }
    // What if nothing of the above was found?
    else {
      // We could be in streaming mode, and then we just wait for more input to arrive.
      // Otherwise, a syntax error has occurred in the input.
      // One exception: error on an unaccounted linebreak (= not inside a triple-quoted literal).
      if (this._inputComplete || (!/^'''|^"""/.test(this._input) && /\n|\r/.test(this._input)))
        reportSyntaxError(this);
      return false;
    }

    // Save the token type for the next iteration.
    this._prevTokenType = token.type;

    // Advance to next part to tokenize.
    this._input = this._input.substr(match[0].length);

    // Emit the parsed token.
    callback(null, token);
    return true;

    function reportSyntaxError(self) {
      match = self._nonwhitespace.exec(self._input);
      delete self._input;
      callback('Syntax error: unexpected "' + match[0] + '" on line ' + self._line + '.');
      return false;
    }
  },

  // ### `unescape` replaces N3 escape codes by their corresponding characters.
  _unescape: function (item) {
    try {
      return item.replace(escapeSequence, function (sequence, unicode4, unicode8, escapedChar) {
        var charCode;
        if (unicode4) {
          charCode = parseInt(unicode4, 16);
          if (isNaN(charCode))
            throw "invalid character code";
          return String.fromCharCode(charCode);
        }
        else if (unicode8) {
          charCode = parseInt(unicode8, 16);
          if (isNaN(charCode))
            throw "invalid character code";
          if (charCode < 0xFFFF)
            return String.fromCharCode(charCode);
          return String.fromCharCode(Math.floor((charCode - 0x10000) / 0x400) + 0xD800) +
                 String.fromCharCode((charCode - 0x10000) % 0x400 + 0xDC00);
        }
        else {
          var replacement = escapeReplacements[escapedChar];
          if (!replacement)
            throw "invalid escape sequence";
          return replacement;
        }
      });
    }
    catch (error) {
      return null;
    }
  },

  // ## Public methods

  // ### `tokenize` starts the transformation of an N3 document into an array of tokens.
  // The input can be a string or a stream.
  tokenize: function (input, callback) {
    var self = this;
    this._line = 1;

    // If the input is a string, continuously emit tokens through callback until the end.
    if (typeof(input) === 'string') {
      this._input = input;
      this._inputComplete = true;
      process.nextTick(function () {
        while (self._next(callback)) {} ;
      });
    }
    // Otherwise, the input must be a stream.
    else {
      this._input = '';
      this._inputComplete = false;

      // Read strings, not buffers.
      if (typeof input.setEncoding === 'function')
        input.setEncoding('utf8');

      // If new data arrives…
      input.on('data', function (data) {
        // …add the new data to the buffer
        self._input += data;
        // …and parse as far as we can.
        while (self._next(callback)) {} ;
      });
      // If we're at the end of the stream…
      input.on('end', function () {
        // …signal completeness…
        self._inputComplete = true;
        // …and parse until the end.
        while (self._next(callback)) {} ;
      });
    }
  }
};

// ## Exports


// **RVInnerN3Parser** parses N3 documents.

var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
    RDF_NIL    = {token: 'uri', value: RDF_PREFIX + 'nil', prefix: null, suffix: null},
    RDF_FIRST  = {token: 'uri', value: RDF_PREFIX + 'first', prefix: null, suffix: null},
    RDF_REST   = {token: 'uri', value: RDF_PREFIX + 'rest', prefix: null, suffix: null};

var absoluteURI = /^[a-z]+:/,
    absolutePath = /^\//,
    hashURI = /^#/,
    documentPart = /[^\/]*$/,
    rootURI = /^(?:[a-z]+:\/*)?[^\/]*/;

var _undefined, noop = function () {};

// ## Constructor
function RVInnerN3Parser(config) {
  if (!(this instanceof RVInnerN3Parser))
    return new RVInnerN3Parser(config);

  config = config || {};

  this._lexer = config.lexer || new N3Lexer();
  this._blankNodes = Object.create(null);
  this._blankNodeCount = 0;
  this._tripleStack = [];
  if(config.baseURI != null)
    config.documentURI = config.baseURI
  if (!config.documentURI) {
    this._baseURI = null;
    this._baseURIPath = null;
  }
  else {
    if(config.documentURI.indexOf("#") !== -1)
        config.documentURI = config.documentURI.split("#")[0];
    this._baseURI = config.documentURI;
    this._baseURIPath = this._baseURI.replace(documentPart, '');
    this._baseURIRoot = this._baseURI.match(rootURI)[0];
  }
}

RVInnerN3Parser.prototype = {
  defaultGraph: null,
  constructor: RVInnerN3Parser,

  // ## Private methods

  // ### `_readInTopContext` reads a token when in the top context.
  _readInTopContext: function (token) {
    switch (token.type) {
    // If an EOF token arrives in the top context, signal that we're done.
    case 'eof':
      return this._callback(null, null, this._prefixes);
    // It could be a prefix declaration.
    case '@prefix':
      this._sparqlStyle = false;
      return this._readPrefix;
    case 'PREFIX':
      this._sparqlStyle = true;
      return this._readPrefix;
    // It could be a base declaration.
    case '@base':
      this._sparqlStyle = false;
      return this._readBaseURI;
    case 'BASE':
      this._sparqlStyle = true;
      return this._readBaseURI;
    // Otherwise, the next token must be a subject.
    default:
      return this._readSubject(token);
    }
  },

  // ### `_readSubject` reads a triple's subject.
  _readSubject: function (token) {
    switch (token.type) {
    case 'explicituri':
      if (this._baseURI === null || absoluteURI.test(token.value))
          this._subject = {token: 'uri', value: token.value, prefix: null, suffix: null};
      else

          this._subject = {token: 'uri', value: this._resolveURI(token.value), prefix: null, suffix: null};
      break;
    case 'qname':
      if (token.prefix === '_') {
          if(this._blankNodes[token.value] !== undefined) {
              this._subject = {'blank': this._blankNodes[token.value] };
          } else {
              this._subject = {'blank': (this._blankNodes[token.value] = '_:' + this._blankNodeCount++)};
          }
      }
      else {
        var prefix = this._prefixes[token.prefix];
        if (prefix === _undefined)
          return this._error('Undefined prefix "' + token.prefix + ':"', token);
        this._subject = {token: 'uri', value: prefix + token.value, prefix: null, suffix: null};

      }
      break;
    case 'bracketopen':
      // Start a new triple with a new blank node as subject.
      this._subject = {'blank': ('_:' + this._blankNodeCount++)};
      this._tripleStack.push({ subject: this._subject, predicate: null, object: null, type: 'blank' });
      return this._readBlankNodeHead;
    case 'liststart':
      // Start a new list
      this._tripleStack.push({ subject: RDF_NIL, predicate: null, object: null, type: 'list' });
      this._subject = null;
      return this._readListItem;
    default:
      return this._error('Unexpected token type "' + token.type, token);
    }
    this._subjectHasPredicate = false;
    // The next token must be a predicate.
    return this._readPredicate;
  },

  // ### `_readPredicate` reads a triple's predicate.
  _readPredicate: function (token) {
    switch (token.type) {
    case 'explicituri':
    case 'abbreviation':
      if (this._baseURI === null || absoluteURI.test(token.value))
        this._predicate = {token: 'uri', value: token.value, prefix: null, suffix: null};
      else {
        var resolved = 
        this._predicate = {token: 'uri', value: this._resolveURI(token.value), prefix: null, suffix: null};
      }
      break;
    case 'qname':
      if (token.prefix === '_') {
        return this._error('Disallowed blank node as predicate', token);
      }
      else {
        var prefix = this._prefixes[token.prefix];
        if (prefix === _undefined)
          return this._error('Undefined prefix "' + token.prefix + ':"', token);
        this._predicate = {token: 'uri', value: prefix + token.value, prefix: null, suffix: null};
      }
      break;
    case 'bracketclose':
      // Expected predicate didn't come, must have been trailing semicolon.
      return this._readBlankNodeTail(token, true);
    case 'dot':
      // A dot is not allowed if the subject did not have a predicate yet
      if (!this._subjectHasPredicate)
        return this._error('Unexpected dot', token);
      // Expected predicate didn't come, must have been trailing semicolon.
      return this._readPunctuation(token, true);
    case 'semicolon':
      // Extra semicolons can be safely ignored
      return this._readPredicate;
    default:
      return this._error('Expected predicate to follow "' + this._subject + '"', token);
    }
    this._subjectHasPredicate = true;
    // The next token must be an object.
    return this._readObject;
  },

  // ### `_readObject` reads a triple's object.
  _readObject: function (token) {
    switch (token.type) {
    case 'explicituri':
      if (this._baseURI === null || absoluteURI.test(token.value))
        this._object = {token: 'uri', value: token.value, prefix: null, suffix: null};
      else
        this._object = {token: 'uri', value: this._resolveURI(token.value), prefix: null, suffix: null};
      break;
    case 'qname':
      if (token.prefix === '_') {
          if(this._blankNodes[token.value] !== undefined) {
              this._object = {'blank': this._blankNodes[token.value] };
          } else {
              this._object = {'blank': (this._blankNodes[token.value] = '_:' + this._blankNodeCount++)};
          }
      }
      else {
        var prefix = this._prefixes[token.prefix];
        if (prefix === _undefined)
          return this._error('Undefined prefix "' + token.prefix + ':"', token);
        this._object = {token: 'uri', value: prefix + token.value, prefix: null, suffix: null};
      }
      break;
    case 'literal':
      this._object = {'literal': token.value};
      return this._readDataTypeOrLang;
    case 'bracketopen':
      // Start a new triple with a new blank node as subject.
      var blank = {'blank': ('_:' + this._blankNodeCount++)};
      this._tripleStack.push({ subject: this._subject, predicate: this._predicate, object: blank, type: 'blank' });
      this._subject = blank;
      return this._readBlankNodeHead;
    case 'liststart':
      // Start a new list
      this._tripleStack.push({ subject: this._subject, predicate: this._predicate, object: RDF_NIL, type: 'list' });
      this._subject = null;
      return this._readListItem;
    default:
      return this._error('Expected object to follow "' + this._predicate + '"', token);
    }
    return this._getTripleEndReader();
  },

  // ### `_readBlankNodeHead` reads the head of a blank node.
  _readBlankNodeHead: function (token) {
    if (token.type === 'bracketclose')
      return this._readBlankNodeTail(token, true);
    else
      return this._readPredicate(token);
  },

  // ### `_readBlankNodeTail` reads the end of a blank node.
  _readBlankNodeTail: function (token, empty) {
    if (token.type !== 'bracketclose')
      return this._readPunctuation(token);

    // Store blank node triple.
    if (empty !== true)
      this._callback(null, { subject: this._subject,
                             predicate: this._predicate,
                             object: this._object,
                             graph: RVInnerN3Parser.prototype.defaultGraph });

    // Restore parent triple that contains the blank node.
    var triple = this._tripleStack.pop();
    this._subject = triple.subject;
    // Was the blank node the object?
    if (triple.object !== null) {
      // Restore predicate and object as well, and continue by reading punctuation.
      this._predicate = triple.predicate;
      this._object = triple.object;
      return this._getTripleEndReader();
    }
    // The blank node was the subject, so continue reading the predicate.
    return this._readPredicate;
  },

  // ### `_readDataTypeOrLang` reads an _optional_ data type or language.
  _readDataTypeOrLang: function (token) {
    switch (token.type) {
    case 'type':
      var value;
      if (token.prefix === '') {
        value = token.value;
      }
      else {
        var prefix = this._prefixes[token.prefix];
        if (prefix === _undefined)
          return this._error('Undefined prefix "' + token.prefix + ':"', token);
        value = prefix + token.value;
      }
      if(this._object.literal) {
        this._object.literal += '^^<' + value + '>';
      } else {
        this._object += '^^<' + value + '>';
        this._object = {literal: this._object};
      }

      return this._getTripleEndReader();
    case 'langcode':
        if(this._object.literal) {
            this._object.literal += '@' + token.value.toLowerCase();
        } else {
            this._object += '@' + token.value.toLowerCase();
            this._object = {literal: this._object};
        }
      return this._getTripleEndReader();
    default:
      return this._getTripleEndReader().call(this, token);
    }
  },

  // ### `_readListItem` reads items from a list.
  _readListItem: function (token) {
    var item = null,                  // The actual list item.
        itemHead = null,              // The head of the rdf:first predicate.
        prevItemHead = this._subject, // The head of the previous rdf:first predicate.
        stack = this._tripleStack,    // The stack of triples part of recursion (lists, blanks, etc.).
        parentTriple = stack[stack.length - 1], // The triple containing the current list.
        next = this._readListItem;    // The next function to execute.

    switch (token.type) {
    case 'explicituri':
      item = {'token': 'uri', 'value': token.value, 'prefix': null, 'suffix': null};
      break;
    case 'qname':
      if (token.prefix === '_') {
          if(this._blankNodes[token.value] !== undefined) {
              item = {'blank': this._blankNodes[token.value] };
          } else {
              tiem = {'blank': (this._blankNodes[token.value] = '_:' + this._blankNodeCount++)};
          }
      }
      else {
        var prefix = this._prefixes[token.prefix];
        if (prefix === _undefined)
          return this._error('Undefined prefix "' + token.prefix + ':"', token);
          item = {'token': 'uri', 'value': prefix + token.value, 'prefix': null, 'suffix': null};
      }
      break;
    case 'literal':
      item = {'literal': token.value };
      next = this._readDataTypeOrLang;
      break;
    case 'bracketopen':
      // Stack the current list triple and start a new triple with a blank node as subject.
      itemHead = {'blank': '_:' + this._blankNodeCount++ };
      item     = {'blank': '_:' + this._blankNodeCount++ };

      stack.push({ subject: itemHead, predicate: RDF_FIRST, object: item, type: 'blank' });
      this._subject = item;
      next = this._readBlankNodeHead;
      break;
    case 'liststart':
      // Stack the current list triple and start a new list
      itemHead = {'blank': '_:' + this._blankNodeCount++};
      stack.push({ subject: itemHead, predicate: RDF_FIRST, object: RDF_NIL, type: 'list' });
      this._subject = null;
      next = this._readListItem;
      break;
    case 'listend':
      // Restore the parent triple.
      stack.pop();
      // If this list is contained within a parent list, return the membership triple here.
      // This will be `<parent list elemen>t rdf:first <this list>.`.
      if (stack.length !== 0 && stack[stack.length - 1].type === 'list')
        this._callback(null, { subject: parentTriple.subject,
                               predicate: parentTriple.predicate,
                               object: parentTriple.object,
                               graph: RVInnerN3Parser.prototype.defaultGraph });
      // Restore the parent triple's subject.
      this._subject = (typeof(parentTriple.subject) === 'string' ? {'token': 'uri', 'value': parentTriple.subject, 'prefix': null, 'suffix': null } : parentTriple.subject);
      // Was this list in the parent triple's subject?
      if (parentTriple.predicate === null) {
        // The next token is the predicate.
        next = this._readPredicate;
        // Skip writing the list tail if this was an empty list.
        if (parentTriple.subject === RDF_NIL)
          return next;
      }
      // The list was in the parent triple's object.
      else {
        // Restore the parent triple's predicate and object as well.
        this._predicate = (typeof(parentTriple.predicate) === 'string' ? {'token': 'uri', 'value': parentTriple.predicate, 'prefix': null, 'suffix': null } : parentTriple.predicate); 
        this._object = (typeof(parentTriple.object) === 'string' ? {'token': 'uri', 'value': parentTriple.object, 'prefix': null, 'suffix': null } : parentTriple.object);

        next = this._getTripleEndReader();
        // Skip writing the list tail if this was an empty list.
        if (parentTriple.object === RDF_NIL)
          return next;
      }
      // Close the list by making the item head nil.
      itemHead = RDF_NIL;
      break;
    default:
      return this._error('Expected list item instead of "' + token.type + '"', token);
    }

     // Create a new blank node if no item head was assigned yet.
    if (itemHead === null)
      this._subject = itemHead = {'blank': '_:' + this._blankNodeCount++};

    // Is this the first element of the list?
    if (prevItemHead === null) {
      // This list is either the object or the subject.
      if (parentTriple.object === RDF_NIL)
        parentTriple.object = itemHead;
      else
        parentTriple.subject = itemHead;
    }
    else {
      // The rest of the list is in the current head.
      this._callback(null, { subject: prevItemHead,
                             predicate: RDF_REST,
                             object: itemHead,
                             graph: RVInnerN3Parser.prototype.defaultGraph });
    }
    // Add the item's value.
    if (item !== null)
      this._callback(null, { subject: itemHead,
                             predicate: RDF_FIRST,
                             object: item,
                             graph: RVInnerN3Parser.prototype.defaultGraph });
    return next;
  },

  // ### `_readPunctuation` reads punctuation between triples or triple parts.
  _readPunctuation: function (token, empty) {
    var next;
    switch (token.type) {
    // A dot just ends the statement, without sharing anything with the next.
    case 'dot':
      next = this._readInTopContext;
      break;
    // Semicolon means the subject is shared; predicate and object are different.
    case 'semicolon':
      next = this._readPredicate;
      break;
    // Comma means both the subject and predicate are shared; the object is different.
    case 'comma':
      next = this._readObject;
      break;
    default:
      return this._error('Expected punctuation to follow "' + this._object + '"', token);
    }
    // A triple has been completed now, so return it.
    if (!empty)
      this._callback(null, { subject: this._subject,
                             predicate: this._predicate,
                             object: this._object,
                             graph: RVInnerN3Parser.prototype.defaultGraph });
    return next;
  },

  // ### `_readPrefix` reads the prefix of a prefix declaration.
  _readPrefix: function (token) {
    if (token.type !== 'prefix')
      return this._error('Expected prefix to follow @prefix', token);
    this._prefix = token.value;
    return this._readPrefixURI;
  },

  // ### `_readPrefixURI` reads the URI of a prefix declaration.
  _readPrefixURI: function (token) {
    if (token.type !== 'explicituri')
      return this._error('Expected explicituri to follow prefix "' + this.prefix + '"', token);
    var prefixURI;
    if (this._baseURI === null || absoluteURI.test(token.value))
      prefixURI = token.value;
    else
      prefixURI = this._resolveURI(token.value);
    this._prefixes[this._prefix] = prefixURI;
    this._prefixCallback(this._prefix, prefixURI);
    return this._readDeclarationPunctuation;
  },

  // ### `_readBaseURI` reads the URI of a base declaration.
  _readBaseURI: function (token) {
    if (token.type !== 'explicituri')
      return this._error('Expected explicituri to follow base declaration', token);
    if (this._baseURI === null || absoluteURI.test(token.value))
      this._baseURI = token.value;
    else
      this._baseURI = this._resolveURI(token.value);
    this._baseURIPath = this._baseURI.replace(documentPart, '');
    this._baseURIRoot = this._baseURI.match(rootURI)[0];
    return this._readDeclarationPunctuation;
  },

  // ### `_readDeclarationPunctuation` reads the punctuation of a declaration.
  _readDeclarationPunctuation: function (token) {
    // SPARQL-style declarations don't have punctuation.
    if (this._sparqlStyle)
      return this._readInTopContext(token);

    if (token.type !== 'dot')
      return this._error('Expected declaration to end with a dot', token);
    return this._readInTopContext;
  },

  // ### `_getTripleEndReader` gets the next reader function at the end of a triple.
  _getTripleEndReader: function () {
    var stack = this._tripleStack;
    if (stack.length === 0)
      return this._readPunctuation;

    switch (stack[stack.length - 1].type) {
    case 'blank':
      return this._readBlankNodeTail;
    case 'list':
      return this._readListItem;
    }
  },

  // ### `_error` emits an error message through the callback.
  _error: function (message, token) {
    this._callback(message + ' at line ' + token.line + '.');
  },

  // ### `_resolveURI` resolves a URI against a base path
  _resolveURI: function (uri) {
    if (hashURI.test(uri))
      return this._baseURI + uri;
    if (absolutePath.test(uri))
      return this._baseURIRoot + uri;
    return this._baseURIPath + uri;
  },

  // ## Public methods

  // ### `parse` parses the N3 input and emits each parsed triple through the callback.
  parse: function (input, tripleCallback, prefixCalback) {
    var self = this;
    // Initialize prefix declarations.
    this._prefixes = {};
    // Set the triple and prefix callbacks.
    this._callback = tripleCallback || noop;
    this._prefixCallback = prefixCalback || noop;
    // The read callback is the next function to be executed when a token arrives.
    // We start reading in the top context.
    this._readCallback = this._readInTopContext;
    // Execute the read callback when a token arrives.
    this._lexer.tokenize(input, function (error, token) {
      if (self._readCallback !== _undefined) {
        if (error !== null)
          self._callback(error);
        else
          self._readCallback = self._readCallback(token);
      }
    });
  }
};

/*
var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
    RDF_NIL    = {token: 'uri', value: RDF_PREFIX + 'nil', prefix: null, suffix: null},
    RDF_FIRST  = {token: 'uri', value: RDF_PREFIX + 'first', prefix: null, suffix: null},
    RDF_REST   = {token: 'uri', value: RDF_PREFIX + 'rest', prefix: null, suffix: null};

var absoluteURI = /^[a-z]+:/;
var hashURI = /^#/;
var documentPart = /[^\/]*$/;

var _undefined;

// ## Constructor
function RVInnerN3Parser(config) {
  config = config || {};

  // We use a dummy constructor to enable construction without `new`.
  function Constructor() {}
  Constructor.prototype = RVInnerN3Parser.prototype;

  // Initialize the new `RVInnerN3Parser`.
  var n3Parser = new Constructor();
  n3Parser._lexer = config.lexer || new N3Lexer();
  n3Parser._blankNodes = Object.create(null);
  n3Parser._blankNodeCount = 0;
  n3Parser._tripleStack = [];
  if (!config.documentURI) {
    n3Parser._baseURI = n3Parser._documentURI = null;
    n3Parser._baseURIROOT = n3Parser._documentURIRoot = null;
  }
  else {
    n3Parser._baseURI = n3Parser._documentURI = config.documentURI;
    n3Parser._baseURIRoot = n3Parser._documentURIRoot = config.documentURI.replace(documentPart, '');
  }

  // Return the new `RVInnerN3Parser`.
  return n3Parser;
}

RVInnerN3Parser.prototype = {
  defaultGraph: null,
  constructor: RVInnerN3Parser,

  // ## Private methods

  // ### `_readInTopContext` reads a token when in the top context.
  _readInTopContext: function (token) {
    switch (token.type) {
    // If an EOF token arrives in the top context, signal that we're done.
    case 'eof':
      return this._callback(null, null);
    // It could be a prefix declaration.
    case '@prefix':
      this._sparqlStyle = false;
      return this._readPrefix;
    case 'PREFIX':
      this._sparqlStyle = true;
      return this._readPrefix;
    // It could be a base declaration.
    case '@base':
      this._sparqlStyle = false;
      return this._readBaseURI;
    case 'BASE':
      this._sparqlStyle = true;
      return this._readBaseURI;
    // Otherwise, the next token must be a subject.
    default:
      return this._readSubject(token);
    }
  },

  // ### `_readSubject` reads a triple's subject.
  _readSubject: function (token) {
    switch (token.type) {
    case 'explicituri':
      if (this._baseURI === null || absoluteURI.test(token.value))
          this._subject = {token: 'uri', value: token.value, prefix: null, suffix: null};
      else
          this._subject = {token: 'uri', value: (hashURI.test(token.value) ? this._baseURI : this._baseURIRoot) + token.value, prefix: null, suffix: null};
      break;
    case 'qname':
      if (token.prefix === '_') {
          if(this._blankNodes[token.value] !== undefined) {
              this._subject = {'blank': this._blankNodes[token.value] };
          } else {
              this._subject = {'blank': (this._blankNodes[token.value] = '_:' + this._blankNodeCount++)};
          }
      }
      else {
        var prefix = this._prefixes[token.prefix];
        if (prefix === _undefined)
          return this._error('Undefined prefix "' + token.prefix + ':"', token);
        this._subject = {token: 'uri', value: prefix + token.value, prefix: null, suffix: null};
      }
      break;
    case 'bracketopen':
      // Start a new triple with a new blank node as subject.
      this._subject = {'blank': ('_:' + this._blankNodeCount++)};
      this._tripleStack.push({ subject: this._subject, predicate: null, object: null, type: 'blank' });
      return this._readBlankNodeHead;
    case 'liststart':
      // Start a new list
      this._tripleStack.push({ subject: RDF_NIL, predicate: null, object: null, type: 'list' });
      this._subject = null;
      return this._readListItem;
    default:
      return this._error('Unexpected token type "' + token.type, token);
    }
    this._subjectHasPredicate = false;
    // The next token must be a predicate.
    return this._readPredicate;
  },

  // ### `_readPredicate` reads a triple's predicate.
  _readPredicate: function (token) {
    switch (token.type) {
    case 'explicituri':
    case 'abbreviation':
      if (this._baseURI === null || absoluteURI.test(token.value))
        this._predicate = {token: 'uri', value: token.value, prefix: null, suffix: null};
      else
        this._predicate = {token: 'uri', value: (hashURI.test(token.value) ? this._baseURI : this._baseURIRoot) + token.value, prefix: null, suffix: null};
      break;
    case 'qname':
      if (token.prefix === '_') {
        return this._error('Disallowed blank node as predicate', token);
      }
      else {
        var prefix = this._prefixes[token.prefix];
        if (prefix === _undefined)
          return this._error('Undefined prefix "' + token.prefix + ':"', token);
        this._predicate = {token: 'uri', value: prefix + token.value, prefix: null, suffix: null};
      }
      break;
    case 'bracketclose':
      // Expected predicate didn't come, must have been trailing semicolon.
      return this._readBlankNodeTail(token, true);
    case 'dot':
      // A dot is not allowed if the subject did not have a predicate yet
      if (!this._subjectHasPredicate)
        return this._error('Unexpected dot', token);
      // Expected predicate didn't come, must have been trailing semicolon.
      return this._readPunctuation(token, true);
    case 'semicolon':
      // Extra semicolons can be safely ignored
      return this._readPredicate;
    default:
      return this._error('Expected predicate to follow "' + this._subject + '"', token);
    }
    this._subjectHasPredicate = true;
    // The next token must be an object.
    return this._readObject;
  },

  // ### `_readObject` reads a triple's object.
  _readObject: function (token) {
    switch (token.type) {
    case 'explicituri':
      if (this._baseURI === null || absoluteURI.test(token.value))
        this._object = {token: 'uri', value: token.value, prefix: null, suffix: null};
      else
        this._object = {token: 'uri', value: (hashURI.test(token.value) ? this._baseURI : this._baseURIRoot) + token.value, prefix: null, suffix: null};
      break;
    case 'qname':
      if (token.prefix === '_') {
          if(this._blankNodes[token.value] !== undefined) {
              this._object = {'blank': this._blankNodes[token.value] };
          } else {
              this._object = {'blank': (this._blankNodes[token.value] = '_:' + this._blankNodeCount++)};
          }
      }
      else {
        var prefix = this._prefixes[token.prefix];
        if (prefix === _undefined)
          return this._error('Undefined prefix "' + token.prefix + ':"', token);
        this._object = {token: 'uri', value: prefix + token.value, prefix: null, suffix: null};
      }
      break;
    case 'literal':
        this._object = {'literal': token.value};
      return this._readDataTypeOrLang;
    case 'bracketopen':
      // Start a new triple with a new blank node as subject.
      var blank = {'blank': '_:' + this._blankNodeCount++};
      this._tripleStack.push({ subject: this._subject, predicate: this._predicate, object: blank, type: 'blank' });
      this._subject = blank;
      return this._readBlankNodeHead;
    case 'liststart':
      // Start a new list
      this._tripleStack.push({ subject: this._subject, predicate: this._predicate, object: RDF_NIL, type: 'list' });
      this._subject = null;
      return this._readListItem;
    default:
      return this._error('Expected object to follow "' + this._predicate + '"', token);
    }
    return this._getNextReader();
  },

  // ### `_readBlankNodeHead` reads the head of a blank node.
  _readBlankNodeHead: function (token) {
    if (token.type === 'bracketclose')
      return this._readBlankNodeTail(token, true);
    else
      return this._readPredicate(token);
  },

  // ### `_readBlankNodeTail` reads the end of a blank node.
  _readBlankNodeTail: function (token, empty) {
    if (token.type !== 'bracketclose')
      return this._readPunctuation(token);

    // Store blank node triple.
    if (empty !== true)
      this._callback(null, { subject: this._subject,
                             predicate: this._predicate,
                             object: this._object,
                             graph: RVInnerN3Parser.prototype.defaultGraph });

    // Restore parent triple that contains the blank node.
    var triple = this._tripleStack.pop();
    this._subject = triple.subject;
    // Was the blank node the object?
    if (triple.object !== null) {
      // Restore predicate and object as well, and continue by reading punctuation.
      this._predicate = triple.predicate;
      this._object = triple.object;
      return this._getNextReader();
    }
    // The blank node was the subject, so continue reading the predicate.
    return this._readPredicate;
  },

  // ### `_readDataTypeOrLang` reads an _optional_ data type or language.
  _readDataTypeOrLang: function (token) {
    switch (token.type) {
    case 'type':
      var value;
      if (token.prefix === '') {
        value = token.value;
      }
      else {
        var prefix = this._prefixes[token.prefix];
        if (prefix === _undefined)
          return this._error('Undefined prefix "' + token.prefix + ':"', token);
        value = prefix + token.value;
      }
      if(this._object.literal) {
        this._object.literal += '^^<' + value + '>';
      } else {
        this._object += '^^<' + value + '>';
        this._object = {literal: this._object};
      }
      return this._readPunctuation;
    case 'langcode':
        if(this._object.literal) {
            this._object.literal += '@' + token.value.toLowerCase();
        } else {
            this._object += '@' + token.value.toLowerCase();
            this._object = {literal: this._object};
        }
      return this._getNextReader();
    default:
      return this._getNextReader().call(this, token);
    }
  },

  // ### `_readListItem` reads items from a list.
  _readListItem: function (token) {
    var item = null,                  // The actual list item.
        itemHead = null,              // The head of the rdf:first predicate.
        prevItemHead = this._subject, // The head of the previous rdf:first predicate.
        stack = this._tripleStack,    // The stack of triples part of recursion (lists, blanks, etc.).
        parentTriple = stack[stack.length - 1], // The triple containing the current list.
        next = this._readListItem;    // The next function to execute.

    switch (token.type) {
    case 'explicituri':
      item = {'token': 'uri', 'value': token.value, 'prefix': null, 'suffix': null};
      break;
    case 'qname':
      if (token.prefix === '_') {
        item = this._blankNodes[token.value] ||
              (this._blankNodes[token.value] = {'blank': '_:' + this._blankNodeCount++});
      }
      else {
        var prefix = this._prefixes[token.prefix];
        if (prefix === _undefined)
          return this._error('Undefined prefix "' + token.prefix + ':"', token);
          item = {'token': 'uri', 'value': prefix + token.value, 'prefix': null, 'suffix': null};
      }
      break;
    case 'literal':
      item = {'literal': token.value };
      next = this._readDataTypeOrLang;
      break;
    case 'bracketopen':
      // Stack the current list triple and start a new triple with a blank node as subject.
      itemHead = {'blank': '_:' + this._blankNodeCount++ };
      item     = {'blank': '_:' + this._blankNodeCount++ };
      stack.push({ subject: itemHead, predicate: RDF_FIRST, object: item, type: 'blank' });
      this._subject = item;
      next = this._readBlankNodeHead;
      break;
    case 'liststart':
      // Stack the current list triple and start a new list
      itemHead = {'blank': '_:' + this._blankNodeCount++};
      stack.push({ subject: itemHead, predicate: RDF_FIRST, object: RDF_NIL, type: 'list' });
      this._subject = null;
      next = this._readListItem;
      break;
    case 'listend':
      // Restore the parent triple.
      stack.pop();
      // If this list is contained within a parent list, return the membership triple here.
      // This will be `<parent list elemen>t rdf:first <this list>.`.
      if (stack.length !== 0 && stack[stack.length - 1].type === 'list')
        this._callback(null, { subject: parentTriple.subject,
                               predicate: parentTriple.predicate,
                               object: parentTriple.object,
                               graph: RVInnerN3Parser.prototype.defaultGraph });
      // Restore the parent triple's subject.
      this._subject = (typeof(parentTriple.subject) === 'string' ? {'token': 'uri', 'value': parentTriple.subject, 'prefix': null, 'suffix': null } : parentTriple.subject);
      // Was this list in the parent triple's subject?
      if (parentTriple.predicate === null) {
        // The next token is the predicate.
        next = this._readPredicate;
        // Skip writing the list tail if this was an empty list.
        if (parentTriple.subject === RDF_NIL)
          return next;
      }
      // The list was in the parent triple's object.
      else {
        // Restore the parent triple's predicate and object as well.
        this._predicate = (typeof(parentTriple.predicate) === 'string' ? {'token': 'uri', 'value': parentTriple.predicate, 'prefix': null, 'suffix': null } : parentTriple.predicate); 
        this._object = (typeof(parentTriple.object) === 'string' ? {'token': 'uri', 'value': parentTriple.object, 'prefix': null, 'suffix': null } : parentTriple.object);
        next = this._getNextReader();
        // Skip writing the list tail if this was an empty list.
        if (parentTriple.object === RDF_NIL)
          return next;
      }
      // Close the list by making the item head nil.
      itemHead = RDF_NIL;
      break;
    default:
      return this._error('Expected list item instead of "' + token.type + '"', token);
    }

     // Create a new blank node if no item head was assigned yet.
    if (itemHead === null)
      this._subject = itemHead = {'blank': '_:' + this._blankNodeCount++};

    // Is this the first element of the list?
    if (prevItemHead === null) {
      // This list is either the object or the subject.
      if (parentTriple.object === RDF_NIL)
        parentTriple.object = itemHead;
      else
        parentTriple.subject = itemHead;
    }
    else {
      // The rest of the list is in the current head.
      this._callback(null, { subject: prevItemHead,
                             predicate: RDF_REST,
                             object: itemHead,
                             graph: RVInnerN3Parser.prototype.defaultGraph });
    }
    // Add the item's value.
    if (item !== null)
      this._callback(null, { subject: itemHead,
                             predicate: RDF_FIRST,
                             object: item,
                             graph: RVInnerN3Parser.prototype.defaultGraph });
    return next;
  },

  // ### `_readPunctuation` reads punctuation between triples or triple parts.
  _readPunctuation: function (token, empty) {
    var next;
    switch (token.type) {
    // A dot just ends the statement, without sharing anything with the next.
    case 'dot':
      next = this._readInTopContext;
      break;
    // Semicolon means the subject is shared; predicate and object are different.
    case 'semicolon':
      next = this._readPredicate;
      break;
    // Comma means both the subject and predicate are shared; the object is different.
    case 'comma':
      next = this._readObject;
      break;
    default:
      return this._error('Expected punctuation to follow "' + this._object + '"', token);
    }
    // A triple has been completed now, so return it.
    if (!empty)
      this._callback(null, { subject: this._subject,
                             predicate: this._predicate,
                             object: this._object,
                             graph: RVInnerN3Parser.prototype.defaultGraph });
    return next;
  },

  // ### `_readPrefix` reads the prefix of a prefix declaration.
  _readPrefix: function (token) {
    if (token.type !== 'prefix')
      return this._error('Expected prefix to follow @prefix', token);
    this._prefix = token.value;
    return this._readPrefixURI;
  },

  // ### `_readPrefixURI` reads the URI of a prefix declaration.
  _readPrefixURI: function (token) {
    if (token.type !== 'explicituri')
      return this._error('Expected explicituri to follow prefix "' + this.prefix + '"', token);
    var prefixURI;
    if (this._baseURI === null || absoluteURI.test(token.value))
      prefixURI = token.value;
    else
      prefixURI = (hashURI.test(token.value) ? this._baseURI : this._baseURIRoot) + token.value;
    this._prefixes[this._prefix] = prefixURI;
    return this._readDeclarationPunctuation;
  },

  // ### `_readBaseURI` reads the URI of a base declaration.
  _readBaseURI: function (token) {
    if (token.type !== 'explicituri')
      return this._error('Expected explicituri to follow base declaration', token);
    if (this._baseURI === null || absoluteURI.test(token.value))
      this._baseURI = token.value;
    else
      this._baseURI = (hashURI.test(token.value) ? this._baseURI : this._baseURIRoot) + token.value;
    this._baseURIRoot = this._baseURI.replace(documentPart, '');
    return this._readDeclarationPunctuation;
  },

  // ### `_readDeclarationPunctuation` reads the punctuation of a declaration.
  _readDeclarationPunctuation: function (token) {
    // SPARQL-style declarations don't have punctuation.
    if (this._sparqlStyle)
      return this._readInTopContext(token);

    if (token.type !== 'dot')
      return this._error('Expected declaration to end with a dot', token);
    return this._readInTopContext;
  },

  // ### `_getNextReader` gets the next reader function at the end of a triple.
  _getNextReader: function () {
    var stack = this._tripleStack;
    if (stack.length === 0)
      return this._readPunctuation;

    switch (stack[stack.length - 1].type) {
    case 'blank':
      return this._readBlankNodeTail;
    case 'list':
      return this._readListItem;
    }
  },

  // ### `_error` emits an error message through the callback.
  _error: function (message, token) {
    this._callback(message + ' at line ' + token.line + '.');
  },

  // ## Public methods

  // ### `parse` parses the N3 input and emits each parsed triple through the callback.
  parse: function (input, callback) {
    var self = this;
    // Initialize prefix declarations.
    this._prefixes = Object.create(null);
    // Set the triple callback.
    this._callback = callback;
    // The read callback is the next function to be executed when a token arrives.
    // We start reading in the top context.
    this._readCallback = this._readInTopContext;
    // Execute the read callback when a token arrives.
    this._lexer.tokenize(input, function (error, token) {
      if(error !== null && self._readCallback === _undefined) {
        self._callback(error);
      } else if (self._readCallback !== _undefined) {
        if (error !== null)
          self._callback(error);
        else
          self._readCallback = self._readCallback(token);
      }
    });
  }
};
*/

// ## Exports

// Export the `RVInnerN3Parser` class as a whole.


var RVN3Parser = {};

RVN3Parser.parser = {};
// The parser is asynchronous
RVN3Parser.parser.async = true;

RVN3Parser.parser.parse = function() {


    var data = arguments[0];
    var graph = arguments[1];
    var options = arguments[2];
    var cb = arguments[3];

    if(arguments.length === 3) {
        graph = null;
        options = arguments[1];
        cb = arguments[2];
    } else if(arguments.length !== 4) {
        cb(false, "Wrong number of arguments, 3, 4 args required");
    }
    if(graph && typeof(graph) === 'string')
        graph = {token: 'uri', value: graph, prefix: null, suffix: null};

    var parser = new RVInnerN3Parser(options);
    RVInnerN3Parser.prototype.defaultGraph = graph;

    var triples = [];

     parser.parse(data, function(err,triple) {
        if(err) {
            cb(false, err);
        } else {
            if(triple) {
               triples.push(triple);
            } else {
               cb(true, triples);
            }
        }
     });
};

// end of ./src/js-communication/src/rvn3_parser.js 
// exports
var RDFLoader = {};

// imports
var N3Parser = RVN3Parser;
RDFLoader.RDFLoader = function (params) {
    this.precedences = ["text/turtle", "text/n3", "application/ld+json", "application/json"/*, "application/rdf+xml"*/];
    this.parsers = {"text/turtle":N3Parser.parser, "text/n3":N3Parser.parser, "application/ld+json":JSONLDParser.parser, "application/json":JSONLDParser.parser/*, "application/rdf+xml":RDFXMLParser.parser*/};
    if (params != null) {
        for (var mime in params["parsers"]) {
            this.parsers[mime] = params["parsers"][mime];
        }
    }

    if (params && params["precedences"] != null) {
        this.precedences = params["precedences"];
        for (var mime in params["parsers"]) {
            if (!Utils.include(this.precedences, mime)) {
                this.precedences.push(mime);
            }
        }
    }

    this.acceptHeaderValue = "";
    for (var i = 0; i < this.precedences.length; i++) {
        if (i != 0) {
            this.acceptHeaderValue = this.acceptHeaderValue + "," + this.precedences[i];
        } else {
            this.acceptHeaderValue = this.acceptHeaderValue + this.precedences[i];
        }
    }
};

RDFLoader.RDFLoader.prototype.registerParser = function(mediaType, parser) {
    this.parsers[mediaType] = parser;
    this.precedences.push(mediaType);
};

RDFLoader.RDFLoader.prototype.unregisterParser = function(mediaType) {
    delete this.parsers[mediaType];
    var mediaTypes = [];
    for(var i=0; i<this.precedences.length; i++) {
        if(this.precedences[i] != mediaType) {
            mediaTypes.push(this.precedences[i]);
        }
    }

    this.precedences = mediaTypes;
};

RDFLoader.RDFLoader.prototype.setAcceptHeaderPrecedence = function(mediaTypes) {
    this.precedences = mediaTypes;
};

RDFLoader.RDFLoader.prototype.load = function(uri, graph, callback) {
    var that = this;
    NetworkTransport.load(uri, this.acceptHeaderValue, function(success, results){
        if(success == true) {
            var mime = results["headers"]["Content-Type"] || results["headers"]["content-type"];
            var data = results['data'];
            if(mime != null) {
                mime = mime.split(";")[0];
                for(var m in that.parsers) {
                    if(m.indexOf("/")!=-1) {
                        var mimeParts = m.split("/");
                        if(mimeParts[1] === '*') {
                            if(mime.indexOf(mimeParts[0])!=-1) {
                                return that.tryToParse(that.parsers[m], graph, data, {documentURI: uri}, callback);
                            }
                        } else {
                            if(mime.indexOf(m)!=-1) {
                                return that.tryToParse(that.parsers[m], graph, data, {documentURI: uri}, callback);
                            } else if(mime.indexOf(mimeParts[1])!=-1) {
                                return that.tryToParse(that.parsers[m], graph, data, {documentURI: uri}, callback);
                            }
                        }
                    } else {
                        if(mime.indexOf(m)!=-1) {
                            return that.tryToParse(that.parsers[m], graph, data, {documentURI: uri}, callback);
                        }
                    }
                }
                callback(false, "Unknown media type : "+mime);
            } else {
                console.log("Unknown media type");
                console.log(results["headers"]);
                callback(false, "Uknown media type");
            }
        } else {
            callback(false, "Network error: "+results);
        }});
};

RDFLoader.RDFLoader.prototype.loadFromFile = function(parser, graph, uri, callback) {
    try {
        var that = this;
        var fs = require('fs');
        fs.readFile(uri.split("file:/")[1], function(err, data) {
            if(err) throw err;
            var data = data.toString('utf8');
            that.tryToParse(parser, graph, data, {documentURI: uri}, callback);
        });
    } catch(e) {
        callback(false, e);
    }
};

RDFLoader.RDFLoader.prototype.tryToParse = function(parser, graph, input, options, callback) {
    // console.log("TRYING TO PARSE");
    // console.log(parser);
    // console.log(graph);
    // console.log(options);
    // console.log(callback);
    try {
        if(typeof(input) === 'string') {
            input = Utils.normalizeUnicodeLiterals(input);
        }
        if(parser.async) {
            parser.parse(input, graph, options, callback);
        } else {
            var parsed = parser.parse(input, graph, options);

            if(parsed != null) {
                callback(true, parsed);
            } else {
                callback(false, "parsing error");
            }
        }
    } catch(e) {
        console.log(e.message);
        console.log(e.stack);
        callback(false, "parsing error with mime type : " + e);
    }
};



// var loader = require("./js-communication/src/rdf_loader").RDFLoader; loader = new loader.RDFLoader(); loader.load('http://dbpedialite.org/titles/Lisp_%28programming_language%29', function(success, results){console.log("hey"); console.log(success); console.log(results)})

// end of ./src/js-communication/src/rdf_loader.js 
// exports
var AbstractQueryTree = {};

// imports

/**
 * @doc
 *
 * Based on <http://www.w3.org/2001/sw/DataAccess/rq23/rq24-algebra.html>
 * W3C's note
 */
AbstractQueryTree.AbstractQueryTree = function() {
};

AbstractQueryTree.AbstractQueryTree.prototype.parseQueryString = function(query_string) {
    //noinspection UnnecessaryLocalVariableJS,UnnecessaryLocalVariableJS
    return SparqlParser.parser.parse(query_string);
};

AbstractQueryTree.AbstractQueryTree.prototype.parseExecutableUnit = function(executableUnit) {
    if(executableUnit.kind === 'select') {
        return this.parseSelect(executableUnit);
    } else if(executableUnit.kind === 'ask') {
        return this.parseSelect(executableUnit);        
    } else if(executableUnit.kind === 'modify') {
        return this.parseSelect(executableUnit);
    } else if(executableUnit.kind === 'construct') {
        return this.parseSelect(executableUnit);        
    } else if(executableUnit.kind === 'insertdata') {
        return this.parseInsertData(executableUnit);        
    } else if(executableUnit.kind === 'deletedata') {
        return this.parseInsertData(executableUnit);        
    } else if(executableUnit.kind === 'load') {
        return executableUnit;
    } else if(executableUnit.kind === 'clear') {
        return executableUnit;
    } else if(executableUnit.kind === 'drop') {
        return executableUnit;
    } else if(executableUnit.kind === 'create') {
        return executableUnit;
    } else {
        throw new Error('unknown executable unit: ' + executableUnit.kind);
    }
};

AbstractQueryTree.AbstractQueryTree.prototype.parseSelect = function(syntaxTree){

    if(syntaxTree == null) {
        console.log("error parsing query");
        return null;
    } else {
        var env = { freshCounter: 0 };
        syntaxTree.pattern = this.build(syntaxTree.pattern, env);
        return syntaxTree;
    }
};

AbstractQueryTree.AbstractQueryTree.prototype.parseInsertData = function(syntaxTree){
    if(syntaxTree == null) {
        console.log("error parsing query");
        return null;
    } else {
        return syntaxTree;
    }
};

AbstractQueryTree.AbstractQueryTree.prototype.build = function(node, env) {
    if(node.token === 'groupgraphpattern') {
        return this._buildGroupGraphPattern(node, env);
    } else if (node.token === 'basicgraphpattern') {
        var bgp = { kind: 'BGP',
                    value: node.triplesContext };
	//console.log("pre1");
	bgp = AbstractQueryTree.translatePathExpressionsInBGP(bgp, env);
	//console.log("translation");
	//console.log(sys.inspect(bgp,true,20));	
	return bgp;
    } else if (node.token === 'graphunionpattern') {
        var a = this.build(node.value[0],env);
        var b = this.build(node.value[1],env);

        return { kind: 'UNION',
                 value: [a,b] };
    } else if(node.token === 'graphgraphpattern') {
        var c = this.build(node.value, env);
        return { kind: 'GRAPH',
                 value: c,
                 graph: node.graph };
    } else {
        throw new Error("not supported token in query:"+node.token);
    }
};

AbstractQueryTree.translatePathExpressionsInBGP = function(bgp, env) {
    var pathExpression;
    var before = [], rest, bottomJoin;
    for(var i=0; i<bgp.value.length; i++) {
	if(bgp.value[i].predicate && bgp.value[i].predicate.token === 'path') {
	    //console.log("FOUND A PATH");
	    pathExpression = bgp.value[i];
	    rest = bgp.value.slice(i+1);
	    var bgpTransformed = AbstractQueryTree.translatePathExpression(pathExpression, env);
	    var optionalPattern = null;
	    //console.log("BACK FROM TRANSFORMED");
	    if(bgpTransformed.kind === 'BGP') {
		before = before.concat(bgpTransformed.value);
	    } else if(bgpTransformed.kind === 'ZERO_OR_MORE_PATH' || bgpTransformed.kind === 'ONE_OR_MORE_PATH'){
		//console.log("BEFORE");
		//console.log(bgpTransformed);
		    

		if(before.length > 0) {
		    bottomJoin =  {kind: 'JOIN',
				   lvalue: {kind: 'BGP', value:before},
				   rvalue: bgpTransformed};
		} else {
		    bottomJoin = bgpTransformed;
		}

		
		if(bgpTransformed.kind === 'ZERO_OR_MORE_PATH') {
		    if(bgpTransformed.y.token === 'var' && bgpTransformed.y.value.indexOf("fresh:")===0 &&
		       bgpTransformed.x.token === 'var' && bgpTransformed.x.value.indexOf("fresh:")===0) {
			//console.log("ADDING EXTRA PATTERN 1)");
			for(var j=0; j<bgp.value.length; j++) {
		   	    //console.log(bgp.value[j]);
		   	    if(bgp.value[j].object && bgp.value[j].object.token === 'var' && bgp.value[j].object.value === bgpTransformed.x.value) {
		   		//console.log(" YES 1)");
		   		optionalPattern = Utils.clone(bgp.value[j]);
		   		optionalPattern.object = bgpTransformed.y;
		   	    }
			}
		    } else if(bgpTransformed.y.token === 'var' && bgpTransformed.y.value.indexOf("fresh:")===0) {
			//console.log("ADDING EXTRA PATTERN 2)");
			for(var j=0; j<bgp.value.length; j++) {
		   	    //console.log(bgp.value[j]);
		   	    if(bgp.value[j].subject && bgp.value[j].subject.token === 'var' && bgp.value[j].subject.value === bgpTransformed.y.value) {
		   		//console.log(" YES 2)");
		   		optionalPattern = Utils.clone(bgp.value[j]);
		   		optionalPattern.subject = bgpTransformed.x;
		   	    }
			}
		    }
		}

		if(rest.length >0) {
		    //console.log("(2a)")
		    var rvalueJoin = AbstractQueryTree.translatePathExpressionsInBGP({kind: 'BGP', value: rest}, env);
		    //console.log("got rvalue");
		    if(optionalPattern != null) {
			var optionals = before.concat([optionalPattern]).concat(rest);
			return { kind: 'UNION',
				 value: [{ kind: 'JOIN',
					   lvalue: bottomJoin,
					   rvalue: rvalueJoin },
					 {kind: 'BGP',
					  value: optionals}] };
		    } else {
			return { kind: 'JOIN',
				 lvalue: bottomJoin,
				 rvalue: rvalueJoin };
		    }
		} else {
		    //console.log("(2b)")
		    return bottomJoin;
		}

	    } else {
		// @todo ????
		return bgpTransformed;
	    }
	} else {
	    before.push(bgp.value[i]);
	}
    }

    //console.log("returning");
    bgp.value = before;
    return bgp;
};


AbstractQueryTree.translatePathExpression  = function(pathExpression, env) {
    // add support for different path patterns
    if(pathExpression.predicate.kind === 'element') {
	// simple paths, maybe modified
	if(pathExpression.predicate.modifier === '+') {
	    pathExpression.predicate.modifier = null;
	    var expandedPath = AbstractQueryTree.translatePathExpression(pathExpression, env);
	    return {kind: 'ONE_OR_MORE_PATH',
		    path: expandedPath,
		    x: pathExpression.subject,
		    y: pathExpression.object};
	} else if(pathExpression.predicate.modifier === '*') {
	    pathExpression.predicate.modifier = null;
	    var expandedPath = AbstractQueryTree.translatePathExpression(pathExpression, env);
	    return {kind: 'ZERO_OR_MORE_PATH',
	     	    path: expandedPath,
                    x: pathExpression.subject,
		    y: pathExpression.object};
	} else {
	    pathExpression.predicate = pathExpression.predicate.value;
	    return {kind: 'BGP', value: [pathExpression]};
	}
    } else if(pathExpression.predicate.kind === 'sequence') {
	var currentSubject = pathExpression.subject;
	var lastObject = pathExpression.object;
	var currentGraph = pathExpression.graph;
	var nextObject, chain;
	var restTriples = [];
	for(var i=0; i< pathExpression.predicate.value.length; i++) {
	    if(i!=pathExpression.predicate.value.length-1) {
		nextObject = {
		    token: "var",
		    value: "fresh:"+env.freshCounter
		};
		env.freshCounter++;
	    } else {
		nextObject = lastObject;
	    }

	    // @todo
	    // what if the predicate is a path with
	    // '*'? same fresh va in subject and object??
	    chain = {
		subject: currentSubject,
		predicate: pathExpression.predicate.value[i],
		object: nextObject
	    };
	
	    if(currentGraph != null)
		chain.graph = Utils.clone(currentGraph);
	    
	    restTriples.push(chain);

	    if(i!=pathExpression.predicate.value.length-1)
		currentSubject = Utils.clone(nextObject);;
	}
	var bgp = {kind: 'BGP', value: restTriples};
	//console.log("BEFORE (1):");
	//console.log(bgp);
	//console.log("--------------");
	return AbstractQueryTree.translatePathExpressionsInBGP(bgp, env);
    }
};

AbstractQueryTree.AbstractQueryTree.prototype._buildGroupGraphPattern = function(node, env) {
    var f = (node.filters || []);
    var g = {kind: "EMPTY_PATTERN"};

    for(var i=0; i<node.patterns.length; i++) {
        var pattern = node.patterns[i];
        if(pattern.token === 'optionalgraphpattern') {
            var parsedPattern = this.build(pattern.value,env);
            if(parsedPattern.kind === 'FILTER') {
                g =  { kind:'LEFT_JOIN',
                       lvalue: g,
                       rvalue: parsedPattern.value,
                       filter: parsedPattern.filter };
            } else {
                g = { kind:'LEFT_JOIN',
                      lvalue: g,
                      rvalue: parsedPattern,
                      filter: true };
            }
        } else {
            var parsedPattern = this.build(pattern,env);
            if(g.kind == "EMPTY_PATTERN") {
                g = parsedPattern;
            } else {
                g = { kind: 'JOIN',
                      lvalue: g,
                      rvalue: parsedPattern };
            }
        }
    }

    if(f.length != 0) {
        if(g.kind === 'EMPTY_PATTERN') {
            return { kind: 'FILTER',
                     filter: f,
                     value: g};
        } else if(g.kind === 'LEFT_JOIN' && g.filter === true) {
            return { kind: 'FILTER',
                     filter: f,
                     value: g};

//            g.filter = f;
//            return g;
        } else if(g.kind === 'LEFT_JOIN') {
            return { kind: 'FILTER',
                     filter: f,
                     value: g};
        } else if(g.kind === 'JOIN') {
            return { kind: 'FILTER',
                     filter: f,
                     value: g};
        } else if(g.kind === 'UNION') {
            return { kind: 'FILTER',
                     filter: f,
                     value: g};
        } else if(g.kind === 'GRAPH') {
            return { kind: 'FILTER',
                     filter: f,
                     value: g};
        } else if(g.kind === 'BGP') {
            return { kind: 'FILTER',
                     filter: f,
                     value: g};
        } else {
            throw new Error("Unknow kind of algebra expression: "+ g.kind);
        }
    } else {
        return g;
    }
};

/**
 * Collects basic triple pattern in a complex SPARQL AQT
 */
AbstractQueryTree.AbstractQueryTree.prototype.collectBasicTriples = function(aqt, acum) {
    if(acum == null) {
        acum = [];
    }

    if(aqt.kind === 'select') {
        acum = this.collectBasicTriples(aqt.pattern,acum);
    } else if(aqt.kind === 'BGP') {
        acum = acum.concat(aqt.value);
    } else if(aqt.kind === 'ZERO_OR_MORE_PATH') {
	acum = this.collectBasicTriples(aqt.path);
    } else if(aqt.kind === 'UNION') {
        acum = this.collectBasicTriples(aqt.value[0],acum);
        acum = this.collectBasicTriples(aqt.value[1],acum);
    } else if(aqt.kind === 'GRAPH') {
        acum = this.collectBasicTriples(aqt.value,acum);
    } else if(aqt.kind === 'LEFT_JOIN' || aqt.kind === 'JOIN') {
        acum = this.collectBasicTriples(aqt.lvalue, acum);
        acum = this.collectBasicTriples(aqt.rvalue, acum);
    } else if(aqt.kind === 'FILTER') {
        acum = this.collectBasicTriples(aqt.value, acum);
    } else if(aqt.kind === 'construct') {
        acum = this.collectBasicTriples(aqt.pattern,acum);
    } else if(aqt.kind === 'EMPTY_PATTERN') {
        // nothing
    } else {
        throw "Unknown pattern: "+aqt.kind;
    }

    return acum;
};

/**
 * Replaces bindings in an AQT
 */
AbstractQueryTree.AbstractQueryTree.prototype.bind = function(aqt, bindings) {
    if(aqt.graph != null && aqt.graph.token && aqt.graph.token === 'var' &&
       bindings[aqt.graph.value] != null) {
        aqt.graph = bindings[aqt.graph.value];
    }
    if(aqt.filter != null) {
        var acum = [];
        for(var i=0; i< aqt.filter.length; i++) {
            aqt.filter[i].value = this._bindFilter(aqt.filter[i].value, bindings);
            acum.push(aqt.filter[i]);
        }
        aqt.filter = acum;
    }
    if(aqt.kind === 'select') {
        aqt.pattern = this.bind(aqt.pattern, bindings);
        //acum = this.collectBasicTriples(aqt.pattern,acum);
    } else if(aqt.kind === 'BGP') {
        aqt.value = this._bindTripleContext(aqt.value, bindings);
        //acum = acum.concat(aqt.value);
    } else if(aqt.kind === 'ZERO_OR_MORE_PATH') {
        aqt.path = this._bindTripleContext(aqt.path, bindings);
	if(aqt.x && aqt.x.token === 'var' && bindings[aqt.x.value] != null) {
	    aqt.x = bindings[aqt.x.value];
	}
	if(aqt.y && aqt.y.token === 'var' && bindings[aqt.y.value] != null) {
	    aqt.y = bindings[aqt.y.value];
	}
    } else if(aqt.kind === 'UNION') {
        aqt.value[0] = this.bind(aqt.value[0],bindings);
        aqt.value[1] = this.bind(aqt.value[1],bindings);
    } else if(aqt.kind === 'GRAPH') {
        aqt.value = this.bind(aqt.value,bindings);
    } else if(aqt.kind === 'LEFT_JOIN' || aqt.kind === 'JOIN') {
        aqt.lvalue = this.bind(aqt.lvalue, bindings);
        aqt.rvalue = this.bind(aqt.rvalue, bindings);
    } else if(aqt.kind === 'FILTER') {
	aqt.filter = this._bindFilter(aqt.filter[i].value, bindings);
    } else if(aqt.kind === 'EMPTY_PATTERN') {
        // nothing
    } else {
        throw "Unknown pattern: "+aqt.kind;
    }

    return aqt;
};

AbstractQueryTree.AbstractQueryTree.prototype._bindTripleContext = function(triples, bindings) {
    for(var i=0; i<triples.length; i++) {
        delete triples[i]['graph'];
        delete triples[i]['variables'];
        for(var p in triples[i]) {
            var comp = triples[i][p];
            if(comp.token === 'var' && bindings[comp.value] != null) {
                triples[i][p] = bindings[comp.value];
            }
        }
    }

    return triples;
};


AbstractQueryTree.AbstractQueryTree.prototype._bindFilter = function(filterExpr, bindings) {
    if(filterExpr.expressionType != null) {
        var expressionType = filterExpr.expressionType;
        if(expressionType == 'relationalexpression') {
            filterExpr.op1 = this._bindFilter(filterExpr.op1, bindings);
            filterExpr.op2 = this._bindFilter(filterExpr.op2, bindings);
        } else if(expressionType == 'conditionalor' || expressionType == 'conditionaland') {
            for(var i=0; i< filterExpr.operands.length; i++) {
                filterExpr.operands[i] = this._bindFilter(filterExpr.operands[i], bindings);
            }
        } else if(expressionType == 'additiveexpression') {
            filterExpr.summand = this._bindFilter(filterExpr.summand, bindings);
            for(var i=0; i<filterExpr.summands.length; i++) {
                filterExpr.summands[i].expression = this._bindFilter(filterExpr.summands[i].expression, bindings);            
            }
        } else if(expressionType == 'builtincall') {
            for(var i=0; i<filterExpr.args.length; i++) {
                filterExpr.args[i] = this._bindFilter(filterExpr.args[i], bindings);
            }
        } else if(expressionType == 'multiplicativeexpression') {
            filterExpr.factor = this._bindFilter(filterExpr.factor, bindings);
            for(var i=0; i<filterExpr.factors.length; i++) {
                filterExpr.factors[i].expression = this._bindFilter(filterExpr.factors[i].expression, bindings);            
            }
        } else if(expressionType == 'unaryexpression') {
            filterExpr.expression = this._bindFilter(filterExpr.expression, bindings);
        } else if(expressionType == 'irireforfunction') {
            for(var i=0; i<filterExpr.factors.args; i++) {
                filterExpr.args[i] = this._bindFilter(filterExpr.args[i], bindings);            
            }
        } else if(expressionType == 'atomic') {        
            if(filterExpr.primaryexpression == 'var') {
                // lookup the var in the bindings
                if(bindings[filterExpr.value.value] != null) {
                    var val = bindings[filterExpr.value.value];
                    if(val.token === 'uri') {
                        filterExpr.primaryexpression = 'iri';
                    } else {
                        filterExpr.primaryexpression = 'literal';
                    }
                    filterExpr.value = val;
                }
            }
        }
    }

    return filterExpr;
};

/**
 * Replaces terms in an AQT
 */
AbstractQueryTree.AbstractQueryTree.prototype.replace = function(aqt, from, to, ns) {
    if(aqt.graph != null && aqt.graph.token && aqt.graph.token === from.token && 
       aqt.graph.value == from.value) {
        aqt.graph = Utils.clone(to);
    }
    if(aqt.filter != null) {
        var acum = [];
        for(var i=0; i< aqt.filter.length; i++) {
            aqt.filter[i].value = this._replaceFilter(aqt.filter[i].value, from, to, ns);
            acum.push(aqt.filter[i]);
        }
        aqt.filter = acum;
    }
    if(aqt.kind === 'select') {
        aqt.pattern = this.replace(aqt.pattern, from, to, ns);
    } else if(aqt.kind === 'BGP') {
        aqt.value = this._replaceTripleContext(aqt.value, from, to, ns);
    } else if(aqt.kind === 'ZERO_OR_MORE_PATH') {
        aqt.path = this._replaceTripleContext(aqt.path, from,to, ns);
	if(aqt.x && aqt.x.token === from.token && aqt.value === from.value) {
	    aqt.x = Utils.clone(to);
	}
	if(aqt.y && aqt.y.token === from.token && aqt.value === from.value) {
	    aqt.y = Utils.clone(to);
	}
    } else if(aqt.kind === 'UNION') {
        aqt.value[0] = this.replace(aqt.value[0],from,to, ns);
        aqt.value[1] = this.replace(aqt.value[1],from,to, ns);
    } else if(aqt.kind === 'GRAPH') {
        aqt.value = this.replace(aqt.value,from,to);
    } else if(aqt.kind === 'LEFT_JOIN' || aqt.kind === 'JOIN') {
        aqt.lvalue = this.replace(aqt.lvalue, from, to, ns);
        aqt.rvalue = this.replace(aqt.rvalue, from, to, ns);
    } else if(aqt.kind === 'FILTER') {
        aqt.value = this._replaceFilter(aqt.value, from,to, ns);
    } else if(aqt.kind === 'EMPTY_PATTERN') {
        // nothing
    } else {
        throw "Unknown pattern: "+aqt.kind;
    }

    return aqt;
};

AbstractQueryTree.AbstractQueryTree.prototype._replaceTripleContext = function(triples, from, to, ns) {
    for(var i=0; i<triples.length; i++) {
        for(var p in triples[i]) {
            var comp = triples[i][p];
	    if(comp.token === 'var' && from.token === 'var' && comp.value === from.value) {
		triples[i][p] = to;
	    } else if(comp.token === 'blank' && from.token === 'blank' && comp.value === from.value) {
		triples[i][p] = to;
	    } else {
		if((comp.token === 'literal' || comp.token ==='uri') && 
		   (from.token === 'literal' || from.token ==='uri') && 
		   comp.token === from.token && Utils.lexicalFormTerm(comp,ns)[comp.token] === Utils.lexicalFormTerm(from,ns)[comp.token]) {
                    triples[i][p] = to;
		}
	    }
        }
    }

    return triples;
};


AbstractQueryTree.AbstractQueryTree.prototype._replaceFilter = function(filterExpr, from, to, ns) {
    if(filterExpr.expressionType != null) {
        var expressionType = filterExpr.expressionType;
        if(expressionType == 'relationalexpression') {
            filterExpr.op1 = this._replaceFilter(filterExpr.op1, from, to, ns);
            filterExpr.op2 = this._replaceFilter(filterExpr.op2, from, to, ns);
        } else if(expressionType == 'conditionalor' || expressionType == 'conditionaland') {
            for(var i=0; i< filterExpr.operands.length; i++) {
                filterExpr.operands[i] = this._replaceFilter(filterExpr.operands[i], from, to, ns);
            }
        } else if(expressionType == 'additiveexpression') {
            filterExpr.summand = this._replaceFilter(filterExpr.summand, from, to, ns);
            for(var i=0; i<filterExpr.summands.length; i++) {
                filterExpr.summands[i].expression = this._replaceFilter(filterExpr.summands[i].expression, from, to, ns);            
            }
        } else if(expressionType == 'builtincall') {
            for(var i=0; i<filterExpr.args.length; i++) {
                filterExpr.args[i] = this._replaceFilter(filterExpr.args[i], from, to, ns);
            }
        } else if(expressionType == 'multiplicativeexpression') {
            filterExpr.factor = this._replaceFilter(filterExpr.factor, from, to, ns);
            for(var i=0; i<filterExpr.factors.length; i++) {
                filterExpr.factors[i].expression = this._replaceFilter(filterExpr.factors[i].expression, from, to, ns);
            }
        } else if(expressionType == 'unaryexpression') {
            filterExpr.expression = this._replaceFilter(filterExpr.expression, from, to, ns);
        } else if(expressionType == 'irireforfunction') {
            for(var i=0; i<filterExpr.factors.args; i++) {
                filterExpr.args[i] = this._replaceFilter(filterExpr.args[i], from, to, ns);
            }
        } else if(expressionType == 'atomic') {        
	    var val = null;
            if(filterExpr.primaryexpression == from.token && filterExpr.value == from.value) {
                    val = to.value;                
            } else if(filterExpr.primaryexpression == 'iri' && from.token == 'uri' && filterExpr.value == from.value) {
                val = to.value;                
	    }

	
	    if(val != null) {
                if(to.token === 'uri') {
                    filterExpr.primaryexpression = 'iri';
                } else {
                    filterExpr.primaryexpression = to.token;
                }
                filterExpr.value = val;
	    }
        }
    }

    return filterExpr;
};

AbstractQueryTree.AbstractQueryTree.prototype.treeWithUnion = function(aqt) {
    if(aqt == null)
	return false;
    if(aqt.kind == null)
	return false;
    if(aqt.kind === 'select') {
        return this.treeWithUnion(aqt.pattern);
    } else if(aqt.kind === 'BGP') {
        return this.treeWithUnion(aqt.value);
    } else if(aqt.kind === 'ZERO_OR_MORE_PATH') {
	return false;
    } else if(aqt.kind === 'UNION') {
	if(aqt.value[0].value != null && aqt.value[0].value.variables != null &&
	   aqt.value[1].value != null && aqt.value[1].value.variables != null) {
	    if(aqt.value[0].variables.join("/") === aqt.values[1].variables.join("/")) {
		if(this.treeWithUnion(aqt.value[0]))
		    return true;
		else
		    return this.treeWithUnion(aqt.value[1]);
	    }
	} else {
	    return true;	    
	}
    } else if(aqt.kind === 'GRAPH') {
	return false;
    } else if(aqt.kind === 'LEFT_JOIN' || aqt.kind === 'JOIN') {
        var leftUnion  = this.treeWithUnion(aqt.lvalue);
	if(leftUnion)
	    return true;
	else
            this.treeWithUnion(aqt.rvalue);
    } else if(aqt.kind === 'FILTER') {
	return false;
    } else if(aqt.kind === 'EMPTY_PATTERN') {
	return false;
    } else {
	return false;
    }
};

// end of ./src/js-sparql-parser/src/abstract_query_tree.js 
// exports
var SparqlParser = {};

SparqlParser.parser = (function(){
  /*
   * Generated by PEG.js 0.7.0.
   *
   * http://pegjs.majda.cz/
   */
  
  function quote(s) {
    /*
     * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a
     * string literal except for the closing quote character, backslash,
     * carriage return, line separator, paragraph separator, and line feed.
     * Any character may appear in the form of an escape sequence.
     *
     * For portability, we also escape escape all control and non-ASCII
     * characters. Note that "\0" and "\v" escape sequences are not used
     * because JSHint does not like the first and IE the second.
     */
     return '"' + s
      .replace(/\\/g, '\\\\')  // backslash
      .replace(/"/g, '\\"')    // closing quote character
      .replace(/\x08/g, '\\b') // backspace
      .replace(/\t/g, '\\t')   // horizontal tab
      .replace(/\n/g, '\\n')   // line feed
      .replace(/\f/g, '\\f')   // form feed
      .replace(/\r/g, '\\r')   // carriage return
      .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape)
      + '"';
  }
  
  var result = {
    /*
     * Parses the input with a generated parser. If the parsing is successfull,
     * returns a value explicitly or implicitly specified by the grammar from
     * which the parser was generated (see |PEG.buildParser|). If the parsing is
     * unsuccessful, throws |PEG.parser.SyntaxError| describing the error.
     */
    parse: function(input, startRule) {
      var parseFunctions = {
        "SPARQL": parse_SPARQL,
        "Query": parse_Query,
        "Prologue": parse_Prologue,
        "BaseDecl": parse_BaseDecl,
        "PrefixDecl": parse_PrefixDecl,
        "SelectQuery": parse_SelectQuery,
        "SubSelect": parse_SubSelect,
        "SelectClause": parse_SelectClause,
        "ConstructQuery": parse_ConstructQuery,
        "DescribeQuery": parse_DescribeQuery,
        "AskQuery": parse_AskQuery,
        "DatasetClause": parse_DatasetClause,
        "DefaultGraphClause": parse_DefaultGraphClause,
        "NamedGraphClause": parse_NamedGraphClause,
        "WhereClause": parse_WhereClause,
        "SolutionModifier": parse_SolutionModifier,
        "GroupClause": parse_GroupClause,
        "GroupCondition": parse_GroupCondition,
        "HavingClause": parse_HavingClause,
        "OrderClause": parse_OrderClause,
        "OrderCondition": parse_OrderCondition,
        "LimitOffsetClauses": parse_LimitOffsetClauses,
        "LimitClause": parse_LimitClause,
        "OffsetClause": parse_OffsetClause,
        "BindingsClause": parse_BindingsClause,
        "BindingValue": parse_BindingValue,
        "Update": parse_Update,
        "Update1": parse_Update1,
        "Load": parse_Load,
        "Clear": parse_Clear,
        "Drop": parse_Drop,
        "Create": parse_Create,
        "InsertData": parse_InsertData,
        "DeleteData": parse_DeleteData,
        "DeleteWhere": parse_DeleteWhere,
        "Modify": parse_Modify,
        "DeleteClause": parse_DeleteClause,
        "InsertClause": parse_InsertClause,
        "UsingClause": parse_UsingClause,
        "GraphRef": parse_GraphRef,
        "GraphRefAll": parse_GraphRefAll,
        "QuadPattern": parse_QuadPattern,
        "QuadData": parse_QuadData,
        "Quads": parse_Quads,
        "QuadsNotTriples": parse_QuadsNotTriples,
        "TriplesTemplate": parse_TriplesTemplate,
        "GroupGraphPattern": parse_GroupGraphPattern,
        "GroupGraphPatternSub": parse_GroupGraphPatternSub,
        "TriplesBlock": parse_TriplesBlock,
        "GraphPatternNotTriples": parse_GraphPatternNotTriples,
        "OptionalGraphPattern": parse_OptionalGraphPattern,
        "GraphGraphPattern": parse_GraphGraphPattern,
        "ServiceGraphPattern": parse_ServiceGraphPattern,
        "MinusGraphPattern": parse_MinusGraphPattern,
        "GroupOrUnionGraphPattern": parse_GroupOrUnionGraphPattern,
        "Filter": parse_Filter,
        "Constraint": parse_Constraint,
        "FunctionCall": parse_FunctionCall,
        "ArgList": parse_ArgList,
        "ExpressionList": parse_ExpressionList,
        "ConstructTemplate": parse_ConstructTemplate,
        "ConstructTriples": parse_ConstructTriples,
        "TriplesSameSubject": parse_TriplesSameSubject,
        "PropertyListNotEmpty": parse_PropertyListNotEmpty,
        "PropertyList": parse_PropertyList,
        "ObjectList": parse_ObjectList,
        "Verb": parse_Verb,
        "TriplesSameSubjectPath": parse_TriplesSameSubjectPath,
        "PropertyListNotEmptyPath": parse_PropertyListNotEmptyPath,
        "PropertyListPath": parse_PropertyListPath,
        "VerbPath": parse_VerbPath,
        "PathAlternative": parse_PathAlternative,
        "PathSequence": parse_PathSequence,
        "PathElt": parse_PathElt,
        "PathEltOrInverse": parse_PathEltOrInverse,
        "PathMod": parse_PathMod,
        "PathPrimary": parse_PathPrimary,
        "PathNegatedPropertySet": parse_PathNegatedPropertySet,
        "PathOneInPropertySet": parse_PathOneInPropertySet,
        "TriplesNode": parse_TriplesNode,
        "BlankNodePropertyList": parse_BlankNodePropertyList,
        "Collection": parse_Collection,
        "GraphNode": parse_GraphNode,
        "VarOrTerm": parse_VarOrTerm,
        "VarOrIRIref": parse_VarOrIRIref,
        "Var": parse_Var,
        "GraphTerm": parse_GraphTerm,
        "ConditionalOrExpression": parse_ConditionalOrExpression,
        "ConditionalAndExpression": parse_ConditionalAndExpression,
        "RelationalExpression": parse_RelationalExpression,
        "AdditiveExpression": parse_AdditiveExpression,
        "MultiplicativeExpression": parse_MultiplicativeExpression,
        "UnaryExpression": parse_UnaryExpression,
        "PrimaryExpression": parse_PrimaryExpression,
        "BrackettedExpression": parse_BrackettedExpression,
        "BuiltInCall": parse_BuiltInCall,
        "RegexExpression": parse_RegexExpression,
        "ExistsFunc": parse_ExistsFunc,
        "NotExistsFunc": parse_NotExistsFunc,
        "Aggregate": parse_Aggregate,
        "IRIrefOrFunction": parse_IRIrefOrFunction,
        "RDFLiteral": parse_RDFLiteral,
        "NumericLiteral": parse_NumericLiteral,
        "NumericLiteralUnsigned": parse_NumericLiteralUnsigned,
        "NumericLiteralPositive": parse_NumericLiteralPositive,
        "NumericLiteralNegative": parse_NumericLiteralNegative,
        "BooleanLiteral": parse_BooleanLiteral,
        "String": parse_String,
        "IRIref": parse_IRIref,
        "PrefixedName": parse_PrefixedName,
        "BlankNode": parse_BlankNode,
        "IRI_REF": parse_IRI_REF,
        "PNAME_NS": parse_PNAME_NS,
        "PNAME_LN": parse_PNAME_LN,
        "BLANK_NODE_LABEL": parse_BLANK_NODE_LABEL,
        "VAR1": parse_VAR1,
        "VAR2": parse_VAR2,
        "LANGTAG": parse_LANGTAG,
        "INTEGER": parse_INTEGER,
        "DECIMAL": parse_DECIMAL,
        "DOUBLE": parse_DOUBLE,
        "INTEGER_POSITIVE": parse_INTEGER_POSITIVE,
        "DECIMAL_POSITIVE": parse_DECIMAL_POSITIVE,
        "DOUBLE_POSITIVE": parse_DOUBLE_POSITIVE,
        "INTEGER_NEGATIVE": parse_INTEGER_NEGATIVE,
        "DECIMAL_NEGATIVE": parse_DECIMAL_NEGATIVE,
        "DOUBLE_NEGATIVE": parse_DOUBLE_NEGATIVE,
        "EXPONENT": parse_EXPONENT,
        "STRING_LITERAL1": parse_STRING_LITERAL1,
        "STRING_LITERAL2": parse_STRING_LITERAL2,
        "STRING_LITERAL_LONG1": parse_STRING_LITERAL_LONG1,
        "STRING_LITERAL_LONG2": parse_STRING_LITERAL_LONG2,
        "ECHAR": parse_ECHAR,
        "NIL": parse_NIL,
        "WS": parse_WS,
        "COMMENT": parse_COMMENT,
        "ANON": parse_ANON,
        "PN_CHARS_BASE": parse_PN_CHARS_BASE,
        "PN_CHARS_U": parse_PN_CHARS_U,
        "VARNAME": parse_VARNAME,
        "PN_CHARS": parse_PN_CHARS,
        "PN_PREFIX": parse_PN_PREFIX,
        "PN_LOCAL": parse_PN_LOCAL
      };
      
      if (startRule !== undefined) {
        if (parseFunctions[startRule] === undefined) {
          throw new Error("Invalid rule name: " + quote(startRule) + ".");
        }
      } else {
        startRule = "SPARQL";
      }
      
      var pos = 0;
      var reportFailures = 0;
      var rightmostFailuresPos = 0;
      var rightmostFailuresExpected = [];
      
      function padLeft(input, padding, length) {
        var result = input;
        
        var padLength = length - input.length;
        for (var i = 0; i < padLength; i++) {
          result = padding + result;
        }
        
        return result;
      }
      
      function escape(ch) {
        var charCode = ch.charCodeAt(0);
        var escapeChar;
        var length;
        
        if (charCode <= 0xFF) {
          escapeChar = 'x';
          length = 2;
        } else {
          escapeChar = 'u';
          length = 4;
        }
        
        return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length);
      }
      
      function matchFailed(failure) {
        if (pos < rightmostFailuresPos) {
          return;
        }
        
        if (pos > rightmostFailuresPos) {
          rightmostFailuresPos = pos;
          rightmostFailuresExpected = [];
        }
        
        rightmostFailuresExpected.push(failure);
      }
      
      function parse_SPARQL() {
        var result0;
        
        result0 = parse_Query();
        if (result0 === null) {
          result0 = parse_Update();
        }
        return result0;
      }
      
      function parse_Query() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_Prologue();
        if (result0 !== null) {
          result1 = parse_SelectQuery();
          if (result1 === null) {
            result1 = parse_ConstructQuery();
            if (result1 === null) {
              result1 = parse_DescribeQuery();
              if (result1 === null) {
                result1 = parse_AskQuery();
              }
            }
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, p, q) {
              return {token: 'query',
                      kind: 'query',
                      prologue: p,
                      units: [q]};
        })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[2] Query");
        }
        return result0;
      }
      
      function parse_Prologue() {
        var result0, result1, result2, result3;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_BaseDecl();
        result0 = result0 !== null ? result0 : "";
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_PrefixDecl();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_PrefixDecl();
            }
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, b, pfx) {
              return { token: 'prologue',
                       base: b,
                       prefixes: pfx }
        })(pos0, result0[0], result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[3] Prologue");
        }
        return result0;
      }
      
      function parse_BaseDecl() {
        var result0, result1, result2, result3;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          if (input.substr(pos, 4) === "BASE") {
            result1 = "BASE";
            pos += 4;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\"BASE\"");
            }
          }
          if (result1 === null) {
            if (input.substr(pos, 4) === "base") {
              result1 = "base";
              pos += 4;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("\"base\"");
              }
            }
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result3 = parse_IRI_REF();
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, i) {
              registerDefaultPrefix(i);
        
              var base = {};
              base.token = 'base';
              base.value = i;
        
              return base;
        })(pos0, result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[4] BaseDecl");
        }
        return result0;
      }
      
      function parse_PrefixDecl() {
        var result0, result1, result2, result3, result4, result5;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          if (input.substr(pos, 6) === "PREFIX") {
            result1 = "PREFIX";
            pos += 6;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\"PREFIX\"");
            }
          }
          if (result1 === null) {
            if (input.substr(pos, 6) === "prefix") {
              result1 = "prefix";
              pos += 6;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("\"prefix\"");
              }
            }
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result3 = parse_PNAME_NS();
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  result5 = parse_IRI_REF();
                  if (result5 !== null) {
                    result0 = [result0, result1, result2, result3, result4, result5];
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, p, l) {
        
              registerPrefix(p,l);
        
              var prefix = {};
              prefix.token = 'prefix';
              prefix.prefix = p;
              prefix.local = l;
        
              return prefix;
        })(pos0, result0[3], result0[5]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[5] PrefixDecl");
        }
        return result0;
      }
      
      function parse_SelectQuery() {
        var result0, result1, result2, result3, result4, result5, result6, result7, result8;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_SelectClause();
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_DatasetClause();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_DatasetClause();
            }
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result4 = parse_WhereClause();
                if (result4 !== null) {
                  result5 = [];
                  result6 = parse_WS();
                  while (result6 !== null) {
                    result5.push(result6);
                    result6 = parse_WS();
                  }
                  if (result5 !== null) {
                    result6 = parse_SolutionModifier();
                    if (result6 !== null) {
                      result7 = [];
                      result8 = parse_WS();
                      while (result8 !== null) {
                        result7.push(result8);
                        result8 = parse_WS();
                      }
                      if (result7 !== null) {
                        result8 = parse_BindingsClause();
                        if (result8 !== null) {
                          result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8];
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, s, gs, w, sm) {
        
              var dataset = {'named':[], 'implicit':[]};
              for(var i=0; i<gs.length; i++) {
                  var g = gs[i];
                  if(g.kind === 'default') {
                      dataset['implicit'].push(g.graph);
                  } else {
                      dataset['named'].push(g.graph)
                  }
              }
        
        
              if(dataset['named'].length === 0 && dataset['implicit'].length === 0) {
                  dataset['implicit'].push({token:'uri',
                                           prefix:null, 
                                           suffix:null, 
                                           value:'https://github.com/antoniogarrote/rdfstore-js#default_graph'});
              }
        
              var query = {};
              query.kind = 'select';
              query.token = 'executableunit'
              query.dataset = dataset;
              query.projection = s.vars;
              query.modifier = s.modifier;
              query.pattern = w
              
              if(sm!=null && sm.limit!=null) {
                  query.limit = sm.limit;
              }
              if(sm!=null && sm.offset!=null) {
                  query.offset = sm.offset;
              }
              if(sm!=null && (sm.order!=null && sm.order!="")) {
                  query.order = sm.order;
              }
              if(sm!=null && sm.group!=null) {
                  query.group = sm.group;
              }
        
              return query
        })(pos0, result0[0], result0[2], result0[4], result0[6]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[6] SelectQuery");
        }
        return result0;
      }
      
      function parse_SubSelect() {
        var result0, result1, result2;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        result0 = parse_SelectClause();
        if (result0 !== null) {
          result1 = parse_WhereClause();
          if (result1 !== null) {
            result2 = parse_SolutionModifier();
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos0;
            }
          } else {
            result0 = null;
            pos = pos0;
          }
        } else {
          result0 = null;
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[7] SubSelect");
        }
        return result0;
      }
      
      function parse_SelectClause() {
        var result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13, result14, result15, result16, result17;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          if (input.substr(pos, 6) === "SELECT") {
            result1 = "SELECT";
            pos += 6;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\"SELECT\"");
            }
          }
          if (result1 === null) {
            if (input.substr(pos, 6) === "select") {
              result1 = "select";
              pos += 6;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("\"select\"");
              }
            }
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              if (input.substr(pos, 8) === "DISTINCT") {
                result3 = "DISTINCT";
                pos += 8;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("\"DISTINCT\"");
                }
              }
              if (result3 === null) {
                if (input.substr(pos, 8) === "distinct") {
                  result3 = "distinct";
                  pos += 8;
                } else {
                  result3 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"distinct\"");
                  }
                }
              }
              if (result3 === null) {
                if (input.substr(pos, 7) === "REDUCED") {
                  result3 = "REDUCED";
                  pos += 7;
                } else {
                  result3 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"REDUCED\"");
                  }
                }
                if (result3 === null) {
                  if (input.substr(pos, 7) === "reduced") {
                    result3 = "reduced";
                    pos += 7;
                  } else {
                    result3 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"reduced\"");
                    }
                  }
                }
              }
              result3 = result3 !== null ? result3 : "";
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  pos2 = pos;
                  result6 = [];
                  result7 = parse_WS();
                  while (result7 !== null) {
                    result6.push(result7);
                    result7 = parse_WS();
                  }
                  if (result6 !== null) {
                    result7 = parse_Var();
                    if (result7 !== null) {
                      result8 = [];
                      result9 = parse_WS();
                      while (result9 !== null) {
                        result8.push(result9);
                        result9 = parse_WS();
                      }
                      if (result8 !== null) {
                        result6 = [result6, result7, result8];
                      } else {
                        result6 = null;
                        pos = pos2;
                      }
                    } else {
                      result6 = null;
                      pos = pos2;
                    }
                  } else {
                    result6 = null;
                    pos = pos2;
                  }
                  if (result6 === null) {
                    pos2 = pos;
                    result6 = [];
                    result7 = parse_WS();
                    while (result7 !== null) {
                      result6.push(result7);
                      result7 = parse_WS();
                    }
                    if (result6 !== null) {
                      if (input.charCodeAt(pos) === 40) {
                        result7 = "(";
                        pos++;
                      } else {
                        result7 = null;
                        if (reportFailures === 0) {
                          matchFailed("\"(\"");
                        }
                      }
                      if (result7 !== null) {
                        result8 = [];
                        result9 = parse_WS();
                        while (result9 !== null) {
                          result8.push(result9);
                          result9 = parse_WS();
                        }
                        if (result8 !== null) {
                          result9 = parse_ConditionalOrExpression();
                          if (result9 !== null) {
                            result10 = [];
                            result11 = parse_WS();
                            while (result11 !== null) {
                              result10.push(result11);
                              result11 = parse_WS();
                            }
                            if (result10 !== null) {
                              if (input.substr(pos, 2) === "AS") {
                                result11 = "AS";
                                pos += 2;
                              } else {
                                result11 = null;
                                if (reportFailures === 0) {
                                  matchFailed("\"AS\"");
                                }
                              }
                              if (result11 === null) {
                                if (input.substr(pos, 2) === "as") {
                                  result11 = "as";
                                  pos += 2;
                                } else {
                                  result11 = null;
                                  if (reportFailures === 0) {
                                    matchFailed("\"as\"");
                                  }
                                }
                              }
                              if (result11 !== null) {
                                result12 = [];
                                result13 = parse_WS();
                                while (result13 !== null) {
                                  result12.push(result13);
                                  result13 = parse_WS();
                                }
                                if (result12 !== null) {
                                  result13 = parse_Var();
                                  if (result13 !== null) {
                                    result14 = [];
                                    result15 = parse_WS();
                                    while (result15 !== null) {
                                      result14.push(result15);
                                      result15 = parse_WS();
                                    }
                                    if (result14 !== null) {
                                      if (input.charCodeAt(pos) === 41) {
                                        result15 = ")";
                                        pos++;
                                      } else {
                                        result15 = null;
                                        if (reportFailures === 0) {
                                          matchFailed("\")\"");
                                        }
                                      }
                                      if (result15 !== null) {
                                        result16 = [];
                                        result17 = parse_WS();
                                        while (result17 !== null) {
                                          result16.push(result17);
                                          result17 = parse_WS();
                                        }
                                        if (result16 !== null) {
                                          result6 = [result6, result7, result8, result9, result10, result11, result12, result13, result14, result15, result16];
                                        } else {
                                          result6 = null;
                                          pos = pos2;
                                        }
                                      } else {
                                        result6 = null;
                                        pos = pos2;
                                      }
                                    } else {
                                      result6 = null;
                                      pos = pos2;
                                    }
                                  } else {
                                    result6 = null;
                                    pos = pos2;
                                  }
                                } else {
                                  result6 = null;
                                  pos = pos2;
                                }
                              } else {
                                result6 = null;
                                pos = pos2;
                              }
                            } else {
                              result6 = null;
                              pos = pos2;
                            }
                          } else {
                            result6 = null;
                            pos = pos2;
                          }
                        } else {
                          result6 = null;
                          pos = pos2;
                        }
                      } else {
                        result6 = null;
                        pos = pos2;
                      }
                    } else {
                      result6 = null;
                      pos = pos2;
                    }
                  }
                  if (result6 !== null) {
                    result5 = [];
                    while (result6 !== null) {
                      result5.push(result6);
                      pos2 = pos;
                      result6 = [];
                      result7 = parse_WS();
                      while (result7 !== null) {
                        result6.push(result7);
                        result7 = parse_WS();
                      }
                      if (result6 !== null) {
                        result7 = parse_Var();
                        if (result7 !== null) {
                          result8 = [];
                          result9 = parse_WS();
                          while (result9 !== null) {
                            result8.push(result9);
                            result9 = parse_WS();
                          }
                          if (result8 !== null) {
                            result6 = [result6, result7, result8];
                          } else {
                            result6 = null;
                            pos = pos2;
                          }
                        } else {
                          result6 = null;
                          pos = pos2;
                        }
                      } else {
                        result6 = null;
                        pos = pos2;
                      }
                      if (result6 === null) {
                        pos2 = pos;
                        result6 = [];
                        result7 = parse_WS();
                        while (result7 !== null) {
                          result6.push(result7);
                          result7 = parse_WS();
                        }
                        if (result6 !== null) {
                          if (input.charCodeAt(pos) === 40) {
                            result7 = "(";
                            pos++;
                          } else {
                            result7 = null;
                            if (reportFailures === 0) {
                              matchFailed("\"(\"");
                            }
                          }
                          if (result7 !== null) {
                            result8 = [];
                            result9 = parse_WS();
                            while (result9 !== null) {
                              result8.push(result9);
                              result9 = parse_WS();
                            }
                            if (result8 !== null) {
                              result9 = parse_ConditionalOrExpression();
                              if (result9 !== null) {
                                result10 = [];
                                result11 = parse_WS();
                                while (result11 !== null) {
                                  result10.push(result11);
                                  result11 = parse_WS();
                                }
                                if (result10 !== null) {
                                  if (input.substr(pos, 2) === "AS") {
                                    result11 = "AS";
                                    pos += 2;
                                  } else {
                                    result11 = null;
                                    if (reportFailures === 0) {
                                      matchFailed("\"AS\"");
                                    }
                                  }
                                  if (result11 === null) {
                                    if (input.substr(pos, 2) === "as") {
                                      result11 = "as";
                                      pos += 2;
                                    } else {
                                      result11 = null;
                                      if (reportFailures === 0) {
                                        matchFailed("\"as\"");
                                      }
                                    }
                                  }
                                  if (result11 !== null) {
                                    result12 = [];
                                    result13 = parse_WS();
                                    while (result13 !== null) {
                                      result12.push(result13);
                                      result13 = parse_WS();
                                    }
                                    if (result12 !== null) {
                                      result13 = parse_Var();
                                      if (result13 !== null) {
                                        result14 = [];
                                        result15 = parse_WS();
                                        while (result15 !== null) {
                                          result14.push(result15);
                                          result15 = parse_WS();
                                        }
                                        if (result14 !== null) {
                                          if (input.charCodeAt(pos) === 41) {
                                            result15 = ")";
                                            pos++;
                                          } else {
                                            result15 = null;
                                            if (reportFailures === 0) {
                                              matchFailed("\")\"");
                                            }
                                          }
                                          if (result15 !== null) {
                                            result16 = [];
                                            result17 = parse_WS();
                                            while (result17 !== null) {
                                              result16.push(result17);
                                              result17 = parse_WS();
                                            }
                                            if (result16 !== null) {
                                              result6 = [result6, result7, result8, result9, result10, result11, result12, result13, result14, result15, result16];
                                            } else {
                                              result6 = null;
                                              pos = pos2;
                                            }
                                          } else {
                                            result6 = null;
                                            pos = pos2;
                                          }
                                        } else {
                                          result6 = null;
                                          pos = pos2;
                                        }
                                      } else {
                                        result6 = null;
                                        pos = pos2;
                                      }
                                    } else {
                                      result6 = null;
                                      pos = pos2;
                                    }
                                  } else {
                                    result6 = null;
                                    pos = pos2;
                                  }
                                } else {
                                  result6 = null;
                                  pos = pos2;
                                }
                              } else {
                                result6 = null;
                                pos = pos2;
                              }
                            } else {
                              result6 = null;
                              pos = pos2;
                            }
                          } else {
                            result6 = null;
                            pos = pos2;
                          }
                        } else {
                          result6 = null;
                          pos = pos2;
                        }
                      }
                    }
                  } else {
                    result5 = null;
                  }
                  if (result5 === null) {
                    pos2 = pos;
                    result5 = [];
                    result6 = parse_WS();
                    while (result6 !== null) {
                      result5.push(result6);
                      result6 = parse_WS();
                    }
                    if (result5 !== null) {
                      if (input.charCodeAt(pos) === 42) {
                        result6 = "*";
                        pos++;
                      } else {
                        result6 = null;
                        if (reportFailures === 0) {
                          matchFailed("\"*\"");
                        }
                      }
                      if (result6 !== null) {
                        result7 = [];
                        result8 = parse_WS();
                        while (result8 !== null) {
                          result7.push(result8);
                          result8 = parse_WS();
                        }
                        if (result7 !== null) {
                          result5 = [result5, result6, result7];
                        } else {
                          result5 = null;
                          pos = pos2;
                        }
                      } else {
                        result5 = null;
                        pos = pos2;
                      }
                    } else {
                      result5 = null;
                      pos = pos2;
                    }
                  }
                  if (result5 !== null) {
                    result0 = [result0, result1, result2, result3, result4, result5];
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, mod, proj) {
             var vars = [];
              if(proj.length === 3 && proj[1]==="*") {
                  return {vars: [{token: 'variable', kind:'*'}], modifier:arrayToString(mod)};
              }
        
              for(var i=0; i< proj.length; i++) {
                  var aVar = proj[i];
        
                  if(aVar.length === 3) {
                      vars.push({token: 'variable', kind:'var', value:aVar[1]});
                  } else {
                      vars.push({token: 'variable', kind:'aliased', expression: aVar[3], alias:aVar[7]})
                  }
              }
        
              return {vars: vars, modifier:arrayToString(mod)};
        })(pos0, result0[3], result0[5]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[8] SelectClause");
        }
        return result0;
      }
      
      function parse_ConstructQuery() {
        var result0, result1, result2, result3, result4, result5, result6, result7, result8, result9;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          if (input.substr(pos, 9) === "CONSTRUCT") {
            result1 = "CONSTRUCT";
            pos += 9;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\"CONSTRUCT\"");
            }
          }
          if (result1 === null) {
            if (input.substr(pos, 9) === "construct") {
              result1 = "construct";
              pos += 9;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("\"construct\"");
              }
            }
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result3 = parse_ConstructTemplate();
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  result5 = [];
                  result6 = parse_DatasetClause();
                  while (result6 !== null) {
                    result5.push(result6);
                    result6 = parse_DatasetClause();
                  }
                  if (result5 !== null) {
                    result6 = [];
                    result7 = parse_WS();
                    while (result7 !== null) {
                      result6.push(result7);
                      result7 = parse_WS();
                    }
                    if (result6 !== null) {
                      result7 = parse_WhereClause();
                      if (result7 !== null) {
                        result8 = [];
                        result9 = parse_WS();
                        while (result9 !== null) {
                          result8.push(result9);
                          result9 = parse_WS();
                        }
                        if (result8 !== null) {
                          result9 = parse_SolutionModifier();
                          if (result9 !== null) {
                            result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9];
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, t, gs, w, sm) {
              var dataset = {'named':[], 'implicit':[]};
              for(var i=0; i<gs.length; i++) {
                  var g = gs[i];
                  if(g.kind === 'default') {
                      dataset['implicit'].push(g.graph);
                  } else {
                      dataset['named'].push(g.graph)
                  }
              }
        
        
              if(dataset['named'].length === 0 && dataset['implicit'].length === 0) {
                  dataset['implicit'].push({token:'uri',
                                           prefix:null, 
                                           suffix:null, 
                                           value:'https://github.com/antoniogarrote/rdfstore-js#default_graph'});
              }
        
              var query = {};
              query.kind = 'construct';
              query.token = 'executableunit'
              query.dataset = dataset;
              query.template = t;
              query.pattern = w
              
              if(sm!=null && sm.limit!=null) {
                  query.limit = sm.limit;
              }
              if(sm!=null && sm.offset!=null) {
                  query.offset = sm.offset;
              }
              if(sm!=null && (sm.order!=null && sm.order!="")) {
                  query.order = sm.order;
              }
              return query
        
        })(pos0, result0[3], result0[5], result0[7], result0[9]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[9] ConstructQuery");
        }
        return result0;
      }
      
      function parse_DescribeQuery() {
        var result0, result1, result2, result3, result4;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        if (input.substr(pos, 8) === "DESCRIBE") {
          result0 = "DESCRIBE";
          pos += 8;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"DESCRIBE\"");
          }
        }
        if (result0 !== null) {
          result2 = parse_VarOrIRIref();
          if (result2 !== null) {
            result1 = [];
            while (result2 !== null) {
              result1.push(result2);
              result2 = parse_VarOrIRIref();
            }
          } else {
            result1 = null;
          }
          if (result1 === null) {
            if (input.charCodeAt(pos) === 42) {
              result1 = "*";
              pos++;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("\"*\"");
              }
            }
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_DatasetClause();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_DatasetClause();
            }
            if (result2 !== null) {
              result3 = parse_WhereClause();
              result3 = result3 !== null ? result3 : "";
              if (result3 !== null) {
                result4 = parse_SolutionModifier();
                if (result4 !== null) {
                  result0 = [result0, result1, result2, result3, result4];
                } else {
                  result0 = null;
                  pos = pos0;
                }
              } else {
                result0 = null;
                pos = pos0;
              }
            } else {
              result0 = null;
              pos = pos0;
            }
          } else {
            result0 = null;
            pos = pos0;
          }
        } else {
          result0 = null;
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[10] DescribeQuery");
        }
        return result0;
      }
      
      function parse_AskQuery() {
        var result0, result1, result2, result3, result4, result5;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          if (input.substr(pos, 3) === "ASK") {
            result1 = "ASK";
            pos += 3;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\"ASK\"");
            }
          }
          if (result1 === null) {
            if (input.substr(pos, 3) === "ask") {
              result1 = "ask";
              pos += 3;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("\"ask\"");
              }
            }
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result3 = [];
              result4 = parse_DatasetClause();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_DatasetClause();
              }
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  result5 = parse_WhereClause();
                  if (result5 !== null) {
                    result0 = [result0, result1, result2, result3, result4, result5];
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, gs, w) {
              var dataset = {'named':[], 'implicit':[]};
              for(var i=0; i<gs.length; i++) {
                  var g = gs[i];
                  if(g.kind === 'implicit') {
                      dataset['implicit'].push(g.graph);
                  } else {
                      dataset['named'].push(g.graph)
                  }
              }
        
        
              if(dataset['named'].length === 0 && dataset['implicit'].length === 0) {
                  dataset['implicit'].push({token:'uri',
                                            prefix:null,
                                            suffix:null,
                                            value:'https://github.com/antoniogarrote/rdfstore-js#default_graph'});
              }
        
              var query = {};
              query.kind = 'ask';
              query.token = 'executableunit'
              query.dataset = dataset;
              query.pattern = w
        
              return query
        })(pos0, result0[3], result0[5]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[11] AskQuery");
        }
        return result0;
      }
      
      function parse_DatasetClause() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 4) === "FROM") {
          result0 = "FROM";
          pos += 4;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"FROM\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 4) === "from") {
            result0 = "from";
            pos += 4;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"from\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_DefaultGraphClause();
            if (result2 === null) {
              result2 = parse_NamedGraphClause();
            }
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, gs) {
              return gs;
        })(pos0, result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[12] DatasetClause");
        }
        return result0;
      }
      
      function parse_DefaultGraphClause() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          result1 = parse_IRIref();
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, s) {
            return {graph:s , kind:'default', token:'graphClause'}
        })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[13] DefaultGraphClause");
        }
        return result0;
      }
      
      function parse_NamedGraphClause() {
        var result0, result1, result2;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 5) === "NAMED") {
          result0 = "NAMED";
          pos += 5;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"NAMED\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 5) === "named") {
            result0 = "named";
            pos += 5;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"named\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_IRIref();
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, s) {      
              return {graph:s, kind:'named', token:'graphCluase'};
        })(pos0, result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[14] NamedGraphClause");
        }
        return result0;
      }
      
      function parse_WhereClause() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 5) === "WHERE") {
          result0 = "WHERE";
          pos += 5;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"WHERE\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 5) === "where") {
            result0 = "where";
            pos += 5;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"where\"");
            }
          }
        }
        result0 = result0 !== null ? result0 : "";
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_GroupGraphPattern();
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, g) {
              return g;
        })(pos0, result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[16] WhereClause");
        }
        return result0;
      }
      
      function parse_SolutionModifier() {
        var result0, result1, result2, result3;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_GroupClause();
        result0 = result0 !== null ? result0 : "";
        if (result0 !== null) {
          result1 = parse_HavingClause();
          result1 = result1 !== null ? result1 : "";
          if (result1 !== null) {
            result2 = parse_OrderClause();
            result2 = result2 !== null ? result2 : "";
            if (result2 !== null) {
              result3 = parse_LimitOffsetClauses();
              result3 = result3 !== null ? result3 : "";
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, gc, oc, lo) {
              var acum = {};
              if(lo != null) {
                  if(lo.limit != null) {
                      acum.limit = lo.limit;
                  } 
                  if(lo.offset != null) {
                      acum.offset = lo.offset;
                  }
              }
        
              if(gc != null) {
                  acum.group = gc;
              }
        
              acum.order = oc;
        
              return acum
        })(pos0, result0[0], result0[2], result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[17] SolutionModifier");
        }
        return result0;
      }
      
      function parse_GroupClause() {
        var result0, result1, result2, result3, result4, result5;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 5) === "GROUP") {
          result0 = "GROUP";
          pos += 5;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"GROUP\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 5) === "group") {
            result0 = "group";
            pos += 5;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"group\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.substr(pos, 2) === "BY") {
              result2 = "BY";
              pos += 2;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"BY\"");
              }
            }
            if (result2 === null) {
              if (input.substr(pos, 2) === "by") {
                result2 = "by";
                pos += 2;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("\"by\"");
                }
              }
            }
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result5 = parse_GroupCondition();
                if (result5 !== null) {
                  result4 = [];
                  while (result5 !== null) {
                    result4.push(result5);
                    result5 = parse_GroupCondition();
                  }
                } else {
                  result4 = null;
                }
                if (result4 !== null) {
                  result0 = [result0, result1, result2, result3, result4];
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, conds) {
              return conds;
        })(pos0, result0[4]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[18] GroupClause");
        }
        return result0;
      }
      
      function parse_GroupCondition() {
        var result0, result1, result2, result3, result4, result5, result6, result7, result8, result9;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          result1 = parse_BuiltInCall();
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, b) {
              return b;
        })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          pos1 = pos;
          result0 = [];
          result1 = parse_WS();
          while (result1 !== null) {
            result0.push(result1);
            result1 = parse_WS();
          }
          if (result0 !== null) {
            result1 = parse_FunctionCall();
            if (result1 !== null) {
              result2 = [];
              result3 = parse_WS();
              while (result3 !== null) {
                result2.push(result3);
                result3 = parse_WS();
              }
              if (result2 !== null) {
                result0 = [result0, result1, result2];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
          if (result0 !== null) {
            result0 = (function(offset, f) {
                return f;
          })(pos0, result0[1]);
          }
          if (result0 === null) {
            pos = pos0;
          }
          if (result0 === null) {
            pos0 = pos;
            pos1 = pos;
            result0 = [];
            result1 = parse_WS();
            while (result1 !== null) {
              result0.push(result1);
              result1 = parse_WS();
            }
            if (result0 !== null) {
              if (input.charCodeAt(pos) === 40) {
                result1 = "(";
                pos++;
              } else {
                result1 = null;
                if (reportFailures === 0) {
                  matchFailed("\"(\"");
                }
              }
              if (result1 !== null) {
                result2 = [];
                result3 = parse_WS();
                while (result3 !== null) {
                  result2.push(result3);
                  result3 = parse_WS();
                }
                if (result2 !== null) {
                  result3 = parse_ConditionalOrExpression();
                  if (result3 !== null) {
                    result4 = [];
                    result5 = parse_WS();
                    while (result5 !== null) {
                      result4.push(result5);
                      result5 = parse_WS();
                    }
                    if (result4 !== null) {
                      pos2 = pos;
                      if (input.substr(pos, 2) === "AS") {
                        result5 = "AS";
                        pos += 2;
                      } else {
                        result5 = null;
                        if (reportFailures === 0) {
                          matchFailed("\"AS\"");
                        }
                      }
                      if (result5 === null) {
                        if (input.substr(pos, 2) === "as") {
                          result5 = "as";
                          pos += 2;
                        } else {
                          result5 = null;
                          if (reportFailures === 0) {
                            matchFailed("\"as\"");
                          }
                        }
                      }
                      if (result5 !== null) {
                        result6 = [];
                        result7 = parse_WS();
                        while (result7 !== null) {
                          result6.push(result7);
                          result7 = parse_WS();
                        }
                        if (result6 !== null) {
                          result7 = parse_Var();
                          if (result7 !== null) {
                            result5 = [result5, result6, result7];
                          } else {
                            result5 = null;
                            pos = pos2;
                          }
                        } else {
                          result5 = null;
                          pos = pos2;
                        }
                      } else {
                        result5 = null;
                        pos = pos2;
                      }
                      result5 = result5 !== null ? result5 : "";
                      if (result5 !== null) {
                        result6 = [];
                        result7 = parse_WS();
                        while (result7 !== null) {
                          result6.push(result7);
                          result7 = parse_WS();
                        }
                        if (result6 !== null) {
                          if (input.charCodeAt(pos) === 41) {
                            result7 = ")";
                            pos++;
                          } else {
                            result7 = null;
                            if (reportFailures === 0) {
                              matchFailed("\")\"");
                            }
                          }
                          if (result7 !== null) {
                            result8 = [];
                            result9 = parse_WS();
                            while (result9 !== null) {
                              result8.push(result9);
                              result9 = parse_WS();
                            }
                            if (result8 !== null) {
                              result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8];
                            } else {
                              result0 = null;
                              pos = pos1;
                            }
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
            if (result0 !== null) {
              result0 = (function(offset, e, alias) {
                  if(alias.length != 0) {
                      return {token: 'aliased_expression',
                              expression: e,
                              alias: alias[2] };
                  } else {
                      return e;
                  }
            })(pos0, result0[3], result0[5]);
            }
            if (result0 === null) {
              pos = pos0;
            }
            if (result0 === null) {
              pos0 = pos;
              pos1 = pos;
              result0 = [];
              result1 = parse_WS();
              while (result1 !== null) {
                result0.push(result1);
                result1 = parse_WS();
              }
              if (result0 !== null) {
                result1 = parse_Var();
                if (result1 !== null) {
                  result2 = [];
                  result3 = parse_WS();
                  while (result3 !== null) {
                    result2.push(result3);
                    result3 = parse_WS();
                  }
                  if (result2 !== null) {
                    result0 = [result0, result1, result2];
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
              if (result0 !== null) {
                result0 = (function(offset, v) {
                    return v;
              })(pos0, result0[1]);
              }
              if (result0 === null) {
                pos = pos0;
              }
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[19] GroupCondition");
        }
        return result0;
      }
      
      function parse_HavingClause() {
        var result0, result1, result2;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        if (input.substr(pos, 6) === "HAVING") {
          result0 = "HAVING";
          pos += 6;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"HAVING\"");
          }
        }
        if (result0 !== null) {
          result2 = parse_Constraint();
          if (result2 !== null) {
            result1 = [];
            while (result2 !== null) {
              result1.push(result2);
              result2 = parse_Constraint();
            }
          } else {
            result1 = null;
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos0;
          }
        } else {
          result0 = null;
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[20] HavingClause");
        }
        return result0;
      }
      
      function parse_OrderClause() {
        var result0, result1, result2, result3, result4, result5, result6;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 5) === "ORDER") {
          result0 = "ORDER";
          pos += 5;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"ORDER\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 5) === "order") {
            result0 = "order";
            pos += 5;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"order\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.substr(pos, 2) === "BY") {
              result2 = "BY";
              pos += 2;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"BY\"");
              }
            }
            if (result2 === null) {
              if (input.substr(pos, 2) === "by") {
                result2 = "by";
                pos += 2;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("\"by\"");
                }
              }
            }
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result5 = parse_OrderCondition();
                if (result5 !== null) {
                  result4 = [];
                  while (result5 !== null) {
                    result4.push(result5);
                    result5 = parse_OrderCondition();
                  }
                } else {
                  result4 = null;
                }
                if (result4 !== null) {
                  result5 = [];
                  result6 = parse_WS();
                  while (result6 !== null) {
                    result5.push(result6);
                    result6 = parse_WS();
                  }
                  if (result5 !== null) {
                    result0 = [result0, result1, result2, result3, result4, result5];
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, os) {
              return os;
        })(pos0, result0[4]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[22] OrderClause");
        }
        return result0;
      }
      
      function parse_OrderCondition() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 3) === "ASC") {
          result0 = "ASC";
          pos += 3;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"ASC\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 3) === "asc") {
            result0 = "asc";
            pos += 3;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"asc\"");
            }
          }
          if (result0 === null) {
            if (input.substr(pos, 4) === "DESC") {
              result0 = "DESC";
              pos += 4;
            } else {
              result0 = null;
              if (reportFailures === 0) {
                matchFailed("\"DESC\"");
              }
            }
            if (result0 === null) {
              if (input.substr(pos, 4) === "desc") {
                result0 = "desc";
                pos += 4;
              } else {
                result0 = null;
                if (reportFailures === 0) {
                  matchFailed("\"desc\"");
                }
              }
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_BrackettedExpression();
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, direction, e) {
              return { direction: direction.toUpperCase(), expression:e };
        })(pos0, result0[0], result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          pos1 = pos;
          result0 = parse_Constraint();
          if (result0 === null) {
            result0 = parse_Var();
          }
          if (result0 !== null) {
            result1 = [];
            result2 = parse_WS();
            while (result2 !== null) {
              result1.push(result2);
              result2 = parse_WS();
            }
            if (result1 !== null) {
              result0 = [result0, result1];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
          if (result0 !== null) {
            result0 = (function(offset, e) {
              if(e.token === 'var') {
                  var e = { token:'expression',
                            expressionType:'atomic',
                            primaryexpression: 'var',
                            value: e };
              }
              return { direction: 'ASC', expression:e };
          })(pos0, result0[0]);
          }
          if (result0 === null) {
            pos = pos0;
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[23] OrderCondition");
        }
        return result0;
      }
      
      function parse_LimitOffsetClauses() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_LimitClause();
        if (result0 !== null) {
          result1 = parse_OffsetClause();
          result1 = result1 !== null ? result1 : "";
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 === null) {
          pos1 = pos;
          result0 = parse_OffsetClause();
          if (result0 !== null) {
            result1 = parse_LimitClause();
            result1 = result1 !== null ? result1 : "";
            if (result1 !== null) {
              result0 = [result0, result1];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        }
        if (result0 !== null) {
          result0 = (function(offset, cls) {
              var acum = {};
              for(var i=0; i<cls.length; i++) {
                  var cl = cls[i];
                  if(cl.limit != null) {
                      acum['limit'] = cl.limit;
                  } else if(cl.offset != null){
                      acum['offset'] = cl.offset;
                  }
              }
        
              return acum;
        })(pos0, result0);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[24] LimitOffsetClauses");
        }
        return result0;
      }
      
      function parse_LimitClause() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 5) === "LIMIT") {
          result0 = "LIMIT";
          pos += 5;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"LIMIT\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 5) === "limit") {
            result0 = "limit";
            pos += 5;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"limit\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_INTEGER();
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, i) {
          return { limit:parseInt(i.value) };
        })(pos0, result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[25] LimitClause");
        }
        return result0;
      }
      
      function parse_OffsetClause() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 6) === "OFFSET") {
          result0 = "OFFSET";
          pos += 6;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"OFFSET\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 6) === "offset") {
            result0 = "offset";
            pos += 6;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"offset\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_INTEGER();
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, i) {
          return { offset:parseInt(i.value) };
        })(pos0, result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[26] OffsetClause");
        }
        return result0;
      }
      
      function parse_BindingsClause() {
        var result0, result1, result2, result3, result4, result5, result6;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        if (input.substr(pos, 8) === "BINDINGS") {
          result0 = "BINDINGS";
          pos += 8;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"BINDINGS\"");
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_Var();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_Var();
          }
          if (result1 !== null) {
            if (input.charCodeAt(pos) === 123) {
              result2 = "{";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"{\"");
              }
            }
            if (result2 !== null) {
              result3 = [];
              pos1 = pos;
              if (input.charCodeAt(pos) === 40) {
                result4 = "(";
                pos++;
              } else {
                result4 = null;
                if (reportFailures === 0) {
                  matchFailed("\"(\"");
                }
              }
              if (result4 !== null) {
                result6 = parse_BindingValue();
                if (result6 !== null) {
                  result5 = [];
                  while (result6 !== null) {
                    result5.push(result6);
                    result6 = parse_BindingValue();
                  }
                } else {
                  result5 = null;
                }
                if (result5 !== null) {
                  if (input.charCodeAt(pos) === 41) {
                    result6 = ")";
                    pos++;
                  } else {
                    result6 = null;
                    if (reportFailures === 0) {
                      matchFailed("\")\"");
                    }
                  }
                  if (result6 !== null) {
                    result4 = [result4, result5, result6];
                  } else {
                    result4 = null;
                    pos = pos1;
                  }
                } else {
                  result4 = null;
                  pos = pos1;
                }
              } else {
                result4 = null;
                pos = pos1;
              }
              if (result4 === null) {
                result4 = parse_NIL();
              }
              while (result4 !== null) {
                result3.push(result4);
                pos1 = pos;
                if (input.charCodeAt(pos) === 40) {
                  result4 = "(";
                  pos++;
                } else {
                  result4 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"(\"");
                  }
                }
                if (result4 !== null) {
                  result6 = parse_BindingValue();
                  if (result6 !== null) {
                    result5 = [];
                    while (result6 !== null) {
                      result5.push(result6);
                      result6 = parse_BindingValue();
                    }
                  } else {
                    result5 = null;
                  }
                  if (result5 !== null) {
                    if (input.charCodeAt(pos) === 41) {
                      result6 = ")";
                      pos++;
                    } else {
                      result6 = null;
                      if (reportFailures === 0) {
                        matchFailed("\")\"");
                      }
                    }
                    if (result6 !== null) {
                      result4 = [result4, result5, result6];
                    } else {
                      result4 = null;
                      pos = pos1;
                    }
                  } else {
                    result4 = null;
                    pos = pos1;
                  }
                } else {
                  result4 = null;
                  pos = pos1;
                }
                if (result4 === null) {
                  result4 = parse_NIL();
                }
              }
              if (result3 !== null) {
                if (input.charCodeAt(pos) === 125) {
                  result4 = "}";
                  pos++;
                } else {
                  result4 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"}\"");
                  }
                }
                if (result4 !== null) {
                  result0 = [result0, result1, result2, result3, result4];
                } else {
                  result0 = null;
                  pos = pos0;
                }
              } else {
                result0 = null;
                pos = pos0;
              }
            } else {
              result0 = null;
              pos = pos0;
            }
          } else {
            result0 = null;
            pos = pos0;
          }
        } else {
          result0 = null;
          pos = pos0;
        }
        result0 = result0 !== null ? result0 : "";
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[27] BindingsClause");
        }
        return result0;
      }
      
      function parse_BindingValue() {
        var result0;
        
        reportFailures++;
        result0 = parse_IRIref();
        if (result0 === null) {
          result0 = parse_RDFLiteral();
          if (result0 === null) {
            result0 = parse_NumericLiteral();
            if (result0 === null) {
              result0 = parse_BooleanLiteral();
              if (result0 === null) {
                if (input.substr(pos, 5) === "UNDEF") {
                  result0 = "UNDEF";
                  pos += 5;
                } else {
                  result0 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"UNDEF\"");
                  }
                }
              }
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[28] BindingValue");
        }
        return result0;
      }
      
      function parse_Update() {
        var result0, result1, result2, result3, result4, result5, result6;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_Prologue();
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_Update1();
            if (result2 !== null) {
              pos2 = pos;
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                if (input.charCodeAt(pos) === 59) {
                  result4 = ";";
                  pos++;
                } else {
                  result4 = null;
                  if (reportFailures === 0) {
                    matchFailed("\";\"");
                  }
                }
                if (result4 !== null) {
                  result5 = [];
                  result6 = parse_WS();
                  while (result6 !== null) {
                    result5.push(result6);
                    result6 = parse_WS();
                  }
                  if (result5 !== null) {
                    result6 = parse_Update();
                    result6 = result6 !== null ? result6 : "";
                    if (result6 !== null) {
                      result3 = [result3, result4, result5, result6];
                    } else {
                      result3 = null;
                      pos = pos2;
                    }
                  } else {
                    result3 = null;
                    pos = pos2;
                  }
                } else {
                  result3 = null;
                  pos = pos2;
                }
              } else {
                result3 = null;
                pos = pos2;
              }
              result3 = result3 !== null ? result3 : "";
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, p, u, us) {
        
              var query = {};
              query.token = 'query';
              query.kind = 'update'
              query.prologue = p;
        
             var units = [u];
        
             if(us.length != null && us[3] != null && us[3].units != null) {
                 units = units.concat(us[3].units);
             }
        
             query.units = units;
             return query;
        })(pos0, result0[0], result0[2], result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[30] Update");
        }
        return result0;
      }
      
      function parse_Update1() {
        var result0;
        
        reportFailures++;
        result0 = parse_Load();
        if (result0 === null) {
          result0 = parse_Clear();
          if (result0 === null) {
            result0 = parse_Drop();
            if (result0 === null) {
              result0 = parse_Create();
              if (result0 === null) {
                result0 = parse_InsertData();
                if (result0 === null) {
                  result0 = parse_DeleteData();
                  if (result0 === null) {
                    result0 = parse_DeleteWhere();
                    if (result0 === null) {
                      result0 = parse_Modify();
                    }
                  }
                }
              }
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[31] Update1");
        }
        return result0;
      }
      
      function parse_Load() {
        var result0, result1, result2, result3, result4, result5, result6;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 4) === "LOAD") {
          result0 = "LOAD";
          pos += 4;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"LOAD\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 4) === "load") {
            result0 = "load";
            pos += 4;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"load\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_IRIref();
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                pos2 = pos;
                if (input.substr(pos, 4) === "INTO") {
                  result4 = "INTO";
                  pos += 4;
                } else {
                  result4 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"INTO\"");
                  }
                }
                if (result4 === null) {
                  if (input.substr(pos, 4) === "into") {
                    result4 = "into";
                    pos += 4;
                  } else {
                    result4 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"into\"");
                    }
                  }
                }
                if (result4 !== null) {
                  result5 = [];
                  result6 = parse_WS();
                  while (result6 !== null) {
                    result5.push(result6);
                    result6 = parse_WS();
                  }
                  if (result5 !== null) {
                    result6 = parse_GraphRef();
                    if (result6 !== null) {
                      result4 = [result4, result5, result6];
                    } else {
                      result4 = null;
                      pos = pos2;
                    }
                  } else {
                    result4 = null;
                    pos = pos2;
                  }
                } else {
                  result4 = null;
                  pos = pos2;
                }
                result4 = result4 !== null ? result4 : "";
                if (result4 !== null) {
                  result0 = [result0, result1, result2, result3, result4];
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, sg, dg) {
              var query = {};
              query.kind = 'load';
              query.token = 'executableunit'
              query.sourceGraph = sg;
              query.destinyGraph = dg[2];
              
              return query;
        })(pos0, result0[2], result0[4]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[32] Load");
        }
        return result0;
      }
      
      function parse_Clear() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 5) === "CLEAR") {
          result0 = "CLEAR";
          pos += 5;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"CLEAR\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 5) === "clear") {
            result0 = "clear";
            pos += 5;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"clear\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.substr(pos, 6) === "SILENT") {
              result2 = "SILENT";
              pos += 6;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"SILENT\"");
              }
            }
            if (result2 === null) {
              if (input.substr(pos, 6) === "silent") {
                result2 = "silent";
                pos += 6;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("\"silent\"");
                }
              }
            }
            result2 = result2 !== null ? result2 : "";
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result4 = parse_GraphRefAll();
                if (result4 !== null) {
                  result0 = [result0, result1, result2, result3, result4];
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, ref) {
              var query = {};
              query.kind = 'clear';
              query.token = 'executableunit'
              query.destinyGraph = ref;
              
              return query;
        })(pos0, result0[4]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[33] Clear");
        }
        return result0;
      }
      
      function parse_Drop() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 4) === "DROP") {
          result0 = "DROP";
          pos += 4;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"DROP\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 4) === "drop") {
            result0 = "drop";
            pos += 4;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"drop\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.substr(pos, 6) === "SILENT") {
              result2 = "SILENT";
              pos += 6;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"SILENT\"");
              }
            }
            if (result2 === null) {
              if (input.substr(pos, 6) === "silent") {
                result2 = "silent";
                pos += 6;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("\"silent\"");
                }
              }
            }
            result2 = result2 !== null ? result2 : "";
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result4 = parse_GraphRefAll();
                if (result4 !== null) {
                  result0 = [result0, result1, result2, result3, result4];
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, ref) {
              var query = {};
              query.kind = 'drop';
              query.token = 'executableunit'
              query.destinyGraph = ref;
              
              return query;
        })(pos0, result0[4]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[34] Drop");
        }
        return result0;
      }
      
      function parse_Create() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 6) === "CREATE") {
          result0 = "CREATE";
          pos += 6;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"CREATE\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 6) === "create") {
            result0 = "create";
            pos += 6;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"create\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.substr(pos, 6) === "SILENT") {
              result2 = "SILENT";
              pos += 6;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"SILENT\"");
              }
            }
            if (result2 === null) {
              if (input.substr(pos, 6) === "silent") {
                result2 = "silent";
                pos += 6;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("\"silent\"");
                }
              }
            }
            result2 = result2 !== null ? result2 : "";
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result4 = parse_GraphRef();
                if (result4 !== null) {
                  result0 = [result0, result1, result2, result3, result4];
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, ref) {
              var query = {};
              query.kind = 'create';
              query.token = 'executableunit'
              query.destinyGraph = ref;
              
              return query;
        })(pos0, result0[4]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[35] Create");
        }
        return result0;
      }
      
      function parse_InsertData() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 6) === "INSERT") {
          result0 = "INSERT";
          pos += 6;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"INSERT\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 6) === "insert") {
            result0 = "insert";
            pos += 6;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"insert\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.substr(pos, 4) === "DATA") {
              result2 = "DATA";
              pos += 4;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"DATA\"");
              }
            }
            if (result2 === null) {
              if (input.substr(pos, 4) === "data") {
                result2 = "data";
                pos += 4;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("\"data\"");
                }
              }
            }
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result4 = parse_QuadData();
                if (result4 !== null) {
                  result0 = [result0, result1, result2, result3, result4];
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, qs) {
              var query = {};
              query.kind = 'insertdata';
              query.token = 'executableunit'
              query.quads = qs;
        
              return query;
        })(pos0, result0[4]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[36] InsertData");
        }
        return result0;
      }
      
      function parse_DeleteData() {
        var result0, result1, result2, result3;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 6) === "DELETE") {
          result0 = "DELETE";
          pos += 6;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"DELETE\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 6) === "delete") {
            result0 = "delete";
            pos += 6;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"delete\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.substr(pos, 4) === "DATA") {
              result2 = "DATA";
              pos += 4;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"DATA\"");
              }
            }
            if (result2 === null) {
              if (input.substr(pos, 4) === "data") {
                result2 = "data";
                pos += 4;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("\"data\"");
                }
              }
            }
            if (result2 !== null) {
              result3 = parse_QuadData();
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, qs) {
              var query = {};
              query.kind = 'deletedata';
              query.token = 'executableunit'
              query.quads = qs;
        
              return query;
        })(pos0, result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[37] DeleteData");
        }
        return result0;
      }
      
      function parse_DeleteWhere() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 6) === "DELETE") {
          result0 = "DELETE";
          pos += 6;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"DELETE\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 6) === "delete") {
            result0 = "delete";
            pos += 6;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"delete\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.substr(pos, 5) === "WHERE") {
              result2 = "WHERE";
              pos += 5;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"WHERE\"");
              }
            }
            if (result2 === null) {
              if (input.substr(pos, 5) === "where") {
                result2 = "where";
                pos += 5;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("\"where\"");
                }
              }
            }
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result4 = parse_GroupGraphPattern();
                if (result4 !== null) {
                  result0 = [result0, result1, result2, result3, result4];
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, p) {
              var query = {};
              query.kind = 'modify';
              query.pattern = p;
              query['with'] = null;
              query['using'] = null;
        
              var quads = [];
        
        
              var patternsCollection = p.patterns[0];
              if(patternsCollection.triplesContext == null && patternsCollection.patterns!=null) {
                  patternsCollection = patternsCollection.patterns[0].triplesContext;
              } else {
                  patternsCollection = patternsCollection.triplesContext;
              }
        
              for(var i=0; i<patternsCollection.length; i++) {
                  var quad = {};
                  var contextQuad = patternsCollection[i];
        
                  quad['subject'] = contextQuad['subject'];
                  quad['predicate'] = contextQuad['predicate'];
                  quad['object'] = contextQuad['object'];
                  quad['graph'] = contextQuad['graph'];
        
                  quads.push(quad);
              }
        
              query['delete'] = quads;
        
              return query;
        })(pos0, result0[4]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[38] DeleteWhere");
        }
        return result0;
      }
      
      function parse_Modify() {
        var result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        pos2 = pos;
        if (input.substr(pos, 4) === "WITH") {
          result0 = "WITH";
          pos += 4;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"WITH\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 4) === "with") {
            result0 = "with";
            pos += 4;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"with\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_IRIref();
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos2;
            }
          } else {
            result0 = null;
            pos = pos2;
          }
        } else {
          result0 = null;
          pos = pos2;
        }
        result0 = result0 !== null ? result0 : "";
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            pos2 = pos;
            result2 = parse_DeleteClause();
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result4 = parse_InsertClause();
                result4 = result4 !== null ? result4 : "";
                if (result4 !== null) {
                  result2 = [result2, result3, result4];
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
            if (result2 === null) {
              result2 = parse_InsertClause();
            }
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result4 = [];
                result5 = parse_UsingClause();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_UsingClause();
                }
                if (result4 !== null) {
                  result5 = [];
                  result6 = parse_WS();
                  while (result6 !== null) {
                    result5.push(result6);
                    result6 = parse_WS();
                  }
                  if (result5 !== null) {
                    if (input.substr(pos, 5) === "WHERE") {
                      result6 = "WHERE";
                      pos += 5;
                    } else {
                      result6 = null;
                      if (reportFailures === 0) {
                        matchFailed("\"WHERE\"");
                      }
                    }
                    if (result6 === null) {
                      if (input.substr(pos, 5) === "where") {
                        result6 = "where";
                        pos += 5;
                      } else {
                        result6 = null;
                        if (reportFailures === 0) {
                          matchFailed("\"where\"");
                        }
                      }
                    }
                    if (result6 !== null) {
                      result7 = [];
                      result8 = parse_WS();
                      while (result8 !== null) {
                        result7.push(result8);
                        result8 = parse_WS();
                      }
                      if (result7 !== null) {
                        result8 = parse_GroupGraphPattern();
                        if (result8 !== null) {
                          result9 = [];
                          result10 = parse_WS();
                          while (result10 !== null) {
                            result9.push(result10);
                            result10 = parse_WS();
                          }
                          if (result9 !== null) {
                            result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9];
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, wg, dic, uc, p) {
              var query = {};
              query.kind = 'modify';
        
              if(wg != "") {
                  query['with'] = wg[2];
              } else {
                  query['with'] = null;
              }
        
        
              if(dic.length === 3 && dic[2] === '') {
                  query['delete'] = dic[0];
                  query.insert = null;
              } else if(dic.length === 3 && dic[0].length != null && dic[1].length != null && dic[2].length != null) {
                  query['delete'] = dic[0];
                  query.insert = dic[2];
              } else  {
                  query.insert = dic;
                  query['delete'] = null;
              }
        
              if(uc != '') {
                  query['using'] = uc;
              }
        
              query.pattern = p;
        
              return query;
        })(pos0, result0[0], result0[2], result0[4], result0[8]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[39] Modify");
        }
        return result0;
      }
      
      function parse_DeleteClause() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 6) === "DELETE") {
          result0 = "DELETE";
          pos += 6;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"DELETE\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 6) === "delete") {
            result0 = "delete";
            pos += 6;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"delete\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = parse_QuadPattern();
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, q) {
              return q;
        })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[40] DeleteClause");
        }
        return result0;
      }
      
      function parse_InsertClause() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 6) === "INSERT") {
          result0 = "INSERT";
          pos += 6;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"INSERT\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 6) === "insert") {
            result0 = "insert";
            pos += 6;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"insert\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = parse_QuadPattern();
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, q) {
          return q;
        })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[41] InsertClause");
        }
        return result0;
      }
      
      function parse_UsingClause() {
        var result0, result1, result2, result3, result4, result5;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          if (input.substr(pos, 5) === "USING") {
            result1 = "USING";
            pos += 5;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\"USING\"");
            }
          }
          if (result1 === null) {
            if (input.substr(pos, 5) === "using") {
              result1 = "using";
              pos += 5;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("\"using\"");
              }
            }
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result3 = parse_IRIref();
              if (result3 === null) {
                pos2 = pos;
                if (input.substr(pos, 5) === "NAMED") {
                  result3 = "NAMED";
                  pos += 5;
                } else {
                  result3 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"NAMED\"");
                  }
                }
                if (result3 === null) {
                  if (input.substr(pos, 5) === "named") {
                    result3 = "named";
                    pos += 5;
                  } else {
                    result3 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"named\"");
                    }
                  }
                }
                if (result3 !== null) {
                  result4 = [];
                  result5 = parse_WS();
                  while (result5 !== null) {
                    result4.push(result5);
                    result5 = parse_WS();
                  }
                  if (result4 !== null) {
                    result5 = parse_IRIref();
                    if (result5 !== null) {
                      result3 = [result3, result4, result5];
                    } else {
                      result3 = null;
                      pos = pos2;
                    }
                  } else {
                    result3 = null;
                    pos = pos2;
                  }
                } else {
                  result3 = null;
                  pos = pos2;
                }
              }
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, g) {
              if(g.length!=null) {
                  return {kind: 'named', uri: g[2]};
              } else {
                  return {kind: 'default', uri: g};
              }
        })(pos0, result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[42] UsingClause");
        }
        return result0;
      }
      
      function parse_GraphRef() {
        var result0, result1, result2;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 5) === "GRAPH") {
          result0 = "GRAPH";
          pos += 5;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"GRAPH\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 5) === "graph") {
            result0 = "graph";
            pos += 5;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"graph\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_IRIref();
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, i) {
              return i;
        })(pos0, result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[43] GraphRef");
        }
        return result0;
      }
      
      function parse_GraphRefAll() {
        var result0;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        result0 = parse_GraphRef();
        if (result0 !== null) {
          result0 = (function(offset, g) {
              return g;
        })(pos0, result0);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          if (input.substr(pos, 7) === "DEFAULT") {
            result0 = "DEFAULT";
            pos += 7;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"DEFAULT\"");
            }
          }
          if (result0 === null) {
            if (input.substr(pos, 7) === "default") {
              result0 = "default";
              pos += 7;
            } else {
              result0 = null;
              if (reportFailures === 0) {
                matchFailed("\"default\"");
              }
            }
          }
          if (result0 !== null) {
            result0 = (function(offset) {
                return 'default';
          })(pos0);
          }
          if (result0 === null) {
            pos = pos0;
          }
          if (result0 === null) {
            pos0 = pos;
            if (input.substr(pos, 5) === "NAMED") {
              result0 = "NAMED";
              pos += 5;
            } else {
              result0 = null;
              if (reportFailures === 0) {
                matchFailed("\"NAMED\"");
              }
            }
            if (result0 === null) {
              if (input.substr(pos, 5) === "named") {
                result0 = "named";
                pos += 5;
              } else {
                result0 = null;
                if (reportFailures === 0) {
                  matchFailed("\"named\"");
                }
              }
            }
            if (result0 !== null) {
              result0 = (function(offset) {
                  return 'named';
            })(pos0);
            }
            if (result0 === null) {
              pos = pos0;
            }
            if (result0 === null) {
              pos0 = pos;
              if (input.substr(pos, 3) === "ALL") {
                result0 = "ALL";
                pos += 3;
              } else {
                result0 = null;
                if (reportFailures === 0) {
                  matchFailed("\"ALL\"");
                }
              }
              if (result0 === null) {
                if (input.substr(pos, 3) === "all") {
                  result0 = "all";
                  pos += 3;
                } else {
                  result0 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"all\"");
                  }
                }
              }
              if (result0 !== null) {
                result0 = (function(offset) {
                    return 'all';
              })(pos0);
              }
              if (result0 === null) {
                pos = pos0;
              }
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[44] GraphRefAll");
        }
        return result0;
      }
      
      function parse_QuadPattern() {
        var result0, result1, result2, result3, result4, result5, result6, result7;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          if (input.charCodeAt(pos) === 123) {
            result1 = "{";
            pos++;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\"{\"");
            }
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result3 = parse_Quads();
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  if (input.charCodeAt(pos) === 125) {
                    result5 = "}";
                    pos++;
                  } else {
                    result5 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"}\"");
                    }
                  }
                  if (result5 !== null) {
                    result6 = [];
                    result7 = parse_WS();
                    while (result7 !== null) {
                      result6.push(result7);
                      result7 = parse_WS();
                    }
                    if (result6 !== null) {
                      result0 = [result0, result1, result2, result3, result4, result5, result6];
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, qs) {
              return qs.quadsContext;
        })(pos0, result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[45] QuadPattern");
        }
        return result0;
      }
      
      function parse_QuadData() {
        var result0, result1, result2, result3, result4, result5, result6, result7;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          if (input.charCodeAt(pos) === 123) {
            result1 = "{";
            pos++;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\"{\"");
            }
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result3 = parse_Quads();
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  if (input.charCodeAt(pos) === 125) {
                    result5 = "}";
                    pos++;
                  } else {
                    result5 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"}\"");
                    }
                  }
                  if (result5 !== null) {
                    result6 = [];
                    result7 = parse_WS();
                    while (result7 !== null) {
                      result6.push(result7);
                      result7 = parse_WS();
                    }
                    if (result6 !== null) {
                      result0 = [result0, result1, result2, result3, result4, result5, result6];
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, qs) {
              return qs.quadsContext;
        })(pos0, result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[46] QuadData");
        }
        return result0;
      }
      
      function parse_Quads() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_TriplesTemplate();
        result0 = result0 !== null ? result0 : "";
        if (result0 !== null) {
          result1 = [];
          pos2 = pos;
          result2 = parse_QuadsNotTriples();
          if (result2 !== null) {
            if (input.charCodeAt(pos) === 46) {
              result3 = ".";
              pos++;
            } else {
              result3 = null;
              if (reportFailures === 0) {
                matchFailed("\".\"");
              }
            }
            result3 = result3 !== null ? result3 : "";
            if (result3 !== null) {
              result4 = parse_TriplesTemplate();
              result4 = result4 !== null ? result4 : "";
              if (result4 !== null) {
                result2 = [result2, result3, result4];
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
          } else {
            result2 = null;
            pos = pos2;
          }
          while (result2 !== null) {
            result1.push(result2);
            pos2 = pos;
            result2 = parse_QuadsNotTriples();
            if (result2 !== null) {
              if (input.charCodeAt(pos) === 46) {
                result3 = ".";
                pos++;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("\".\"");
                }
              }
              result3 = result3 !== null ? result3 : "";
              if (result3 !== null) {
                result4 = parse_TriplesTemplate();
                result4 = result4 !== null ? result4 : "";
                if (result4 !== null) {
                  result2 = [result2, result3, result4];
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, ts, qs) {
              var quads = []
              if(ts.triplesContext != null && ts.triplesContext != null) {
                for(var i=0; i<ts.triplesContext.length; i++) {
                    var triple = ts.triplesContext[i]
                    triple.graph = null;
                    quads.push(triple)
                }
              }
        
              if(qs && qs.length>0 && qs[0].length > 0) {
                  quads = quads.concat(qs[0][0].quadsContext);
        
                  if( qs[0][2] != null && qs[0][2].triplesContext != null) {
                    for(var i=0; i<qs[0][2].triplesContext.length; i++) {
                        var triple = qs[0][2].triplesContext[i]
                        triple.graph = null;
                        quads.push(triple)
                    }
                  }
              }
        
              return {token:'quads',
                      quadsContext: quads}
        })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[47] Quads");
        }
        return result0;
      }
      
      function parse_QuadsNotTriples() {
        var result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          if (input.substr(pos, 5) === "GRAPH") {
            result1 = "GRAPH";
            pos += 5;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\"GRAPH\"");
            }
          }
          if (result1 === null) {
            if (input.substr(pos, 5) === "graph") {
              result1 = "graph";
              pos += 5;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("\"graph\"");
              }
            }
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result3 = parse_VarOrIRIref();
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  if (input.charCodeAt(pos) === 123) {
                    result5 = "{";
                    pos++;
                  } else {
                    result5 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"{\"");
                    }
                  }
                  if (result5 !== null) {
                    result6 = [];
                    result7 = parse_WS();
                    while (result7 !== null) {
                      result6.push(result7);
                      result7 = parse_WS();
                    }
                    if (result6 !== null) {
                      result7 = parse_TriplesTemplate();
                      result7 = result7 !== null ? result7 : "";
                      if (result7 !== null) {
                        result8 = [];
                        result9 = parse_WS();
                        while (result9 !== null) {
                          result8.push(result9);
                          result9 = parse_WS();
                        }
                        if (result8 !== null) {
                          if (input.charCodeAt(pos) === 125) {
                            result9 = "}";
                            pos++;
                          } else {
                            result9 = null;
                            if (reportFailures === 0) {
                              matchFailed("\"}\"");
                            }
                          }
                          if (result9 !== null) {
                            result10 = [];
                            result11 = parse_WS();
                            while (result11 !== null) {
                              result10.push(result11);
                              result11 = parse_WS();
                            }
                            if (result10 !== null) {
                              result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10];
                            } else {
                              result0 = null;
                              pos = pos1;
                            }
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, g, ts) {
              var quads = []
              for(var i=0; i<ts.triplesContext.length; i++) {
                  var triple = ts.triplesContext[i]
                  triple.graph = g;
                  quads.push(triple)
              }
        
              return {token:'quadsnottriples',
                      quadsContext: quads}
        })(pos0, result0[3], result0[7]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[48] QuadsNotTriples");
        }
        return result0;
      }
      
      function parse_TriplesTemplate() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_TriplesSameSubject();
        if (result0 !== null) {
          pos2 = pos;
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.charCodeAt(pos) === 46) {
              result2 = ".";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\".\"");
              }
            }
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result4 = parse_TriplesTemplate();
                result4 = result4 !== null ? result4 : "";
                if (result4 !== null) {
                  result1 = [result1, result2, result3, result4];
                } else {
                  result1 = null;
                  pos = pos2;
                }
              } else {
                result1 = null;
                pos = pos2;
              }
            } else {
              result1 = null;
              pos = pos2;
            }
          } else {
            result1 = null;
            pos = pos2;
          }
          result1 = result1 !== null ? result1 : "";
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, b, bs) {
             var triples = b.triplesContext;
             var toTest = null;
              if(typeof(bs) === 'object') {
                    if(bs.length != null) {
                          if(bs[3].triplesContext!=null) {
                             triples = triples.concat(bs[3].triplesContext);
                      }
                   }
              }
        
             return {token:'triplestemplate',
                     triplesContext: triples}
        })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[49] TriplesTemplate");
        }
        return result0;
      }
      
      function parse_GroupGraphPattern() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 123) {
          result0 = "{";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"{\"");
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_SubSelect();
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                if (input.charCodeAt(pos) === 125) {
                  result4 = "}";
                  pos++;
                } else {
                  result4 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"}\"");
                  }
                }
                if (result4 !== null) {
                  result0 = [result0, result1, result2, result3, result4];
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, p) {
              return p;
        })(pos0, result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          pos1 = pos;
          if (input.charCodeAt(pos) === 123) {
            result0 = "{";
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"{\"");
            }
          }
          if (result0 !== null) {
            result1 = [];
            result2 = parse_WS();
            while (result2 !== null) {
              result1.push(result2);
              result2 = parse_WS();
            }
            if (result1 !== null) {
              result2 = parse_GroupGraphPatternSub();
              if (result2 !== null) {
                result3 = [];
                result4 = parse_WS();
                while (result4 !== null) {
                  result3.push(result4);
                  result4 = parse_WS();
                }
                if (result3 !== null) {
                  if (input.charCodeAt(pos) === 125) {
                    result4 = "}";
                    pos++;
                  } else {
                    result4 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"}\"");
                    }
                  }
                  if (result4 !== null) {
                    result0 = [result0, result1, result2, result3, result4];
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
          if (result0 !== null) {
            result0 = (function(offset, p) {
                return p;
          })(pos0, result0[2]);
          }
          if (result0 === null) {
            pos = pos0;
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[50] GroupGraphPattern");
        }
        return result0;
      }
      
      function parse_GroupGraphPatternSub() {
        var result0, result1, result2, result3, result4, result5, result6, result7;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_TriplesBlock();
        result0 = result0 !== null ? result0 : "";
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = [];
            pos2 = pos;
            result3 = parse_GraphPatternNotTriples();
            if (result3 !== null) {
              result4 = [];
              result5 = parse_WS();
              while (result5 !== null) {
                result4.push(result5);
                result5 = parse_WS();
              }
              if (result4 !== null) {
                if (input.charCodeAt(pos) === 46) {
                  result5 = ".";
                  pos++;
                } else {
                  result5 = null;
                  if (reportFailures === 0) {
                    matchFailed("\".\"");
                  }
                }
                result5 = result5 !== null ? result5 : "";
                if (result5 !== null) {
                  result6 = [];
                  result7 = parse_WS();
                  while (result7 !== null) {
                    result6.push(result7);
                    result7 = parse_WS();
                  }
                  if (result6 !== null) {
                    result7 = parse_TriplesBlock();
                    result7 = result7 !== null ? result7 : "";
                    if (result7 !== null) {
                      result3 = [result3, result4, result5, result6, result7];
                    } else {
                      result3 = null;
                      pos = pos2;
                    }
                  } else {
                    result3 = null;
                    pos = pos2;
                  }
                } else {
                  result3 = null;
                  pos = pos2;
                }
              } else {
                result3 = null;
                pos = pos2;
              }
            } else {
              result3 = null;
              pos = pos2;
            }
            while (result3 !== null) {
              result2.push(result3);
              pos2 = pos;
              result3 = parse_GraphPatternNotTriples();
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  if (input.charCodeAt(pos) === 46) {
                    result5 = ".";
                    pos++;
                  } else {
                    result5 = null;
                    if (reportFailures === 0) {
                      matchFailed("\".\"");
                    }
                  }
                  result5 = result5 !== null ? result5 : "";
                  if (result5 !== null) {
                    result6 = [];
                    result7 = parse_WS();
                    while (result7 !== null) {
                      result6.push(result7);
                      result7 = parse_WS();
                    }
                    if (result6 !== null) {
                      result7 = parse_TriplesBlock();
                      result7 = result7 !== null ? result7 : "";
                      if (result7 !== null) {
                        result3 = [result3, result4, result5, result6, result7];
                      } else {
                        result3 = null;
                        pos = pos2;
                      }
                    } else {
                      result3 = null;
                      pos = pos2;
                    }
                  } else {
                    result3 = null;
                    pos = pos2;
                  }
                } else {
                  result3 = null;
                  pos = pos2;
                }
              } else {
                result3 = null;
                pos = pos2;
              }
            }
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, tb, tbs) {
              var subpatterns = [];
              if(tb != null && tb != []) {
                  subpatterns.push(tb);
              }
        
              for(var i=0; i<tbs.length; i++) {
                  for(var j=0; j< tbs[i].length; j++) {
                      if(tbs[i][j].token != null) {
                          subpatterns.push(tbs[i][j]);
                      }
                  }
              }
        
              var compactedSubpatterns = [];
        
              var currentBasicGraphPatterns = [];
              var currentFilters = [];
        
              for(var i=0; i<subpatterns.length; i++) {
                  if(subpatterns[i].token!='triplespattern' && subpatterns[i].token != 'filter') {
                      if(currentBasicGraphPatterns.length != 0 || currentFilters.length != 0) {
                          var triplesContext = [];
                          for(var j=0; j<currentBasicGraphPatterns.length; j++) {
                              triplesContext = triplesContext.concat(currentBasicGraphPatterns[j].triplesContext);
                          }
                          if(triplesContext.length > 0) {  
                              compactedSubpatterns.push({token: 'basicgraphpattern',
                                                         triplesContext: triplesContext});
                          }
                          currentBasicGraphPatterns = [];
                      }
                      compactedSubpatterns.push(subpatterns[i]);
                  } else {
                      if(subpatterns[i].token === 'triplespattern') {
                          currentBasicGraphPatterns.push(subpatterns[i]);
                      } else {
                          currentFilters.push(subpatterns[i]);
                      }
                  }
              }
        
              if(currentBasicGraphPatterns.length != 0 || currentFilters.length != 0) {
                  var triplesContext = [];
                  for(var j=0; j<currentBasicGraphPatterns.length; j++) {
                      triplesContext = triplesContext.concat(currentBasicGraphPatterns[j].triplesContext);
                  }
                  if(triplesContext.length > 0) {
                    compactedSubpatterns.push({token: 'basicgraphpattern',
                                               triplesContext: triplesContext});
                  }
              }
        
        //      if(compactedSubpatterns.length == 1) {
        //          compactedSubpatterns[0].filters = currentFilters;
        //          return compactedSubpatterns[0];
        //      } else  {
                  return { token: 'groupgraphpattern',
                           patterns: compactedSubpatterns,
                           filters: currentFilters }
        //      }
        })(pos0, result0[0], result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[51] GroupGraphPatternSub");
        }
        return result0;
      }
      
      function parse_TriplesBlock() {
        var result0, result1, result2, result3;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_TriplesSameSubjectPath();
        if (result0 !== null) {
          pos2 = pos;
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.charCodeAt(pos) === 46) {
              result2 = ".";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\".\"");
              }
            }
            if (result2 !== null) {
              result3 = parse_TriplesBlock();
              result3 = result3 !== null ? result3 : "";
              if (result3 !== null) {
                result1 = [result1, result2, result3];
              } else {
                result1 = null;
                pos = pos2;
              }
            } else {
              result1 = null;
              pos = pos2;
            }
          } else {
            result1 = null;
            pos = pos2;
          }
          result1 = result1 !== null ? result1 : "";
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, b, bs) {
             var triples = b.triplesContext;
             var toTest = null;
              if(typeof(bs) === 'object') {
                    if(bs.length != null) {
                          if(bs[2].triplesContext!=null) {
                             triples = triples.concat(bs[2].triplesContext);
                      }
                   }
              }
        
             return {token:'triplespattern',
                     triplesContext: triples}
        })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[54] TriplesBlock");
        }
        return result0;
      }
      
      function parse_GraphPatternNotTriples() {
        var result0;
        
        reportFailures++;
        result0 = parse_GroupOrUnionGraphPattern();
        if (result0 === null) {
          result0 = parse_OptionalGraphPattern();
          if (result0 === null) {
            result0 = parse_MinusGraphPattern();
            if (result0 === null) {
              result0 = parse_GraphGraphPattern();
              if (result0 === null) {
                result0 = parse_ServiceGraphPattern();
                if (result0 === null) {
                  result0 = parse_Filter();
                }
              }
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[53] GraphPatternNotTriples");
        }
        return result0;
      }
      
      function parse_OptionalGraphPattern() {
        var result0, result1, result2, result3;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          if (input.substr(pos, 8) === "OPTIONAL") {
            result1 = "OPTIONAL";
            pos += 8;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\"OPTIONAL\"");
            }
          }
          if (result1 === null) {
            if (input.substr(pos, 8) === "optional") {
              result1 = "optional";
              pos += 8;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("\"optional\"");
              }
            }
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result3 = parse_GroupGraphPattern();
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, v) {
              return { token: 'optionalgraphpattern',
                       value: v }
        })(pos0, result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[54] OptionalGraphPattern");
        }
        return result0;
      }
      
      function parse_GraphGraphPattern() {
        var result0, result1, result2, result3, result4, result5;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          if (input.substr(pos, 5) === "GRAPH") {
            result1 = "GRAPH";
            pos += 5;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\"GRAPH\"");
            }
          }
          if (result1 === null) {
            if (input.substr(pos, 5) === "graph") {
              result1 = "graph";
              pos += 5;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("\"graph\"");
              }
            }
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result3 = parse_VarOrIRIref();
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  result5 = parse_GroupGraphPattern();
                  if (result5 !== null) {
                    result0 = [result0, result1, result2, result3, result4, result5];
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, g, gg) {
              for(var i=0; i<gg.patterns.length; i++) {
                var quads = []
                var ts = gg.patterns[i];
                for(var j=0; j<ts.triplesContext.length; j++) {
                    var triple = ts.triplesContext[j]
                    triple.graph = g;
                }
              }
        
              gg.token = 'groupgraphpattern'
              return gg;
        })(pos0, result0[3], result0[5]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[55] GraphGraphPattern");
        }
        return result0;
      }
      
      function parse_ServiceGraphPattern() {
        var result0, result1, result2;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 7) === "SERVICE") {
          result0 = "SERVICE";
          pos += 7;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"SERVICE\"");
          }
        }
        if (result0 !== null) {
          result1 = parse_VarOrIRIref();
          if (result1 !== null) {
            result2 = parse_GroupGraphPattern();
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, v, ts) {
              return {token: 'servicegraphpattern',
                      status: 'todo',
                      value: [v,ts] }
        })(pos0, result0[1], result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[56] ServiceGraphPattern");
        }
        return result0;
      }
      
      function parse_MinusGraphPattern() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 5) === "MINUS") {
          result0 = "MINUS";
          pos += 5;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"MINUS\"");
          }
        }
        if (result0 !== null) {
          result1 = parse_GroupGraphPattern();
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, ts) {
              return {token: 'minusgraphpattern',
                      status: 'todo',
                      value: ts}
        })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[57] MinusGraphPattern");
        }
        return result0;
      }
      
      function parse_GroupOrUnionGraphPattern() {
        var result0, result1, result2, result3, result4, result5;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_GroupGraphPattern();
        if (result0 !== null) {
          result1 = [];
          pos2 = pos;
          result2 = [];
          result3 = parse_WS();
          while (result3 !== null) {
            result2.push(result3);
            result3 = parse_WS();
          }
          if (result2 !== null) {
            if (input.substr(pos, 5) === "UNION") {
              result3 = "UNION";
              pos += 5;
            } else {
              result3 = null;
              if (reportFailures === 0) {
                matchFailed("\"UNION\"");
              }
            }
            if (result3 === null) {
              if (input.substr(pos, 5) === "union") {
                result3 = "union";
                pos += 5;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("\"union\"");
                }
              }
            }
            if (result3 !== null) {
              result4 = [];
              result5 = parse_WS();
              while (result5 !== null) {
                result4.push(result5);
                result5 = parse_WS();
              }
              if (result4 !== null) {
                result5 = parse_GroupGraphPattern();
                if (result5 !== null) {
                  result2 = [result2, result3, result4, result5];
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
          } else {
            result2 = null;
            pos = pos2;
          }
          while (result2 !== null) {
            result1.push(result2);
            pos2 = pos;
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              if (input.substr(pos, 5) === "UNION") {
                result3 = "UNION";
                pos += 5;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("\"UNION\"");
                }
              }
              if (result3 === null) {
                if (input.substr(pos, 5) === "union") {
                  result3 = "union";
                  pos += 5;
                } else {
                  result3 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"union\"");
                  }
                }
              }
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  result5 = parse_GroupGraphPattern();
                  if (result5 !== null) {
                    result2 = [result2, result3, result4, result5];
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, a, b) {
              if(b.length === 0) {
                  return a;
              } else {
        
                  var lastToken = {token: 'graphunionpattern',
                                   value: [a]};
        
                  for(var i=0; i<b.length; i++) {
                      if(i==b.length-1) {
                          lastToken.value.push(b[i][3]);
                      } else {
                          lastToken.value.push(b[i][3]);
                          var newToken = {token: 'graphunionpattern',
                                          value: [lastToken]}
        
                          lastToken = newToken;
                      }
                  }
        
                  return lastToken;
        
              }
        })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[58] GroupOrUnionGraphPattern");
        }
        return result0;
      }
      
      function parse_Filter() {
        var result0, result1, result2, result3;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          if (input.substr(pos, 6) === "FILTER") {
            result1 = "FILTER";
            pos += 6;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\"FILTER\"");
            }
          }
          if (result1 === null) {
            if (input.substr(pos, 6) === "filter") {
              result1 = "filter";
              pos += 6;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("\"filter\"");
              }
            }
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result3 = parse_Constraint();
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, c) {
              return {token: 'filter',
                      value: c}
        })(pos0, result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[59] Filter");
        }
        return result0;
      }
      
      function parse_Constraint() {
        var result0;
        
        reportFailures++;
        result0 = parse_BrackettedExpression();
        if (result0 === null) {
          result0 = parse_BuiltInCall();
          if (result0 === null) {
            result0 = parse_FunctionCall();
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[60] Constraint");
        }
        return result0;
      }
      
      function parse_FunctionCall() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_IRIref();
        if (result0 !== null) {
          result1 = parse_ArgList();
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, i, args) {
              var fcall = {};
              fcall.token = "expression";
              fcall.expressionType = 'irireforfunction'
              fcall.iriref = i;
              fcall.args = args.value;
        
              return fcall;
        })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[61] FunctionCall");
        }
        return result0;
      }
      
      function parse_ArgList() {
        var result0, result1, result2, result3, result4, result5;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        result0 = parse_NIL();
        if (result0 !== null) {
          result0 = (function(offset) {
              var args = {};
              args.token = 'args';
              args.value = [];
              return args;
        })(pos0);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          pos1 = pos;
          if (input.charCodeAt(pos) === 40) {
            result0 = "(";
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"(\"");
            }
          }
          if (result0 !== null) {
            if (input.substr(pos, 8) === "DISTINCT") {
              result1 = "DISTINCT";
              pos += 8;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("\"DISTINCT\"");
              }
            }
            if (result1 === null) {
              if (input.substr(pos, 8) === "distinct") {
                result1 = "distinct";
                pos += 8;
              } else {
                result1 = null;
                if (reportFailures === 0) {
                  matchFailed("\"distinct\"");
                }
              }
            }
            result1 = result1 !== null ? result1 : "";
            if (result1 !== null) {
              result2 = parse_ConditionalOrExpression();
              if (result2 !== null) {
                result3 = [];
                pos2 = pos;
                if (input.charCodeAt(pos) === 44) {
                  result4 = ",";
                  pos++;
                } else {
                  result4 = null;
                  if (reportFailures === 0) {
                    matchFailed("\",\"");
                  }
                }
                if (result4 !== null) {
                  result5 = parse_ConditionalOrExpression();
                  if (result5 !== null) {
                    result4 = [result4, result5];
                  } else {
                    result4 = null;
                    pos = pos2;
                  }
                } else {
                  result4 = null;
                  pos = pos2;
                }
                while (result4 !== null) {
                  result3.push(result4);
                  pos2 = pos;
                  if (input.charCodeAt(pos) === 44) {
                    result4 = ",";
                    pos++;
                  } else {
                    result4 = null;
                    if (reportFailures === 0) {
                      matchFailed("\",\"");
                    }
                  }
                  if (result4 !== null) {
                    result5 = parse_ConditionalOrExpression();
                    if (result5 !== null) {
                      result4 = [result4, result5];
                    } else {
                      result4 = null;
                      pos = pos2;
                    }
                  } else {
                    result4 = null;
                    pos = pos2;
                  }
                }
                if (result3 !== null) {
                  if (input.charCodeAt(pos) === 41) {
                    result4 = ")";
                    pos++;
                  } else {
                    result4 = null;
                    if (reportFailures === 0) {
                      matchFailed("\")\"");
                    }
                  }
                  if (result4 !== null) {
                    result0 = [result0, result1, result2, result3, result4];
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
          if (result0 !== null) {
            result0 = (function(offset, d, e, es) {
                var cleanEx = [];
          
                for(var i=0; i<es.length; i++) {
                    cleanEx.push(es[i][1]);
                }
                var args = {};
                args.token = 'args';
                args.value = [e].concat(cleanEx);
          
                if(d!=null && d.toUpperCase()==="DISTINCT") {
                    args.distinct = true;
                } else {
                    args.distinct = false;
                }
          
                return args;
          })(pos0, result0[1], result0[2], result0[3]);
          }
          if (result0 === null) {
            pos = pos0;
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[62] ArgList");
        }
        return result0;
      }
      
      function parse_ExpressionList() {
        var result0, result1, result2, result3, result4, result5, result6;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        result0 = parse_NIL();
        if (result0 !== null) {
          result0 = (function(offset) {
              var args = {};
              args.token = 'args';
              args.value = [];
              return args;
        })(pos0);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          pos1 = pos;
          if (input.charCodeAt(pos) === 40) {
            result0 = "(";
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"(\"");
            }
          }
          if (result0 !== null) {
            result1 = parse_ConditionalOrExpression();
            if (result1 !== null) {
              result2 = [];
              pos2 = pos;
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                if (input.charCodeAt(pos) === 44) {
                  result4 = ",";
                  pos++;
                } else {
                  result4 = null;
                  if (reportFailures === 0) {
                    matchFailed("\",\"");
                  }
                }
                if (result4 !== null) {
                  result5 = [];
                  result6 = parse_WS();
                  while (result6 !== null) {
                    result5.push(result6);
                    result6 = parse_WS();
                  }
                  if (result5 !== null) {
                    result6 = parse_ConditionalOrExpression();
                    if (result6 !== null) {
                      result3 = [result3, result4, result5, result6];
                    } else {
                      result3 = null;
                      pos = pos2;
                    }
                  } else {
                    result3 = null;
                    pos = pos2;
                  }
                } else {
                  result3 = null;
                  pos = pos2;
                }
              } else {
                result3 = null;
                pos = pos2;
              }
              while (result3 !== null) {
                result2.push(result3);
                pos2 = pos;
                result3 = [];
                result4 = parse_WS();
                while (result4 !== null) {
                  result3.push(result4);
                  result4 = parse_WS();
                }
                if (result3 !== null) {
                  if (input.charCodeAt(pos) === 44) {
                    result4 = ",";
                    pos++;
                  } else {
                    result4 = null;
                    if (reportFailures === 0) {
                      matchFailed("\",\"");
                    }
                  }
                  if (result4 !== null) {
                    result5 = [];
                    result6 = parse_WS();
                    while (result6 !== null) {
                      result5.push(result6);
                      result6 = parse_WS();
                    }
                    if (result5 !== null) {
                      result6 = parse_ConditionalOrExpression();
                      if (result6 !== null) {
                        result3 = [result3, result4, result5, result6];
                      } else {
                        result3 = null;
                        pos = pos2;
                      }
                    } else {
                      result3 = null;
                      pos = pos2;
                    }
                  } else {
                    result3 = null;
                    pos = pos2;
                  }
                } else {
                  result3 = null;
                  pos = pos2;
                }
              }
              if (result2 !== null) {
                if (input.charCodeAt(pos) === 41) {
                  result3 = ")";
                  pos++;
                } else {
                  result3 = null;
                  if (reportFailures === 0) {
                    matchFailed("\")\"");
                  }
                }
                if (result3 !== null) {
                  result0 = [result0, result1, result2, result3];
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
          if (result0 !== null) {
            result0 = (function(offset, e, es) {
                var cleanEx = [];
          
                for(var i=0; i<es.length; i++) {
                    cleanEx.push(es[i][3]);
                }
                var args = {};
                args.token = 'args';
                args.value = [e].concat(cleanEx);
          
                return args;
          })(pos0, result0[1], result0[2]);
          }
          if (result0 === null) {
            pos = pos0;
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[63] ExpressionList");
        }
        return result0;
      }
      
      function parse_ConstructTemplate() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 123) {
          result0 = "{";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"{\"");
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_ConstructTriples();
            result2 = result2 !== null ? result2 : "";
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                if (input.charCodeAt(pos) === 125) {
                  result4 = "}";
                  pos++;
                } else {
                  result4 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"}\"");
                  }
                }
                if (result4 !== null) {
                  result0 = [result0, result1, result2, result3, result4];
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, ts) {
              return ts;
        })(pos0, result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[64] ConstructTemplate");
        }
        return result0;
      }
      
      function parse_ConstructTriples() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_TriplesSameSubject();
        if (result0 !== null) {
          pos2 = pos;
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.charCodeAt(pos) === 46) {
              result2 = ".";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\".\"");
              }
            }
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result4 = parse_ConstructTriples();
                result4 = result4 !== null ? result4 : "";
                if (result4 !== null) {
                  result1 = [result1, result2, result3, result4];
                } else {
                  result1 = null;
                  pos = pos2;
                }
              } else {
                result1 = null;
                pos = pos2;
              }
            } else {
              result1 = null;
              pos = pos2;
            }
          } else {
            result1 = null;
            pos = pos2;
          }
          result1 = result1 !== null ? result1 : "";
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, b, bs) {
             var triples = b.triplesContext;
             var toTest = null;
              if(typeof(bs) === 'object') {
                    if(bs.length != null) {
                          if(bs[3].triplesContext!=null) {
                             triples = triples.concat(bs[3].triplesContext);
                      }
                   }
              }
        
             return {token:'triplestemplate',
                     triplesContext: triples}
        })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[65] ConstructTriples");
        }
        return result0;
      }
      
      function parse_TriplesSameSubject() {
        var result0, result1, result2, result3;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          result1 = parse_VarOrTerm();
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result3 = parse_PropertyListNotEmpty();
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, s, pairs) {
              var triplesContext = pairs.triplesContext;
              var subject = s;
              if(pairs.pairs) {
                for(var i=0; i< pairs.pairs.length; i++) {
                    var pair = pairs.pairs[i];
                    var triple = null;
        	    if(pair[1].length != null)
        	      pair[1] = pair[1][0]
                    if(subject.token && subject.token==='triplesnodecollection') {
                        triple = {subject: subject.chainSubject[0], predicate: pair[0], object: pair[1]}
                        triplesContext.push(triple);
                        triplesContext = triplesContext.concat(subject.triplesContext);
                    } else {
                        triple = {subject: subject, predicate: pair[0], object: pair[1]}
                        triplesContext.push(triple);
                    }
                }
              }
        
              var token = {};
              token.token = "triplessamesubject";
              token.triplesContext = triplesContext;
              token.chainSubject = subject;
        
              return token;
          })(pos0, result0[1], result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          pos1 = pos;
          result0 = [];
          result1 = parse_WS();
          while (result1 !== null) {
            result0.push(result1);
            result1 = parse_WS();
          }
          if (result0 !== null) {
            result1 = parse_TriplesNode();
            if (result1 !== null) {
              result2 = [];
              result3 = parse_WS();
              while (result3 !== null) {
                result2.push(result3);
                result3 = parse_WS();
              }
              if (result2 !== null) {
                result3 = parse_PropertyList();
                if (result3 !== null) {
                  result0 = [result0, result1, result2, result3];
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
          if (result0 !== null) {
            result0 = (function(offset, tn, pairs) {
                var triplesContext = tn.triplesContext;
                var subject = tn.chainSubject;
          
                if(pairs.pairs) {
                  for(var i=0; i< pairs.pairs.length; i++) {
                      var pair = pairs.pairs[i];
                      if(pair[1].length != null)
          	      pair[1] = pair[1][0]
          
                      if(tn.token === "triplesnodecollection") {
                          for(var j=0; j<subject.length; j++) {
                              var subj = subject[j];
                              if(subj.triplesContext != null) {
                                  var triple = {subject: subj.chainSubject, predicate: pair[0], object: pair[1]}
                                  triplesContext.concat(subj.triplesContext);
                              } else {
                                  var triple = {subject: subject[j], predicate: pair[0], object: pair[1]}
                                  triplesContext.push(triple);
                              }
                          }
                      } else {
                          var triple = {subject: subject, predicate: pair[0], object: pair[1]}
                          triplesContext.push(triple);
                      }
                  }
                }
          
                var token = {};
                token.token = "triplessamesubject";
                token.triplesContext = triplesContext;
                token.chainSubject = subject;
          
                return token;
            })(pos0, result0[1], result0[3]);
          }
          if (result0 === null) {
            pos = pos0;
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[66] TriplesSameSubject");
        }
        return result0;
      }
      
      function parse_PropertyListNotEmpty() {
        var result0, result1, result2, result3, result4, result5, result6, result7, result8, result9;
        var pos0, pos1, pos2, pos3;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_Verb();
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_ObjectList();
            if (result2 !== null) {
              result3 = [];
              pos2 = pos;
              result4 = [];
              result5 = parse_WS();
              while (result5 !== null) {
                result4.push(result5);
                result5 = parse_WS();
              }
              if (result4 !== null) {
                if (input.charCodeAt(pos) === 59) {
                  result5 = ";";
                  pos++;
                } else {
                  result5 = null;
                  if (reportFailures === 0) {
                    matchFailed("\";\"");
                  }
                }
                if (result5 !== null) {
                  result6 = [];
                  result7 = parse_WS();
                  while (result7 !== null) {
                    result6.push(result7);
                    result7 = parse_WS();
                  }
                  if (result6 !== null) {
                    pos3 = pos;
                    result7 = parse_Verb();
                    if (result7 !== null) {
                      result8 = [];
                      result9 = parse_WS();
                      while (result9 !== null) {
                        result8.push(result9);
                        result9 = parse_WS();
                      }
                      if (result8 !== null) {
                        result9 = parse_ObjectList();
                        if (result9 !== null) {
                          result7 = [result7, result8, result9];
                        } else {
                          result7 = null;
                          pos = pos3;
                        }
                      } else {
                        result7 = null;
                        pos = pos3;
                      }
                    } else {
                      result7 = null;
                      pos = pos3;
                    }
                    result7 = result7 !== null ? result7 : "";
                    if (result7 !== null) {
                      result4 = [result4, result5, result6, result7];
                    } else {
                      result4 = null;
                      pos = pos2;
                    }
                  } else {
                    result4 = null;
                    pos = pos2;
                  }
                } else {
                  result4 = null;
                  pos = pos2;
                }
              } else {
                result4 = null;
                pos = pos2;
              }
              while (result4 !== null) {
                result3.push(result4);
                pos2 = pos;
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  if (input.charCodeAt(pos) === 59) {
                    result5 = ";";
                    pos++;
                  } else {
                    result5 = null;
                    if (reportFailures === 0) {
                      matchFailed("\";\"");
                    }
                  }
                  if (result5 !== null) {
                    result6 = [];
                    result7 = parse_WS();
                    while (result7 !== null) {
                      result6.push(result7);
                      result7 = parse_WS();
                    }
                    if (result6 !== null) {
                      pos3 = pos;
                      result7 = parse_Verb();
                      if (result7 !== null) {
                        result8 = [];
                        result9 = parse_WS();
                        while (result9 !== null) {
                          result8.push(result9);
                          result9 = parse_WS();
                        }
                        if (result8 !== null) {
                          result9 = parse_ObjectList();
                          if (result9 !== null) {
                            result7 = [result7, result8, result9];
                          } else {
                            result7 = null;
                            pos = pos3;
                          }
                        } else {
                          result7 = null;
                          pos = pos3;
                        }
                      } else {
                        result7 = null;
                        pos = pos3;
                      }
                      result7 = result7 !== null ? result7 : "";
                      if (result7 !== null) {
                        result4 = [result4, result5, result6, result7];
                      } else {
                        result4 = null;
                        pos = pos2;
                      }
                    } else {
                      result4 = null;
                      pos = pos2;
                    }
                  } else {
                    result4 = null;
                    pos = pos2;
                  }
                } else {
                  result4 = null;
                  pos = pos2;
                }
              }
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, v, ol, rest) {
              var token = {}
              token.token = 'propertylist';
              var triplesContext = [];
              var pairs = [];
              var test = [];
        
              for( var i=0; i<ol.length; i++) {
        
                 if(ol[i].triplesContext != null) {
                     triplesContext = triplesContext.concat(ol[i].triplesContext);
                     if(ol[i].token==='triplesnodecollection' && ol[i].chainSubject.length != null) {
                         pairs.push([v, ol[i].chainSubject[0]]);
                     } else {
                         pairs.push([v, ol[i].chainSubject]);
                     }
        
                  } else {
                      pairs.push([v, ol[i]])
                  }
        
              }
        
        
              for(var i=0; i<rest.length; i++) {
                  var tok = rest[i][3];
                  var newVerb  = tok[0];
                  var newObjsList = tok[2] || [];
        
                  for(var j=0; j<newObjsList.length; j++) {
                   if(newObjsList[j].triplesContext != null) {
                      triplesContext = triplesContext.concat(newObjsList[j].triplesContext);
                     pairs.push([newVerb, newObjsList[j].chainSubject]);
                    } else {
                      pairs.push([newVerb, newObjsList[j]])
                    }
                  }
              }
        
              token.pairs = pairs;
              token.triplesContext = triplesContext;
        
              return token;
        
        })(pos0, result0[0], result0[2], result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[67] PropertyListNotEmpty");
        }
        return result0;
      }
      
      function parse_PropertyList() {
        var result0;
        
        reportFailures++;
        result0 = parse_PropertyListNotEmpty();
        result0 = result0 !== null ? result0 : "";
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[68] PropertyList");
        }
        return result0;
      }
      
      function parse_ObjectList() {
        var result0, result1, result2, result3, result4, result5;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_GraphNode();
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = [];
            pos2 = pos;
            if (input.charCodeAt(pos) === 44) {
              result3 = ",";
              pos++;
            } else {
              result3 = null;
              if (reportFailures === 0) {
                matchFailed("\",\"");
              }
            }
            if (result3 !== null) {
              result4 = [];
              result5 = parse_WS();
              while (result5 !== null) {
                result4.push(result5);
                result5 = parse_WS();
              }
              if (result4 !== null) {
                result5 = parse_GraphNode();
                if (result5 !== null) {
                  result3 = [result3, result4, result5];
                } else {
                  result3 = null;
                  pos = pos2;
                }
              } else {
                result3 = null;
                pos = pos2;
              }
            } else {
              result3 = null;
              pos = pos2;
            }
            while (result3 !== null) {
              result2.push(result3);
              pos2 = pos;
              if (input.charCodeAt(pos) === 44) {
                result3 = ",";
                pos++;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("\",\"");
                }
              }
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  result5 = parse_GraphNode();
                  if (result5 !== null) {
                    result3 = [result3, result4, result5];
                  } else {
                    result3 = null;
                    pos = pos2;
                  }
                } else {
                  result3 = null;
                  pos = pos2;
                }
              } else {
                result3 = null;
                pos = pos2;
              }
            }
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, obj, objs) {
        
                var toReturn = [];
        
                toReturn.push(obj);
        
                for(var i=0; i<objs.length; i++) {
                    for(var j=0; j<objs[i].length; j++) {
                        if(typeof(objs[i][j])=="object" && objs[i][j].token != null) {
                            toReturn.push(objs[i][j]);
                        }
                    }
                }
        
                return toReturn;
            })(pos0, result0[0], result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[69] ObjectList");
        }
        return result0;
      }
      
      function parse_Verb() {
        var result0;
        var pos0;
        
        reportFailures++;
        result0 = parse_VarOrIRIref();
        if (result0 === null) {
          pos0 = pos;
          if (input.charCodeAt(pos) === 97) {
            result0 = "a";
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"a\"");
            }
          }
          if (result0 !== null) {
            result0 = (function(offset) {
                return{token: 'uri', prefix:null, suffix:null, value:"http://www.w3.org/1999/02/22-rdf-syntax-ns#type"}
            })(pos0);
          }
          if (result0 === null) {
            pos = pos0;
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[71] Verb");
        }
        return result0;
      }
      
      function parse_TriplesSameSubjectPath() {
        var result0, result1, result2, result3;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          result1 = parse_VarOrTerm();
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result3 = parse_PropertyListNotEmptyPath();
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, s, pairs) {
              var triplesContext = pairs.triplesContext;
              var subject = s;
              if(pairs.pairs) {
                for(var i=0; i< pairs.pairs.length; i++) {
                    var pair = pairs.pairs[i];
                    var triple = null;
        	    if(pair[1].length != null)
        	      pair[1] = pair[1][0]
                    if(subject.token && subject.token==='triplesnodecollection') {
                        triple = {subject: subject.chainSubject[0], predicate: pair[0], object: pair[1]}
                        triplesContext.push(triple);
                        triplesContext = triplesContext.concat(subject.triplesContext);
                    } else {
                        triple = {subject: subject, predicate: pair[0], object: pair[1]}
                        triplesContext.push(triple);
                    }
                }
              }
        
              var token = {};
              token.token = "triplessamesubject";
              token.triplesContext = triplesContext;
              token.chainSubject = subject;
        
              return token;
          })(pos0, result0[1], result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          pos1 = pos;
          result0 = [];
          result1 = parse_WS();
          while (result1 !== null) {
            result0.push(result1);
            result1 = parse_WS();
          }
          if (result0 !== null) {
            result1 = parse_TriplesNode();
            if (result1 !== null) {
              result2 = [];
              result3 = parse_WS();
              while (result3 !== null) {
                result2.push(result3);
                result3 = parse_WS();
              }
              if (result2 !== null) {
                result3 = parse_PropertyListPath();
                if (result3 !== null) {
                  result0 = [result0, result1, result2, result3];
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
          if (result0 !== null) {
            result0 = (function(offset, tn, pairs) {
                var triplesContext = tn.triplesContext;
                var subject = tn.chainSubject;
          
                if(pairs.pairs) {
                  for(var i=0; i< pairs.pairs.length; i++) {
                      var pair = pairs.pairs[i];
                      if(pair[1].length != null)
          	      pair[1] = pair[1][0]
          
                      if(tn.token === "triplesnodecollection") {
                          for(var j=0; j<subject.length; j++) {
                              var subj = subject[j];
                              if(subj.triplesContext != null) {
                                  var triple = {subject: subj.chainSubject, predicate: pair[0], object: pair[1]}
                                  triplesContext.concat(subj.triplesContext);
                              } else {
                                  var triple = {subject: subject[j], predicate: pair[0], object: pair[1]}
                                  triplesContext.push(triple);
                              }
                          }
                      } else {
                          var triple = {subject: subject, predicate: pair[0], object: pair[1]}
                          triplesContext.push(triple);
                      }
                  }
                }
          
                var token = {};
                token.token = "triplessamesubject";
                token.triplesContext = triplesContext;
                token.chainSubject = subject;
          
                return token;
          
              })(pos0, result0[1], result0[3]);
          }
          if (result0 === null) {
            pos = pos0;
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[72] TriplesSameSubjectPath");
        }
        return result0;
      }
      
      function parse_PropertyListNotEmptyPath() {
        var result0, result1, result2, result3, result4, result5, result6, result7, result8;
        var pos0, pos1, pos2, pos3;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_VerbPath();
        if (result0 === null) {
          result0 = parse_Var();
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_ObjectList();
            if (result2 !== null) {
              result3 = [];
              pos2 = pos;
              result4 = [];
              result5 = parse_WS();
              while (result5 !== null) {
                result4.push(result5);
                result5 = parse_WS();
              }
              if (result4 !== null) {
                if (input.charCodeAt(pos) === 59) {
                  result5 = ";";
                  pos++;
                } else {
                  result5 = null;
                  if (reportFailures === 0) {
                    matchFailed("\";\"");
                  }
                }
                if (result5 !== null) {
                  result6 = [];
                  result7 = parse_WS();
                  while (result7 !== null) {
                    result6.push(result7);
                    result7 = parse_WS();
                  }
                  if (result6 !== null) {
                    pos3 = pos;
                    result7 = parse_VerbPath();
                    if (result7 === null) {
                      result7 = parse_Var();
                    }
                    if (result7 !== null) {
                      result8 = parse_ObjectList();
                      if (result8 !== null) {
                        result7 = [result7, result8];
                      } else {
                        result7 = null;
                        pos = pos3;
                      }
                    } else {
                      result7 = null;
                      pos = pos3;
                    }
                    result7 = result7 !== null ? result7 : "";
                    if (result7 !== null) {
                      result4 = [result4, result5, result6, result7];
                    } else {
                      result4 = null;
                      pos = pos2;
                    }
                  } else {
                    result4 = null;
                    pos = pos2;
                  }
                } else {
                  result4 = null;
                  pos = pos2;
                }
              } else {
                result4 = null;
                pos = pos2;
              }
              while (result4 !== null) {
                result3.push(result4);
                pos2 = pos;
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  if (input.charCodeAt(pos) === 59) {
                    result5 = ";";
                    pos++;
                  } else {
                    result5 = null;
                    if (reportFailures === 0) {
                      matchFailed("\";\"");
                    }
                  }
                  if (result5 !== null) {
                    result6 = [];
                    result7 = parse_WS();
                    while (result7 !== null) {
                      result6.push(result7);
                      result7 = parse_WS();
                    }
                    if (result6 !== null) {
                      pos3 = pos;
                      result7 = parse_VerbPath();
                      if (result7 === null) {
                        result7 = parse_Var();
                      }
                      if (result7 !== null) {
                        result8 = parse_ObjectList();
                        if (result8 !== null) {
                          result7 = [result7, result8];
                        } else {
                          result7 = null;
                          pos = pos3;
                        }
                      } else {
                        result7 = null;
                        pos = pos3;
                      }
                      result7 = result7 !== null ? result7 : "";
                      if (result7 !== null) {
                        result4 = [result4, result5, result6, result7];
                      } else {
                        result4 = null;
                        pos = pos2;
                      }
                    } else {
                      result4 = null;
                      pos = pos2;
                    }
                  } else {
                    result4 = null;
                    pos = pos2;
                  }
                } else {
                  result4 = null;
                  pos = pos2;
                }
              }
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, v, ol, rest) {
              token = {}
              token.token = 'propertylist';
              var triplesContext = [];
              var pairs = [];
              var test = [];
        
              for( var i=0; i<ol.length; i++) {
        
                 if(ol[i].triplesContext != null) {
                     triplesContext = triplesContext.concat(ol[i].triplesContext);
                     if(ol[i].token==='triplesnodecollection' && ol[i].chainSubject.length != null) {
                         pairs.push([v, ol[i].chainSubject[0]]);
                     } else {
                         pairs.push([v, ol[i].chainSubject]);
                     }
        
                  } else {
                      pairs.push([v, ol[i]])
                  }
        
              }
        
        
              for(var i=0; i<rest.length; i++) {
                  var tok = rest[i][3];
                  var newVerb  = tok[0];
                  var newObjsList = tok[1] || [];
        
                  for(var j=0; j<newObjsList.length; j++) {
                   if(newObjsList[j].triplesContext != null) {
                      triplesContext = triplesContext.concat(newObjsList[j].triplesContext);
                     pairs.push([newVerb, newObjsList[j].chainSubject]);
                    } else {
                      pairs.push([newVerb, newObjsList[j]])
                    }
                  }
              }
        
              token.pairs = pairs;
              token.triplesContext = triplesContext;
        
              return token;
        })(pos0, result0[0], result0[2], result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[73] PropertyListNotEmptyPath");
        }
        return result0;
      }
      
      function parse_PropertyListPath() {
        var result0;
        
        reportFailures++;
        result0 = parse_PropertyListNotEmpty();
        result0 = result0 !== null ? result0 : "";
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[74] PropertyListPath");
        }
        return result0;
      }
      
      function parse_VerbPath() {
        var result0;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        result0 = parse_PathAlternative();
        if (result0 !== null) {
          result0 = (function(offset, p) {
              var path = {};
              path.token = 'path';
              path.kind = 'element';
              path.value = p;
        
              return p;
          })(pos0, result0);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[75]");
        }
        return result0;
      }
      
      function parse_PathAlternative() {
        var result0, result1, result2, result3;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_PathSequence();
        if (result0 !== null) {
          result1 = [];
          pos2 = pos;
          if (input.charCodeAt(pos) === 124) {
            result2 = "|";
            pos++;
          } else {
            result2 = null;
            if (reportFailures === 0) {
              matchFailed("\"|\"");
            }
          }
          if (result2 !== null) {
            result3 = parse_PathSequence();
            if (result3 !== null) {
              result2 = [result2, result3];
            } else {
              result2 = null;
              pos = pos2;
            }
          } else {
            result2 = null;
            pos = pos2;
          }
          while (result2 !== null) {
            result1.push(result2);
            pos2 = pos;
            if (input.charCodeAt(pos) === 124) {
              result2 = "|";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"|\"");
              }
            }
            if (result2 !== null) {
              result3 = parse_PathSequence();
              if (result3 !== null) {
                result2 = [result2, result3];
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, first, rest) {
        	if(rest == null || rest.length === 0) {
        	    return first;
        	} else {
        	    var acum = [];
        	    for(var i=0; i<rest.length; i++)
        		acum.push(rest[1]);
        
        	    var path = {};
        	    path.token = 'path';
        	    path.kind = 'alternative';
        	    path.value = acum;
        
        	    return path;
        	}
            })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[78] PathAlternative");
        }
        return result0;
      }
      
      function parse_PathSequence() {
        var result0, result1, result2, result3;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_PathEltOrInverse();
        if (result0 !== null) {
          result1 = [];
          pos2 = pos;
          if (input.charCodeAt(pos) === 47) {
            result2 = "/";
            pos++;
          } else {
            result2 = null;
            if (reportFailures === 0) {
              matchFailed("\"/\"");
            }
          }
          if (result2 !== null) {
            result3 = parse_PathEltOrInverse();
            if (result3 !== null) {
              result2 = [result2, result3];
            } else {
              result2 = null;
              pos = pos2;
            }
          } else {
            result2 = null;
            pos = pos2;
          }
          while (result2 !== null) {
            result1.push(result2);
            pos2 = pos;
            if (input.charCodeAt(pos) === 47) {
              result2 = "/";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"/\"");
              }
            }
            if (result2 !== null) {
              result3 = parse_PathEltOrInverse();
              if (result3 !== null) {
                result2 = [result2, result3];
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, first, rest) {
        	if(rest == null || rest.length === 0) {
        	    return first;
        	} else {
        	    var acum = [first];
        
        	    for(var i=0; i<rest.length; i++) 
        		acum.push(rest[i][1]);
        
        	    var path = {};
        	    path.token = 'path';
        	    path.kind = 'sequence';
        	
        	    path.value = acum;
        		
        	    return path;
        	}
            })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[79] PathSequence");
        }
        return result0;
      }
      
      function parse_PathElt() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_PathPrimary();
        if (result0 !== null) {
          result1 = parse_PathMod();
          result1 = result1 !== null ? result1 : "";
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, p, mod) {
        	if(p.token && p.token != 'path' && mod == '') {
        	    return p;
        	} else if(p.token && p.token != path && mod != '') {
        	    var path = {};
        	    path.token = 'path';
        	    path.kind = 'element';
        	    path.value = p;
        	    path.modifier = mod;
        	    return path;
        	} else {
        	    p.modifier = mod;
        	    return p;
        	}
            })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[88] PathElt");
        }
        return result0;
      }
      
      function parse_PathEltOrInverse() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        result0 = parse_PathElt();
        if (result0 === null) {
          pos0 = pos;
          pos1 = pos;
          if (input.charCodeAt(pos) === 94) {
            result0 = "^";
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"^\"");
            }
          }
          if (result0 !== null) {
            result1 = parse_PathElt();
            if (result1 !== null) {
              result0 = [result0, result1];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
          if (result0 !== null) {
            result0 = (function(offset, elt) {
          	var path = {};
          	path.token = 'path';
          	path.kind = 'inversePath';
          	path.value = elt;
          
          	return path;
              })(pos0, result0[1]);
          }
          if (result0 === null) {
            pos = pos0;
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[81] PathEltOrInverse");
        }
        return result0;
      }
      
      function parse_PathMod() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1, pos2, pos3;
        
        reportFailures++;
        if (input.charCodeAt(pos) === 42) {
          result0 = "*";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"*\"");
          }
        }
        if (result0 === null) {
          if (input.charCodeAt(pos) === 63) {
            result0 = "?";
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"?\"");
            }
          }
          if (result0 === null) {
            if (input.charCodeAt(pos) === 43) {
              result0 = "+";
              pos++;
            } else {
              result0 = null;
              if (reportFailures === 0) {
                matchFailed("\"+\"");
              }
            }
            if (result0 === null) {
              pos0 = pos;
              if (input.charCodeAt(pos) === 123) {
                result0 = "{";
                pos++;
              } else {
                result0 = null;
                if (reportFailures === 0) {
                  matchFailed("\"{\"");
                }
              }
              if (result0 !== null) {
                pos1 = pos;
                result1 = parse_INTEGER();
                if (result1 !== null) {
                  pos2 = pos;
                  if (input.charCodeAt(pos) === 44) {
                    result2 = ",";
                    pos++;
                  } else {
                    result2 = null;
                    if (reportFailures === 0) {
                      matchFailed("\",\"");
                    }
                  }
                  if (result2 !== null) {
                    if (input.charCodeAt(pos) === 125) {
                      result3 = "}";
                      pos++;
                    } else {
                      result3 = null;
                      if (reportFailures === 0) {
                        matchFailed("\"}\"");
                      }
                    }
                    if (result3 === null) {
                      pos3 = pos;
                      result3 = parse_INTEGER();
                      if (result3 !== null) {
                        if (input.charCodeAt(pos) === 125) {
                          result4 = "}";
                          pos++;
                        } else {
                          result4 = null;
                          if (reportFailures === 0) {
                            matchFailed("\"}\"");
                          }
                        }
                        if (result4 !== null) {
                          result3 = [result3, result4];
                        } else {
                          result3 = null;
                          pos = pos3;
                        }
                      } else {
                        result3 = null;
                        pos = pos3;
                      }
                    }
                    if (result3 !== null) {
                      result2 = [result2, result3];
                    } else {
                      result2 = null;
                      pos = pos2;
                    }
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                  if (result2 === null) {
                    if (input.charCodeAt(pos) === 125) {
                      result2 = "}";
                      pos++;
                    } else {
                      result2 = null;
                      if (reportFailures === 0) {
                        matchFailed("\"}\"");
                      }
                    }
                  }
                  if (result2 !== null) {
                    result1 = [result1, result2];
                  } else {
                    result1 = null;
                    pos = pos1;
                  }
                } else {
                  result1 = null;
                  pos = pos1;
                }
                if (result1 === null) {
                  pos1 = pos;
                  if (input.charCodeAt(pos) === 44) {
                    result1 = ",";
                    pos++;
                  } else {
                    result1 = null;
                    if (reportFailures === 0) {
                      matchFailed("\",\"");
                    }
                  }
                  if (result1 !== null) {
                    result2 = parse_INTEGER();
                    if (result2 !== null) {
                      if (input.charCodeAt(pos) === 125) {
                        result3 = "}";
                        pos++;
                      } else {
                        result3 = null;
                        if (reportFailures === 0) {
                          matchFailed("\"}\"");
                        }
                      }
                      if (result3 !== null) {
                        result1 = [result1, result2, result3];
                      } else {
                        result1 = null;
                        pos = pos1;
                      }
                    } else {
                      result1 = null;
                      pos = pos1;
                    }
                  } else {
                    result1 = null;
                    pos = pos1;
                  }
                }
                if (result1 !== null) {
                  result0 = [result0, result1];
                } else {
                  result0 = null;
                  pos = pos0;
                }
              } else {
                result0 = null;
                pos = pos0;
              }
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[82] PathMod");
        }
        return result0;
      }
      
      function parse_PathPrimary() {
        var result0, result1, result2;
        var pos0, pos1;
        
        reportFailures++;
        result0 = parse_IRIref();
        if (result0 === null) {
          pos0 = pos;
          if (input.charCodeAt(pos) === 97) {
            result0 = "a";
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"a\"");
            }
          }
          if (result0 !== null) {
            result0 = (function(offset) {
          	return{token: 'uri', prefix:null, suffix:null, value:"http://www.w3.org/1999/02/22-rdf-syntax-ns#type"}
              })(pos0);
          }
          if (result0 === null) {
            pos = pos0;
          }
          if (result0 === null) {
            pos0 = pos;
            if (input.charCodeAt(pos) === 33) {
              result0 = "!";
              pos++;
            } else {
              result0 = null;
              if (reportFailures === 0) {
                matchFailed("\"!\"");
              }
            }
            if (result0 !== null) {
              result1 = parse_PathNegatedPropertySet();
              if (result1 !== null) {
                result0 = [result0, result1];
              } else {
                result0 = null;
                pos = pos0;
              }
            } else {
              result0 = null;
              pos = pos0;
            }
            if (result0 === null) {
              pos0 = pos;
              pos1 = pos;
              if (input.charCodeAt(pos) === 40) {
                result0 = "(";
                pos++;
              } else {
                result0 = null;
                if (reportFailures === 0) {
                  matchFailed("\"(\"");
                }
              }
              if (result0 !== null) {
                result1 = parse_PathAlternative();
                if (result1 !== null) {
                  if (input.charCodeAt(pos) === 41) {
                    result2 = ")";
                    pos++;
                  } else {
                    result2 = null;
                    if (reportFailures === 0) {
                      matchFailed("\")\"");
                    }
                  }
                  if (result2 !== null) {
                    result0 = [result0, result1, result2];
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
              if (result0 !== null) {
                result0 = (function(offset, p) {
              	return p;
                  })(pos0, result0[1]);
              }
              if (result0 === null) {
                pos = pos0;
              }
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[83] PathPrimary");
        }
        return result0;
      }
      
      function parse_PathNegatedPropertySet() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1, pos2;
        
        result0 = parse_PathOneInPropertySet();
        if (result0 === null) {
          pos0 = pos;
          if (input.charCodeAt(pos) === 40) {
            result0 = "(";
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"(\"");
            }
          }
          if (result0 !== null) {
            pos1 = pos;
            result1 = parse_PathOneInPropertySet();
            if (result1 !== null) {
              result2 = [];
              pos2 = pos;
              if (input.charCodeAt(pos) === 124) {
                result3 = "|";
                pos++;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("\"|\"");
                }
              }
              if (result3 !== null) {
                result4 = parse_PathOneInPropertySet();
                if (result4 !== null) {
                  result3 = [result3, result4];
                } else {
                  result3 = null;
                  pos = pos2;
                }
              } else {
                result3 = null;
                pos = pos2;
              }
              while (result3 !== null) {
                result2.push(result3);
                pos2 = pos;
                if (input.charCodeAt(pos) === 124) {
                  result3 = "|";
                  pos++;
                } else {
                  result3 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"|\"");
                  }
                }
                if (result3 !== null) {
                  result4 = parse_PathOneInPropertySet();
                  if (result4 !== null) {
                    result3 = [result3, result4];
                  } else {
                    result3 = null;
                    pos = pos2;
                  }
                } else {
                  result3 = null;
                  pos = pos2;
                }
              }
              if (result2 !== null) {
                result1 = [result1, result2];
              } else {
                result1 = null;
                pos = pos1;
              }
            } else {
              result1 = null;
              pos = pos1;
            }
            result1 = result1 !== null ? result1 : "";
            if (result1 !== null) {
              if (input.charCodeAt(pos) === 41) {
                result2 = ")";
                pos++;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("\")\"");
                }
              }
              if (result2 !== null) {
                result0 = [result0, result1, result2];
              } else {
                result0 = null;
                pos = pos0;
              }
            } else {
              result0 = null;
              pos = pos0;
            }
          } else {
            result0 = null;
            pos = pos0;
          }
        }
        return result0;
      }
      
      function parse_PathOneInPropertySet() {
        var result0, result1;
        var pos0;
        
        reportFailures++;
        result0 = parse_IRIref();
        if (result0 === null) {
          if (input.charCodeAt(pos) === 97) {
            result0 = "a";
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"a\"");
            }
          }
          if (result0 === null) {
            pos0 = pos;
            if (input.charCodeAt(pos) === 94) {
              result0 = "^";
              pos++;
            } else {
              result0 = null;
              if (reportFailures === 0) {
                matchFailed("\"^\"");
              }
            }
            if (result0 !== null) {
              result1 = parse_IRIref();
              if (result1 === null) {
                if (input.charCodeAt(pos) === 97) {
                  result1 = "a";
                  pos++;
                } else {
                  result1 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"a\"");
                  }
                }
              }
              if (result1 !== null) {
                result0 = [result0, result1];
              } else {
                result0 = null;
                pos = pos0;
              }
            } else {
              result0 = null;
              pos = pos0;
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[85] PathOneInPropertySet");
        }
        return result0;
      }
      
      function parse_TriplesNode() {
        var result0;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        result0 = parse_Collection();
        if (result0 !== null) {
          result0 = (function(offset, c) {
              var triplesContext = [];
              var chainSubject = [];
        
              var triple = null;
        
              // catch NIL
              /*
              if(c.length == 1 && c[0].token && c[0].token === 'nil') {
                  GlobalBlankNodeCounter++;
                  return  {token: "triplesnodecollection", 
                           triplesContext:[{subject: {token:'blank', value:("_:"+GlobalBlankNodeCounter)},
                                            predicate:{token:'uri', prefix:null, suffix:null, value:'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest'},
                                            object:  {token:'blank', value:("_:"+(GlobalBlankNodeCounter+1))}}], 
                           chainSubject:{token:'blank', value:("_:"+GlobalBlankNodeCounter)}};
        
              }
              */
        
              // other cases
              for(var i=0; i<c.length; i++) {
                  GlobalBlankNodeCounter++;
                  //_:b0  rdf:first  1 ;
                  //rdf:rest   _:b1 .
                  var nextObject = null;
                  if(c[i].chainSubject == null && c[i].triplesContext == null) {
                      nextObject = c[i];
                  } else {
                      nextObject = c[i].chainSubject;
                      triplesContext = triplesContext.concat(nextSubject.triplesContext);
                  }
                  var currentSubject = null;
                  triple = {subject: {token:'blank', value:("_:"+GlobalBlankNodeCounter)},
                            predicate:{token:'uri', prefix:null, suffix:null, value:'http://www.w3.org/1999/02/22-rdf-syntax-ns#first'},
                            object:nextObject };
        
                  if(i==0) {
                      chainSubject.push(triple.subject);
                  }
        
                  triplesContext.push(triple);
        
                  if(i===(c.length-1)) {
                      triple = {subject: {token:'blank', value:("_:"+GlobalBlankNodeCounter)},
                                predicate:{token:'uri', prefix:null, suffix:null, value:'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest'},
                                object:   {token:'uri', prefix:null, suffix:null, value:'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'}};
                  } else {
                      triple = {subject: {token:'blank', value:("_:"+GlobalBlankNodeCounter)},
                                predicate:{token:'uri', prefix:null, suffix:null, value:'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest'},
                                object:  {token:'blank', value:("_:"+(GlobalBlankNodeCounter+1))} };
                  }
        
                  triplesContext.push(triple);
              }
        
              return {token:"triplesnodecollection", triplesContext:triplesContext, chainSubject:chainSubject};
        })(pos0, result0);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          result0 = parse_BlankNodePropertyList();
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[87] TriplesNode");
        }
        return result0;
      }
      
      function parse_BlankNodePropertyList() {
        var result0, result1, result2, result3, result4, result5, result6, result7;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          if (input.charCodeAt(pos) === 91) {
            result1 = "[";
            pos++;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\"[\"");
            }
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result3 = parse_PropertyListNotEmpty();
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  if (input.charCodeAt(pos) === 93) {
                    result5 = "]";
                    pos++;
                  } else {
                    result5 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"]\"");
                    }
                  }
                  if (result5 !== null) {
                    result6 = [];
                    result7 = parse_WS();
                    while (result7 !== null) {
                      result6.push(result7);
                      result7 = parse_WS();
                    }
                    if (result6 !== null) {
                      result0 = [result0, result1, result2, result3, result4, result5, result6];
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, pl) {
        
              GlobalBlankNodeCounter++;
              var subject = {token:'blank', value:'_:'+GlobalBlankNodeCounter};
              var newTriples =  [];
        
              for(var i=0; i< pl.pairs.length; i++) {
                  var pair = pl.pairs[i];
                  var triple = {}
                  triple.subject = subject;
                  triple.predicate = pair[0];
                  if(pair[1].length != null)
        	    pair[1] = pair[1][0]
                  triple.object = pair[1];
                  newTriples.push(triple);
              }
        
              return {token: 'triplesnode',
                      kind: 'blanknodepropertylist',
                      triplesContext: pl.triplesContext.concat(newTriples),
                      chainSubject: subject};
        })(pos0, result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[88] BlankNodePropertyList");
        }
        return result0;
      }
      
      function parse_Collection() {
        var result0, result1, result2, result3, result4, result5, result6, result7;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          if (input.charCodeAt(pos) === 40) {
            result1 = "(";
            pos++;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\"(\"");
            }
          }
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result4 = parse_GraphNode();
              if (result4 !== null) {
                result3 = [];
                while (result4 !== null) {
                  result3.push(result4);
                  result4 = parse_GraphNode();
                }
              } else {
                result3 = null;
              }
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  if (input.charCodeAt(pos) === 41) {
                    result5 = ")";
                    pos++;
                  } else {
                    result5 = null;
                    if (reportFailures === 0) {
                      matchFailed("\")\"");
                    }
                  }
                  if (result5 !== null) {
                    result6 = [];
                    result7 = parse_WS();
                    while (result7 !== null) {
                      result6.push(result7);
                      result7 = parse_WS();
                    }
                    if (result6 !== null) {
                      result0 = [result0, result1, result2, result3, result4, result5, result6];
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, gn) {
              return gn;
        })(pos0, result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[89] Collection");
        }
        return result0;
      }
      
      function parse_GraphNode() {
        var result0, result1, result2, result3;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = [];
        result1 = parse_WS();
        while (result1 !== null) {
          result0.push(result1);
          result1 = parse_WS();
        }
        if (result0 !== null) {
          result1 = parse_VarOrTerm();
          if (result1 !== null) {
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 === null) {
          pos1 = pos;
          result0 = [];
          result1 = parse_WS();
          while (result1 !== null) {
            result0.push(result1);
            result1 = parse_WS();
          }
          if (result0 !== null) {
            result1 = parse_TriplesNode();
            if (result1 !== null) {
              result2 = [];
              result3 = parse_WS();
              while (result3 !== null) {
                result2.push(result3);
                result3 = parse_WS();
              }
              if (result2 !== null) {
                result0 = [result0, result1, result2];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        }
        if (result0 !== null) {
          result0 = (function(offset, gn) {
          return gn[1];
        })(pos0, result0);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[90] GraphNode");
        }
        return result0;
      }
      
      function parse_VarOrTerm() {
        var result0;
        
        reportFailures++;
        result0 = parse_Var();
        if (result0 === null) {
          result0 = parse_GraphTerm();
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[91] VarOrTerm");
        }
        return result0;
      }
      
      function parse_VarOrIRIref() {
        var result0;
        
        reportFailures++;
        result0 = parse_Var();
        if (result0 === null) {
          result0 = parse_IRIref();
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[92] VarOrIRIref");
        }
        return result0;
      }
      
      function parse_Var() {
        var result0;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        result0 = parse_VAR1();
        if (result0 === null) {
          result0 = parse_VAR2();
        }
        if (result0 !== null) {
          result0 = (function(offset, v) {
              var term = {};
              term.token = 'var';
              term.value = v;
              return term;
          })(pos0, result0);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[93] Var");
        }
        return result0;
      }
      
      function parse_GraphTerm() {
        var result0;
        
        reportFailures++;
        result0 = parse_IRIref();
        if (result0 === null) {
          result0 = parse_RDFLiteral();
          if (result0 === null) {
            result0 = parse_NumericLiteral();
            if (result0 === null) {
              result0 = parse_BooleanLiteral();
              if (result0 === null) {
                result0 = parse_BlankNode();
                if (result0 === null) {
                  result0 = parse_NIL();
                }
              }
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[94] GraphTerm");
        }
        return result0;
      }
      
      function parse_ConditionalOrExpression() {
        var result0, result1, result2, result3, result4, result5;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_ConditionalAndExpression();
        if (result0 !== null) {
          result1 = [];
          pos2 = pos;
          result2 = [];
          result3 = parse_WS();
          while (result3 !== null) {
            result2.push(result3);
            result3 = parse_WS();
          }
          if (result2 !== null) {
            if (input.substr(pos, 2) === "||") {
              result3 = "||";
              pos += 2;
            } else {
              result3 = null;
              if (reportFailures === 0) {
                matchFailed("\"||\"");
              }
            }
            if (result3 !== null) {
              result4 = [];
              result5 = parse_WS();
              while (result5 !== null) {
                result4.push(result5);
                result5 = parse_WS();
              }
              if (result4 !== null) {
                result5 = parse_ConditionalAndExpression();
                if (result5 !== null) {
                  result2 = [result2, result3, result4, result5];
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
          } else {
            result2 = null;
            pos = pos2;
          }
          while (result2 !== null) {
            result1.push(result2);
            pos2 = pos;
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              if (input.substr(pos, 2) === "||") {
                result3 = "||";
                pos += 2;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("\"||\"");
                }
              }
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  result5 = parse_ConditionalAndExpression();
                  if (result5 !== null) {
                    result2 = [result2, result3, result4, result5];
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, v, vs) {
              if(vs.length === 0) {
                  return v;
              }
        
              var exp = {};
              exp.token = "expression";
              exp.expressionType = "conditionalor";
              var ops = [v];
        
              for(var i=0; i<vs.length; i++) {
                  ops.push(vs[i][3]);
              }
        
              exp.operands = ops;
        
              return exp;
        })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[96] ConditionalOrExpression");
        }
        return result0;
      }
      
      function parse_ConditionalAndExpression() {
        var result0, result1, result2, result3, result4, result5;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_RelationalExpression();
        if (result0 !== null) {
          result1 = [];
          pos2 = pos;
          result2 = [];
          result3 = parse_WS();
          while (result3 !== null) {
            result2.push(result3);
            result3 = parse_WS();
          }
          if (result2 !== null) {
            if (input.substr(pos, 2) === "&&") {
              result3 = "&&";
              pos += 2;
            } else {
              result3 = null;
              if (reportFailures === 0) {
                matchFailed("\"&&\"");
              }
            }
            if (result3 !== null) {
              result4 = [];
              result5 = parse_WS();
              while (result5 !== null) {
                result4.push(result5);
                result5 = parse_WS();
              }
              if (result4 !== null) {
                result5 = parse_RelationalExpression();
                if (result5 !== null) {
                  result2 = [result2, result3, result4, result5];
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
          } else {
            result2 = null;
            pos = pos2;
          }
          while (result2 !== null) {
            result1.push(result2);
            pos2 = pos;
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              if (input.substr(pos, 2) === "&&") {
                result3 = "&&";
                pos += 2;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("\"&&\"");
                }
              }
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  result5 = parse_RelationalExpression();
                  if (result5 !== null) {
                    result2 = [result2, result3, result4, result5];
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, v, vs) {
              if(vs.length === 0) {
                  return v;
              }
              var exp = {};
              exp.token = "expression";
              exp.expressionType = "conditionaland";
              var ops = [v];
        
              for(var i=0; i<vs.length; i++) {
                  ops.push(vs[i][3]);
              }
        
              exp.operands = ops;
        
              return exp;
        })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[97] ConditionalAndExpression");
        }
        return result0;
      }
      
      function parse_RelationalExpression() {
        var result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_AdditiveExpression();
        if (result0 !== null) {
          result1 = [];
          pos2 = pos;
          result2 = [];
          result3 = parse_WS();
          while (result3 !== null) {
            result2.push(result3);
            result3 = parse_WS();
          }
          if (result2 !== null) {
            if (input.charCodeAt(pos) === 61) {
              result3 = "=";
              pos++;
            } else {
              result3 = null;
              if (reportFailures === 0) {
                matchFailed("\"=\"");
              }
            }
            if (result3 !== null) {
              result4 = [];
              result5 = parse_WS();
              while (result5 !== null) {
                result4.push(result5);
                result5 = parse_WS();
              }
              if (result4 !== null) {
                result5 = parse_AdditiveExpression();
                if (result5 !== null) {
                  result2 = [result2, result3, result4, result5];
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
          } else {
            result2 = null;
            pos = pos2;
          }
          if (result2 === null) {
            pos2 = pos;
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              if (input.substr(pos, 2) === "!=") {
                result3 = "!=";
                pos += 2;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("\"!=\"");
                }
              }
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  result5 = parse_AdditiveExpression();
                  if (result5 !== null) {
                    result2 = [result2, result3, result4, result5];
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
            if (result2 === null) {
              pos2 = pos;
              result2 = [];
              result3 = parse_WS();
              while (result3 !== null) {
                result2.push(result3);
                result3 = parse_WS();
              }
              if (result2 !== null) {
                if (input.charCodeAt(pos) === 60) {
                  result3 = "<";
                  pos++;
                } else {
                  result3 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"<\"");
                  }
                }
                if (result3 !== null) {
                  result4 = [];
                  result5 = parse_WS();
                  while (result5 !== null) {
                    result4.push(result5);
                    result5 = parse_WS();
                  }
                  if (result4 !== null) {
                    result5 = parse_AdditiveExpression();
                    if (result5 !== null) {
                      result2 = [result2, result3, result4, result5];
                    } else {
                      result2 = null;
                      pos = pos2;
                    }
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
              if (result2 === null) {
                pos2 = pos;
                result2 = [];
                result3 = parse_WS();
                while (result3 !== null) {
                  result2.push(result3);
                  result3 = parse_WS();
                }
                if (result2 !== null) {
                  if (input.charCodeAt(pos) === 62) {
                    result3 = ">";
                    pos++;
                  } else {
                    result3 = null;
                    if (reportFailures === 0) {
                      matchFailed("\">\"");
                    }
                  }
                  if (result3 !== null) {
                    result4 = [];
                    result5 = parse_WS();
                    while (result5 !== null) {
                      result4.push(result5);
                      result5 = parse_WS();
                    }
                    if (result4 !== null) {
                      result5 = parse_AdditiveExpression();
                      if (result5 !== null) {
                        result2 = [result2, result3, result4, result5];
                      } else {
                        result2 = null;
                        pos = pos2;
                      }
                    } else {
                      result2 = null;
                      pos = pos2;
                    }
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
                if (result2 === null) {
                  pos2 = pos;
                  result2 = [];
                  result3 = parse_WS();
                  while (result3 !== null) {
                    result2.push(result3);
                    result3 = parse_WS();
                  }
                  if (result2 !== null) {
                    if (input.substr(pos, 2) === "<=") {
                      result3 = "<=";
                      pos += 2;
                    } else {
                      result3 = null;
                      if (reportFailures === 0) {
                        matchFailed("\"<=\"");
                      }
                    }
                    if (result3 !== null) {
                      result4 = [];
                      result5 = parse_WS();
                      while (result5 !== null) {
                        result4.push(result5);
                        result5 = parse_WS();
                      }
                      if (result4 !== null) {
                        result5 = parse_AdditiveExpression();
                        if (result5 !== null) {
                          result2 = [result2, result3, result4, result5];
                        } else {
                          result2 = null;
                          pos = pos2;
                        }
                      } else {
                        result2 = null;
                        pos = pos2;
                      }
                    } else {
                      result2 = null;
                      pos = pos2;
                    }
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                  if (result2 === null) {
                    pos2 = pos;
                    result2 = [];
                    result3 = parse_WS();
                    while (result3 !== null) {
                      result2.push(result3);
                      result3 = parse_WS();
                    }
                    if (result2 !== null) {
                      if (input.substr(pos, 2) === ">=") {
                        result3 = ">=";
                        pos += 2;
                      } else {
                        result3 = null;
                        if (reportFailures === 0) {
                          matchFailed("\">=\"");
                        }
                      }
                      if (result3 !== null) {
                        result4 = [];
                        result5 = parse_WS();
                        while (result5 !== null) {
                          result4.push(result5);
                          result5 = parse_WS();
                        }
                        if (result4 !== null) {
                          result5 = parse_AdditiveExpression();
                          if (result5 !== null) {
                            result2 = [result2, result3, result4, result5];
                          } else {
                            result2 = null;
                            pos = pos2;
                          }
                        } else {
                          result2 = null;
                          pos = pos2;
                        }
                      } else {
                        result2 = null;
                        pos = pos2;
                      }
                    } else {
                      result2 = null;
                      pos = pos2;
                    }
                    if (result2 === null) {
                      pos2 = pos;
                      result2 = [];
                      result3 = parse_WS();
                      while (result3 !== null) {
                        result2.push(result3);
                        result3 = parse_WS();
                      }
                      if (result2 !== null) {
                        if (input.charCodeAt(pos) === 73) {
                          result3 = "I";
                          pos++;
                        } else {
                          result3 = null;
                          if (reportFailures === 0) {
                            matchFailed("\"I\"");
                          }
                        }
                        if (result3 === null) {
                          if (input.charCodeAt(pos) === 105) {
                            result3 = "i";
                            pos++;
                          } else {
                            result3 = null;
                            if (reportFailures === 0) {
                              matchFailed("\"i\"");
                            }
                          }
                        }
                        if (result3 !== null) {
                          if (input.charCodeAt(pos) === 78) {
                            result4 = "N";
                            pos++;
                          } else {
                            result4 = null;
                            if (reportFailures === 0) {
                              matchFailed("\"N\"");
                            }
                          }
                          if (result4 === null) {
                            if (input.charCodeAt(pos) === 110) {
                              result4 = "n";
                              pos++;
                            } else {
                              result4 = null;
                              if (reportFailures === 0) {
                                matchFailed("\"n\"");
                              }
                            }
                          }
                          if (result4 !== null) {
                            result5 = [];
                            result6 = parse_WS();
                            while (result6 !== null) {
                              result5.push(result6);
                              result6 = parse_WS();
                            }
                            if (result5 !== null) {
                              result6 = parse_ExpressionList();
                              if (result6 !== null) {
                                result2 = [result2, result3, result4, result5, result6];
                              } else {
                                result2 = null;
                                pos = pos2;
                              }
                            } else {
                              result2 = null;
                              pos = pos2;
                            }
                          } else {
                            result2 = null;
                            pos = pos2;
                          }
                        } else {
                          result2 = null;
                          pos = pos2;
                        }
                      } else {
                        result2 = null;
                        pos = pos2;
                      }
                      if (result2 === null) {
                        pos2 = pos;
                        result2 = [];
                        result3 = parse_WS();
                        while (result3 !== null) {
                          result2.push(result3);
                          result3 = parse_WS();
                        }
                        if (result2 !== null) {
                          if (input.charCodeAt(pos) === 78) {
                            result3 = "N";
                            pos++;
                          } else {
                            result3 = null;
                            if (reportFailures === 0) {
                              matchFailed("\"N\"");
                            }
                          }
                          if (result3 === null) {
                            if (input.charCodeAt(pos) === 110) {
                              result3 = "n";
                              pos++;
                            } else {
                              result3 = null;
                              if (reportFailures === 0) {
                                matchFailed("\"n\"");
                              }
                            }
                          }
                          if (result3 !== null) {
                            if (input.charCodeAt(pos) === 79) {
                              result4 = "O";
                              pos++;
                            } else {
                              result4 = null;
                              if (reportFailures === 0) {
                                matchFailed("\"O\"");
                              }
                            }
                            if (result4 === null) {
                              if (input.charCodeAt(pos) === 111) {
                                result4 = "o";
                                pos++;
                              } else {
                                result4 = null;
                                if (reportFailures === 0) {
                                  matchFailed("\"o\"");
                                }
                              }
                            }
                            if (result4 !== null) {
                              if (input.charCodeAt(pos) === 84) {
                                result5 = "T";
                                pos++;
                              } else {
                                result5 = null;
                                if (reportFailures === 0) {
                                  matchFailed("\"T\"");
                                }
                              }
                              if (result5 === null) {
                                if (input.charCodeAt(pos) === 116) {
                                  result5 = "t";
                                  pos++;
                                } else {
                                  result5 = null;
                                  if (reportFailures === 0) {
                                    matchFailed("\"t\"");
                                  }
                                }
                              }
                              if (result5 !== null) {
                                result6 = [];
                                result7 = parse_WS();
                                while (result7 !== null) {
                                  result6.push(result7);
                                  result7 = parse_WS();
                                }
                                if (result6 !== null) {
                                  if (input.charCodeAt(pos) === 73) {
                                    result7 = "I";
                                    pos++;
                                  } else {
                                    result7 = null;
                                    if (reportFailures === 0) {
                                      matchFailed("\"I\"");
                                    }
                                  }
                                  if (result7 === null) {
                                    if (input.charCodeAt(pos) === 105) {
                                      result7 = "i";
                                      pos++;
                                    } else {
                                      result7 = null;
                                      if (reportFailures === 0) {
                                        matchFailed("\"i\"");
                                      }
                                    }
                                  }
                                  if (result7 !== null) {
                                    if (input.charCodeAt(pos) === 78) {
                                      result8 = "N";
                                      pos++;
                                    } else {
                                      result8 = null;
                                      if (reportFailures === 0) {
                                        matchFailed("\"N\"");
                                      }
                                    }
                                    if (result8 === null) {
                                      if (input.charCodeAt(pos) === 110) {
                                        result8 = "n";
                                        pos++;
                                      } else {
                                        result8 = null;
                                        if (reportFailures === 0) {
                                          matchFailed("\"n\"");
                                        }
                                      }
                                    }
                                    if (result8 !== null) {
                                      result9 = [];
                                      result10 = parse_WS();
                                      while (result10 !== null) {
                                        result9.push(result10);
                                        result10 = parse_WS();
                                      }
                                      if (result9 !== null) {
                                        result10 = parse_ExpressionList();
                                        if (result10 !== null) {
                                          result2 = [result2, result3, result4, result5, result6, result7, result8, result9, result10];
                                        } else {
                                          result2 = null;
                                          pos = pos2;
                                        }
                                      } else {
                                        result2 = null;
                                        pos = pos2;
                                      }
                                    } else {
                                      result2 = null;
                                      pos = pos2;
                                    }
                                  } else {
                                    result2 = null;
                                    pos = pos2;
                                  }
                                } else {
                                  result2 = null;
                                  pos = pos2;
                                }
                              } else {
                                result2 = null;
                                pos = pos2;
                              }
                            } else {
                              result2 = null;
                              pos = pos2;
                            }
                          } else {
                            result2 = null;
                            pos = pos2;
                          }
                        } else {
                          result2 = null;
                          pos = pos2;
                        }
                      }
                    }
                  }
                }
              }
            }
          }
          while (result2 !== null) {
            result1.push(result2);
            pos2 = pos;
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              if (input.charCodeAt(pos) === 61) {
                result3 = "=";
                pos++;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("\"=\"");
                }
              }
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  result5 = parse_AdditiveExpression();
                  if (result5 !== null) {
                    result2 = [result2, result3, result4, result5];
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
            if (result2 === null) {
              pos2 = pos;
              result2 = [];
              result3 = parse_WS();
              while (result3 !== null) {
                result2.push(result3);
                result3 = parse_WS();
              }
              if (result2 !== null) {
                if (input.substr(pos, 2) === "!=") {
                  result3 = "!=";
                  pos += 2;
                } else {
                  result3 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"!=\"");
                  }
                }
                if (result3 !== null) {
                  result4 = [];
                  result5 = parse_WS();
                  while (result5 !== null) {
                    result4.push(result5);
                    result5 = parse_WS();
                  }
                  if (result4 !== null) {
                    result5 = parse_AdditiveExpression();
                    if (result5 !== null) {
                      result2 = [result2, result3, result4, result5];
                    } else {
                      result2 = null;
                      pos = pos2;
                    }
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
              if (result2 === null) {
                pos2 = pos;
                result2 = [];
                result3 = parse_WS();
                while (result3 !== null) {
                  result2.push(result3);
                  result3 = parse_WS();
                }
                if (result2 !== null) {
                  if (input.charCodeAt(pos) === 60) {
                    result3 = "<";
                    pos++;
                  } else {
                    result3 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"<\"");
                    }
                  }
                  if (result3 !== null) {
                    result4 = [];
                    result5 = parse_WS();
                    while (result5 !== null) {
                      result4.push(result5);
                      result5 = parse_WS();
                    }
                    if (result4 !== null) {
                      result5 = parse_AdditiveExpression();
                      if (result5 !== null) {
                        result2 = [result2, result3, result4, result5];
                      } else {
                        result2 = null;
                        pos = pos2;
                      }
                    } else {
                      result2 = null;
                      pos = pos2;
                    }
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
                if (result2 === null) {
                  pos2 = pos;
                  result2 = [];
                  result3 = parse_WS();
                  while (result3 !== null) {
                    result2.push(result3);
                    result3 = parse_WS();
                  }
                  if (result2 !== null) {
                    if (input.charCodeAt(pos) === 62) {
                      result3 = ">";
                      pos++;
                    } else {
                      result3 = null;
                      if (reportFailures === 0) {
                        matchFailed("\">\"");
                      }
                    }
                    if (result3 !== null) {
                      result4 = [];
                      result5 = parse_WS();
                      while (result5 !== null) {
                        result4.push(result5);
                        result5 = parse_WS();
                      }
                      if (result4 !== null) {
                        result5 = parse_AdditiveExpression();
                        if (result5 !== null) {
                          result2 = [result2, result3, result4, result5];
                        } else {
                          result2 = null;
                          pos = pos2;
                        }
                      } else {
                        result2 = null;
                        pos = pos2;
                      }
                    } else {
                      result2 = null;
                      pos = pos2;
                    }
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                  if (result2 === null) {
                    pos2 = pos;
                    result2 = [];
                    result3 = parse_WS();
                    while (result3 !== null) {
                      result2.push(result3);
                      result3 = parse_WS();
                    }
                    if (result2 !== null) {
                      if (input.substr(pos, 2) === "<=") {
                        result3 = "<=";
                        pos += 2;
                      } else {
                        result3 = null;
                        if (reportFailures === 0) {
                          matchFailed("\"<=\"");
                        }
                      }
                      if (result3 !== null) {
                        result4 = [];
                        result5 = parse_WS();
                        while (result5 !== null) {
                          result4.push(result5);
                          result5 = parse_WS();
                        }
                        if (result4 !== null) {
                          result5 = parse_AdditiveExpression();
                          if (result5 !== null) {
                            result2 = [result2, result3, result4, result5];
                          } else {
                            result2 = null;
                            pos = pos2;
                          }
                        } else {
                          result2 = null;
                          pos = pos2;
                        }
                      } else {
                        result2 = null;
                        pos = pos2;
                      }
                    } else {
                      result2 = null;
                      pos = pos2;
                    }
                    if (result2 === null) {
                      pos2 = pos;
                      result2 = [];
                      result3 = parse_WS();
                      while (result3 !== null) {
                        result2.push(result3);
                        result3 = parse_WS();
                      }
                      if (result2 !== null) {
                        if (input.substr(pos, 2) === ">=") {
                          result3 = ">=";
                          pos += 2;
                        } else {
                          result3 = null;
                          if (reportFailures === 0) {
                            matchFailed("\">=\"");
                          }
                        }
                        if (result3 !== null) {
                          result4 = [];
                          result5 = parse_WS();
                          while (result5 !== null) {
                            result4.push(result5);
                            result5 = parse_WS();
                          }
                          if (result4 !== null) {
                            result5 = parse_AdditiveExpression();
                            if (result5 !== null) {
                              result2 = [result2, result3, result4, result5];
                            } else {
                              result2 = null;
                              pos = pos2;
                            }
                          } else {
                            result2 = null;
                            pos = pos2;
                          }
                        } else {
                          result2 = null;
                          pos = pos2;
                        }
                      } else {
                        result2 = null;
                        pos = pos2;
                      }
                      if (result2 === null) {
                        pos2 = pos;
                        result2 = [];
                        result3 = parse_WS();
                        while (result3 !== null) {
                          result2.push(result3);
                          result3 = parse_WS();
                        }
                        if (result2 !== null) {
                          if (input.charCodeAt(pos) === 73) {
                            result3 = "I";
                            pos++;
                          } else {
                            result3 = null;
                            if (reportFailures === 0) {
                              matchFailed("\"I\"");
                            }
                          }
                          if (result3 === null) {
                            if (input.charCodeAt(pos) === 105) {
                              result3 = "i";
                              pos++;
                            } else {
                              result3 = null;
                              if (reportFailures === 0) {
                                matchFailed("\"i\"");
                              }
                            }
                          }
                          if (result3 !== null) {
                            if (input.charCodeAt(pos) === 78) {
                              result4 = "N";
                              pos++;
                            } else {
                              result4 = null;
                              if (reportFailures === 0) {
                                matchFailed("\"N\"");
                              }
                            }
                            if (result4 === null) {
                              if (input.charCodeAt(pos) === 110) {
                                result4 = "n";
                                pos++;
                              } else {
                                result4 = null;
                                if (reportFailures === 0) {
                                  matchFailed("\"n\"");
                                }
                              }
                            }
                            if (result4 !== null) {
                              result5 = [];
                              result6 = parse_WS();
                              while (result6 !== null) {
                                result5.push(result6);
                                result6 = parse_WS();
                              }
                              if (result5 !== null) {
                                result6 = parse_ExpressionList();
                                if (result6 !== null) {
                                  result2 = [result2, result3, result4, result5, result6];
                                } else {
                                  result2 = null;
                                  pos = pos2;
                                }
                              } else {
                                result2 = null;
                                pos = pos2;
                              }
                            } else {
                              result2 = null;
                              pos = pos2;
                            }
                          } else {
                            result2 = null;
                            pos = pos2;
                          }
                        } else {
                          result2 = null;
                          pos = pos2;
                        }
                        if (result2 === null) {
                          pos2 = pos;
                          result2 = [];
                          result3 = parse_WS();
                          while (result3 !== null) {
                            result2.push(result3);
                            result3 = parse_WS();
                          }
                          if (result2 !== null) {
                            if (input.charCodeAt(pos) === 78) {
                              result3 = "N";
                              pos++;
                            } else {
                              result3 = null;
                              if (reportFailures === 0) {
                                matchFailed("\"N\"");
                              }
                            }
                            if (result3 === null) {
                              if (input.charCodeAt(pos) === 110) {
                                result3 = "n";
                                pos++;
                              } else {
                                result3 = null;
                                if (reportFailures === 0) {
                                  matchFailed("\"n\"");
                                }
                              }
                            }
                            if (result3 !== null) {
                              if (input.charCodeAt(pos) === 79) {
                                result4 = "O";
                                pos++;
                              } else {
                                result4 = null;
                                if (reportFailures === 0) {
                                  matchFailed("\"O\"");
                                }
                              }
                              if (result4 === null) {
                                if (input.charCodeAt(pos) === 111) {
                                  result4 = "o";
                                  pos++;
                                } else {
                                  result4 = null;
                                  if (reportFailures === 0) {
                                    matchFailed("\"o\"");
                                  }
                                }
                              }
                              if (result4 !== null) {
                                if (input.charCodeAt(pos) === 84) {
                                  result5 = "T";
                                  pos++;
                                } else {
                                  result5 = null;
                                  if (reportFailures === 0) {
                                    matchFailed("\"T\"");
                                  }
                                }
                                if (result5 === null) {
                                  if (input.charCodeAt(pos) === 116) {
                                    result5 = "t";
                                    pos++;
                                  } else {
                                    result5 = null;
                                    if (reportFailures === 0) {
                                      matchFailed("\"t\"");
                                    }
                                  }
                                }
                                if (result5 !== null) {
                                  result6 = [];
                                  result7 = parse_WS();
                                  while (result7 !== null) {
                                    result6.push(result7);
                                    result7 = parse_WS();
                                  }
                                  if (result6 !== null) {
                                    if (input.charCodeAt(pos) === 73) {
                                      result7 = "I";
                                      pos++;
                                    } else {
                                      result7 = null;
                                      if (reportFailures === 0) {
                                        matchFailed("\"I\"");
                                      }
                                    }
                                    if (result7 === null) {
                                      if (input.charCodeAt(pos) === 105) {
                                        result7 = "i";
                                        pos++;
                                      } else {
                                        result7 = null;
                                        if (reportFailures === 0) {
                                          matchFailed("\"i\"");
                                        }
                                      }
                                    }
                                    if (result7 !== null) {
                                      if (input.charCodeAt(pos) === 78) {
                                        result8 = "N";
                                        pos++;
                                      } else {
                                        result8 = null;
                                        if (reportFailures === 0) {
                                          matchFailed("\"N\"");
                                        }
                                      }
                                      if (result8 === null) {
                                        if (input.charCodeAt(pos) === 110) {
                                          result8 = "n";
                                          pos++;
                                        } else {
                                          result8 = null;
                                          if (reportFailures === 0) {
                                            matchFailed("\"n\"");
                                          }
                                        }
                                      }
                                      if (result8 !== null) {
                                        result9 = [];
                                        result10 = parse_WS();
                                        while (result10 !== null) {
                                          result9.push(result10);
                                          result10 = parse_WS();
                                        }
                                        if (result9 !== null) {
                                          result10 = parse_ExpressionList();
                                          if (result10 !== null) {
                                            result2 = [result2, result3, result4, result5, result6, result7, result8, result9, result10];
                                          } else {
                                            result2 = null;
                                            pos = pos2;
                                          }
                                        } else {
                                          result2 = null;
                                          pos = pos2;
                                        }
                                      } else {
                                        result2 = null;
                                        pos = pos2;
                                      }
                                    } else {
                                      result2 = null;
                                      pos = pos2;
                                    }
                                  } else {
                                    result2 = null;
                                    pos = pos2;
                                  }
                                } else {
                                  result2 = null;
                                  pos = pos2;
                                }
                              } else {
                                result2 = null;
                                pos = pos2;
                              }
                            } else {
                              result2 = null;
                              pos = pos2;
                            }
                          } else {
                            result2 = null;
                            pos = pos2;
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, op1, op2) {
              if(op2.length === 0) {
                  return op1;
              } else if(op2[0][1] === 'i' || op2[0][1] === 'I' || op2[0][1] === 'n' || op2[0][1] === 'N'){
                var exp = {};
        
                if(op2[0][1] === 'i' || op2[0][1] === 'I') {
                  var operator = "=";
                  exp.expressionType = "conditionalor"         
                } else {
                  var operator = "!=";
                  exp.expressionType = "conditionaland"         
                }
                var lop = op1;
                var rops = []
                for(var opi=0; opi<op2[0].length; opi++) {
                  if(op2[0][opi].token ==="args") {
                    rops = op2[0][opi].value;
                    break;
                  }
                }       
        
                exp.token = "expression";
                exp.operands = [];
                for(var i=0; i<rops.length; i++) {
                  var nextOperand = {};
                  nextOperand.token = "expression";
                  nextOperand.expressionType = "relationalexpression";
                  nextOperand.operator = operator;
                  nextOperand.op1 = lop;
                  nextOperand.op2 = rops[i];
        
                  exp.operands.push(nextOperand);
                }       
                return exp;
              } else {
                var exp = {};
                exp.expressionType = "relationalexpression"
                exp.operator = op2[0][1];
                exp.op1 = op1;
                exp.op2 = op2[0][3];
                exp.token = "expression";
        
                return exp;
              }
          })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[99] RelationalExpression");
        }
        return result0;
      }
      
      function parse_AdditiveExpression() {
        var result0, result1, result2, result3, result4, result5, result6;
        var pos0, pos1, pos2, pos3;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_MultiplicativeExpression();
        if (result0 !== null) {
          result1 = [];
          pos2 = pos;
          result2 = [];
          result3 = parse_WS();
          while (result3 !== null) {
            result2.push(result3);
            result3 = parse_WS();
          }
          if (result2 !== null) {
            if (input.charCodeAt(pos) === 43) {
              result3 = "+";
              pos++;
            } else {
              result3 = null;
              if (reportFailures === 0) {
                matchFailed("\"+\"");
              }
            }
            if (result3 !== null) {
              result4 = [];
              result5 = parse_WS();
              while (result5 !== null) {
                result4.push(result5);
                result5 = parse_WS();
              }
              if (result4 !== null) {
                result5 = parse_MultiplicativeExpression();
                if (result5 !== null) {
                  result2 = [result2, result3, result4, result5];
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
          } else {
            result2 = null;
            pos = pos2;
          }
          if (result2 === null) {
            pos2 = pos;
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              if (input.charCodeAt(pos) === 45) {
                result3 = "-";
                pos++;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("\"-\"");
                }
              }
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  result5 = parse_MultiplicativeExpression();
                  if (result5 !== null) {
                    result2 = [result2, result3, result4, result5];
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
            if (result2 === null) {
              pos2 = pos;
              result2 = parse_NumericLiteralNegative();
              if (result2 === null) {
                result2 = parse_NumericLiteralNegative();
              }
              if (result2 !== null) {
                pos3 = pos;
                result3 = [];
                result4 = parse_WS();
                while (result4 !== null) {
                  result3.push(result4);
                  result4 = parse_WS();
                }
                if (result3 !== null) {
                  if (input.charCodeAt(pos) === 42) {
                    result4 = "*";
                    pos++;
                  } else {
                    result4 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"*\"");
                    }
                  }
                  if (result4 !== null) {
                    result5 = [];
                    result6 = parse_WS();
                    while (result6 !== null) {
                      result5.push(result6);
                      result6 = parse_WS();
                    }
                    if (result5 !== null) {
                      result6 = parse_UnaryExpression();
                      if (result6 !== null) {
                        result3 = [result3, result4, result5, result6];
                      } else {
                        result3 = null;
                        pos = pos3;
                      }
                    } else {
                      result3 = null;
                      pos = pos3;
                    }
                  } else {
                    result3 = null;
                    pos = pos3;
                  }
                } else {
                  result3 = null;
                  pos = pos3;
                }
                if (result3 === null) {
                  pos3 = pos;
                  result3 = [];
                  result4 = parse_WS();
                  while (result4 !== null) {
                    result3.push(result4);
                    result4 = parse_WS();
                  }
                  if (result3 !== null) {
                    if (input.charCodeAt(pos) === 47) {
                      result4 = "/";
                      pos++;
                    } else {
                      result4 = null;
                      if (reportFailures === 0) {
                        matchFailed("\"/\"");
                      }
                    }
                    if (result4 !== null) {
                      result5 = [];
                      result6 = parse_WS();
                      while (result6 !== null) {
                        result5.push(result6);
                        result6 = parse_WS();
                      }
                      if (result5 !== null) {
                        result6 = parse_UnaryExpression();
                        if (result6 !== null) {
                          result3 = [result3, result4, result5, result6];
                        } else {
                          result3 = null;
                          pos = pos3;
                        }
                      } else {
                        result3 = null;
                        pos = pos3;
                      }
                    } else {
                      result3 = null;
                      pos = pos3;
                    }
                  } else {
                    result3 = null;
                    pos = pos3;
                  }
                }
                result3 = result3 !== null ? result3 : "";
                if (result3 !== null) {
                  result2 = [result2, result3];
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            }
          }
          while (result2 !== null) {
            result1.push(result2);
            pos2 = pos;
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              if (input.charCodeAt(pos) === 43) {
                result3 = "+";
                pos++;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("\"+\"");
                }
              }
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  result5 = parse_MultiplicativeExpression();
                  if (result5 !== null) {
                    result2 = [result2, result3, result4, result5];
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
            if (result2 === null) {
              pos2 = pos;
              result2 = [];
              result3 = parse_WS();
              while (result3 !== null) {
                result2.push(result3);
                result3 = parse_WS();
              }
              if (result2 !== null) {
                if (input.charCodeAt(pos) === 45) {
                  result3 = "-";
                  pos++;
                } else {
                  result3 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"-\"");
                  }
                }
                if (result3 !== null) {
                  result4 = [];
                  result5 = parse_WS();
                  while (result5 !== null) {
                    result4.push(result5);
                    result5 = parse_WS();
                  }
                  if (result4 !== null) {
                    result5 = parse_MultiplicativeExpression();
                    if (result5 !== null) {
                      result2 = [result2, result3, result4, result5];
                    } else {
                      result2 = null;
                      pos = pos2;
                    }
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
              if (result2 === null) {
                pos2 = pos;
                result2 = parse_NumericLiteralNegative();
                if (result2 === null) {
                  result2 = parse_NumericLiteralNegative();
                }
                if (result2 !== null) {
                  pos3 = pos;
                  result3 = [];
                  result4 = parse_WS();
                  while (result4 !== null) {
                    result3.push(result4);
                    result4 = parse_WS();
                  }
                  if (result3 !== null) {
                    if (input.charCodeAt(pos) === 42) {
                      result4 = "*";
                      pos++;
                    } else {
                      result4 = null;
                      if (reportFailures === 0) {
                        matchFailed("\"*\"");
                      }
                    }
                    if (result4 !== null) {
                      result5 = [];
                      result6 = parse_WS();
                      while (result6 !== null) {
                        result5.push(result6);
                        result6 = parse_WS();
                      }
                      if (result5 !== null) {
                        result6 = parse_UnaryExpression();
                        if (result6 !== null) {
                          result3 = [result3, result4, result5, result6];
                        } else {
                          result3 = null;
                          pos = pos3;
                        }
                      } else {
                        result3 = null;
                        pos = pos3;
                      }
                    } else {
                      result3 = null;
                      pos = pos3;
                    }
                  } else {
                    result3 = null;
                    pos = pos3;
                  }
                  if (result3 === null) {
                    pos3 = pos;
                    result3 = [];
                    result4 = parse_WS();
                    while (result4 !== null) {
                      result3.push(result4);
                      result4 = parse_WS();
                    }
                    if (result3 !== null) {
                      if (input.charCodeAt(pos) === 47) {
                        result4 = "/";
                        pos++;
                      } else {
                        result4 = null;
                        if (reportFailures === 0) {
                          matchFailed("\"/\"");
                        }
                      }
                      if (result4 !== null) {
                        result5 = [];
                        result6 = parse_WS();
                        while (result6 !== null) {
                          result5.push(result6);
                          result6 = parse_WS();
                        }
                        if (result5 !== null) {
                          result6 = parse_UnaryExpression();
                          if (result6 !== null) {
                            result3 = [result3, result4, result5, result6];
                          } else {
                            result3 = null;
                            pos = pos3;
                          }
                        } else {
                          result3 = null;
                          pos = pos3;
                        }
                      } else {
                        result3 = null;
                        pos = pos3;
                      }
                    } else {
                      result3 = null;
                      pos = pos3;
                    }
                  }
                  result3 = result3 !== null ? result3 : "";
                  if (result3 !== null) {
                    result2 = [result2, result3];
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
              }
            }
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, op1, ops) {
              if(ops.length === 0) {
                  return op1;
              }
        
              var ex = {};
              ex.token = 'expression';
              ex.expressionType = 'additiveexpression';
              ex.summand = op1;
              ex.summands = [];
        
              for(var i=0; i<ops.length; i++) {
                  var summand = ops[i];
                  var sum = {};
                  if(summand.length == 4 && typeof(summand[1]) === "string") {
                      sum.operator = summand[1];
                      sum.expression = summand[3];
                  } else {
                      var subexp = {}
                      var firstFactor = sum[0];
                      var operator = sum[1][1];
                      var secondFactor = sum[1][3];
                      var operator = null;
                      if(firstFactor.value < 0) {
                          sum.operator = '-';
                          firstFactor.value = - firstFactor.value;
                      } else {
                          sum.operator = '+';
                      }
                      subexp.token = 'expression';
                      subexp.expressionType = 'multiplicativeexpression';
                      subexp.operator = firstFactor;
                      subexp.factors = [{operator: operator, expression: secondFactor}];
        
                      sum.expression = subexp;
                  }
                  ex.summands.push(sum);
              }
        
              return ex;
        })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[101] AdditiveExpression");
        }
        return result0;
      }
      
      function parse_MultiplicativeExpression() {
        var result0, result1, result2, result3, result4, result5;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_UnaryExpression();
        if (result0 !== null) {
          result1 = [];
          pos2 = pos;
          result2 = [];
          result3 = parse_WS();
          while (result3 !== null) {
            result2.push(result3);
            result3 = parse_WS();
          }
          if (result2 !== null) {
            if (input.charCodeAt(pos) === 42) {
              result3 = "*";
              pos++;
            } else {
              result3 = null;
              if (reportFailures === 0) {
                matchFailed("\"*\"");
              }
            }
            if (result3 !== null) {
              result4 = [];
              result5 = parse_WS();
              while (result5 !== null) {
                result4.push(result5);
                result5 = parse_WS();
              }
              if (result4 !== null) {
                result5 = parse_UnaryExpression();
                if (result5 !== null) {
                  result2 = [result2, result3, result4, result5];
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
          } else {
            result2 = null;
            pos = pos2;
          }
          if (result2 === null) {
            pos2 = pos;
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              if (input.charCodeAt(pos) === 47) {
                result3 = "/";
                pos++;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("\"/\"");
                }
              }
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  result5 = parse_UnaryExpression();
                  if (result5 !== null) {
                    result2 = [result2, result3, result4, result5];
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
          }
          while (result2 !== null) {
            result1.push(result2);
            pos2 = pos;
            result2 = [];
            result3 = parse_WS();
            while (result3 !== null) {
              result2.push(result3);
              result3 = parse_WS();
            }
            if (result2 !== null) {
              if (input.charCodeAt(pos) === 42) {
                result3 = "*";
                pos++;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("\"*\"");
                }
              }
              if (result3 !== null) {
                result4 = [];
                result5 = parse_WS();
                while (result5 !== null) {
                  result4.push(result5);
                  result5 = parse_WS();
                }
                if (result4 !== null) {
                  result5 = parse_UnaryExpression();
                  if (result5 !== null) {
                    result2 = [result2, result3, result4, result5];
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
            if (result2 === null) {
              pos2 = pos;
              result2 = [];
              result3 = parse_WS();
              while (result3 !== null) {
                result2.push(result3);
                result3 = parse_WS();
              }
              if (result2 !== null) {
                if (input.charCodeAt(pos) === 47) {
                  result3 = "/";
                  pos++;
                } else {
                  result3 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"/\"");
                  }
                }
                if (result3 !== null) {
                  result4 = [];
                  result5 = parse_WS();
                  while (result5 !== null) {
                    result4.push(result5);
                    result5 = parse_WS();
                  }
                  if (result4 !== null) {
                    result5 = parse_UnaryExpression();
                    if (result5 !== null) {
                      result2 = [result2, result3, result4, result5];
                    } else {
                      result2 = null;
                      pos = pos2;
                    }
                  } else {
                    result2 = null;
                    pos = pos2;
                  }
                } else {
                  result2 = null;
                  pos = pos2;
                }
              } else {
                result2 = null;
                pos = pos2;
              }
            }
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, exp, exps) {
              if(exps.length === 0) {
                  return exp;
              }
        
              var ex = {};
              ex.token = 'expression';
              ex.expressionType = 'multiplicativeexpression';
              ex.factor = exp;
              ex.factors = [];
              for(var i=0; i<exps.length; i++) {
                  var factor = exps[i];
                  var fact = {};
                  fact.operator = factor[1];
                  fact.expression = factor[3];
                  ex.factors.push(fact);
              }
        
              return ex;
        })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[102] MultiplicativeExpression");
        }
        return result0;
      }
      
      function parse_UnaryExpression() {
        var result0, result1, result2;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 33) {
          result0 = "!";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"!\"");
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_PrimaryExpression();
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, e) {
              var ex = {};
              ex.token = 'expression';
              ex.expressionType = 'unaryexpression';
              ex.unaryexpression = "!";
              ex.expression = e;
        
              return ex;
          })(pos0, result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          pos1 = pos;
          if (input.charCodeAt(pos) === 43) {
            result0 = "+";
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"+\"");
            }
          }
          if (result0 !== null) {
            result1 = [];
            result2 = parse_WS();
            while (result2 !== null) {
              result1.push(result2);
              result2 = parse_WS();
            }
            if (result1 !== null) {
              result2 = parse_PrimaryExpression();
              if (result2 !== null) {
                result0 = [result0, result1, result2];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
          if (result0 !== null) {
            result0 = (function(offset, v) {
                var ex = {};
                ex.token = 'expression';
                ex.expressionType = 'unaryexpression';
                ex.unaryexpression = "+";
                ex.expression = v;
          
                return ex;
            })(pos0, result0[2]);
          }
          if (result0 === null) {
            pos = pos0;
          }
          if (result0 === null) {
            pos0 = pos;
            pos1 = pos;
            if (input.charCodeAt(pos) === 45) {
              result0 = "-";
              pos++;
            } else {
              result0 = null;
              if (reportFailures === 0) {
                matchFailed("\"-\"");
              }
            }
            if (result0 !== null) {
              result1 = [];
              result2 = parse_WS();
              while (result2 !== null) {
                result1.push(result2);
                result2 = parse_WS();
              }
              if (result1 !== null) {
                result2 = parse_PrimaryExpression();
                if (result2 !== null) {
                  result0 = [result0, result1, result2];
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
            if (result0 !== null) {
              result0 = (function(offset, v) {
                  var ex = {};
                  ex.token = 'expression';
                  ex.expressionType = 'unaryexpression';
                  ex.unaryexpression = "-";
                  ex.expression = v;
            
                  return ex;
              })(pos0, result0[2]);
            }
            if (result0 === null) {
              pos = pos0;
            }
            if (result0 === null) {
              result0 = parse_PrimaryExpression();
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[103] UnaryExpression");
        }
        return result0;
      }
      
      function parse_PrimaryExpression() {
        var result0;
        var pos0;
        
        reportFailures++;
        result0 = parse_BrackettedExpression();
        if (result0 === null) {
          result0 = parse_BuiltInCall();
          if (result0 === null) {
            result0 = parse_IRIrefOrFunction();
            if (result0 === null) {
              pos0 = pos;
              result0 = parse_RDFLiteral();
              if (result0 !== null) {
                result0 = (function(offset, v) {
                    var ex = {};
                    ex.token = 'expression';
                    ex.expressionType = 'atomic';
                    ex.primaryexpression = 'rdfliteral';
                    ex.value = v;
              
                    return ex;
                })(pos0, result0);
              }
              if (result0 === null) {
                pos = pos0;
              }
              if (result0 === null) {
                pos0 = pos;
                result0 = parse_NumericLiteral();
                if (result0 !== null) {
                  result0 = (function(offset, v) {
                      var ex = {};
                      ex.token = 'expression';
                      ex.expressionType = 'atomic';
                      ex.primaryexpression = 'numericliteral';
                      ex.value = v;
                
                      return ex;
                  })(pos0, result0);
                }
                if (result0 === null) {
                  pos = pos0;
                }
                if (result0 === null) {
                  pos0 = pos;
                  result0 = parse_BooleanLiteral();
                  if (result0 !== null) {
                    result0 = (function(offset, v) {
                        var ex = {};
                        ex.token = 'expression';
                        ex.expressionType = 'atomic';
                        ex.primaryexpression = 'booleanliteral';
                        ex.value = v;
                  
                        return ex;
                    })(pos0, result0);
                  }
                  if (result0 === null) {
                    pos = pos0;
                  }
                  if (result0 === null) {
                    result0 = parse_Aggregate();
                    if (result0 === null) {
                      pos0 = pos;
                      result0 = parse_Var();
                      if (result0 !== null) {
                        result0 = (function(offset, v) {
                            var ex = {};
                            ex.token = 'expression';
                            ex.expressionType = 'atomic';
                            ex.primaryexpression = 'var';
                            ex.value = v;
                      
                            return ex;
                        })(pos0, result0);
                      }
                      if (result0 === null) {
                        pos = pos0;
                      }
                    }
                  }
                }
              }
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[104] PrimaryExpression");
        }
        return result0;
      }
      
      function parse_BrackettedExpression() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 40) {
          result0 = "(";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"(\"");
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_ConditionalOrExpression();
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                if (input.charCodeAt(pos) === 41) {
                  result4 = ")";
                  pos++;
                } else {
                  result4 = null;
                  if (reportFailures === 0) {
                    matchFailed("\")\"");
                  }
                }
                if (result4 !== null) {
                  result0 = [result0, result1, result2, result3, result4];
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, e) {
              return e;
        })(pos0, result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[105] BrackettedExpression");
        }
        return result0;
      }
      
      function parse_BuiltInCall() {
        var result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13, result14;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 3) === "STR") {
          result0 = "STR";
          pos += 3;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"STR\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 3) === "str") {
            result0 = "str";
            pos += 3;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"str\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.charCodeAt(pos) === 40) {
              result2 = "(";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"(\"");
              }
            }
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result4 = parse_ConditionalOrExpression();
                if (result4 !== null) {
                  result5 = [];
                  result6 = parse_WS();
                  while (result6 !== null) {
                    result5.push(result6);
                    result6 = parse_WS();
                  }
                  if (result5 !== null) {
                    if (input.charCodeAt(pos) === 41) {
                      result6 = ")";
                      pos++;
                    } else {
                      result6 = null;
                      if (reportFailures === 0) {
                        matchFailed("\")\"");
                      }
                    }
                    if (result6 !== null) {
                      result0 = [result0, result1, result2, result3, result4, result5, result6];
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, e) {
              var ex = {};
              ex.token = 'expression'
              ex.expressionType = 'builtincall'
              ex.builtincall = 'str'
              ex.args = [e]
        
              return ex;
          })(pos0, result0[4]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          pos1 = pos;
          if (input.substr(pos, 4) === "LANG") {
            result0 = "LANG";
            pos += 4;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"LANG\"");
            }
          }
          if (result0 === null) {
            if (input.substr(pos, 4) === "lang") {
              result0 = "lang";
              pos += 4;
            } else {
              result0 = null;
              if (reportFailures === 0) {
                matchFailed("\"lang\"");
              }
            }
          }
          if (result0 !== null) {
            result1 = [];
            result2 = parse_WS();
            while (result2 !== null) {
              result1.push(result2);
              result2 = parse_WS();
            }
            if (result1 !== null) {
              if (input.charCodeAt(pos) === 40) {
                result2 = "(";
                pos++;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("\"(\"");
                }
              }
              if (result2 !== null) {
                result3 = [];
                result4 = parse_WS();
                while (result4 !== null) {
                  result3.push(result4);
                  result4 = parse_WS();
                }
                if (result3 !== null) {
                  result4 = parse_ConditionalOrExpression();
                  if (result4 !== null) {
                    result5 = [];
                    result6 = parse_WS();
                    while (result6 !== null) {
                      result5.push(result6);
                      result6 = parse_WS();
                    }
                    if (result5 !== null) {
                      if (input.charCodeAt(pos) === 41) {
                        result6 = ")";
                        pos++;
                      } else {
                        result6 = null;
                        if (reportFailures === 0) {
                          matchFailed("\")\"");
                        }
                      }
                      if (result6 !== null) {
                        result0 = [result0, result1, result2, result3, result4, result5, result6];
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
          if (result0 !== null) {
            result0 = (function(offset, e) {
                var ex = {};
                ex.token = 'expression'
                ex.expressionType = 'builtincall'
                ex.builtincall = 'lang'
                ex.args = [e]
          
                return ex;
          })(pos0, result0[4]);
          }
          if (result0 === null) {
            pos = pos0;
          }
          if (result0 === null) {
            pos0 = pos;
            pos1 = pos;
            if (input.substr(pos, 11) === "LANGMATCHES") {
              result0 = "LANGMATCHES";
              pos += 11;
            } else {
              result0 = null;
              if (reportFailures === 0) {
                matchFailed("\"LANGMATCHES\"");
              }
            }
            if (result0 === null) {
              if (input.substr(pos, 11) === "langmatches") {
                result0 = "langmatches";
                pos += 11;
              } else {
                result0 = null;
                if (reportFailures === 0) {
                  matchFailed("\"langmatches\"");
                }
              }
            }
            if (result0 !== null) {
              result1 = [];
              result2 = parse_WS();
              while (result2 !== null) {
                result1.push(result2);
                result2 = parse_WS();
              }
              if (result1 !== null) {
                if (input.charCodeAt(pos) === 40) {
                  result2 = "(";
                  pos++;
                } else {
                  result2 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"(\"");
                  }
                }
                if (result2 !== null) {
                  result3 = [];
                  result4 = parse_WS();
                  while (result4 !== null) {
                    result3.push(result4);
                    result4 = parse_WS();
                  }
                  if (result3 !== null) {
                    result4 = parse_ConditionalOrExpression();
                    if (result4 !== null) {
                      result5 = [];
                      result6 = parse_WS();
                      while (result6 !== null) {
                        result5.push(result6);
                        result6 = parse_WS();
                      }
                      if (result5 !== null) {
                        if (input.charCodeAt(pos) === 44) {
                          result6 = ",";
                          pos++;
                        } else {
                          result6 = null;
                          if (reportFailures === 0) {
                            matchFailed("\",\"");
                          }
                        }
                        if (result6 !== null) {
                          result7 = [];
                          result8 = parse_WS();
                          while (result8 !== null) {
                            result7.push(result8);
                            result8 = parse_WS();
                          }
                          if (result7 !== null) {
                            result8 = parse_ConditionalOrExpression();
                            if (result8 !== null) {
                              result9 = [];
                              result10 = parse_WS();
                              while (result10 !== null) {
                                result9.push(result10);
                                result10 = parse_WS();
                              }
                              if (result9 !== null) {
                                if (input.charCodeAt(pos) === 41) {
                                  result10 = ")";
                                  pos++;
                                } else {
                                  result10 = null;
                                  if (reportFailures === 0) {
                                    matchFailed("\")\"");
                                  }
                                }
                                if (result10 !== null) {
                                  result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10];
                                } else {
                                  result0 = null;
                                  pos = pos1;
                                }
                              } else {
                                result0 = null;
                                pos = pos1;
                              }
                            } else {
                              result0 = null;
                              pos = pos1;
                            }
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
            if (result0 !== null) {
              result0 = (function(offset, e1, e2) {
                  var ex = {};
                  ex.token = 'expression'
                  ex.expressionType = 'builtincall'
                  ex.builtincall = 'langmatches'
                  ex.args = [e1,e2]
            
                  return ex;
            })(pos0, result0[4], result0[8]);
            }
            if (result0 === null) {
              pos = pos0;
            }
            if (result0 === null) {
              pos0 = pos;
              pos1 = pos;
              if (input.substr(pos, 8) === "DATATYPE") {
                result0 = "DATATYPE";
                pos += 8;
              } else {
                result0 = null;
                if (reportFailures === 0) {
                  matchFailed("\"DATATYPE\"");
                }
              }
              if (result0 === null) {
                if (input.substr(pos, 8) === "datatype") {
                  result0 = "datatype";
                  pos += 8;
                } else {
                  result0 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"datatype\"");
                  }
                }
              }
              if (result0 !== null) {
                result1 = [];
                result2 = parse_WS();
                while (result2 !== null) {
                  result1.push(result2);
                  result2 = parse_WS();
                }
                if (result1 !== null) {
                  if (input.charCodeAt(pos) === 40) {
                    result2 = "(";
                    pos++;
                  } else {
                    result2 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"(\"");
                    }
                  }
                  if (result2 !== null) {
                    result3 = [];
                    result4 = parse_WS();
                    while (result4 !== null) {
                      result3.push(result4);
                      result4 = parse_WS();
                    }
                    if (result3 !== null) {
                      result4 = parse_ConditionalOrExpression();
                      if (result4 !== null) {
                        result5 = [];
                        result6 = parse_WS();
                        while (result6 !== null) {
                          result5.push(result6);
                          result6 = parse_WS();
                        }
                        if (result5 !== null) {
                          if (input.charCodeAt(pos) === 41) {
                            result6 = ")";
                            pos++;
                          } else {
                            result6 = null;
                            if (reportFailures === 0) {
                              matchFailed("\")\"");
                            }
                          }
                          if (result6 !== null) {
                            result0 = [result0, result1, result2, result3, result4, result5, result6];
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
              if (result0 !== null) {
                result0 = (function(offset, e) {
                    var ex = {};
                    ex.token = 'expression'
                    ex.expressionType = 'builtincall'
                    ex.builtincall = 'datatype'
                    ex.args = [e]
              
                    return ex;
              })(pos0, result0[4]);
              }
              if (result0 === null) {
                pos = pos0;
              }
              if (result0 === null) {
                pos0 = pos;
                pos1 = pos;
                if (input.substr(pos, 5) === "BOUND") {
                  result0 = "BOUND";
                  pos += 5;
                } else {
                  result0 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"BOUND\"");
                  }
                }
                if (result0 === null) {
                  if (input.substr(pos, 5) === "bound") {
                    result0 = "bound";
                    pos += 5;
                  } else {
                    result0 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"bound\"");
                    }
                  }
                }
                if (result0 !== null) {
                  result1 = [];
                  result2 = parse_WS();
                  while (result2 !== null) {
                    result1.push(result2);
                    result2 = parse_WS();
                  }
                  if (result1 !== null) {
                    if (input.charCodeAt(pos) === 40) {
                      result2 = "(";
                      pos++;
                    } else {
                      result2 = null;
                      if (reportFailures === 0) {
                        matchFailed("\"(\"");
                      }
                    }
                    if (result2 !== null) {
                      result3 = [];
                      result4 = parse_WS();
                      while (result4 !== null) {
                        result3.push(result4);
                        result4 = parse_WS();
                      }
                      if (result3 !== null) {
                        result4 = parse_Var();
                        if (result4 !== null) {
                          result5 = [];
                          result6 = parse_WS();
                          while (result6 !== null) {
                            result5.push(result6);
                            result6 = parse_WS();
                          }
                          if (result5 !== null) {
                            if (input.charCodeAt(pos) === 41) {
                              result6 = ")";
                              pos++;
                            } else {
                              result6 = null;
                              if (reportFailures === 0) {
                                matchFailed("\")\"");
                              }
                            }
                            if (result6 !== null) {
                              result0 = [result0, result1, result2, result3, result4, result5, result6];
                            } else {
                              result0 = null;
                              pos = pos1;
                            }
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
                if (result0 !== null) {
                  result0 = (function(offset, v) {
                      var ex = {};
                      ex.token = 'expression'
                      ex.expressionType = 'builtincall'
                      ex.builtincall = 'bound'
                      ex.args = [v]
                
                      return ex;
                })(pos0, result0[4]);
                }
                if (result0 === null) {
                  pos = pos0;
                }
                if (result0 === null) {
                  pos0 = pos;
                  pos1 = pos;
                  if (input.substr(pos, 3) === "IRI") {
                    result0 = "IRI";
                    pos += 3;
                  } else {
                    result0 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"IRI\"");
                    }
                  }
                  if (result0 === null) {
                    if (input.substr(pos, 3) === "iri") {
                      result0 = "iri";
                      pos += 3;
                    } else {
                      result0 = null;
                      if (reportFailures === 0) {
                        matchFailed("\"iri\"");
                      }
                    }
                  }
                  if (result0 !== null) {
                    result1 = [];
                    result2 = parse_WS();
                    while (result2 !== null) {
                      result1.push(result2);
                      result2 = parse_WS();
                    }
                    if (result1 !== null) {
                      if (input.charCodeAt(pos) === 40) {
                        result2 = "(";
                        pos++;
                      } else {
                        result2 = null;
                        if (reportFailures === 0) {
                          matchFailed("\"(\"");
                        }
                      }
                      if (result2 !== null) {
                        result3 = [];
                        result4 = parse_WS();
                        while (result4 !== null) {
                          result3.push(result4);
                          result4 = parse_WS();
                        }
                        if (result3 !== null) {
                          result4 = parse_ConditionalOrExpression();
                          if (result4 !== null) {
                            result5 = [];
                            result6 = parse_WS();
                            while (result6 !== null) {
                              result5.push(result6);
                              result6 = parse_WS();
                            }
                            if (result5 !== null) {
                              if (input.charCodeAt(pos) === 41) {
                                result6 = ")";
                                pos++;
                              } else {
                                result6 = null;
                                if (reportFailures === 0) {
                                  matchFailed("\")\"");
                                }
                              }
                              if (result6 !== null) {
                                result0 = [result0, result1, result2, result3, result4, result5, result6];
                              } else {
                                result0 = null;
                                pos = pos1;
                              }
                            } else {
                              result0 = null;
                              pos = pos1;
                            }
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                  if (result0 !== null) {
                    result0 = (function(offset, e) {
                        var ex = {};
                        ex.token = 'expression';
                        ex.expressionType = 'builtincall';
                        ex.builtincall = 'iri'
                        ex.args = [e];
                  
                        return ex;
                  })(pos0, result0[4]);
                  }
                  if (result0 === null) {
                    pos = pos0;
                  }
                  if (result0 === null) {
                    pos0 = pos;
                    pos1 = pos;
                    if (input.substr(pos, 3) === "URI") {
                      result0 = "URI";
                      pos += 3;
                    } else {
                      result0 = null;
                      if (reportFailures === 0) {
                        matchFailed("\"URI\"");
                      }
                    }
                    if (result0 === null) {
                      if (input.substr(pos, 3) === "uri") {
                        result0 = "uri";
                        pos += 3;
                      } else {
                        result0 = null;
                        if (reportFailures === 0) {
                          matchFailed("\"uri\"");
                        }
                      }
                    }
                    if (result0 !== null) {
                      result1 = [];
                      result2 = parse_WS();
                      while (result2 !== null) {
                        result1.push(result2);
                        result2 = parse_WS();
                      }
                      if (result1 !== null) {
                        if (input.charCodeAt(pos) === 40) {
                          result2 = "(";
                          pos++;
                        } else {
                          result2 = null;
                          if (reportFailures === 0) {
                            matchFailed("\"(\"");
                          }
                        }
                        if (result2 !== null) {
                          result3 = [];
                          result4 = parse_WS();
                          while (result4 !== null) {
                            result3.push(result4);
                            result4 = parse_WS();
                          }
                          if (result3 !== null) {
                            result4 = parse_ConditionalOrExpression();
                            if (result4 !== null) {
                              result5 = [];
                              result6 = parse_WS();
                              while (result6 !== null) {
                                result5.push(result6);
                                result6 = parse_WS();
                              }
                              if (result5 !== null) {
                                if (input.charCodeAt(pos) === 41) {
                                  result6 = ")";
                                  pos++;
                                } else {
                                  result6 = null;
                                  if (reportFailures === 0) {
                                    matchFailed("\")\"");
                                  }
                                }
                                if (result6 !== null) {
                                  result0 = [result0, result1, result2, result3, result4, result5, result6];
                                } else {
                                  result0 = null;
                                  pos = pos1;
                                }
                              } else {
                                result0 = null;
                                pos = pos1;
                              }
                            } else {
                              result0 = null;
                              pos = pos1;
                            }
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                    if (result0 !== null) {
                      result0 = (function(offset, e) {
                          var ex = {};
                          ex.token = 'expression';
                          ex.expressionType = 'builtincall';
                          ex.builtincall = 'uri'
                          ex.args = [e];
                    
                          return ex;
                    })(pos0, result0[4]);
                    }
                    if (result0 === null) {
                      pos = pos0;
                    }
                    if (result0 === null) {
                      pos0 = pos;
                      pos1 = pos;
                      if (input.substr(pos, 5) === "BNODE") {
                        result0 = "BNODE";
                        pos += 5;
                      } else {
                        result0 = null;
                        if (reportFailures === 0) {
                          matchFailed("\"BNODE\"");
                        }
                      }
                      if (result0 === null) {
                        if (input.substr(pos, 5) === "bnode") {
                          result0 = "bnode";
                          pos += 5;
                        } else {
                          result0 = null;
                          if (reportFailures === 0) {
                            matchFailed("\"bnode\"");
                          }
                        }
                      }
                      if (result0 !== null) {
                        result1 = [];
                        result2 = parse_WS();
                        while (result2 !== null) {
                          result1.push(result2);
                          result2 = parse_WS();
                        }
                        if (result1 !== null) {
                          pos2 = pos;
                          if (input.charCodeAt(pos) === 40) {
                            result2 = "(";
                            pos++;
                          } else {
                            result2 = null;
                            if (reportFailures === 0) {
                              matchFailed("\"(\"");
                            }
                          }
                          if (result2 !== null) {
                            result3 = [];
                            result4 = parse_WS();
                            while (result4 !== null) {
                              result3.push(result4);
                              result4 = parse_WS();
                            }
                            if (result3 !== null) {
                              result4 = parse_ConditionalOrExpression();
                              if (result4 !== null) {
                                result5 = [];
                                result6 = parse_WS();
                                while (result6 !== null) {
                                  result5.push(result6);
                                  result6 = parse_WS();
                                }
                                if (result5 !== null) {
                                  if (input.charCodeAt(pos) === 41) {
                                    result6 = ")";
                                    pos++;
                                  } else {
                                    result6 = null;
                                    if (reportFailures === 0) {
                                      matchFailed("\")\"");
                                    }
                                  }
                                  if (result6 !== null) {
                                    result2 = [result2, result3, result4, result5, result6];
                                  } else {
                                    result2 = null;
                                    pos = pos2;
                                  }
                                } else {
                                  result2 = null;
                                  pos = pos2;
                                }
                              } else {
                                result2 = null;
                                pos = pos2;
                              }
                            } else {
                              result2 = null;
                              pos = pos2;
                            }
                          } else {
                            result2 = null;
                            pos = pos2;
                          }
                          if (result2 === null) {
                            result2 = parse_NIL();
                          }
                          if (result2 !== null) {
                            result0 = [result0, result1, result2];
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                      if (result0 !== null) {
                        result0 = (function(offset, arg) {
                            var ex = {};
                            ex.token = 'expression';
                            ex.expressionType = 'builtincall';
                            ex.builtincall = 'bnode';
                            if(arg.length === 5) {
                                ex.args = [arg[2]];
                            } else {
                                ex.args = null;
                            }
                      
                            return ex;
                      })(pos0, result0[2]);
                      }
                      if (result0 === null) {
                        pos = pos0;
                      }
                      if (result0 === null) {
                        pos0 = pos;
                        pos1 = pos;
                        if (input.substr(pos, 8) === "COALESCE") {
                          result0 = "COALESCE";
                          pos += 8;
                        } else {
                          result0 = null;
                          if (reportFailures === 0) {
                            matchFailed("\"COALESCE\"");
                          }
                        }
                        if (result0 === null) {
                          if (input.substr(pos, 8) === "coalesce") {
                            result0 = "coalesce";
                            pos += 8;
                          } else {
                            result0 = null;
                            if (reportFailures === 0) {
                              matchFailed("\"coalesce\"");
                            }
                          }
                        }
                        if (result0 !== null) {
                          result1 = [];
                          result2 = parse_WS();
                          while (result2 !== null) {
                            result1.push(result2);
                            result2 = parse_WS();
                          }
                          if (result1 !== null) {
                            result2 = parse_ExpressionList();
                            if (result2 !== null) {
                              result0 = [result0, result1, result2];
                            } else {
                              result0 = null;
                              pos = pos1;
                            }
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                        if (result0 !== null) {
                          result0 = (function(offset, args) {
                              var ex = {};
                              ex.token = 'expression';
                              ex.expressionType = 'builtincall';
                              ex.builtincall = 'coalesce';
                              ex.args = args;
                        
                              return ex;    
                        })(pos0, result0[2]);
                        }
                        if (result0 === null) {
                          pos = pos0;
                        }
                        if (result0 === null) {
                          pos0 = pos;
                          pos1 = pos;
                          if (input.substr(pos, 2) === "IF") {
                            result0 = "IF";
                            pos += 2;
                          } else {
                            result0 = null;
                            if (reportFailures === 0) {
                              matchFailed("\"IF\"");
                            }
                          }
                          if (result0 === null) {
                            if (input.substr(pos, 2) === "if") {
                              result0 = "if";
                              pos += 2;
                            } else {
                              result0 = null;
                              if (reportFailures === 0) {
                                matchFailed("\"if\"");
                              }
                            }
                          }
                          if (result0 !== null) {
                            result1 = [];
                            result2 = parse_WS();
                            while (result2 !== null) {
                              result1.push(result2);
                              result2 = parse_WS();
                            }
                            if (result1 !== null) {
                              if (input.charCodeAt(pos) === 40) {
                                result2 = "(";
                                pos++;
                              } else {
                                result2 = null;
                                if (reportFailures === 0) {
                                  matchFailed("\"(\"");
                                }
                              }
                              if (result2 !== null) {
                                result3 = [];
                                result4 = parse_WS();
                                while (result4 !== null) {
                                  result3.push(result4);
                                  result4 = parse_WS();
                                }
                                if (result3 !== null) {
                                  result4 = parse_ConditionalOrExpression();
                                  if (result4 !== null) {
                                    result5 = [];
                                    result6 = parse_WS();
                                    while (result6 !== null) {
                                      result5.push(result6);
                                      result6 = parse_WS();
                                    }
                                    if (result5 !== null) {
                                      if (input.charCodeAt(pos) === 44) {
                                        result6 = ",";
                                        pos++;
                                      } else {
                                        result6 = null;
                                        if (reportFailures === 0) {
                                          matchFailed("\",\"");
                                        }
                                      }
                                      if (result6 !== null) {
                                        result7 = [];
                                        result8 = parse_WS();
                                        while (result8 !== null) {
                                          result7.push(result8);
                                          result8 = parse_WS();
                                        }
                                        if (result7 !== null) {
                                          result8 = parse_ConditionalOrExpression();
                                          if (result8 !== null) {
                                            result9 = [];
                                            result10 = parse_WS();
                                            while (result10 !== null) {
                                              result9.push(result10);
                                              result10 = parse_WS();
                                            }
                                            if (result9 !== null) {
                                              if (input.charCodeAt(pos) === 44) {
                                                result10 = ",";
                                                pos++;
                                              } else {
                                                result10 = null;
                                                if (reportFailures === 0) {
                                                  matchFailed("\",\"");
                                                }
                                              }
                                              if (result10 !== null) {
                                                result11 = [];
                                                result12 = parse_WS();
                                                while (result12 !== null) {
                                                  result11.push(result12);
                                                  result12 = parse_WS();
                                                }
                                                if (result11 !== null) {
                                                  result12 = parse_ConditionalOrExpression();
                                                  if (result12 !== null) {
                                                    result13 = [];
                                                    result14 = parse_WS();
                                                    while (result14 !== null) {
                                                      result13.push(result14);
                                                      result14 = parse_WS();
                                                    }
                                                    if (result13 !== null) {
                                                      if (input.charCodeAt(pos) === 41) {
                                                        result14 = ")";
                                                        pos++;
                                                      } else {
                                                        result14 = null;
                                                        if (reportFailures === 0) {
                                                          matchFailed("\")\"");
                                                        }
                                                      }
                                                      if (result14 !== null) {
                                                        result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13, result14];
                                                      } else {
                                                        result0 = null;
                                                        pos = pos1;
                                                      }
                                                    } else {
                                                      result0 = null;
                                                      pos = pos1;
                                                    }
                                                  } else {
                                                    result0 = null;
                                                    pos = pos1;
                                                  }
                                                } else {
                                                  result0 = null;
                                                  pos = pos1;
                                                }
                                              } else {
                                                result0 = null;
                                                pos = pos1;
                                              }
                                            } else {
                                              result0 = null;
                                              pos = pos1;
                                            }
                                          } else {
                                            result0 = null;
                                            pos = pos1;
                                          }
                                        } else {
                                          result0 = null;
                                          pos = pos1;
                                        }
                                      } else {
                                        result0 = null;
                                        pos = pos1;
                                      }
                                    } else {
                                      result0 = null;
                                      pos = pos1;
                                    }
                                  } else {
                                    result0 = null;
                                    pos = pos1;
                                  }
                                } else {
                                  result0 = null;
                                  pos = pos1;
                                }
                              } else {
                                result0 = null;
                                pos = pos1;
                              }
                            } else {
                              result0 = null;
                              pos = pos1;
                            }
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                          if (result0 !== null) {
                            result0 = (function(offset, test, trueCond, falseCond) {
                              var ex = {};
                              ex.token = 'expression';
                              ex.expressionType = 'builtincall';
                              ex.builtincall = 'if';
                              ex.args = [test,trueCond,falseCond];
                          
                              return ex;
                          })(pos0, result0[4], result0[8], result0[12]);
                          }
                          if (result0 === null) {
                            pos = pos0;
                          }
                          if (result0 === null) {
                            pos0 = pos;
                            pos1 = pos;
                            if (input.substr(pos, 9) === "ISLITERAL") {
                              result0 = "ISLITERAL";
                              pos += 9;
                            } else {
                              result0 = null;
                              if (reportFailures === 0) {
                                matchFailed("\"ISLITERAL\"");
                              }
                            }
                            if (result0 === null) {
                              if (input.substr(pos, 9) === "isliteral") {
                                result0 = "isliteral";
                                pos += 9;
                              } else {
                                result0 = null;
                                if (reportFailures === 0) {
                                  matchFailed("\"isliteral\"");
                                }
                              }
                            }
                            if (result0 !== null) {
                              result1 = [];
                              result2 = parse_WS();
                              while (result2 !== null) {
                                result1.push(result2);
                                result2 = parse_WS();
                              }
                              if (result1 !== null) {
                                if (input.charCodeAt(pos) === 40) {
                                  result2 = "(";
                                  pos++;
                                } else {
                                  result2 = null;
                                  if (reportFailures === 0) {
                                    matchFailed("\"(\"");
                                  }
                                }
                                if (result2 !== null) {
                                  result3 = [];
                                  result4 = parse_WS();
                                  while (result4 !== null) {
                                    result3.push(result4);
                                    result4 = parse_WS();
                                  }
                                  if (result3 !== null) {
                                    result4 = parse_ConditionalOrExpression();
                                    if (result4 !== null) {
                                      result5 = [];
                                      result6 = parse_WS();
                                      while (result6 !== null) {
                                        result5.push(result6);
                                        result6 = parse_WS();
                                      }
                                      if (result5 !== null) {
                                        if (input.charCodeAt(pos) === 41) {
                                          result6 = ")";
                                          pos++;
                                        } else {
                                          result6 = null;
                                          if (reportFailures === 0) {
                                            matchFailed("\")\"");
                                          }
                                        }
                                        if (result6 !== null) {
                                          result0 = [result0, result1, result2, result3, result4, result5, result6];
                                        } else {
                                          result0 = null;
                                          pos = pos1;
                                        }
                                      } else {
                                        result0 = null;
                                        pos = pos1;
                                      }
                                    } else {
                                      result0 = null;
                                      pos = pos1;
                                    }
                                  } else {
                                    result0 = null;
                                    pos = pos1;
                                  }
                                } else {
                                  result0 = null;
                                  pos = pos1;
                                }
                              } else {
                                result0 = null;
                                pos = pos1;
                              }
                            } else {
                              result0 = null;
                              pos = pos1;
                            }
                            if (result0 !== null) {
                              result0 = (function(offset, arg) {
                                var ex = {};
                                ex.token = 'expression';
                                ex.expressionType = 'builtincall';
                                ex.builtincall = 'isliteral';
                                ex.args = [arg];
                            
                                return ex;
                            })(pos0, result0[4]);
                            }
                            if (result0 === null) {
                              pos = pos0;
                            }
                            if (result0 === null) {
                              pos0 = pos;
                              pos1 = pos;
                              if (input.substr(pos, 7) === "ISBLANK") {
                                result0 = "ISBLANK";
                                pos += 7;
                              } else {
                                result0 = null;
                                if (reportFailures === 0) {
                                  matchFailed("\"ISBLANK\"");
                                }
                              }
                              if (result0 === null) {
                                if (input.substr(pos, 7) === "isblank") {
                                  result0 = "isblank";
                                  pos += 7;
                                } else {
                                  result0 = null;
                                  if (reportFailures === 0) {
                                    matchFailed("\"isblank\"");
                                  }
                                }
                              }
                              if (result0 !== null) {
                                result1 = [];
                                result2 = parse_WS();
                                while (result2 !== null) {
                                  result1.push(result2);
                                  result2 = parse_WS();
                                }
                                if (result1 !== null) {
                                  if (input.charCodeAt(pos) === 40) {
                                    result2 = "(";
                                    pos++;
                                  } else {
                                    result2 = null;
                                    if (reportFailures === 0) {
                                      matchFailed("\"(\"");
                                    }
                                  }
                                  if (result2 !== null) {
                                    result3 = [];
                                    result4 = parse_WS();
                                    while (result4 !== null) {
                                      result3.push(result4);
                                      result4 = parse_WS();
                                    }
                                    if (result3 !== null) {
                                      result4 = parse_ConditionalOrExpression();
                                      if (result4 !== null) {
                                        result5 = [];
                                        result6 = parse_WS();
                                        while (result6 !== null) {
                                          result5.push(result6);
                                          result6 = parse_WS();
                                        }
                                        if (result5 !== null) {
                                          if (input.charCodeAt(pos) === 41) {
                                            result6 = ")";
                                            pos++;
                                          } else {
                                            result6 = null;
                                            if (reportFailures === 0) {
                                              matchFailed("\")\"");
                                            }
                                          }
                                          if (result6 !== null) {
                                            result0 = [result0, result1, result2, result3, result4, result5, result6];
                                          } else {
                                            result0 = null;
                                            pos = pos1;
                                          }
                                        } else {
                                          result0 = null;
                                          pos = pos1;
                                        }
                                      } else {
                                        result0 = null;
                                        pos = pos1;
                                      }
                                    } else {
                                      result0 = null;
                                      pos = pos1;
                                    }
                                  } else {
                                    result0 = null;
                                    pos = pos1;
                                  }
                                } else {
                                  result0 = null;
                                  pos = pos1;
                                }
                              } else {
                                result0 = null;
                                pos = pos1;
                              }
                              if (result0 !== null) {
                                result0 = (function(offset, arg) {
                                  var ex = {};
                                  ex.token = 'expression';
                                  ex.expressionType = 'builtincall';
                                  ex.builtincall = 'isblank';
                                  ex.args = [arg];
                              
                                  return ex;
                              })(pos0, result0[4]);
                              }
                              if (result0 === null) {
                                pos = pos0;
                              }
                              if (result0 === null) {
                                pos0 = pos;
                                pos1 = pos;
                                if (input.substr(pos, 8) === "SAMETERM") {
                                  result0 = "SAMETERM";
                                  pos += 8;
                                } else {
                                  result0 = null;
                                  if (reportFailures === 0) {
                                    matchFailed("\"SAMETERM\"");
                                  }
                                }
                                if (result0 === null) {
                                  if (input.substr(pos, 8) === "sameterm") {
                                    result0 = "sameterm";
                                    pos += 8;
                                  } else {
                                    result0 = null;
                                    if (reportFailures === 0) {
                                      matchFailed("\"sameterm\"");
                                    }
                                  }
                                }
                                if (result0 !== null) {
                                  result1 = [];
                                  result2 = parse_WS();
                                  while (result2 !== null) {
                                    result1.push(result2);
                                    result2 = parse_WS();
                                  }
                                  if (result1 !== null) {
                                    if (input.charCodeAt(pos) === 40) {
                                      result2 = "(";
                                      pos++;
                                    } else {
                                      result2 = null;
                                      if (reportFailures === 0) {
                                        matchFailed("\"(\"");
                                      }
                                    }
                                    if (result2 !== null) {
                                      result3 = [];
                                      result4 = parse_WS();
                                      while (result4 !== null) {
                                        result3.push(result4);
                                        result4 = parse_WS();
                                      }
                                      if (result3 !== null) {
                                        result4 = parse_ConditionalOrExpression();
                                        if (result4 !== null) {
                                          result5 = [];
                                          result6 = parse_WS();
                                          while (result6 !== null) {
                                            result5.push(result6);
                                            result6 = parse_WS();
                                          }
                                          if (result5 !== null) {
                                            if (input.charCodeAt(pos) === 44) {
                                              result6 = ",";
                                              pos++;
                                            } else {
                                              result6 = null;
                                              if (reportFailures === 0) {
                                                matchFailed("\",\"");
                                              }
                                            }
                                            if (result6 !== null) {
                                              result7 = [];
                                              result8 = parse_WS();
                                              while (result8 !== null) {
                                                result7.push(result8);
                                                result8 = parse_WS();
                                              }
                                              if (result7 !== null) {
                                                result8 = parse_ConditionalOrExpression();
                                                if (result8 !== null) {
                                                  result9 = [];
                                                  result10 = parse_WS();
                                                  while (result10 !== null) {
                                                    result9.push(result10);
                                                    result10 = parse_WS();
                                                  }
                                                  if (result9 !== null) {
                                                    if (input.charCodeAt(pos) === 41) {
                                                      result10 = ")";
                                                      pos++;
                                                    } else {
                                                      result10 = null;
                                                      if (reportFailures === 0) {
                                                        matchFailed("\")\"");
                                                      }
                                                    }
                                                    if (result10 !== null) {
                                                      result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10];
                                                    } else {
                                                      result0 = null;
                                                      pos = pos1;
                                                    }
                                                  } else {
                                                    result0 = null;
                                                    pos = pos1;
                                                  }
                                                } else {
                                                  result0 = null;
                                                  pos = pos1;
                                                }
                                              } else {
                                                result0 = null;
                                                pos = pos1;
                                              }
                                            } else {
                                              result0 = null;
                                              pos = pos1;
                                            }
                                          } else {
                                            result0 = null;
                                            pos = pos1;
                                          }
                                        } else {
                                          result0 = null;
                                          pos = pos1;
                                        }
                                      } else {
                                        result0 = null;
                                        pos = pos1;
                                      }
                                    } else {
                                      result0 = null;
                                      pos = pos1;
                                    }
                                  } else {
                                    result0 = null;
                                    pos = pos1;
                                  }
                                } else {
                                  result0 = null;
                                  pos = pos1;
                                }
                                if (result0 !== null) {
                                  result0 = (function(offset, e1, e2) {
                                    var ex = {};
                                    ex.token = 'expression';
                                    ex.expressionType = 'builtincall';
                                    ex.builtincall = 'sameterm';
                                    ex.args = [e1, e2];
                                    return ex;
                                })(pos0, result0[4], result0[8]);
                                }
                                if (result0 === null) {
                                  pos = pos0;
                                }
                                if (result0 === null) {
                                  pos0 = pos;
                                  pos1 = pos;
                                  if (input.substr(pos, 5) === "ISURI") {
                                    result0 = "ISURI";
                                    pos += 5;
                                  } else {
                                    result0 = null;
                                    if (reportFailures === 0) {
                                      matchFailed("\"ISURI\"");
                                    }
                                  }
                                  if (result0 === null) {
                                    if (input.substr(pos, 5) === "isuri") {
                                      result0 = "isuri";
                                      pos += 5;
                                    } else {
                                      result0 = null;
                                      if (reportFailures === 0) {
                                        matchFailed("\"isuri\"");
                                      }
                                    }
                                    if (result0 === null) {
                                      if (input.substr(pos, 5) === "ISIRI") {
                                        result0 = "ISIRI";
                                        pos += 5;
                                      } else {
                                        result0 = null;
                                        if (reportFailures === 0) {
                                          matchFailed("\"ISIRI\"");
                                        }
                                      }
                                      if (result0 === null) {
                                        if (input.substr(pos, 5) === "isiri") {
                                          result0 = "isiri";
                                          pos += 5;
                                        } else {
                                          result0 = null;
                                          if (reportFailures === 0) {
                                            matchFailed("\"isiri\"");
                                          }
                                        }
                                      }
                                    }
                                  }
                                  if (result0 !== null) {
                                    result1 = [];
                                    result2 = parse_WS();
                                    while (result2 !== null) {
                                      result1.push(result2);
                                      result2 = parse_WS();
                                    }
                                    if (result1 !== null) {
                                      if (input.charCodeAt(pos) === 40) {
                                        result2 = "(";
                                        pos++;
                                      } else {
                                        result2 = null;
                                        if (reportFailures === 0) {
                                          matchFailed("\"(\"");
                                        }
                                      }
                                      if (result2 !== null) {
                                        result3 = [];
                                        result4 = parse_WS();
                                        while (result4 !== null) {
                                          result3.push(result4);
                                          result4 = parse_WS();
                                        }
                                        if (result3 !== null) {
                                          result4 = parse_ConditionalOrExpression();
                                          if (result4 !== null) {
                                            result5 = [];
                                            result6 = parse_WS();
                                            while (result6 !== null) {
                                              result5.push(result6);
                                              result6 = parse_WS();
                                            }
                                            if (result5 !== null) {
                                              if (input.charCodeAt(pos) === 41) {
                                                result6 = ")";
                                                pos++;
                                              } else {
                                                result6 = null;
                                                if (reportFailures === 0) {
                                                  matchFailed("\")\"");
                                                }
                                              }
                                              if (result6 !== null) {
                                                result0 = [result0, result1, result2, result3, result4, result5, result6];
                                              } else {
                                                result0 = null;
                                                pos = pos1;
                                              }
                                            } else {
                                              result0 = null;
                                              pos = pos1;
                                            }
                                          } else {
                                            result0 = null;
                                            pos = pos1;
                                          }
                                        } else {
                                          result0 = null;
                                          pos = pos1;
                                        }
                                      } else {
                                        result0 = null;
                                        pos = pos1;
                                      }
                                    } else {
                                      result0 = null;
                                      pos = pos1;
                                    }
                                  } else {
                                    result0 = null;
                                    pos = pos1;
                                  }
                                  if (result0 !== null) {
                                    result0 = (function(offset, arg) {
                                      var ex = {};
                                      ex.token = 'expression';
                                      ex.expressionType = 'builtincall';
                                      ex.builtincall = 'isuri';
                                      ex.args = [arg];
                                  
                                      return ex;
                                  })(pos0, result0[4]);
                                  }
                                  if (result0 === null) {
                                    pos = pos0;
                                  }
                                  if (result0 === null) {
                                    pos0 = pos;
                                    pos1 = pos;
                                    if (input.substr(pos, 7) === "custom:") {
                                      result0 = "custom:";
                                      pos += 7;
                                    } else {
                                      result0 = null;
                                      if (reportFailures === 0) {
                                        matchFailed("\"custom:\"");
                                      }
                                    }
                                    if (result0 === null) {
                                      if (input.substr(pos, 7) === "CUSTOM:") {
                                        result0 = "CUSTOM:";
                                        pos += 7;
                                      } else {
                                        result0 = null;
                                        if (reportFailures === 0) {
                                          matchFailed("\"CUSTOM:\"");
                                        }
                                      }
                                    }
                                    if (result0 !== null) {
                                      if (/^[a-zA-Z0-9_]/.test(input.charAt(pos))) {
                                        result2 = input.charAt(pos);
                                        pos++;
                                      } else {
                                        result2 = null;
                                        if (reportFailures === 0) {
                                          matchFailed("[a-zA-Z0-9_]");
                                        }
                                      }
                                      if (result2 !== null) {
                                        result1 = [];
                                        while (result2 !== null) {
                                          result1.push(result2);
                                          if (/^[a-zA-Z0-9_]/.test(input.charAt(pos))) {
                                            result2 = input.charAt(pos);
                                            pos++;
                                          } else {
                                            result2 = null;
                                            if (reportFailures === 0) {
                                              matchFailed("[a-zA-Z0-9_]");
                                            }
                                          }
                                        }
                                      } else {
                                        result1 = null;
                                      }
                                      if (result1 !== null) {
                                        result2 = [];
                                        result3 = parse_WS();
                                        while (result3 !== null) {
                                          result2.push(result3);
                                          result3 = parse_WS();
                                        }
                                        if (result2 !== null) {
                                          if (input.charCodeAt(pos) === 40) {
                                            result3 = "(";
                                            pos++;
                                          } else {
                                            result3 = null;
                                            if (reportFailures === 0) {
                                              matchFailed("\"(\"");
                                            }
                                          }
                                          if (result3 !== null) {
                                            result4 = [];
                                            pos2 = pos;
                                            result5 = [];
                                            result6 = parse_WS();
                                            while (result6 !== null) {
                                              result5.push(result6);
                                              result6 = parse_WS();
                                            }
                                            if (result5 !== null) {
                                              result6 = parse_ConditionalOrExpression();
                                              if (result6 !== null) {
                                                if (input.charCodeAt(pos) === 44) {
                                                  result7 = ",";
                                                  pos++;
                                                } else {
                                                  result7 = null;
                                                  if (reportFailures === 0) {
                                                    matchFailed("\",\"");
                                                  }
                                                }
                                                if (result7 !== null) {
                                                  result5 = [result5, result6, result7];
                                                } else {
                                                  result5 = null;
                                                  pos = pos2;
                                                }
                                              } else {
                                                result5 = null;
                                                pos = pos2;
                                              }
                                            } else {
                                              result5 = null;
                                              pos = pos2;
                                            }
                                            while (result5 !== null) {
                                              result4.push(result5);
                                              pos2 = pos;
                                              result5 = [];
                                              result6 = parse_WS();
                                              while (result6 !== null) {
                                                result5.push(result6);
                                                result6 = parse_WS();
                                              }
                                              if (result5 !== null) {
                                                result6 = parse_ConditionalOrExpression();
                                                if (result6 !== null) {
                                                  if (input.charCodeAt(pos) === 44) {
                                                    result7 = ",";
                                                    pos++;
                                                  } else {
                                                    result7 = null;
                                                    if (reportFailures === 0) {
                                                      matchFailed("\",\"");
                                                    }
                                                  }
                                                  if (result7 !== null) {
                                                    result5 = [result5, result6, result7];
                                                  } else {
                                                    result5 = null;
                                                    pos = pos2;
                                                  }
                                                } else {
                                                  result5 = null;
                                                  pos = pos2;
                                                }
                                              } else {
                                                result5 = null;
                                                pos = pos2;
                                              }
                                            }
                                            if (result4 !== null) {
                                              result5 = [];
                                              result6 = parse_WS();
                                              while (result6 !== null) {
                                                result5.push(result6);
                                                result6 = parse_WS();
                                              }
                                              if (result5 !== null) {
                                                result6 = parse_ConditionalOrExpression();
                                                if (result6 !== null) {
                                                  result7 = [];
                                                  result8 = parse_WS();
                                                  while (result8 !== null) {
                                                    result7.push(result8);
                                                    result8 = parse_WS();
                                                  }
                                                  if (result7 !== null) {
                                                    if (input.charCodeAt(pos) === 41) {
                                                      result8 = ")";
                                                      pos++;
                                                    } else {
                                                      result8 = null;
                                                      if (reportFailures === 0) {
                                                        matchFailed("\")\"");
                                                      }
                                                    }
                                                    if (result8 !== null) {
                                                      result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8];
                                                    } else {
                                                      result0 = null;
                                                      pos = pos1;
                                                    }
                                                  } else {
                                                    result0 = null;
                                                    pos = pos1;
                                                  }
                                                } else {
                                                  result0 = null;
                                                  pos = pos1;
                                                }
                                              } else {
                                                result0 = null;
                                                pos = pos1;
                                              }
                                            } else {
                                              result0 = null;
                                              pos = pos1;
                                            }
                                          } else {
                                            result0 = null;
                                            pos = pos1;
                                          }
                                        } else {
                                          result0 = null;
                                          pos = pos1;
                                        }
                                      } else {
                                        result0 = null;
                                        pos = pos1;
                                      }
                                    } else {
                                      result0 = null;
                                      pos = pos1;
                                    }
                                    if (result0 !== null) {
                                      result0 = (function(offset, fnname, alter, finalarg) {
                                      var ex = {};
                                      ex.token = 'expression';
                                      ex.expressionType = 'custom';
                                      ex.name = fnname.join('');
                                      var acum = [];
                                      for(var i=0; i<alter.length; i++)
                                        acum.push(alter[i][1]);
                                      acum.push(finalarg);
                                      ex.args = acum;
                                    
                                      return ex;
                                    })(pos0, result0[1], result0[4], result0[6]);
                                    }
                                    if (result0 === null) {
                                      pos = pos0;
                                    }
                                    if (result0 === null) {
                                      result0 = parse_RegexExpression();
                                      if (result0 === null) {
                                        result0 = parse_ExistsFunc();
                                        if (result0 === null) {
                                          result0 = parse_NotExistsFunc();
                                        }
                                      }
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[106] BuiltInCall");
        }
        return result0;
      }
      
      function parse_RegexExpression() {
        var result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 5) === "REGEX") {
          result0 = "REGEX";
          pos += 5;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"REGEX\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 5) === "regex") {
            result0 = "regex";
            pos += 5;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"regex\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.charCodeAt(pos) === 40) {
              result2 = "(";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"(\"");
              }
            }
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result4 = parse_ConditionalOrExpression();
                if (result4 !== null) {
                  result5 = [];
                  result6 = parse_WS();
                  while (result6 !== null) {
                    result5.push(result6);
                    result6 = parse_WS();
                  }
                  if (result5 !== null) {
                    if (input.charCodeAt(pos) === 44) {
                      result6 = ",";
                      pos++;
                    } else {
                      result6 = null;
                      if (reportFailures === 0) {
                        matchFailed("\",\"");
                      }
                    }
                    if (result6 !== null) {
                      result7 = [];
                      result8 = parse_WS();
                      while (result8 !== null) {
                        result7.push(result8);
                        result8 = parse_WS();
                      }
                      if (result7 !== null) {
                        result8 = parse_ConditionalOrExpression();
                        if (result8 !== null) {
                          result9 = [];
                          result10 = parse_WS();
                          while (result10 !== null) {
                            result9.push(result10);
                            result10 = parse_WS();
                          }
                          if (result9 !== null) {
                            pos2 = pos;
                            if (input.charCodeAt(pos) === 44) {
                              result10 = ",";
                              pos++;
                            } else {
                              result10 = null;
                              if (reportFailures === 0) {
                                matchFailed("\",\"");
                              }
                            }
                            if (result10 !== null) {
                              result11 = [];
                              result12 = parse_WS();
                              while (result12 !== null) {
                                result11.push(result12);
                                result12 = parse_WS();
                              }
                              if (result11 !== null) {
                                result12 = parse_ConditionalOrExpression();
                                if (result12 !== null) {
                                  result10 = [result10, result11, result12];
                                } else {
                                  result10 = null;
                                  pos = pos2;
                                }
                              } else {
                                result10 = null;
                                pos = pos2;
                              }
                            } else {
                              result10 = null;
                              pos = pos2;
                            }
                            result10 = result10 !== null ? result10 : "";
                            if (result10 !== null) {
                              result11 = [];
                              result12 = parse_WS();
                              while (result12 !== null) {
                                result11.push(result12);
                                result12 = parse_WS();
                              }
                              if (result11 !== null) {
                                if (input.charCodeAt(pos) === 41) {
                                  result12 = ")";
                                  pos++;
                                } else {
                                  result12 = null;
                                  if (reportFailures === 0) {
                                    matchFailed("\")\"");
                                  }
                                }
                                if (result12 !== null) {
                                  result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12];
                                } else {
                                  result0 = null;
                                  pos = pos1;
                                }
                              } else {
                                result0 = null;
                                pos = pos1;
                              }
                            } else {
                              result0 = null;
                              pos = pos1;
                            }
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, e1, e2, eo) {
              var regex = {};
              regex.token = 'expression';
              regex.expressionType = 'regex';
              regex.text = e1;
              regex.pattern = e2;
              regex.flags = eo[2];
        
              return regex;
        })(pos0, result0[4], result0[8], result0[10]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[107] RegexExpression");
        }
        return result0;
      }
      
      function parse_ExistsFunc() {
        var result0, result1, result2;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 6) === "EXISTS") {
          result0 = "EXISTS";
          pos += 6;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"EXISTS\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 6) === "exists") {
            result0 = "exists";
            pos += 6;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"exists\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            result2 = parse_GroupGraphPattern();
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, ggp) {
            var ex = {};
            ex.token = 'expression';
            ex.expressionType = 'builtincall';
            ex.builtincall = 'exists';
            ex.args = [ggp];
        
            return ex;
        })(pos0, result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[108] ExistsFunc");
        }
        return result0;
      }
      
      function parse_NotExistsFunc() {
        var result0, result1, result2, result3, result4;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 3) === "NOT") {
          result0 = "NOT";
          pos += 3;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"NOT\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 3) === "not") {
            result0 = "not";
            pos += 3;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"not\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.substr(pos, 6) === "EXISTS") {
              result2 = "EXISTS";
              pos += 6;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"EXISTS\"");
              }
            }
            if (result2 === null) {
              if (input.substr(pos, 6) === "exists") {
                result2 = "exists";
                pos += 6;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("\"exists\"");
                }
              }
            }
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                result4 = parse_GroupGraphPattern();
                if (result4 !== null) {
                  result0 = [result0, result1, result2, result3, result4];
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, ggp) {
            var ex = {};
            ex.token = 'expression';
            ex.expressionType = 'builtincall';
            ex.builtincall = 'notexists';
            ex.args = [ggp];
        
            return ex;
        })(pos0, result0[4]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[109] NotExistsFunc");
        }
        return result0;
      }
      
      function parse_Aggregate() {
        var result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 5) === "COUNT") {
          result0 = "COUNT";
          pos += 5;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"COUNT\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 5) === "count") {
            result0 = "count";
            pos += 5;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"count\"");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.charCodeAt(pos) === 40) {
              result2 = "(";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"(\"");
              }
            }
            if (result2 !== null) {
              result3 = [];
              result4 = parse_WS();
              while (result4 !== null) {
                result3.push(result4);
                result4 = parse_WS();
              }
              if (result3 !== null) {
                if (input.substr(pos, 8) === "DISTINCT") {
                  result4 = "DISTINCT";
                  pos += 8;
                } else {
                  result4 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"DISTINCT\"");
                  }
                }
                if (result4 === null) {
                  if (input.substr(pos, 8) === "distinct") {
                    result4 = "distinct";
                    pos += 8;
                  } else {
                    result4 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"distinct\"");
                    }
                  }
                }
                result4 = result4 !== null ? result4 : "";
                if (result4 !== null) {
                  result5 = [];
                  result6 = parse_WS();
                  while (result6 !== null) {
                    result5.push(result6);
                    result6 = parse_WS();
                  }
                  if (result5 !== null) {
                    if (input.charCodeAt(pos) === 42) {
                      result6 = "*";
                      pos++;
                    } else {
                      result6 = null;
                      if (reportFailures === 0) {
                        matchFailed("\"*\"");
                      }
                    }
                    if (result6 === null) {
                      result6 = parse_ConditionalOrExpression();
                    }
                    if (result6 !== null) {
                      result7 = [];
                      result8 = parse_WS();
                      while (result8 !== null) {
                        result7.push(result8);
                        result8 = parse_WS();
                      }
                      if (result7 !== null) {
                        if (input.charCodeAt(pos) === 41) {
                          result8 = ")";
                          pos++;
                        } else {
                          result8 = null;
                          if (reportFailures === 0) {
                            matchFailed("\")\"");
                          }
                        }
                        if (result8 !== null) {
                          result9 = [];
                          result10 = parse_WS();
                          while (result10 !== null) {
                            result9.push(result10);
                            result10 = parse_WS();
                          }
                          if (result9 !== null) {
                            result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9];
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, d, e) {
              var exp = {};
              exp.token = 'expression';
              exp.expressionType = 'aggregate';
              exp.aggregateType = 'count';
              exp.distinct = (d != "" ? 'DISTINCT' : d);
              exp.expression = e;
        
              return exp;
        
          })(pos0, result0[4], result0[6]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          pos1 = pos;
          if (input.substr(pos, 3) === "SUM") {
            result0 = "SUM";
            pos += 3;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"SUM\"");
            }
          }
          if (result0 === null) {
            if (input.substr(pos, 3) === "sum") {
              result0 = "sum";
              pos += 3;
            } else {
              result0 = null;
              if (reportFailures === 0) {
                matchFailed("\"sum\"");
              }
            }
          }
          if (result0 !== null) {
            result1 = [];
            result2 = parse_WS();
            while (result2 !== null) {
              result1.push(result2);
              result2 = parse_WS();
            }
            if (result1 !== null) {
              if (input.charCodeAt(pos) === 40) {
                result2 = "(";
                pos++;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("\"(\"");
                }
              }
              if (result2 !== null) {
                result3 = [];
                result4 = parse_WS();
                while (result4 !== null) {
                  result3.push(result4);
                  result4 = parse_WS();
                }
                if (result3 !== null) {
                  if (input.substr(pos, 8) === "DISTINCT") {
                    result4 = "DISTINCT";
                    pos += 8;
                  } else {
                    result4 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"DISTINCT\"");
                    }
                  }
                  if (result4 === null) {
                    if (input.substr(pos, 8) === "distinct") {
                      result4 = "distinct";
                      pos += 8;
                    } else {
                      result4 = null;
                      if (reportFailures === 0) {
                        matchFailed("\"distinct\"");
                      }
                    }
                  }
                  result4 = result4 !== null ? result4 : "";
                  if (result4 !== null) {
                    result5 = [];
                    result6 = parse_WS();
                    while (result6 !== null) {
                      result5.push(result6);
                      result6 = parse_WS();
                    }
                    if (result5 !== null) {
                      result6 = parse_ConditionalOrExpression();
                      if (result6 !== null) {
                        result7 = [];
                        result8 = parse_WS();
                        while (result8 !== null) {
                          result7.push(result8);
                          result8 = parse_WS();
                        }
                        if (result7 !== null) {
                          if (input.charCodeAt(pos) === 41) {
                            result8 = ")";
                            pos++;
                          } else {
                            result8 = null;
                            if (reportFailures === 0) {
                              matchFailed("\")\"");
                            }
                          }
                          if (result8 !== null) {
                            result9 = [];
                            result10 = parse_WS();
                            while (result10 !== null) {
                              result9.push(result10);
                              result10 = parse_WS();
                            }
                            if (result9 !== null) {
                              result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9];
                            } else {
                              result0 = null;
                              pos = pos1;
                            }
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
          if (result0 !== null) {
            result0 = (function(offset, d, e) {
                var exp = {};
                exp.token = 'expression';
                exp.expressionType = 'aggregate';
                exp.aggregateType = 'sum';
                exp.distinct = (d != "" ? 'DISTINCT' : d);
                exp.expression = e;
          
                return exp;
          
            })(pos0, result0[4], result0[6]);
          }
          if (result0 === null) {
            pos = pos0;
          }
          if (result0 === null) {
            pos0 = pos;
            pos1 = pos;
            if (input.substr(pos, 3) === "MIN") {
              result0 = "MIN";
              pos += 3;
            } else {
              result0 = null;
              if (reportFailures === 0) {
                matchFailed("\"MIN\"");
              }
            }
            if (result0 === null) {
              if (input.substr(pos, 3) === "min") {
                result0 = "min";
                pos += 3;
              } else {
                result0 = null;
                if (reportFailures === 0) {
                  matchFailed("\"min\"");
                }
              }
            }
            if (result0 !== null) {
              result1 = [];
              result2 = parse_WS();
              while (result2 !== null) {
                result1.push(result2);
                result2 = parse_WS();
              }
              if (result1 !== null) {
                if (input.charCodeAt(pos) === 40) {
                  result2 = "(";
                  pos++;
                } else {
                  result2 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"(\"");
                  }
                }
                if (result2 !== null) {
                  result3 = [];
                  result4 = parse_WS();
                  while (result4 !== null) {
                    result3.push(result4);
                    result4 = parse_WS();
                  }
                  if (result3 !== null) {
                    if (input.substr(pos, 8) === "DISTINCT") {
                      result4 = "DISTINCT";
                      pos += 8;
                    } else {
                      result4 = null;
                      if (reportFailures === 0) {
                        matchFailed("\"DISTINCT\"");
                      }
                    }
                    if (result4 === null) {
                      if (input.substr(pos, 8) === "distinct") {
                        result4 = "distinct";
                        pos += 8;
                      } else {
                        result4 = null;
                        if (reportFailures === 0) {
                          matchFailed("\"distinct\"");
                        }
                      }
                    }
                    result4 = result4 !== null ? result4 : "";
                    if (result4 !== null) {
                      result5 = [];
                      result6 = parse_WS();
                      while (result6 !== null) {
                        result5.push(result6);
                        result6 = parse_WS();
                      }
                      if (result5 !== null) {
                        result6 = parse_ConditionalOrExpression();
                        if (result6 !== null) {
                          result7 = [];
                          result8 = parse_WS();
                          while (result8 !== null) {
                            result7.push(result8);
                            result8 = parse_WS();
                          }
                          if (result7 !== null) {
                            if (input.charCodeAt(pos) === 41) {
                              result8 = ")";
                              pos++;
                            } else {
                              result8 = null;
                              if (reportFailures === 0) {
                                matchFailed("\")\"");
                              }
                            }
                            if (result8 !== null) {
                              result9 = [];
                              result10 = parse_WS();
                              while (result10 !== null) {
                                result9.push(result10);
                                result10 = parse_WS();
                              }
                              if (result9 !== null) {
                                result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9];
                              } else {
                                result0 = null;
                                pos = pos1;
                              }
                            } else {
                              result0 = null;
                              pos = pos1;
                            }
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
            if (result0 !== null) {
              result0 = (function(offset, d, e) {
                  var exp = {};
                  exp.token = 'expression';
                  exp.expressionType = 'aggregate';
                  exp.aggregateType = 'min';
                  exp.distinct = (d != "" ? 'DISTINCT' : d);
                  exp.expression = e;
            
                  return exp;
            
              })(pos0, result0[4], result0[6]);
            }
            if (result0 === null) {
              pos = pos0;
            }
            if (result0 === null) {
              pos0 = pos;
              pos1 = pos;
              if (input.substr(pos, 3) === "MAX") {
                result0 = "MAX";
                pos += 3;
              } else {
                result0 = null;
                if (reportFailures === 0) {
                  matchFailed("\"MAX\"");
                }
              }
              if (result0 === null) {
                if (input.substr(pos, 3) === "max") {
                  result0 = "max";
                  pos += 3;
                } else {
                  result0 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"max\"");
                  }
                }
              }
              if (result0 !== null) {
                result1 = [];
                result2 = parse_WS();
                while (result2 !== null) {
                  result1.push(result2);
                  result2 = parse_WS();
                }
                if (result1 !== null) {
                  if (input.charCodeAt(pos) === 40) {
                    result2 = "(";
                    pos++;
                  } else {
                    result2 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"(\"");
                    }
                  }
                  if (result2 !== null) {
                    result3 = [];
                    result4 = parse_WS();
                    while (result4 !== null) {
                      result3.push(result4);
                      result4 = parse_WS();
                    }
                    if (result3 !== null) {
                      if (input.substr(pos, 8) === "DISTINCT") {
                        result4 = "DISTINCT";
                        pos += 8;
                      } else {
                        result4 = null;
                        if (reportFailures === 0) {
                          matchFailed("\"DISTINCT\"");
                        }
                      }
                      if (result4 === null) {
                        if (input.substr(pos, 8) === "distinct") {
                          result4 = "distinct";
                          pos += 8;
                        } else {
                          result4 = null;
                          if (reportFailures === 0) {
                            matchFailed("\"distinct\"");
                          }
                        }
                      }
                      result4 = result4 !== null ? result4 : "";
                      if (result4 !== null) {
                        result5 = [];
                        result6 = parse_WS();
                        while (result6 !== null) {
                          result5.push(result6);
                          result6 = parse_WS();
                        }
                        if (result5 !== null) {
                          result6 = parse_ConditionalOrExpression();
                          if (result6 !== null) {
                            result7 = [];
                            result8 = parse_WS();
                            while (result8 !== null) {
                              result7.push(result8);
                              result8 = parse_WS();
                            }
                            if (result7 !== null) {
                              if (input.charCodeAt(pos) === 41) {
                                result8 = ")";
                                pos++;
                              } else {
                                result8 = null;
                                if (reportFailures === 0) {
                                  matchFailed("\")\"");
                                }
                              }
                              if (result8 !== null) {
                                result9 = [];
                                result10 = parse_WS();
                                while (result10 !== null) {
                                  result9.push(result10);
                                  result10 = parse_WS();
                                }
                                if (result9 !== null) {
                                  result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9];
                                } else {
                                  result0 = null;
                                  pos = pos1;
                                }
                              } else {
                                result0 = null;
                                pos = pos1;
                              }
                            } else {
                              result0 = null;
                              pos = pos1;
                            }
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
              } else {
                result0 = null;
                pos = pos1;
              }
              if (result0 !== null) {
                result0 = (function(offset, d, e) {
                    var exp = {};
                    exp.token = 'expression'
                    exp.expressionType = 'aggregate'
                    exp.aggregateType = 'max'
                    exp.distinct = (d != "" ? 'DISTINCT' : d);
                    exp.expression = e
              
                    return exp
              
                })(pos0, result0[4], result0[6]);
              }
              if (result0 === null) {
                pos = pos0;
              }
              if (result0 === null) {
                pos0 = pos;
                pos1 = pos;
                if (input.substr(pos, 3) === "AVG") {
                  result0 = "AVG";
                  pos += 3;
                } else {
                  result0 = null;
                  if (reportFailures === 0) {
                    matchFailed("\"AVG\"");
                  }
                }
                if (result0 === null) {
                  if (input.substr(pos, 3) === "avg") {
                    result0 = "avg";
                    pos += 3;
                  } else {
                    result0 = null;
                    if (reportFailures === 0) {
                      matchFailed("\"avg\"");
                    }
                  }
                }
                if (result0 !== null) {
                  result1 = [];
                  result2 = parse_WS();
                  while (result2 !== null) {
                    result1.push(result2);
                    result2 = parse_WS();
                  }
                  if (result1 !== null) {
                    if (input.charCodeAt(pos) === 40) {
                      result2 = "(";
                      pos++;
                    } else {
                      result2 = null;
                      if (reportFailures === 0) {
                        matchFailed("\"(\"");
                      }
                    }
                    if (result2 !== null) {
                      result3 = [];
                      result4 = parse_WS();
                      while (result4 !== null) {
                        result3.push(result4);
                        result4 = parse_WS();
                      }
                      if (result3 !== null) {
                        if (input.substr(pos, 8) === "DISTINCT") {
                          result4 = "DISTINCT";
                          pos += 8;
                        } else {
                          result4 = null;
                          if (reportFailures === 0) {
                            matchFailed("\"DISTINCT\"");
                          }
                        }
                        if (result4 === null) {
                          if (input.substr(pos, 8) === "distinct") {
                            result4 = "distinct";
                            pos += 8;
                          } else {
                            result4 = null;
                            if (reportFailures === 0) {
                              matchFailed("\"distinct\"");
                            }
                          }
                        }
                        result4 = result4 !== null ? result4 : "";
                        if (result4 !== null) {
                          result5 = [];
                          result6 = parse_WS();
                          while (result6 !== null) {
                            result5.push(result6);
                            result6 = parse_WS();
                          }
                          if (result5 !== null) {
                            result6 = parse_ConditionalOrExpression();
                            if (result6 !== null) {
                              result7 = [];
                              result8 = parse_WS();
                              while (result8 !== null) {
                                result7.push(result8);
                                result8 = parse_WS();
                              }
                              if (result7 !== null) {
                                if (input.charCodeAt(pos) === 41) {
                                  result8 = ")";
                                  pos++;
                                } else {
                                  result8 = null;
                                  if (reportFailures === 0) {
                                    matchFailed("\")\"");
                                  }
                                }
                                if (result8 !== null) {
                                  result9 = [];
                                  result10 = parse_WS();
                                  while (result10 !== null) {
                                    result9.push(result10);
                                    result10 = parse_WS();
                                  }
                                  if (result9 !== null) {
                                    result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9];
                                  } else {
                                    result0 = null;
                                    pos = pos1;
                                  }
                                } else {
                                  result0 = null;
                                  pos = pos1;
                                }
                              } else {
                                result0 = null;
                                pos = pos1;
                              }
                            } else {
                              result0 = null;
                              pos = pos1;
                            }
                          } else {
                            result0 = null;
                            pos = pos1;
                          }
                        } else {
                          result0 = null;
                          pos = pos1;
                        }
                      } else {
                        result0 = null;
                        pos = pos1;
                      }
                    } else {
                      result0 = null;
                      pos = pos1;
                    }
                  } else {
                    result0 = null;
                    pos = pos1;
                  }
                } else {
                  result0 = null;
                  pos = pos1;
                }
                if (result0 !== null) {
                  result0 = (function(offset, d, e) {
                      var exp = {};
                      exp.token = 'expression'
                      exp.expressionType = 'aggregate'
                      exp.aggregateType = 'avg'
                      exp.distinct = (d != "" ? 'DISTINCT' : d);
                      exp.expression = e
                
                      return exp
                
                  })(pos0, result0[4], result0[6]);
                }
                if (result0 === null) {
                  pos = pos0;
                }
              }
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[110] Aggregate");
        }
        return result0;
      }
      
      function parse_IRIrefOrFunction() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_IRIref();
        if (result0 !== null) {
          result1 = parse_ArgList();
          result1 = result1 !== null ? result1 : "";
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, i, args) {
              var fcall = {};
              fcall.token = "expression";
              fcall.expressionType = 'irireforfunction';
              fcall.iriref = i;
              fcall.args = args.value;
        
              return fcall;
        })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[117] IRIrefOrFunction");
        }
        return result0;
      }
      
      function parse_RDFLiteral() {
        var result0, result1, result2;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_String();
        if (result0 !== null) {
          result1 = parse_LANGTAG();
          if (result1 === null) {
            pos2 = pos;
            if (input.substr(pos, 2) === "^^") {
              result1 = "^^";
              pos += 2;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("\"^^\"");
              }
            }
            if (result1 !== null) {
              result2 = parse_IRIref();
              if (result2 !== null) {
                result1 = [result1, result2];
              } else {
                result1 = null;
                pos = pos2;
              }
            } else {
              result1 = null;
              pos = pos2;
            }
          }
          result1 = result1 !== null ? result1 : "";
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, s, e) {
              if(typeof(e) === "string" && e.length > 0) {
                  return {token:'literal', value:s.value, lang:e.slice(1), type:null}
              } else {
                  if(typeof(e) === "object") {
                      e.shift(); // remove the '^^' char
                      return {token:'literal', value:s.value, lang:null, type:e[0] }
                  } else {
                      return { token:'literal', value:s.value, lang:null, type:null }
                  }
              }
        })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[112] RDFLiteral");
        }
        return result0;
      }
      
      function parse_NumericLiteral() {
        var result0;
        
        reportFailures++;
        result0 = parse_NumericLiteralUnsigned();
        if (result0 === null) {
          result0 = parse_NumericLiteralPositive();
          if (result0 === null) {
            result0 = parse_NumericLiteralNegative();
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[113] NumericLiteral");
        }
        return result0;
      }
      
      function parse_NumericLiteralUnsigned() {
        var result0;
        
        reportFailures++;
        result0 = parse_DOUBLE();
        if (result0 === null) {
          result0 = parse_DECIMAL();
          if (result0 === null) {
            result0 = parse_INTEGER();
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[114] NumericLiteralUnsigned");
        }
        return result0;
      }
      
      function parse_NumericLiteralPositive() {
        var result0;
        
        reportFailures++;
        result0 = parse_DOUBLE_POSITIVE();
        if (result0 === null) {
          result0 = parse_DECIMAL_POSITIVE();
          if (result0 === null) {
            result0 = parse_INTEGER_POSITIVE();
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[115] NumericLiteralPositive");
        }
        return result0;
      }
      
      function parse_NumericLiteralNegative() {
        var result0;
        
        reportFailures++;
        result0 = parse_DOUBLE_NEGATIVE();
        if (result0 === null) {
          result0 = parse_DECIMAL_NEGATIVE();
          if (result0 === null) {
            result0 = parse_INTEGER_NEGATIVE();
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[116] NumericLiteralNegative");
        }
        return result0;
      }
      
      function parse_BooleanLiteral() {
        var result0;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        if (input.substr(pos, 4) === "TRUE") {
          result0 = "TRUE";
          pos += 4;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"TRUE\"");
          }
        }
        if (result0 === null) {
          if (input.substr(pos, 4) === "true") {
            result0 = "true";
            pos += 4;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"true\"");
            }
          }
        }
        if (result0 !== null) {
          result0 = (function(offset) {
              var lit = {};
              lit.token = "literal";
              lit.lang = null;
              lit.type = "http://www.w3.org/2001/XMLSchema#boolean";
              lit.value = true;
              return lit;
         })(pos0);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          if (input.substr(pos, 5) === "FALSE") {
            result0 = "FALSE";
            pos += 5;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"FALSE\"");
            }
          }
          if (result0 === null) {
            if (input.substr(pos, 5) === "false") {
              result0 = "false";
              pos += 5;
            } else {
              result0 = null;
              if (reportFailures === 0) {
                matchFailed("\"false\"");
              }
            }
          }
          if (result0 !== null) {
            result0 = (function(offset) {
                var lit = {};
                lit.token = "literal";
                lit.lang = null;
                lit.type = "http://www.w3.org/2001/XMLSchema#boolean";
                lit.value = false;
                return lit;
          })(pos0);
          }
          if (result0 === null) {
            pos = pos0;
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[117] BooleanLiteral");
        }
        return result0;
      }
      
      function parse_String() {
        var result0;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        result0 = parse_STRING_LITERAL_LONG1();
        if (result0 !== null) {
          result0 = (function(offset, s) { return {token:'string', value:s} })(pos0, result0);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          result0 = parse_STRING_LITERAL_LONG2();
          if (result0 !== null) {
            result0 = (function(offset, s) { return {token:'string', value:s} })(pos0, result0);
          }
          if (result0 === null) {
            pos = pos0;
          }
          if (result0 === null) {
            pos0 = pos;
            result0 = parse_STRING_LITERAL1();
            if (result0 !== null) {
              result0 = (function(offset, s) { return {token:'string', value:s} })(pos0, result0);
            }
            if (result0 === null) {
              pos = pos0;
            }
            if (result0 === null) {
              pos0 = pos;
              result0 = parse_STRING_LITERAL2();
              if (result0 !== null) {
                result0 = (function(offset, s) { return {token:'string', value:s} })(pos0, result0);
              }
              if (result0 === null) {
                pos = pos0;
              }
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[118] String");
        }
        return result0;
      }
      
      function parse_IRIref() {
        var result0;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        result0 = parse_IRI_REF();
        if (result0 !== null) {
          result0 = (function(offset, iri) { return {token: 'uri', prefix:null, suffix:null, value:iri} })(pos0, result0);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          result0 = parse_PrefixedName();
          if (result0 !== null) {
            result0 = (function(offset, p) { return p })(pos0, result0);
          }
          if (result0 === null) {
            pos = pos0;
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[119] IRIref");
        }
        return result0;
      }
      
      function parse_PrefixedName() {
        var result0;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        result0 = parse_PNAME_LN();
        if (result0 !== null) {
          result0 = (function(offset, p) { return {token: 'uri', prefix:p[0], suffix:p[1], value:null } })(pos0, result0);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          result0 = parse_PNAME_NS();
          if (result0 !== null) {
            result0 = (function(offset, p) { return {token: 'uri', prefix:p, suffix:'', value:null } })(pos0, result0);
          }
          if (result0 === null) {
            pos = pos0;
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[120] PrefixedName");
        }
        return result0;
      }
      
      function parse_BlankNode() {
        var result0;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        result0 = parse_BLANK_NODE_LABEL();
        if (result0 !== null) {
          result0 = (function(offset, l) { return {token:'blank', value:l}})(pos0, result0);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          result0 = parse_ANON();
          if (result0 !== null) {
            result0 = (function(offset) { GlobalBlankNodeCounter++; return {token:'blank', value:'_:'+GlobalBlankNodeCounter} })(pos0);
          }
          if (result0 === null) {
            pos = pos0;
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[121] BlankNode");
        }
        return result0;
      }
      
      function parse_IRI_REF() {
        var result0, result1, result2;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 60) {
          result0 = "<";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"<\"");
          }
        }
        if (result0 !== null) {
          result1 = [];
          if (/^[^<>"{}|^`\\]/.test(input.charAt(pos))) {
            result2 = input.charAt(pos);
            pos++;
          } else {
            result2 = null;
            if (reportFailures === 0) {
              matchFailed("[^<>\"{}|^`\\\\]");
            }
          }
          while (result2 !== null) {
            result1.push(result2);
            if (/^[^<>"{}|^`\\]/.test(input.charAt(pos))) {
              result2 = input.charAt(pos);
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("[^<>\"{}|^`\\\\]");
              }
            }
          }
          if (result1 !== null) {
            if (input.charCodeAt(pos) === 62) {
              result2 = ">";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\">\"");
              }
            }
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, iri_ref) { return iri_ref.join('') })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[122] IRI_REF");
        }
        return result0;
      }
      
      function parse_PNAME_NS() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_PN_PREFIX();
        result0 = result0 !== null ? result0 : "";
        if (result0 !== null) {
          if (input.charCodeAt(pos) === 58) {
            result1 = ":";
            pos++;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\":\"");
            }
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, p) { return p })(pos0, result0[0]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[123] PNAME_NS");
        }
        return result0;
      }
      
      function parse_PNAME_LN() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_PNAME_NS();
        if (result0 !== null) {
          result1 = parse_PN_LOCAL();
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, p, s) { return [p, s] })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[124] PNAME_LN");
        }
        return result0;
      }
      
      function parse_BLANK_NODE_LABEL() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 2) === "_:") {
          result0 = "_:";
          pos += 2;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"_:\"");
          }
        }
        if (result0 !== null) {
          result1 = parse_PN_LOCAL();
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, l) { return l })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[125] BLANK_NODE_LABEL");
        }
        return result0;
      }
      
      function parse_VAR1() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 63) {
          result0 = "?";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"?\"");
          }
        }
        if (result0 !== null) {
          result1 = parse_VARNAME();
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, v) { return v })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[126] VAR1");
        }
        return result0;
      }
      
      function parse_VAR2() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 36) {
          result0 = "$";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"$\"");
          }
        }
        if (result0 !== null) {
          result1 = parse_VARNAME();
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, v) { return v })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[127] VAR2");
        }
        return result0;
      }
      
      function parse_LANGTAG() {
        var result0, result1, result2, result3, result4, result5;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 64) {
          result0 = "@";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"@\"");
          }
        }
        if (result0 !== null) {
          if (/^[a-zA-Z]/.test(input.charAt(pos))) {
            result2 = input.charAt(pos);
            pos++;
          } else {
            result2 = null;
            if (reportFailures === 0) {
              matchFailed("[a-zA-Z]");
            }
          }
          if (result2 !== null) {
            result1 = [];
            while (result2 !== null) {
              result1.push(result2);
              if (/^[a-zA-Z]/.test(input.charAt(pos))) {
                result2 = input.charAt(pos);
                pos++;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("[a-zA-Z]");
                }
              }
            }
          } else {
            result1 = null;
          }
          if (result1 !== null) {
            result2 = [];
            pos2 = pos;
            if (input.charCodeAt(pos) === 45) {
              result3 = "-";
              pos++;
            } else {
              result3 = null;
              if (reportFailures === 0) {
                matchFailed("\"-\"");
              }
            }
            if (result3 !== null) {
              if (/^[a-zA-Z0-9]/.test(input.charAt(pos))) {
                result5 = input.charAt(pos);
                pos++;
              } else {
                result5 = null;
                if (reportFailures === 0) {
                  matchFailed("[a-zA-Z0-9]");
                }
              }
              if (result5 !== null) {
                result4 = [];
                while (result5 !== null) {
                  result4.push(result5);
                  if (/^[a-zA-Z0-9]/.test(input.charAt(pos))) {
                    result5 = input.charAt(pos);
                    pos++;
                  } else {
                    result5 = null;
                    if (reportFailures === 0) {
                      matchFailed("[a-zA-Z0-9]");
                    }
                  }
                }
              } else {
                result4 = null;
              }
              if (result4 !== null) {
                result3 = [result3, result4];
              } else {
                result3 = null;
                pos = pos2;
              }
            } else {
              result3 = null;
              pos = pos2;
            }
            while (result3 !== null) {
              result2.push(result3);
              pos2 = pos;
              if (input.charCodeAt(pos) === 45) {
                result3 = "-";
                pos++;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("\"-\"");
                }
              }
              if (result3 !== null) {
                if (/^[a-zA-Z0-9]/.test(input.charAt(pos))) {
                  result5 = input.charAt(pos);
                  pos++;
                } else {
                  result5 = null;
                  if (reportFailures === 0) {
                    matchFailed("[a-zA-Z0-9]");
                  }
                }
                if (result5 !== null) {
                  result4 = [];
                  while (result5 !== null) {
                    result4.push(result5);
                    if (/^[a-zA-Z0-9]/.test(input.charAt(pos))) {
                      result5 = input.charAt(pos);
                      pos++;
                    } else {
                      result5 = null;
                      if (reportFailures === 0) {
                        matchFailed("[a-zA-Z0-9]");
                      }
                    }
                  }
                } else {
                  result4 = null;
                }
                if (result4 !== null) {
                  result3 = [result3, result4];
                } else {
                  result3 = null;
                  pos = pos2;
                }
              } else {
                result3 = null;
                pos = pos2;
              }
            }
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, a, b) {
        
              if(b.length===0) {
                  return ("@"+a.join('')).toLowerCase();
              } else {
                  return ("@"+a.join('')+"-"+b[0][1].join('')).toLowerCase();
              }
        })(pos0, result0[1], result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[128] LANGTAG");
        }
        return result0;
      }
      
      function parse_INTEGER() {
        var result0, result1;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        if (/^[0-9]/.test(input.charAt(pos))) {
          result1 = input.charAt(pos);
          pos++;
        } else {
          result1 = null;
          if (reportFailures === 0) {
            matchFailed("[0-9]");
          }
        }
        if (result1 !== null) {
          result0 = [];
          while (result1 !== null) {
            result0.push(result1);
            if (/^[0-9]/.test(input.charAt(pos))) {
              result1 = input.charAt(pos);
              pos++;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("[0-9]");
              }
            }
          }
        } else {
          result0 = null;
        }
        if (result0 !== null) {
          result0 = (function(offset, d) {
              var lit = {};
              lit.token = "literal";
              lit.lang = null;
              lit.type = "http://www.w3.org/2001/XMLSchema#integer";
              lit.value = flattenString(d);
              return lit;
        })(pos0, result0);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[129] INTEGER");
        }
        return result0;
      }
      
      function parse_DECIMAL() {
        var result0, result1, result2, result3;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (/^[0-9]/.test(input.charAt(pos))) {
          result1 = input.charAt(pos);
          pos++;
        } else {
          result1 = null;
          if (reportFailures === 0) {
            matchFailed("[0-9]");
          }
        }
        if (result1 !== null) {
          result0 = [];
          while (result1 !== null) {
            result0.push(result1);
            if (/^[0-9]/.test(input.charAt(pos))) {
              result1 = input.charAt(pos);
              pos++;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("[0-9]");
              }
            }
          }
        } else {
          result0 = null;
        }
        if (result0 !== null) {
          if (input.charCodeAt(pos) === 46) {
            result1 = ".";
            pos++;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\".\"");
            }
          }
          if (result1 !== null) {
            result2 = [];
            if (/^[0-9]/.test(input.charAt(pos))) {
              result3 = input.charAt(pos);
              pos++;
            } else {
              result3 = null;
              if (reportFailures === 0) {
                matchFailed("[0-9]");
              }
            }
            while (result3 !== null) {
              result2.push(result3);
              if (/^[0-9]/.test(input.charAt(pos))) {
                result3 = input.charAt(pos);
                pos++;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("[0-9]");
                }
              }
            }
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, a, b, c) {
        
              var lit = {};
              lit.token = "literal";
              lit.lang = null;
              lit.type = "http://www.w3.org/2001/XMLSchema#decimal";
              lit.value = flattenString([a,b,c]);
              return lit;
        })(pos0, result0[0], result0[1], result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          pos1 = pos;
          if (input.charCodeAt(pos) === 46) {
            result0 = ".";
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\".\"");
            }
          }
          if (result0 !== null) {
            if (/^[0-9]/.test(input.charAt(pos))) {
              result2 = input.charAt(pos);
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("[0-9]");
              }
            }
            if (result2 !== null) {
              result1 = [];
              while (result2 !== null) {
                result1.push(result2);
                if (/^[0-9]/.test(input.charAt(pos))) {
                  result2 = input.charAt(pos);
                  pos++;
                } else {
                  result2 = null;
                  if (reportFailures === 0) {
                    matchFailed("[0-9]");
                  }
                }
              }
            } else {
              result1 = null;
            }
            if (result1 !== null) {
              result0 = [result0, result1];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
          if (result0 !== null) {
            result0 = (function(offset, a, b) {
                var lit = {};
                lit.token = "literal";
                lit.lang = null;
                lit.type = "http://www.w3.org/2001/XMLSchema#decimal";
                lit.value = flattenString([a,b]);
                return lit;
           })(pos0, result0[0], result0[1]);
          }
          if (result0 === null) {
            pos = pos0;
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[130] DECIMAL");
        }
        return result0;
      }
      
      function parse_DOUBLE() {
        var result0, result1, result2, result3;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (/^[0-9]/.test(input.charAt(pos))) {
          result1 = input.charAt(pos);
          pos++;
        } else {
          result1 = null;
          if (reportFailures === 0) {
            matchFailed("[0-9]");
          }
        }
        if (result1 !== null) {
          result0 = [];
          while (result1 !== null) {
            result0.push(result1);
            if (/^[0-9]/.test(input.charAt(pos))) {
              result1 = input.charAt(pos);
              pos++;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("[0-9]");
              }
            }
          }
        } else {
          result0 = null;
        }
        if (result0 !== null) {
          if (input.charCodeAt(pos) === 46) {
            result1 = ".";
            pos++;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("\".\"");
            }
          }
          if (result1 !== null) {
            result2 = [];
            if (/^[0-9]/.test(input.charAt(pos))) {
              result3 = input.charAt(pos);
              pos++;
            } else {
              result3 = null;
              if (reportFailures === 0) {
                matchFailed("[0-9]");
              }
            }
            while (result3 !== null) {
              result2.push(result3);
              if (/^[0-9]/.test(input.charAt(pos))) {
                result3 = input.charAt(pos);
                pos++;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("[0-9]");
                }
              }
            }
            if (result2 !== null) {
              result3 = parse_EXPONENT();
              if (result3 !== null) {
                result0 = [result0, result1, result2, result3];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, a, b, c, e) {
              var lit = {};
              lit.token = "literal";
              lit.lang = null;
              lit.type = "http://www.w3.org/2001/XMLSchema#double";
              lit.value = flattenString([a,b,c,e]);
              return lit;
        })(pos0, result0[0], result0[1], result0[2], result0[3]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        if (result0 === null) {
          pos0 = pos;
          pos1 = pos;
          if (input.charCodeAt(pos) === 46) {
            result0 = ".";
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\".\"");
            }
          }
          if (result0 !== null) {
            if (/^[0-9]/.test(input.charAt(pos))) {
              result2 = input.charAt(pos);
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("[0-9]");
              }
            }
            if (result2 !== null) {
              result1 = [];
              while (result2 !== null) {
                result1.push(result2);
                if (/^[0-9]/.test(input.charAt(pos))) {
                  result2 = input.charAt(pos);
                  pos++;
                } else {
                  result2 = null;
                  if (reportFailures === 0) {
                    matchFailed("[0-9]");
                  }
                }
              }
            } else {
              result1 = null;
            }
            if (result1 !== null) {
              result2 = parse_EXPONENT();
              if (result2 !== null) {
                result0 = [result0, result1, result2];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
          if (result0 !== null) {
            result0 = (function(offset, a, b, c) {
                var lit = {};
                lit.token = "literal";
                lit.lang = null;
                lit.type = "http://www.w3.org/2001/XMLSchema#double";
                lit.value = flattenString([a,b,c]);
                return lit;
          })(pos0, result0[0], result0[1], result0[2]);
          }
          if (result0 === null) {
            pos = pos0;
          }
          if (result0 === null) {
            pos0 = pos;
            pos1 = pos;
            if (/^[0-9]/.test(input.charAt(pos))) {
              result1 = input.charAt(pos);
              pos++;
            } else {
              result1 = null;
              if (reportFailures === 0) {
                matchFailed("[0-9]");
              }
            }
            if (result1 !== null) {
              result0 = [];
              while (result1 !== null) {
                result0.push(result1);
                if (/^[0-9]/.test(input.charAt(pos))) {
                  result1 = input.charAt(pos);
                  pos++;
                } else {
                  result1 = null;
                  if (reportFailures === 0) {
                    matchFailed("[0-9]");
                  }
                }
              }
            } else {
              result0 = null;
            }
            if (result0 !== null) {
              result1 = parse_EXPONENT();
              if (result1 !== null) {
                result0 = [result0, result1];
              } else {
                result0 = null;
                pos = pos1;
              }
            } else {
              result0 = null;
              pos = pos1;
            }
            if (result0 !== null) {
              result0 = (function(offset, a, b) {
                  var lit = {};
                  lit.token = "literal";
                  lit.lang = null;
                  lit.type = "http://www.w3.org/2001/XMLSchema#double";
                  lit.value = flattenString([a,b]);
                  return lit;
            })(pos0, result0[0], result0[1]);
            }
            if (result0 === null) {
              pos = pos0;
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[131] DOUBLE");
        }
        return result0;
      }
      
      function parse_INTEGER_POSITIVE() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 43) {
          result0 = "+";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"+\"");
          }
        }
        if (result0 !== null) {
          result1 = parse_INTEGER();
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, d) { d.value = "+"+d.value; return d; })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[132] INTEGER_POSITIVE");
        }
        return result0;
      }
      
      function parse_DECIMAL_POSITIVE() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 43) {
          result0 = "+";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"+\"");
          }
        }
        if (result0 !== null) {
          result1 = parse_DECIMAL();
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, d) { d.value = "+"+d.value; return d })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[133] DECIMAL_POSITIVE");
        }
        return result0;
      }
      
      function parse_DOUBLE_POSITIVE() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 43) {
          result0 = "+";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"+\"");
          }
        }
        if (result0 !== null) {
          result1 = parse_DOUBLE();
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, d) { d.value = "+"+d.value; return d })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[134] DOUBLE_POSITIVE");
        }
        return result0;
      }
      
      function parse_INTEGER_NEGATIVE() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 45) {
          result0 = "-";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"-\"");
          }
        }
        if (result0 !== null) {
          result1 = parse_INTEGER();
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, d) { d.value = "-"+d.value; return d; })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[135] INTEGER_NEGATIVE");
        }
        return result0;
      }
      
      function parse_DECIMAL_NEGATIVE() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 45) {
          result0 = "-";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"-\"");
          }
        }
        if (result0 !== null) {
          result1 = parse_DECIMAL();
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, d) { d.value = "-"+d.value; return d; })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[136] DECIMAL_NEGATIVE");
        }
        return result0;
      }
      
      function parse_DOUBLE_NEGATIVE() {
        var result0, result1;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 45) {
          result0 = "-";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"-\"");
          }
        }
        if (result0 !== null) {
          result1 = parse_DOUBLE();
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, d) { d.value = "-"+d.value; return d; })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[137] DOUBLE_NEGATIVE");
        }
        return result0;
      }
      
      function parse_EXPONENT() {
        var result0, result1, result2, result3;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (/^[eE]/.test(input.charAt(pos))) {
          result0 = input.charAt(pos);
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("[eE]");
          }
        }
        if (result0 !== null) {
          if (/^[+\-]/.test(input.charAt(pos))) {
            result1 = input.charAt(pos);
            pos++;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("[+\\-]");
            }
          }
          result1 = result1 !== null ? result1 : "";
          if (result1 !== null) {
            if (/^[0-9]/.test(input.charAt(pos))) {
              result3 = input.charAt(pos);
              pos++;
            } else {
              result3 = null;
              if (reportFailures === 0) {
                matchFailed("[0-9]");
              }
            }
            if (result3 !== null) {
              result2 = [];
              while (result3 !== null) {
                result2.push(result3);
                if (/^[0-9]/.test(input.charAt(pos))) {
                  result3 = input.charAt(pos);
                  pos++;
                } else {
                  result3 = null;
                  if (reportFailures === 0) {
                    matchFailed("[0-9]");
                  }
                }
              }
            } else {
              result2 = null;
            }
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, a, b, c) { return flattenString([a,b,c]) })(pos0, result0[0], result0[1], result0[2]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[138] EXPONENT");
        }
        return result0;
      }
      
      function parse_STRING_LITERAL1() {
        var result0, result1, result2;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 39) {
          result0 = "'";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"'\"");
          }
        }
        if (result0 !== null) {
          result1 = [];
          if (/^[^'\\\n\r]/.test(input.charAt(pos))) {
            result2 = input.charAt(pos);
            pos++;
          } else {
            result2 = null;
            if (reportFailures === 0) {
              matchFailed("[^'\\\\\\n\\r]");
            }
          }
          if (result2 === null) {
            result2 = parse_ECHAR();
          }
          while (result2 !== null) {
            result1.push(result2);
            if (/^[^'\\\n\r]/.test(input.charAt(pos))) {
              result2 = input.charAt(pos);
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("[^'\\\\\\n\\r]");
              }
            }
            if (result2 === null) {
              result2 = parse_ECHAR();
            }
          }
          if (result1 !== null) {
            if (input.charCodeAt(pos) === 39) {
              result2 = "'";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"'\"");
              }
            }
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, content) { return flattenString(content) })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[139] STRING_LITERAL1");
        }
        return result0;
      }
      
      function parse_STRING_LITERAL2() {
        var result0, result1, result2;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 34) {
          result0 = "\"";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"\\\"\"");
          }
        }
        if (result0 !== null) {
          result1 = [];
          if (/^[^"\\\n\r]/.test(input.charAt(pos))) {
            result2 = input.charAt(pos);
            pos++;
          } else {
            result2 = null;
            if (reportFailures === 0) {
              matchFailed("[^\"\\\\\\n\\r]");
            }
          }
          if (result2 === null) {
            result2 = parse_ECHAR();
          }
          while (result2 !== null) {
            result1.push(result2);
            if (/^[^"\\\n\r]/.test(input.charAt(pos))) {
              result2 = input.charAt(pos);
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("[^\"\\\\\\n\\r]");
              }
            }
            if (result2 === null) {
              result2 = parse_ECHAR();
            }
          }
          if (result1 !== null) {
            if (input.charCodeAt(pos) === 34) {
              result2 = "\"";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"\\\"\"");
              }
            }
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, content) { return flattenString(content) })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[140] STRING_LITERAL2");
        }
        return result0;
      }
      
      function parse_STRING_LITERAL_LONG1() {
        var result0, result1, result2, result3;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 3) === "'''") {
          result0 = "'''";
          pos += 3;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"'''\"");
          }
        }
        if (result0 !== null) {
          result1 = [];
          pos2 = pos;
          if (input.charCodeAt(pos) === 39) {
            result2 = "'";
            pos++;
          } else {
            result2 = null;
            if (reportFailures === 0) {
              matchFailed("\"'\"");
            }
          }
          if (result2 === null) {
            if (input.substr(pos, 2) === "''") {
              result2 = "''";
              pos += 2;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"''\"");
              }
            }
          }
          result2 = result2 !== null ? result2 : "";
          if (result2 !== null) {
            if (/^[^']/.test(input.charAt(pos))) {
              result3 = input.charAt(pos);
              pos++;
            } else {
              result3 = null;
              if (reportFailures === 0) {
                matchFailed("[^']");
              }
            }
            if (result3 !== null) {
              result2 = [result2, result3];
            } else {
              result2 = null;
              pos = pos2;
            }
          } else {
            result2 = null;
            pos = pos2;
          }
          if (result2 === null) {
            result2 = parse_ECHAR();
          }
          while (result2 !== null) {
            result1.push(result2);
            pos2 = pos;
            if (input.charCodeAt(pos) === 39) {
              result2 = "'";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"'\"");
              }
            }
            if (result2 === null) {
              if (input.substr(pos, 2) === "''") {
                result2 = "''";
                pos += 2;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("\"''\"");
                }
              }
            }
            result2 = result2 !== null ? result2 : "";
            if (result2 !== null) {
              if (/^[^']/.test(input.charAt(pos))) {
                result3 = input.charAt(pos);
                pos++;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("[^']");
                }
              }
              if (result3 !== null) {
                result2 = [result2, result3];
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
            if (result2 === null) {
              result2 = parse_ECHAR();
            }
          }
          if (result1 !== null) {
            if (input.substr(pos, 3) === "'''") {
              result2 = "'''";
              pos += 3;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"'''\"");
              }
            }
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, content) { return flattenString(content) })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[141] STRING_LITERAL_LONG1");
        }
        return result0;
      }
      
      function parse_STRING_LITERAL_LONG2() {
        var result0, result1, result2, result3;
        var pos0, pos1, pos2;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.substr(pos, 3) === "\"\"\"") {
          result0 = "\"\"\"";
          pos += 3;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"\\\"\\\"\\\"\"");
          }
        }
        if (result0 !== null) {
          result1 = [];
          pos2 = pos;
          if (input.charCodeAt(pos) === 34) {
            result2 = "\"";
            pos++;
          } else {
            result2 = null;
            if (reportFailures === 0) {
              matchFailed("\"\\\"\"");
            }
          }
          if (result2 === null) {
            if (input.substr(pos, 2) === "\"\"") {
              result2 = "\"\"";
              pos += 2;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"\\\"\\\"\"");
              }
            }
          }
          result2 = result2 !== null ? result2 : "";
          if (result2 !== null) {
            if (/^[^"]/.test(input.charAt(pos))) {
              result3 = input.charAt(pos);
              pos++;
            } else {
              result3 = null;
              if (reportFailures === 0) {
                matchFailed("[^\"]");
              }
            }
            if (result3 !== null) {
              result2 = [result2, result3];
            } else {
              result2 = null;
              pos = pos2;
            }
          } else {
            result2 = null;
            pos = pos2;
          }
          if (result2 === null) {
            result2 = parse_ECHAR();
          }
          while (result2 !== null) {
            result1.push(result2);
            pos2 = pos;
            if (input.charCodeAt(pos) === 34) {
              result2 = "\"";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"\\\"\"");
              }
            }
            if (result2 === null) {
              if (input.substr(pos, 2) === "\"\"") {
                result2 = "\"\"";
                pos += 2;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("\"\\\"\\\"\"");
                }
              }
            }
            result2 = result2 !== null ? result2 : "";
            if (result2 !== null) {
              if (/^[^"]/.test(input.charAt(pos))) {
                result3 = input.charAt(pos);
                pos++;
              } else {
                result3 = null;
                if (reportFailures === 0) {
                  matchFailed("[^\"]");
                }
              }
              if (result3 !== null) {
                result2 = [result2, result3];
              } else {
                result2 = null;
                pos = pos2;
              }
            } else {
              result2 = null;
              pos = pos2;
            }
            if (result2 === null) {
              result2 = parse_ECHAR();
            }
          }
          if (result1 !== null) {
            if (input.substr(pos, 3) === "\"\"\"") {
              result2 = "\"\"\"";
              pos += 3;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"\\\"\\\"\\\"\"");
              }
            }
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, content) { return flattenString(content) })(pos0, result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[142] STRING_LITERAL_LONG2");
        }
        return result0;
      }
      
      function parse_ECHAR() {
        var result0, result1;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        if (input.charCodeAt(pos) === 92) {
          result0 = "\\";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"\\\\\"");
          }
        }
        if (result0 !== null) {
          if (/^[tbnrf"']/.test(input.charAt(pos))) {
            result1 = input.charAt(pos);
            pos++;
          } else {
            result1 = null;
            if (reportFailures === 0) {
              matchFailed("[tbnrf\"']");
            }
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos0;
          }
        } else {
          result0 = null;
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[143] ECHAR");
        }
        return result0;
      }
      
      function parse_NIL() {
        var result0, result1, result2;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        if (input.charCodeAt(pos) === 40) {
          result0 = "(";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"(\"");
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.charCodeAt(pos) === 41) {
              result2 = ")";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\")\"");
              }
            }
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos1;
            }
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset) {
        
              return  {token: "triplesnodecollection", 
                       triplesContext:[], 
                       chainSubject:[{token:'uri', value:"http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"}]};
        })(pos0);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[144] NIL");
        }
        return result0;
      }
      
      function parse_WS() {
        var result0;
        
        reportFailures++;
        if (/^[ ]/.test(input.charAt(pos))) {
          result0 = input.charAt(pos);
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("[ ]");
          }
        }
        if (result0 === null) {
          if (/^[\t]/.test(input.charAt(pos))) {
            result0 = input.charAt(pos);
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("[\\t]");
            }
          }
          if (result0 === null) {
            if (/^[\r]/.test(input.charAt(pos))) {
              result0 = input.charAt(pos);
              pos++;
            } else {
              result0 = null;
              if (reportFailures === 0) {
                matchFailed("[\\r]");
              }
            }
            if (result0 === null) {
              if (/^[\n]/.test(input.charAt(pos))) {
                result0 = input.charAt(pos);
                pos++;
              } else {
                result0 = null;
                if (reportFailures === 0) {
                  matchFailed("[\\n]");
                }
              }
              if (result0 === null) {
                result0 = parse_COMMENT();
              }
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[145] WS");
        }
        return result0;
      }
      
      function parse_COMMENT() {
        var result0, result1, result2;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        if (input.charCodeAt(pos) === 35) {
          result0 = "#";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"#\"");
          }
        }
        if (result0 !== null) {
          result1 = [];
          if (/^[^\n\r]/.test(input.charAt(pos))) {
            result2 = input.charAt(pos);
            pos++;
          } else {
            result2 = null;
            if (reportFailures === 0) {
              matchFailed("[^\\n\\r]");
            }
          }
          while (result2 !== null) {
            result1.push(result2);
            if (/^[^\n\r]/.test(input.charAt(pos))) {
              result2 = input.charAt(pos);
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("[^\\n\\r]");
              }
            }
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos0;
          }
        } else {
          result0 = null;
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed(" COMMENT");
        }
        return result0;
      }
      
      function parse_ANON() {
        var result0, result1, result2;
        var pos0;
        
        reportFailures++;
        pos0 = pos;
        if (input.charCodeAt(pos) === 91) {
          result0 = "[";
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("\"[\"");
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_WS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_WS();
          }
          if (result1 !== null) {
            if (input.charCodeAt(pos) === 93) {
              result2 = "]";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\"]\"");
              }
            }
            if (result2 !== null) {
              result0 = [result0, result1, result2];
            } else {
              result0 = null;
              pos = pos0;
            }
          } else {
            result0 = null;
            pos = pos0;
          }
        } else {
          result0 = null;
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[146] ANON");
        }
        return result0;
      }
      
      function parse_PN_CHARS_BASE() {
        var result0;
        
        reportFailures++;
        if (/^[A-Z]/.test(input.charAt(pos))) {
          result0 = input.charAt(pos);
          pos++;
        } else {
          result0 = null;
          if (reportFailures === 0) {
            matchFailed("[A-Z]");
          }
        }
        if (result0 === null) {
          if (/^[a-z]/.test(input.charAt(pos))) {
            result0 = input.charAt(pos);
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("[a-z]");
            }
          }
          if (result0 === null) {
            if (/^[\xC0-\xD6]/.test(input.charAt(pos))) {
              result0 = input.charAt(pos);
              pos++;
            } else {
              result0 = null;
              if (reportFailures === 0) {
                matchFailed("[\\xC0-\\xD6]");
              }
            }
            if (result0 === null) {
              if (/^[\xD8-\xF6]/.test(input.charAt(pos))) {
                result0 = input.charAt(pos);
                pos++;
              } else {
                result0 = null;
                if (reportFailures === 0) {
                  matchFailed("[\\xD8-\\xF6]");
                }
              }
              if (result0 === null) {
                if (/^[\xF8-\u02FF]/.test(input.charAt(pos))) {
                  result0 = input.charAt(pos);
                  pos++;
                } else {
                  result0 = null;
                  if (reportFailures === 0) {
                    matchFailed("[\\xF8-\\u02FF]");
                  }
                }
                if (result0 === null) {
                  if (/^[\u0370-\u037D]/.test(input.charAt(pos))) {
                    result0 = input.charAt(pos);
                    pos++;
                  } else {
                    result0 = null;
                    if (reportFailures === 0) {
                      matchFailed("[\\u0370-\\u037D]");
                    }
                  }
                  if (result0 === null) {
                    if (/^[\u037F-\u1FFF]/.test(input.charAt(pos))) {
                      result0 = input.charAt(pos);
                      pos++;
                    } else {
                      result0 = null;
                      if (reportFailures === 0) {
                        matchFailed("[\\u037F-\\u1FFF]");
                      }
                    }
                    if (result0 === null) {
                      if (/^[\u200C-\u200D]/.test(input.charAt(pos))) {
                        result0 = input.charAt(pos);
                        pos++;
                      } else {
                        result0 = null;
                        if (reportFailures === 0) {
                          matchFailed("[\\u200C-\\u200D]");
                        }
                      }
                      if (result0 === null) {
                        if (/^[\u2070-\u218F]/.test(input.charAt(pos))) {
                          result0 = input.charAt(pos);
                          pos++;
                        } else {
                          result0 = null;
                          if (reportFailures === 0) {
                            matchFailed("[\\u2070-\\u218F]");
                          }
                        }
                        if (result0 === null) {
                          if (/^[\u2C00-\u2FEF]/.test(input.charAt(pos))) {
                            result0 = input.charAt(pos);
                            pos++;
                          } else {
                            result0 = null;
                            if (reportFailures === 0) {
                              matchFailed("[\\u2C00-\\u2FEF]");
                            }
                          }
                          if (result0 === null) {
                            if (/^[\u3001-\uD7FF]/.test(input.charAt(pos))) {
                              result0 = input.charAt(pos);
                              pos++;
                            } else {
                              result0 = null;
                              if (reportFailures === 0) {
                                matchFailed("[\\u3001-\\uD7FF]");
                              }
                            }
                            if (result0 === null) {
                              if (/^[\uF900-\uFDCF]/.test(input.charAt(pos))) {
                                result0 = input.charAt(pos);
                                pos++;
                              } else {
                                result0 = null;
                                if (reportFailures === 0) {
                                  matchFailed("[\\uF900-\\uFDCF]");
                                }
                              }
                              if (result0 === null) {
                                if (/^[\uFDF0-\uFFFD]/.test(input.charAt(pos))) {
                                  result0 = input.charAt(pos);
                                  pos++;
                                } else {
                                  result0 = null;
                                  if (reportFailures === 0) {
                                    matchFailed("[\\uFDF0-\\uFFFD]");
                                  }
                                }
                                if (result0 === null) {
                                  if (/^[\u1000-\uEFFF]/.test(input.charAt(pos))) {
                                    result0 = input.charAt(pos);
                                    pos++;
                                  } else {
                                    result0 = null;
                                    if (reportFailures === 0) {
                                      matchFailed("[\\u1000-\\uEFFF]");
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[147] PN_CHARS_BASE");
        }
        return result0;
      }
      
      function parse_PN_CHARS_U() {
        var result0;
        
        reportFailures++;
        result0 = parse_PN_CHARS_BASE();
        if (result0 === null) {
          if (input.charCodeAt(pos) === 95) {
            result0 = "_";
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"_\"");
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[148] PN_CHARS_U");
        }
        return result0;
      }
      
      function parse_VARNAME() {
        var result0, result1, result2;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_PN_CHARS_U();
        if (result0 === null) {
          if (/^[0-9]/.test(input.charAt(pos))) {
            result0 = input.charAt(pos);
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("[0-9]");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_PN_CHARS_U();
          if (result2 === null) {
            if (/^[0-9]/.test(input.charAt(pos))) {
              result2 = input.charAt(pos);
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("[0-9]");
              }
            }
            if (result2 === null) {
              if (/^[\xB7]/.test(input.charAt(pos))) {
                result2 = input.charAt(pos);
                pos++;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("[\\xB7]");
                }
              }
              if (result2 === null) {
                if (/^[\u0300-\u036F]/.test(input.charAt(pos))) {
                  result2 = input.charAt(pos);
                  pos++;
                } else {
                  result2 = null;
                  if (reportFailures === 0) {
                    matchFailed("[\\u0300-\\u036F]");
                  }
                }
                if (result2 === null) {
                  if (/^[\u203F-\u2040]/.test(input.charAt(pos))) {
                    result2 = input.charAt(pos);
                    pos++;
                  } else {
                    result2 = null;
                    if (reportFailures === 0) {
                      matchFailed("[\\u203F-\\u2040]");
                    }
                  }
                }
              }
            }
          }
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_PN_CHARS_U();
            if (result2 === null) {
              if (/^[0-9]/.test(input.charAt(pos))) {
                result2 = input.charAt(pos);
                pos++;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("[0-9]");
                }
              }
              if (result2 === null) {
                if (/^[\xB7]/.test(input.charAt(pos))) {
                  result2 = input.charAt(pos);
                  pos++;
                } else {
                  result2 = null;
                  if (reportFailures === 0) {
                    matchFailed("[\\xB7]");
                  }
                }
                if (result2 === null) {
                  if (/^[\u0300-\u036F]/.test(input.charAt(pos))) {
                    result2 = input.charAt(pos);
                    pos++;
                  } else {
                    result2 = null;
                    if (reportFailures === 0) {
                      matchFailed("[\\u0300-\\u036F]");
                    }
                  }
                  if (result2 === null) {
                    if (/^[\u203F-\u2040]/.test(input.charAt(pos))) {
                      result2 = input.charAt(pos);
                      pos++;
                    } else {
                      result2 = null;
                      if (reportFailures === 0) {
                        matchFailed("[\\u203F-\\u2040]");
                      }
                    }
                  }
                }
              }
            }
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, init, rpart) { return init+rpart.join('') })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[149] VARNAME");
        }
        return result0;
      }
      
      function parse_PN_CHARS() {
        var result0;
        
        reportFailures++;
        result0 = parse_PN_CHARS_U();
        if (result0 === null) {
          if (input.charCodeAt(pos) === 45) {
            result0 = "-";
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("\"-\"");
            }
          }
          if (result0 === null) {
            if (/^[0-9]/.test(input.charAt(pos))) {
              result0 = input.charAt(pos);
              pos++;
            } else {
              result0 = null;
              if (reportFailures === 0) {
                matchFailed("[0-9]");
              }
            }
            if (result0 === null) {
              if (/^[\xB7]/.test(input.charAt(pos))) {
                result0 = input.charAt(pos);
                pos++;
              } else {
                result0 = null;
                if (reportFailures === 0) {
                  matchFailed("[\\xB7]");
                }
              }
              if (result0 === null) {
                if (/^[\u0300-\u036F]/.test(input.charAt(pos))) {
                  result0 = input.charAt(pos);
                  pos++;
                } else {
                  result0 = null;
                  if (reportFailures === 0) {
                    matchFailed("[\\u0300-\\u036F]");
                  }
                }
                if (result0 === null) {
                  if (/^[\u203F-\u2040]/.test(input.charAt(pos))) {
                    result0 = input.charAt(pos);
                    pos++;
                  } else {
                    result0 = null;
                    if (reportFailures === 0) {
                      matchFailed("[\\u203F-\\u2040]");
                    }
                  }
                }
              }
            }
          }
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[150] PN_CHARS");
        }
        return result0;
      }
      
      function parse_PN_PREFIX() {
        var result0, result1, result2;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_PN_CHARS_BASE();
        if (result0 !== null) {
          result1 = [];
          result2 = parse_PN_CHARS();
          if (result2 === null) {
            if (input.charCodeAt(pos) === 46) {
              result2 = ".";
              pos++;
            } else {
              result2 = null;
              if (reportFailures === 0) {
                matchFailed("\".\"");
              }
            }
          }
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_PN_CHARS();
            if (result2 === null) {
              if (input.charCodeAt(pos) === 46) {
                result2 = ".";
                pos++;
              } else {
                result2 = null;
                if (reportFailures === 0) {
                  matchFailed("\".\"");
                }
              }
            }
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, base, rest) { if(rest[rest.length-1] == '.'){
                                                      	throw new Error("Wrong PN_PREFIX, cannot finish with '.'")
        					      } else {
        						  return base + rest.join('');
        					      }})(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[151] PN_PREFIX");
        }
        return result0;
      }
      
      function parse_PN_LOCAL() {
        var result0, result1, result2;
        var pos0, pos1;
        
        reportFailures++;
        pos0 = pos;
        pos1 = pos;
        result0 = parse_PN_CHARS_U();
        if (result0 === null) {
          if (/^[0-9]/.test(input.charAt(pos))) {
            result0 = input.charAt(pos);
            pos++;
          } else {
            result0 = null;
            if (reportFailures === 0) {
              matchFailed("[0-9]");
            }
          }
        }
        if (result0 !== null) {
          result1 = [];
          result2 = parse_PN_CHARS();
          while (result2 !== null) {
            result1.push(result2);
            result2 = parse_PN_CHARS();
          }
          if (result1 !== null) {
            result0 = [result0, result1];
          } else {
            result0 = null;
            pos = pos1;
          }
        } else {
          result0 = null;
          pos = pos1;
        }
        if (result0 !== null) {
          result0 = (function(offset, base, rest) { 
                                                               return base + rest.join('');
                                                             })(pos0, result0[0], result0[1]);
        }
        if (result0 === null) {
          pos = pos0;
        }
        reportFailures--;
        if (reportFailures === 0 && result0 === null) {
          matchFailed("[152] PN_LOCAL");
        }
        return result0;
      }
      
      
      function cleanupExpected(expected) {
        expected.sort();
        
        var lastExpected = null;
        var cleanExpected = [];
        for (var i = 0; i < expected.length; i++) {
          if (expected[i] !== lastExpected) {
            cleanExpected.push(expected[i]);
            lastExpected = expected[i];
          }
        }
        return cleanExpected;
      }
      
      function computeErrorPosition() {
        /*
         * The first idea was to use |String.split| to break the input up to the
         * error position along newlines and derive the line and column from
         * there. However IE's |split| implementation is so broken that it was
         * enough to prevent it.
         */
        
        var line = 1;
        var column = 1;
        var seenCR = false;
        
        for (var i = 0; i < Math.max(pos, rightmostFailuresPos); i++) {
          var ch = input.charAt(i);
          if (ch === "\n") {
            if (!seenCR) { line++; }
            column = 1;
            seenCR = false;
          } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
            line++;
            column = 1;
            seenCR = true;
          } else {
            column++;
            seenCR = false;
          }
        }
        
        return { line: line, column: column };
      }
      
      
          var flattenString = function(arrs) {
              var acum ="";
              for(var i=0; i< arrs.length; i++) {
                if(typeof(arrs[i])==='string') {
                  acum = acum + arrs[i];
                } else {
                  acum = acum + arrs[i].join('');
                }
              }
      
              return acum;
          }
      
      
          var GlobalBlankNodeCounter = 0;
      
          var prefixes = {};
      
          var registerPrefix = function(prefix, uri) {
              prefixes[prefix] = uri;
          }
      
          var registerDefaultPrefix = function(uri) {
              prefixes[null] = uri;
          }
      
          var arrayToString = function(array) {
              var tmp = "";
              for(var i=0; i<array.length; i++) {
                  tmp = tmp + array[i];            
              }
      
              return tmp.toUpperCase();
          }
      
      
      var result = parseFunctions[startRule]();
      
      /*
       * The parser is now in one of the following three states:
       *
       * 1. The parser successfully parsed the whole input.
       *
       *    - |result !== null|
       *    - |pos === input.length|
       *    - |rightmostFailuresExpected| may or may not contain something
       *
       * 2. The parser successfully parsed only a part of the input.
       *
       *    - |result !== null|
       *    - |pos < input.length|
       *    - |rightmostFailuresExpected| may or may not contain something
       *
       * 3. The parser did not successfully parse any part of the input.
       *
       *   - |result === null|
       *   - |pos === 0|
       *   - |rightmostFailuresExpected| contains at least one failure
       *
       * All code following this comment (including called functions) must
       * handle these states.
       */
      if (result === null || pos !== input.length) {
        var offset = Math.max(pos, rightmostFailuresPos);
        var found = offset < input.length ? input.charAt(offset) : null;
        var errorPosition = computeErrorPosition();
        
        throw new this.SyntaxError(
          cleanupExpected(rightmostFailuresExpected),
          found,
          offset,
          errorPosition.line,
          errorPosition.column
        );
      }
      
      return result;
    },
    
    /* Returns the parser source code. */
    toSource: function() { return this._source; }
  };
  
  /* Thrown when a parser encounters a syntax error. */
  
  result.SyntaxError = function(expected, found, offset, line, column) {
    function buildMessage(expected, found) {
      var expectedHumanized, foundHumanized;
      
      switch (expected.length) {
        case 0:
          expectedHumanized = "end of input";
          break;
        case 1:
          expectedHumanized = expected[0];
          break;
        default:
          expectedHumanized = expected.slice(0, expected.length - 1).join(", ")
            + " or "
            + expected[expected.length - 1];
      }
      
      foundHumanized = found ? quote(found) : "end of input";
      
      return "Expected " + expectedHumanized + " but " + foundHumanized + " found.";
    }
    
    this.name = "SyntaxError";
    this.expected = expected;
    this.found = found;
    this.message = buildMessage(expected, found);
    this.offset = offset;
    this.line = line;
    this.column = column;
  };
  
  result.SyntaxError.prototype = Error.prototype;
  
  return result;
})();

// end of ./src/js-sparql-parser/src/sparql_parser.js 
// exports
var RDFJSInterface = {};

// imports

/**
 * Implementation of <http://www.w3.org/TR/rdf-interfaces/>
 */

// Uris map

RDFJSInterface.defaultContext = { "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#",
                                  "dcterms": "http://purl.org/dc/terms/",
                                  "foaf": "http://xmlns.com/foaf/0.1/",
                                  "cal": "http://www.w3.org/2002/12/cal/ical#",
                                  "vcard": "http://www.w3.org/2006/vcard/ns# ",
                                  "geo": "http://www.w3.org/2003/01/geo/wgs84_pos#",
                                  "cc": "http://creativecommons.org/ns#",
                                  "sioc": "http://rdfs.org/sioc/ns#",
                                  "doap": "http://usefulinc.com/ns/doap#",
                                  "com": "http://purl.org/commerce#",
                                  "ps": "http://purl.org/payswarm#",
                                  "gr": "http://purl.org/goodrelations/v1#",
                                  "sig": "http://purl.org/signature#",
                                  "ccard": "http://purl.org/commerce/creditcard#"
                                };

RDFJSInterface.UrisMap = function() {
    this.defaultNs = "";
    this.interfaceProperties = ['get', 'remove', 'set', 'setDefault',
                                'addAll', 'resolve', 'shrink'];
};

RDFJSInterface.UrisMap.prototype.values = function() {
    var collected = {};
    for(var p in this) {
        if(!Utils.include(this.interfaceProperties,p) && 
           typeof(this[p])!=='function' &&
           p!=='defaultNs' &&
           p!=='interfaceProperties') {
            collected[p] = this[p];
        }
    }

    return collected;
};

RDFJSInterface.UrisMap.prototype.get = function(prefix) {
    if(prefix.indexOf(" ") != -1) {
        throw "Prefix must not contain any whitespaces";
    }
    return this[prefix];
};

RDFJSInterface.UrisMap.prototype.remove = function(prefix) {
    if(prefix.indexOf(" ") != -1) {
        throw "Prefix must not contain any whitespaces";
    }

    delete this[prefix];

    return null;
};

RDFJSInterface.UrisMap.prototype.set = function(prefix, iri) {
    if(prefix.indexOf(" ") != -1) {
        throw "Prefix must not contain any whitespaces";
    }

    this[prefix] = iri;
};


RDFJSInterface.UrisMap.prototype.setDefault = function(iri) {
    this.defaultNs =iri;
};

RDFJSInterface.UrisMap.prototype.addAll = function(prefixMap, override) {
    for(var prefix in prefixMap) {
        if(!Utils.include(this.interfaceProperties, prefix)) {
            if(this[prefix] != null) {
                if(override === true) {
                    this[prefix] = prefixMap[prefix];
                }
            } else {
                this[prefix] = prefixMap[prefix];
            }
        }
    }

    return this;
};

RDFJSInterface.UrisMap.prototype.resolve = function(curie) {
    var parts = curie.split(":");
    var ns = parts[0];
    var suffix = parts[1];
    if(ns === '') {
        if(this.defaultNs == null) {
            return null;
        } else {
            return this.defaultNs + suffix;
        }
    } else if(this.hasOwnProperty(ns)) {
        return this[ns] + suffix;
    } else {
        return null;
    }
};

RDFJSInterface.UrisMap.prototype.shrink = function(iri) {
    for(var ns in this) {
        var prefix = this[ns];
        if(iri.indexOf(prefix) === 0) {
            if(prefix !== '' && ns != 'defaultNs') {
                var suffix = iri.split(prefix)[1];
                return ns + ":" + suffix;
            }
        }
    }

    return iri;
};

// Profile

RDFJSInterface.Profile = function() {
    this.prefixes = new RDFJSInterface.UrisMap();
    this.terms = new RDFJSInterface.UrisMap();
};

RDFJSInterface.Profile.prototype.importProfile = function(profile, override) {    
    this.prefixes.addAll(profile.prefixes, override);
    this.terms.addAll(profile.terms, override);
};


RDFJSInterface.Profile.prototype.resolve = function(toResolve) {
    if(toResolve.indexOf(":") != -1) {
        return this.prefixes.resolve(toResolve);
    } else if(this.terms[toResolve] != null) {
        return this.terms.resolve(toResolve);
    } else {
        return null;
    }
};

RDFJSInterface.Profile.prototype.setDefaultPrefix = function(iri) {
    this.prefixes.setDefault(iri);
};

RDFJSInterface.Profile.prototype.setDefaultVocabulary = function(iri) {
    this.terms.setDefault(iri);
};

RDFJSInterface.Profile.prototype.setPrefix = function(prefix, iri) {
    this.prefixes.set(prefix, iri);
};

RDFJSInterface.Profile.prototype.setTerm = function(term, iri) {
    this.terms.set(term, iri);
};

// RDF environemnt
RDFJSInterface.RDFEnvironment = function () {
    this.blankNodeCounter = 0;
    var that = this;
    this.filters = {
        s:function (s) {
            return function (t) {
                return t.subject.equals(s);
            };
        },
        p:function (p) {
            return function (t) {
                return t.predicate.equals(p);
            };
        },
        o:function (o) {
            return function (t) {
                return t.object.equals(o);
            };
        },
        sp:function (s, p) {
            return function (t) {
                return t.subject.equals(s) && t.predicate.equals(p);
            };
        },
        so:function (s, o) {
            return function (t) {
                return t.subject.equals(s) && t.object.equals(o);
            };
        },
        po:function (p, o) {
            return function (t) {
                return t.predicate.equals(p) && t.object.equals(o);
            };
        },
        spo:function (s, p, o) {
            return function (t) {
                return t.subject.equals(s) && t.predicate.equals(p) && t.object.equals(o);
            };
        },
        describes:function (v) {
            return function (t) {
                return t.subject.equals(v) || t.object.equals(v);
            };
        },
        type:function (o) {
            var type = that.resolve("rdf:type");
            return function (t) {
                return t.predicate.equals(type) && t.object.equals(o);
            };
        }
    };

    for (var p in RDFJSInterface.defaultContext) {
        this.prefixes.set(p, RDFJSInterface.defaultContext[p]);
    }
};
Utils['extends'](RDFJSInterface.Profile,RDFJSInterface.RDFEnvironment);

RDFJSInterface.RDFEnvironment.prototype.createBlankNode = function() {
     var bnode =  new RDFJSInterface.BlankNode(this.blankNodeCounter);
    this.blankNodeCounter++;
    return bnode;
};

RDFJSInterface.RDFEnvironment.prototype.createNamedNode = function(value) {
    var resolvedValue = this.resolve(value);
    if(resolvedValue != null) {
        return new RDFJSInterface.NamedNode(resolvedValue);
    } else {
        return new RDFJSInterface.NamedNode(value);
    }
};

RDFJSInterface.RDFEnvironment.prototype.createLiteral = function(value, language, datatype) {
    if(datatype != null) {
        return new RDFJSInterface.Literal(value, language, datatype.toString());
    } else {
        return new RDFJSInterface.Literal(value, language, datatype);
    }
};

RDFJSInterface.RDFEnvironment.prototype.createTriple = function(subject, predicate, object) {
    return new RDFJSInterface.Triple(subject, predicate, object);
};

RDFJSInterface.RDFEnvironment.prototype.createGraph = function(triples) {
    var graph = new RDFJSInterface.Graph();
    if(triples != null) {
        for(var i=0; i<triples.length; i++) {
            graph.add(triples[i]);
        }
    }
    return graph;
};

RDFJSInterface.RDFEnvironment.prototype.createAction = function(test, action) {
    return function(triple) {
        if(test(triple)) {
            return action(triple);
        } else {
            return triple;
        }
    }
};

RDFJSInterface.RDFEnvironment.prototype.createProfile = function(empty) {
    // empty (opt);
    if(empty === true) {
        return new RDFJSInterface.RDFEnvironment.Profile();
    } else {
        var profile = new RDFJSInterface.RDFEnvironment.Profile();
        profile.importProfile(this);

        return profile;
    }
};

RDFJSInterface.RDFEnvironment.prototype.createTermMap = function(empty) {
    if(empty === true) {
        return new RDFJSInterface.UrisMap();
    } else {
      var cloned = this.terms.values();
      var termMap = new RDFJSInterface.UrisMap();
   
      for(var p in cloned) {
          termMap[p] = cloned[p];
      }
   
      return termMap;
    }
};

RDFJSInterface.RDFEnvironment.prototype.createPrefixMap = function(empty) {
    if(empty === true) {
        return new RDFJSInterface.UrisMap();
    } else {
      var cloned = this.prefixes.values();
      var prefixMap = new RDFJSInterface.UrisMap();
   
      for(var p in cloned) {
          prefixMap[p] = cloned[p];
      }
   
      return prefixMap;
    }    
};

// Common RDFNode interface

RDFJSInterface.RDFNode = function(interfaceName){
    this.interfaceName = interfaceName;
    this.attributes  = ["interfaceName", "nominalValue"]
};

RDFJSInterface.RDFNode.prototype.equals = function(otherNode) {
    if(otherNode.interfaceName == null) {
        return this.valueOf() == otherNode;

    } else {
        for(var i in this.attributes) {
            var attribute = this.attributes[i];
            if(this[attribute] != otherNode[attribute]) {
                return false;
            }
        }
      
        return true;
    }
};


// Blank node

RDFJSInterface.BlankNode = function(bnodeId) {
    RDFJSInterface.RDFNode.call(this, "BlankNode");
    this.nominalValue = "_:"+bnodeId;
    this.bnodeId = bnodeId;
};

Utils['extends'](RDFJSInterface.RDFNode,RDFJSInterface.BlankNode);

RDFJSInterface.BlankNode.prototype.toString = function(){
    return this.nominalValue;
};

RDFJSInterface.BlankNode.prototype.toNT = function() {
    return this.nominalValue;
};

RDFJSInterface.BlankNode.prototype.valueOf = function() {
    return this.nominalValue;
};

// Literal node

RDFJSInterface.Literal = function(value, language, datatype) {
    RDFJSInterface.RDFNode.call(this, "Literal");
    this.nominalValue = value;
    if(language != null) {
        this.language = language;
    } else if(datatype != null) {
        this.datatype = datatype;
    }
};

Utils['extends'](RDFJSInterface.RDFNode,RDFJSInterface.Literal);

RDFJSInterface.Literal.prototype.toString = function(){
    if(this.nominalValue.match("\n")) {
        var tmp = '"""'+this.nominalValue+'"""';
        if(this.nominalValue.match(/"""/)) {
            var tmp = "'''"+this.nominalValue+"'''";
        }
    } else {
        if(this.nominalValue.match(/"/)) {
            var tmp = "'"+this.nominalValue+"'";
            if(this.nominalValue.match(/'/)) {
                var tmp = '"""'+this.nominalValue+'"""';
                if(this.nominalValue.match(/"""/)) {
                    var tmp = "'''"+this.nominalValue+"'''";
                    if(this.nominalValue.match(/'''/)) {
                        throw "Literal not possible to escape in a String.";
                    }
                }
            }
        } else {
            var tmp = '"'+this.nominalValue+'"';
        }
    };
    if(this.language != null) {
        tmp = tmp + "@" + this.language;
    } else if(this.datatype != null || this.type) {
        tmp = tmp + "^^<" + (this.datatype||this.type) + ">";
    }
    return tmp;
};

RDFJSInterface.Literal.prototype.toNT = function() {
    return this.toString();
};

RDFJSInterface.Literal.prototype.valueOf = function() {
    return QueryFilters.effectiveTypeValue({token: 'literal', 
                                            type: (this.type || this.datatype), 
                                            value: this.nominalValue, 
                                            language: this.language});
};

// NamedNode node

RDFJSInterface.NamedNode = function(val) {
    RDFJSInterface.RDFNode.call(this, "NamedNode");
    if(val.value != null) {
        this.nominalValue = val.value;
    } else {
        this.nominalValue = val;
    }
};

Utils['extends'](RDFJSInterface.RDFNode,RDFJSInterface.NamedNode);

RDFJSInterface.NamedNode.prototype.toString = function(){
    return this.nominalValue;
};

RDFJSInterface.NamedNode.prototype.toNT = function() {
    return "<"+this.toString()+">";
};

RDFJSInterface.NamedNode.prototype.valueOf = function() {
    return this.nominalValue;
};

// Triple interface
RDFJSInterface.Triple = function(subject, predicate, object){
    this.subject = subject;
    this.predicate = predicate;
    this.object = object;
};

RDFJSInterface.Triple.prototype.equals = function(otherTriple) {
    return this.subject.equals(otherTriple.subject) &&
           this.predicate.equals(otherTriple.predicate) &&
           this.object.equals(otherTriple.object);
};

RDFJSInterface.Triple.prototype.toString = function() {
    return this.subject.toNT()+" "+this.predicate.toNT()+" "+this.object.toNT()+" . \r\n";
};

// Graph interface

RDFJSInterface.Graph = function() {
    this.triples = [];
    this.duplicates = {};
    this.actions = [];
    this.length = 0;
};

RDFJSInterface.Graph.prototype.add = function(triple) {
    for(var i=0; i<this.actions.length; i++) {
        triple = this.actions[i](triple);
    }
    
    var id = triple.subject.toString()+triple.predicate.toString()+triple.object.toString();
    if(!this.duplicates[id]) {
        this.duplicates[id] = true;
        this.triples.push(triple);
    }

    this.length = this.triples.length;
    return this;
};

RDFJSInterface.Graph.prototype.addAction = function (tripleAction, run) {
    this.actions.push(tripleAction);
    if (run == true) {
        for (var i = 0; i < this.triples.length; i++) {
            this.triples[i] = tripleAction(this.triples[i]);
        }
    }

    return this;
};

RDFJSInterface.Graph.prototype.addAll = function (graph) {
    var newTriples = graph.toArray();
    for (var i = 0; i < newTriples.length; i++) {
        this.add(newTriples[i]);
    }

    this.length = this.triples.length;
    return this;
};

RDFJSInterface.Graph.prototype.remove = function(triple) {
    var toRemove = null;
    for(var i=0; i<this.triples.length; i++) {
        if(this.triples[i].equals(triple)) {
            var id = triple.subject.toString()+triple.predicate.toString()+triple.object.toString();
            delete this.duplicates[id];
            toRemove = i;
            break;
        }
    }

    if(toRemove!=null) {
        this.triples.splice(toRemove,1);
    }

    this.length = this.triples.length;
    return this;
};

RDFJSInterface.Graph.prototype.toArray = function() {
    return this.triples;
};

RDFJSInterface.Graph.prototype.some = function(p) {
    for(var i=0; i<this.triples.length; i++) {
        if(p(this.triples[i],this) === true) {
            return true;
        }
    }

    return false;
};

RDFJSInterface.Graph.prototype.every = function(p) {
    for(var i=0; i<this.triples.length; i++) {
        if(p(this.triples[i],this) === false) {
            return false;
        }
    }

    return true;
};

RDFJSInterface.Graph.prototype.filter = function(f) {
    var tmp = new RDFJSInterface.Graph();

    for(var i=0; i<this.triples.length; i++) {
        if(f(this.triples[i],this) === true) {
            tmp.add(this.triples[i]);
        }
    }

    return tmp;
};

RDFJSInterface.Graph.prototype.forEach = function(f) {
    for(var i=0; i<this.triples.length; i++) {
        f(this.triples[i],this);
    }
};

RDFJSInterface.Graph.prototype.merge = function(g) {
    var newGraph = new RDFJSInterface.Graph();
    for(var i=0; i<this.triples.length; i++)
        newGraph.add(this.triples[i]);
    
    return newGraph;
};

RDFJSInterface.Graph.prototype.match = function(subject, predicate, object, limit) {
    var graph = new RDFJSInterface.Graph();

    var matched = 0;
    for(var i=0; i<this.triples.length; i++) {
        var triple = this.triples[i];
        if(subject == null || (triple.subject.equals(subject))) {
            if(predicate == null || (triple.predicate.equals(predicate))) {
                if(object == null || (triple.object.equals(object))) {
                    if(limit==null || matched < limit) {
                        matched++;
                        graph.add(triple);
                    } else {
                        return graph;
                    }
                }
            }
        }
    }

    return graph;
};

RDFJSInterface.Graph.prototype.removeMatches = function(subject, predicate, object) {
    var toRemove = [];
    for(var i=0; i<this.triples.length; i++) {
        var triple = this.triples[i];
        if(subject == null || (triple.subject.equals(subject))) {
            if(predicate == null || (triple.predicate.equals(predicate))) {
                if(object == null || (triple.object.equals(object))) {
                    toRemove.push(triple);
                }
            }
        }
    }

    for(var i=0; i<toRemove.length; i++) {
        this.remove(toRemove[i]);
    }

    return this;
};

RDFJSInterface.Graph.prototype.toNT = function() {
    var n3 = "";

    this.forEach(function(triple) {
        n3 = n3 + triple.toString();
    });

    return n3;
};

// Builders for the query engine

RDFJSInterface.buildRDFResource = function(value, bindings, engine, env) {
    if(value.token === 'blank') {
        return RDFJSInterface.buildBlankNode(value, bindings, engine, env);
    } else if(value.token === 'literal') {
        return RDFJSInterface.buildLiteral(value, bindings, engine, env);
    } else if(value.token === 'uri') {
        return RDFJSInterface.buildNamedNode(value, bindings, engine, env);
    } else if(value.token === 'var') {
        var result = bindings[value.value];
        if(result != null) {
            return RDFJSInterface.buildRDFResource(result, bindings, engine, env);
        } else {
            return null;
        }
    } else {
        return null;
    }
};

RDFJSInterface.buildBlankNode = function(value, bindings, engine, env) {
    if(value.valuetmp != null) {
        value.value = value.valuetmp;
    }
    if(value.value.indexOf("_:") === 0) {
        value.value = value.value.split("_:")[1];
    }
    return new RDFJSInterface.BlankNode(value.value);
};

RDFJSInterface.buildLiteral = function(value, bindings, engine, env) {
    return new RDFJSInterface.Literal(value.value, value.lang, value.type);
};

RDFJSInterface.buildNamedNode = function(value, bindings, engine, env) {
    if(value.value != null) {
        return new RDFJSInterface.NamedNode(value);
    } else {
        if(value.prefix != null) {
            var prefix = engine.resolveNsInEnvironment(value.prefix, env);
            value.value = prefix+value.suffix;
            return new RDFJSInterface.NamedNode(value);
        } else {
            return new RDFJSInterface.NamedNode(value);
        }
    }
};

RDFJSInterface.rdf = new RDFJSInterface.RDFEnvironment();

// end of ./src/js-query-engine/src/rdf_js_interface.js 
// exports
var QueryFilters = {};

// imports

QueryFilters.checkFilters = function(pattern, bindings, nullifyErrors, dataset, queryEnv, queryEngine) {
    var filters = pattern.filter;
    var nullified = [];
    if(filters==null || pattern.length != null) {
        return bindings;
    }

    for(var i=0; i<filters.length; i++) {
        var filter = filters[i];
        var filteredBindings = QueryFilters.run(filter.value, bindings, nullifyErrors, dataset, queryEnv, queryEngine);
        var acum = [];
        for(var j=0; j<filteredBindings.length; j++) {
            if(filteredBindings[j]["__nullify__"]!=null) {
                nullified.push(filteredBindings[j]);
            } else {
                acum.push(filteredBindings[j]);
            }
        }

        bindings = acum;
    }

    return bindings.concat(nullified);
};

QueryFilters.boundVars = function(filterExpr) {
    if(filterExpr.expressionType != null) {
        var expressionType = filterExpr.expressionType;
        if(expressionType == 'relationalexpression') {
            var op1 = filterExpr.op1;
            var op2 = filterExpr.op2;
            return QueryFilters.boundVars(op1)+QueryFilters.boundVars(op2);
        } else if(expressionType == 'conditionalor' || expressionType == 'conditionaland') {
            var vars = [];
            for(var i=0; i< filterExpr.operands; i++) {
                vars = vars.concat(QueryFilters.boundVars(filterExpr.operands[i]));
            }
            return vars;
        } else if(expressionType == 'builtincall') {
            if(filterExpr.args == null) {
                return [];
            } else {
                var acum = [];
                for(var i=0; i< filterExpr.args.length; i++) {
                    acum = acum.concat(QueryFilters.boundVars(filterExpr.args[i]));
                }
                return acum;
            }
        } else if(expressionType == 'multiplicativeexpression') {
            var acum = QueryFilters.boundVars(filterExpr.factor);
            for(var i=0; i<filterExpr.factors.length; i++) {
                acum = acum.concat(QueryFilters.boundVars(filterExpr.factors[i].expression))
            }
            return acum;
        } else if(expressionType == 'additiveexpression') {
            var acum = QueryFilters.boundVars(filterExpr.summand);
            for(var i=0; i<filterExpr.summands.length; i++) {
                acum = acum.concat(QueryFilters.boundVars(filterExpr.summands[i].expression));
            }

            return acum;
        } else if(expressionType == 'regex') {
            var acum = QueryFilters.boundVars(filterExpr.expression1);
            return acum.concat(QueryFilters.boundVars(filterExpr.expression2));
        } else if(expressionType == 'unaryexpression') {
            return QueryFilters.boundVars(filterExpr.expression);
        } else if(expressionType == 'atomic') {           
            if(filterExpr.primaryexpression == 'var') {
                return [filterExpr.value];
            } else {
                // numeric, literal, etc...
                return [];
            }
        }
    } else {
        console.log("ERROR");
        console.log(filterExpr);
        throw("Cannot find bound expressions in a no expression token");
    }
};

QueryFilters.run = function(filterExpr, bindings, nullifyFilters, dataset, env, queryEngine) {    
    var denormBindings = queryEngine.copyDenormalizedBindings(bindings, env.outCache);
    var filteredBindings = [];
    for(var i=0; i<bindings.length; i++) {
        var thisDenormBindings = denormBindings[i];
        var ebv = QueryFilters.runFilter(filterExpr, thisDenormBindings, queryEngine, dataset, env);
        // ebv can be directly a RDFTerm (e.g. atomic expression in filter)
        // this additional call to ebv will return -> true/false/error
        var ebv = QueryFilters.ebv(ebv);
        //console.log("EBV:")
        //console.log(ebv)
        //console.log("FOR:")
        //console.log(thisDenormBindings)
        if(QueryFilters.isEbvError(ebv)) {
            // error
            if(nullifyFilters) {
                var thisBindings = {"__nullify__": true, "bindings": bindings[i]};
                filteredBindings.push(thisBindings);
            }
        } else if(ebv === true) {
            // true
            filteredBindings.push(bindings[i]);
        } else {
            // false
            if(nullifyFilters) {
                var thisBindings = {"__nullify__": true, "bindings": bindings[i]};
                filteredBindings.push(thisBindings);
            }
        }
    }
    return filteredBindings;
};

QueryFilters.collect = function(filterExpr, bindings, dataset, env, queryEngine, callback) {
    var denormBindings = queryEngine.copyDenormalizedBindings(bindings, env.outCache);
    var filteredBindings = [];
    for(var i=0; i<denormBindings.length; i++) {
        var thisDenormBindings = denormBindings[i];
        var ebv = QueryFilters.runFilter(filterExpr, thisDenormBindings, queryEngine, dataset, env);
        filteredBindings.push({binding:bindings[i], value:ebv});
    }
    return(filteredBindings);
};

QueryFilters.runDistinct = function(projectedBindings, projectionVariables) {
};

// @todo add more aggregation functions here
QueryFilters.runAggregator = function(aggregator, bindingsGroup, queryEngine, dataset, env) {
    if(bindingsGroup == null || bindingsGroup.length === 0) {
        return QueryFilters.ebvError();
    } else if(aggregator.token === 'variable' && aggregator.kind == 'var') {
        return bindingsGroup[0][aggregator.value.value];
    } else if(aggregator.token === 'variable' && aggregator.kind === 'aliased') {
        if(aggregator.expression.expressionType === 'atomic' && aggregator.expression.primaryexpression === 'var') {
            return bindingsGroup[0][aggregator.expression.value.value];
        } else if(aggregator.expression.expressionType === 'aggregate') {
            if(aggregator.expression.aggregateType === 'max') {
                var max = null;
                for(var i=0; i< bindingsGroup.length; i++) {
                    var bindings = bindingsGroup[i];
                    var ebv = QueryFilters.runFilter(aggregator.expression.expression, bindings, queryEngine, dataset, env);                    
                    if(!QueryFilters.isEbvError(ebv)) {
                        if(max === null) {
                            max = ebv;
                        } else {
                            if(QueryFilters.runLtFunction(max, ebv).value === true) {
                                max = ebv;
                            }
                        }
                    }
                }

                if(max===null) {
                    return QueryFilters.ebvError();
                } else {
                    return max;
                }
            } else if(aggregator.expression.aggregateType === 'min') {
                var min = null;
                for(var i=0; i< bindingsGroup.length; i++) {
                    var bindings = bindingsGroup[i];
                    var ebv = QueryFilters.runFilter(aggregator.expression.expression, bindings, queryEngine, dataset, env);                    
                    if(!QueryFilters.isEbvError(ebv)) {
                        if(min === null) {
                            min = ebv;
                        } else {
                            if(QueryFilters.runGtFunction(min, ebv).value === true) {
                                min = ebv;
                            }
                        }
                    }
                }

                if(min===null) {
                    return QueryFilters.ebvError();
                } else {
                    return min;
                }
            } else if(aggregator.expression.aggregateType === 'count') {
                var distinct = {};
                var count = 0;
                if(aggregator.expression.expression === '*') {
                    if(aggregator.expression.distinct != null && aggregator.expression.distinct != '') {
                        for(var i=0; i< bindingsGroup.length; i++) {
                            var bindings = bindingsGroup[i];
                            var key = Utils.hashTerm(bindings);
                            if(distinct[key] == null) {
                                distinct[key] = true;
                                count++;
                            }
                        } 
                    } else {
                        count = bindingsGroup.length;
                    }                   
                } else {
                  for(var i=0; i< bindingsGroup.length; i++) {
                      var bindings = bindingsGroup[i];
                      var ebv = QueryFilters.runFilter(aggregator.expression.expression, bindings, queryEngine, dataset, env);                    
                      if(!QueryFilters.isEbvError(ebv)) {
                          if(aggregator.expression.distinct != null && aggregator.expression.distinct != '') {
                              var key = Utils.hashTerm(ebv);
                              if(distinct[key] == null) {
                                  distinct[key] = true;
                                  count++;
                              }
                          } else {
                              count++;
                          }
                      }
                  }
                }

                return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#integer", value:''+count};
            } else if(aggregator.expression.aggregateType === 'avg') {
                var distinct = {};
                var aggregated = {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#integer", value:'0'};
                var count = 0;
                for(var i=0; i< bindingsGroup.length; i++) {
                    var bindings = bindingsGroup[i];
                    var ebv = QueryFilters.runFilter(aggregator.expression.expression, bindings, queryEngine, dataset, env);                    
                    if(!QueryFilters.isEbvError(ebv)) {
                        if(aggregator.expression.distinct != null && aggregator.expression.distinct != '') {
                            var key = Utils.hashTerm(ebv);
                            if(distinct[key] == null) {
                                distinct[key] = true;
                                if(QueryFilters.isNumeric(ebv)) {
                                    aggregated = QueryFilters.runSumFunction(aggregated, ebv);
                                    count++;
                                }
                            }
                        } else {
                            if(QueryFilters.isNumeric(ebv)) {
                                aggregated = QueryFilters.runSumFunction(aggregated, ebv);
                                count++;
                            }
                        }
                    }
                }

                var result = QueryFilters.runDivFunction(aggregated, {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#integer", value:''+count});
                result.value = ''+result.value;
                return result;
            } else if(aggregator.expression.aggregateType === 'sum') {
                var distinct = {};
                var aggregated = {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#integer", value:'0'};
                for(var i=0; i< bindingsGroup.length; i++) {
                    var bindings = bindingsGroup[i];
                    var ebv = QueryFilters.runFilter(aggregator.expression.expression, bindings, queryEngine, dataset, env);                    
                    if(!QueryFilters.isEbvError(ebv)) {
                        if(aggregator.expression.distinct != null && aggregator.expression.distinct != '') {
                            var key = Utils.hashTerm(ebv);
                            if(distinct[key] == null) {
                                distinct[key] = true;
                                if(QueryFilters.isNumeric(ebv)) {
                                    aggregated = QueryFilters.runSumFunction(aggregated, ebv);
                                }
                            }
                        } else {
                            if(QueryFilters.isNumeric(ebv)) {
                                aggregated = QueryFilters.runSumFunction(aggregated, ebv);
                            }
                        }
                    }
                }
                
                aggregated.value =''+aggregated.value;
                return aggregated;
            } else {
                var ebv = QueryFilters.runFilter(aggregate.expression, bindingsGroup[0], dataset, {blanks:{}, outCache:{}});
                return ebv;
            }
        }
    }
};

QueryFilters.runFilter = function(filterExpr, bindings, queryEngine, dataset, env) {
    //console.log("RUNNING FILTER");
    //console.log(filterExpr);
    if(filterExpr.expressionType != null) {
        var expressionType = filterExpr.expressionType;
        if(expressionType == 'relationalexpression') {
            var op1 = QueryFilters.runFilter(filterExpr.op1, bindings,queryEngine, dataset, env);
            var op2 = QueryFilters.runFilter(filterExpr.op2, bindings,queryEngine, dataset, env);
            return QueryFilters.runRelationalFilter(filterExpr, op1, op2, bindings, queryEngine, dataset, env);
        } else if(expressionType == 'conditionalor') {
            return QueryFilters.runOrFunction(filterExpr, bindings, queryEngine, dataset, env);
        } else if (expressionType == 'conditionaland') {
            return QueryFilters.runAndFunction(filterExpr, bindings, queryEngine, dataset, env);
        } else if(expressionType == 'additiveexpression') {
            return QueryFilters.runAddition(filterExpr.summand, filterExpr.summands, bindings, queryEngine, dataset, env);
        } else if(expressionType == 'builtincall') {
            return QueryFilters.runBuiltInCall(filterExpr.builtincall, filterExpr.args, bindings, queryEngine, dataset, env);
        } else if(expressionType == 'multiplicativeexpression') {
            return QueryFilters.runMultiplication(filterExpr.factor, filterExpr.factors, bindings, queryEngine, dataset, env);
        } else if(expressionType == 'unaryexpression') {
            return QueryFilters.runUnaryExpression(filterExpr.unaryexpression, filterExpr.expression, bindings, queryEngine, dataset, env);
        } else if(expressionType == 'irireforfunction') {
            return QueryFilters.runIriRefOrFunction(filterExpr.iriref, filterExpr.args, bindings, queryEngine, dataset, env);
        } else if(expressionType == 'regex') {
            return QueryFilters.runRegex(filterExpr.text, filterExpr.pattern, filterExpr.flags, bindings, queryEngine, dataset, env)
        } else if(expressionType == 'custom') {
            return QueryFilters.runBuiltInCall(filterExpr.name, filterExpr.args, bindings, queryEngine, dataset, env);
        } else if(expressionType == 'atomic') {        
            if(filterExpr.primaryexpression == 'var') {
                // lookup the var in the bindings
                var val = bindings[filterExpr.value.value];
                return val;
            } else {
                // numeric, literal, etc...
                //return queryEngine.filterExpr.value;
                if(typeof(filterExpr.value) != 'object') {
                    return filterExpr.value
                } else {
                    if(filterExpr.value.type == null || typeof(filterExpr.value.type) != 'object') {
                        return filterExpr.value
                    } else {
                        // type can be parsed as a hash using namespaces

                        filterExpr.value.type =  Utils.lexicalFormBaseUri(filterExpr.value.type, env);
                        return filterExpr.value
                    }
                }
            }
        } else {
            throw("Unknown filter expression type");
        }
    } else {
        throw("Cannot find bound expressions in a no expression token");
    }
};

QueryFilters.isRDFTerm = function(val) {
    if(val==null) {
        return false;
    } if((val.token && val.token == 'literal') ||
       (val.token && val.token == 'uri') ||
       (val.token && val.token == 'blank')) {
        return true;
    } else {
        return false;
    }
};


/*
17.4.1.7 RDFterm-equal

 xsd:boolean   RDF term term1 = RDF term term2

Returns TRUE if term1 and term2 are the same RDF term as defined in Resource Description Framework (RDF): 
Concepts and Abstract Syntax [CONCEPTS]; produces a type error if the arguments are both literal but are not 
the same RDF term *; returns FALSE otherwise. term1 and term2 are the same if any of the following is true:

    term1 and term2 are equivalent IRIs as defined in 6.4 RDF URI References of [CONCEPTS].
    term1 and term2 are equivalent literals as defined in 6.5.1 Literal Equality of [CONCEPTS].
    term1 and term2 are the same blank node as described in 6.6 Blank Nodes of [CONCEPTS].
*/
QueryFilters.RDFTermEquality = function(v1, v2, queryEngine, env) {
    if(v1.token === 'literal' && v2.token === 'literal') {
        if(v1.lang == v2.lang && v1.type == v2.type && v1.value == v2.value) {

            return true;
        } else {


            if(v1.type != null && v2.type != null) {
                return  QueryFilters.ebvError();
            } else if(QueryFilters.isSimpleLiteral(v1) && v2.type!=null){
                return QueryFilters.ebvError();
            } else if(QueryFilters.isSimpleLiteral(v2) && v1.type!=null){
                return QueryFilters.ebvError();
            } else {
                return false;
            }

//            if(v1.value != v2.value) {
//                return QueryFilters.ebvError();                                
//            } else if(v1.type && v2.type && v1.type!=v2.type) {
//                return QueryFilters.ebvError();                
//            } else if(QueryFilters.isSimpleLiteral(v1) && v2.type!=null){
//                return QueryFilters.ebvError();
//            } else if(QueryFilters.isSimpleLiteral(v2) && v1.type!=null){
//                return QueryFilters.ebvError();
//            } else {
//                return false;
//            }

        }
    } else if(v1.token === 'uri' && v2.token === 'uri') {
        return Utils.lexicalFormBaseUri(v1, env) == Utils.lexicalFormBaseUri(v2, env);
    } else if(v1.token === 'blank' && v2.token === 'blank') {
        return v1.value == v2.value;
    } else {
        return false;
    }
};


QueryFilters.isInteger = function(val) {
    if(val == null) {
        return false;
    }
    if(val.token === 'literal') {
        if(val.type == "http://www.w3.org/2001/XMLSchema#integer" ||
           val.type == "http://www.w3.org/2001/XMLSchema#decimal" ||
           val.type == "http://www.w3.org/2001/XMLSchema#double" ||
           val.type == "http://www.w3.org/2001/XMLSchema#nonPositiveInteger" ||
           val.type == "http://www.w3.org/2001/XMLSchema#negativeInteger" ||
           val.type == "http://www.w3.org/2001/XMLSchema#long" ||
           val.type == "http://www.w3.org/2001/XMLSchema#int" ||
           val.type == "http://www.w3.org/2001/XMLSchema#short" ||
           val.type == "http://www.w3.org/2001/XMLSchema#byte" ||
           val.type == "http://www.w3.org/2001/XMLSchema#nonNegativeInteger" ||
           val.type == "http://www.w3.org/2001/XMLSchema#unsignedLong" ||
           val.type == "http://www.w3.org/2001/XMLSchema#unsignedInt" ||
           val.type == "http://www.w3.org/2001/XMLSchema#unsignedShort" ||
           val.type == "http://www.w3.org/2001/XMLSchema#unsignedByte" ||
           val.type == "http://www.w3.org/2001/XMLSchema#positiveInteger" ) {
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
};

QueryFilters.isFloat = function(val) {
    if(val == null) {
        return false;
    }
    if(val.token === 'literal') {
        if(val.type == "http://www.w3.org/2001/XMLSchema#float") {
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
};

QueryFilters.isDecimal = function(val) {
    if(val == null) {
        return false;
    }
    if(val.token === 'literal') {
        if(val.type == "http://www.w3.org/2001/XMLSchema#decimal") {
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
};

QueryFilters.isDouble = function(val) {
    if(val == null) {
        return false;
    }
    if(val.token === 'literal') {
        if(val.type == "http://www.w3.org/2001/XMLSchema#double") {
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
};


QueryFilters.isNumeric = function(val) {
    if(val == null) {
        return false;
    }
    if(val.token === 'literal') {
        if(val.type == "http://www.w3.org/2001/XMLSchema#integer" ||
           val.type == "http://www.w3.org/2001/XMLSchema#decimal" ||
           val.type == "http://www.w3.org/2001/XMLSchema#float" ||
           val.type == "http://www.w3.org/2001/XMLSchema#double" ||
           val.type == "http://www.w3.org/2001/XMLSchema#nonPositiveInteger" ||
           val.type == "http://www.w3.org/2001/XMLSchema#negativeInteger" ||
           val.type == "http://www.w3.org/2001/XMLSchema#long" ||
           val.type == "http://www.w3.org/2001/XMLSchema#int" ||
           val.type == "http://www.w3.org/2001/XMLSchema#short" ||
           val.type == "http://www.w3.org/2001/XMLSchema#byte" ||
           val.type == "http://www.w3.org/2001/XMLSchema#nonNegativeInteger" ||
           val.type == "http://www.w3.org/2001/XMLSchema#unsignedLong" ||
           val.type == "http://www.w3.org/2001/XMLSchema#unsignedInt" ||
           val.type == "http://www.w3.org/2001/XMLSchema#unsignedShort" ||
           val.type == "http://www.w3.org/2001/XMLSchema#unsignedByte" ||
           val.type == "http://www.w3.org/2001/XMLSchema#positiveInteger" ) {
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
};

QueryFilters.isSimpleLiteral = function(val) {
    if(val && val.token == 'literal') {
        if(val.type == null && val.lang == null) {
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
};

QueryFilters.isXsdType = function(type, val) {
    if(val && val.token == 'literal') {
        return val.type == "http://www.w3.org/2001/XMLSchema#"+type;
    } else {
        return false;
    }
};

QueryFilters.ebv = function (term) {
    if (term == null || QueryFilters.isEbvError(term)) {
        return QueryFilters.ebvError();
    } else {
        if (term.token && term.token === 'literal') {
            if (term.type == "http://www.w3.org/2001/XMLSchema#integer" ||
                term.type == "http://www.w3.org/2001/XMLSchema#decimal" ||
                term.type == "http://www.w3.org/2001/XMLSchema#double" ||
                term.type == "http://www.w3.org/2001/XMLSchema#nonPositiveInteger" ||
                term.type == "http://www.w3.org/2001/XMLSchema#negativeInteger" ||
                term.type == "http://www.w3.org/2001/XMLSchema#long" ||
                term.type == "http://www.w3.org/2001/XMLSchema#int" ||
                term.type == "http://www.w3.org/2001/XMLSchema#short" ||
                term.type == "http://www.w3.org/2001/XMLSchema#byte" ||
                term.type == "http://www.w3.org/2001/XMLSchema#nonNegativeInteger" ||
                term.type == "http://www.w3.org/2001/XMLSchema#unsignedLong" ||
                term.type == "http://www.w3.org/2001/XMLSchema#unsignedInt" ||
                term.type == "http://www.w3.org/2001/XMLSchema#unsignedShort" ||
                term.type == "http://www.w3.org/2001/XMLSchema#unsignedByte" ||
                term.type == "http://www.w3.org/2001/XMLSchema#positiveInteger") {
                var tmp = parseFloat(term.value);
                if (isNaN(tmp)) {
                    return false;
                } else {
                    return parseFloat(term.value) != 0;
                }
            } else if (term.type === "http://www.w3.org/2001/XMLSchema#boolean") {
                return (term.value === 'true' || term.value === true || term.value === 'True');
            } else if (term.type === "http://www.w3.org/2001/XMLSchema#string") {
                return term.value != "";
            } else if (term.type === "http://www.w3.org/2001/XMLSchema#dateTime") {
                return (new Date(term.value)) != null;
            } else if (QueryFilters.isEbvError(term)) {
                return term;
            } else if (term.type == null) {
                if (term.value != "") {
                    return true;
                } else {
                    return false;
                }
            } else {
                return QueryFilters.ebvError();
            }
        } else {
            return term.value === true;
        }
    }
};

QueryFilters.effectiveBooleanValue = QueryFilters.ebv;

QueryFilters.ebvTrue = function() {
    var val = {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#boolean", value:true};
    return val;
};

QueryFilters.ebvFalse = function() {
    var val = {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#boolean", value:false};
    return val;
};

QueryFilters.ebvError = function() {
    var val = {token: 'literal', type:"https://github.com/antoniogarrote/js-tools/types#error", value:null};
    return val;
};

QueryFilters.isEbvError = function(term) {
    if(typeof(term) == 'object' && term != null) {
        return term.type === "https://github.com/antoniogarrote/js-tools/types#error";
//    } else if(term == null) {
//        return true;
    } else {
        return false;
    }
};

QueryFilters.ebvBoolean = function (bool) {
    if (QueryFilters.isEbvError(bool)) {
        return bool;
    } else {
        if (bool === true) {
            return QueryFilters.ebvTrue();
        } else {
            return QueryFilters.ebvFalse();
        }
    }
};


QueryFilters.runRelationalFilter = function(filterExpr, op1, op2, bindings, queryEngine, dataset, env) {
    var operator = filterExpr.operator;
    if(operator === '=') {
        return QueryFilters.runEqualityFunction(op1, op2, bindings, queryEngine, dataset, env);
    } else if(operator === '!=') {
        var res = QueryFilters.runEqualityFunction(op1, op2, bindings, queryEngine, dataset, env);
        if(QueryFilters.isEbvError(res)) {
            return res;
        } else {
            res.value = !res.value;
            return res;
        }
    } else if(operator === '<') {
        return QueryFilters.runLtFunction(op1, op2, bindings);
    } else if(operator === '>') {
        return QueryFilters.runGtFunction(op1, op2, bindings);
    } else if(operator === '<=') {
        return QueryFilters.runLtEqFunction(op1, op2, bindings);
    } else if(operator === '>=') {
        return QueryFilters.runGtEqFunction(op1, op2, bindings);
    } else {
        throw("Error applying relational filter, unknown operator");
    }
};

/**
 * Transforms a JS object representing a [typed] literal in a javascript
 * value that can be used in javascript operations and functions
 */
QueryFilters.effectiveTypeValue = function(val){
    if(val.token == 'literal') {
        if(val.type == "http://www.w3.org/2001/XMLSchema#integer") {
            var tmp = parseInt(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
              return tmp;
            //}
        } else if(val.type == "http://www.w3.org/2001/XMLSchema#decimal") {
            var tmp = parseFloat(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
                return tmp;
            //}
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#float") {
            var tmp = parseFloat(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
                return tmp;
            //}
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#double") {
            var tmp = parseFloat(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
                return tmp;
            //}
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#nonPositiveInteger") {
            var tmp = parseFloat(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
                return tmp;
            //}
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#negativeInteger") {
            var tmp = parseInt(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
                return tmp;
            //}
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#long") {
            var tmp = parseInt(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
                return tmp;
            //}
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#int") {
            var tmp = parseInt(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
                return tmp;
            //}
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#short") {
            var tmp = parseInt(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
                return tmp;
            //}
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#byte") {
            var tmp = parseInt(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
                return tmp;
            //}
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#nonNegativeInteger") {
            var tmp = parseInt(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
                return tmp;
            //}
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#unsignedLong") {
            var tmp = parseInt(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
                return tmp;
            //}
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#unsignedInt") {
            var tmp = parseInt(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
                return tmp;
            //}
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#unsignedShort") {
            var tmp = parseInt(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
                return tmp;
            //}
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#unsignedByte") {
            var tmp = parseInt(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
                return tmp;
            //}
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#positiveInteger" ) {
            var tmp = parseInt(val.value);
            //if(isNaN(tmp)) {
            //    return false;
            //} else {
                return tmp;
            //}
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#date" || 
                   val.type == "http://www.w3.org/2001/XMLSchema#dateTime" ) {
            try {
                var d = Utils.parseISO8601(val.value);            
                return(d);
            } catch(e) {
                return null;
            }
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#boolean" ) {
            return val.value === true || val.value === 'true' || val.value === '1' || val.value === 1 || val.value === true ? true :
                val.value === false || val.value === 'false' || val.value === '0' || val.value === 0 || val.value === false ? false :
                undefined;
        } else if (val.type == "http://www.w3.org/2001/XMLSchema#string" ) {
            return val.value === null || val.value === undefined ? undefined : ''+val.value;
        } else if (val.type == null) {
            // plain literal -> just manipulate the string
            return val.value;
        } else {
            return val.value
        }
    } else {
        // @todo
        console.log("not implemented yet");
        console.log(val);
        throw("value not supported in operations yet");
    }
};

/*
  A logical-or that encounters an error on only one branch will return TRUE if the other branch is TRUE and an error if the other branch is FALSE.
  A logical-or or logical-and that encounters errors on both branches will produce either of the errors.
*/
QueryFilters.runOrFunction = function(filterExpr, bindings, queryEngine, dataset, env) {

    var acum = null;

    for(var i=0; i< filterExpr.operands.length; i++) {
        var ebv = QueryFilters.runFilter(filterExpr.operands[i], bindings, queryEngine, dataset, env);
        if(QueryFilters.isEbvError(ebv) == false) {
            ebv = QueryFilters.ebv(ebv);
        }
        if(acum == null) {
            acum = ebv;
        } else if(QueryFilters.isEbvError(ebv)) {
            if(QueryFilters.isEbvError(acum)) {
                acum = QueryFilters.ebvError();
            } else if(acum === true) {
                acum = true;
            } else {
                acum = QueryFilters.ebvError();
            }
        } else if(ebv === true) {
            acum = true;
        } else {
            if(QueryFilters.isEbvError(acum)) {
                acum = QueryFilters.ebvError();
            }
        }
    }

    return QueryFilters.ebvBoolean(acum);
};

/*
  A logical-and that encounters an error on only one branch will return an error if the other branch is TRUE and FALSE if the other branch is FALSE.
  A logical-or or logical-and that encounters errors on both branches will produce either of the errors.
*/
QueryFilters.runAndFunction = function(filterExpr, bindings, queryEngine, dataset, env) {

    var acum = null;

    for(var i=0; i< filterExpr.operands.length; i++) {

        var ebv = QueryFilters.runFilter(filterExpr.operands[i], bindings, queryEngine, dataset, env);

        if(QueryFilters.isEbvError(ebv) == false) {
            ebv = QueryFilters.ebv(ebv);
        }

        if(acum == null) {
            acum = ebv;
        } else if(QueryFilters.isEbvError(ebv)) {
            if(QueryFilters.isEbvError(acum)) {
                acum = QueryFilters.ebvError();
            } else if(acum === true) {
                acum = QueryFilters.ebvError();
            } else {
                acum = false;
            }
        } else if(ebv === true) {
            if(QueryFilters.isEbvError(acum)) {
                acum = QueryFilters.ebvError();
            }
        } else {
            acum = false;
        }
    }

    return QueryFilters.ebvBoolean(acum);
};


QueryFilters.runEqualityFunction = function(op1, op2, bindings, queryEngine, dataset, env) {
    if(QueryFilters.isEbvError(op1) || QueryFilters.isEbvError(op2)) {
        return QueryFilters.ebvError();
    }
    if(QueryFilters.isNumeric(op1) && QueryFilters.isNumeric(op2)) {
        var eop1 = QueryFilters.effectiveTypeValue(op1);
        var eop2 = QueryFilters.effectiveTypeValue(op2);
        if(isNaN(eop1) || isNaN(eop2)) {
            return QueryFilters.ebvBoolean(QueryFilters.RDFTermEquality(op1, op2, queryEngine, env));
        } else {
            return QueryFilters.ebvBoolean(eop1 == eop2);
        }
    } else if((QueryFilters.isSimpleLiteral(op1) || QueryFilters.isXsdType("string", op1)) && 
              (QueryFilters.isSimpleLiteral(op2) || QueryFilters.isXsdType("string", op2))) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) == QueryFilters.effectiveTypeValue(op2));       
    } else if(QueryFilters.isXsdType("boolean", op1) && QueryFilters.isXsdType("boolean", op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) == QueryFilters.effectiveTypeValue(op2));
    } else if((QueryFilters.isXsdType("dateTime", op1)||QueryFilters.isXsdType("date", op1)) && (QueryFilters.isXsdType("dateTime", op2)||QueryFilters.isXsdType("date", op2))) {
        if(QueryFilters.isXsdType("dateTime", op1) && QueryFilters.isXsdType("date", op2)) {
            return QueryFilters.ebvFalse();
        }
        if(QueryFilters.isXsdType("date", op1) && QueryFilters.isXsdType("dateTime", op2)) {
            return QueryFilters.ebvFalse();
        }

        var comp = Utils.compareDateComponents(op1.value, op2.value);
        if(comp != null) {
            if(comp == 0) {
                return QueryFilters.ebvTrue();
            } else {
                return QueryFilters.ebvFalse();
            }
        } else {
                return QueryFilters.ebvError();
        }
    } else if(QueryFilters.isRDFTerm(op1) && QueryFilters.isRDFTerm(op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.RDFTermEquality(op1, op2, queryEngine, env));
    } else {
        return QueryFilters.ebvFalse();
    }
};

QueryFilters.runGtFunction = function(op1, op2, bindings) {
    if(QueryFilters.isEbvError(op1) || QueryFilters.isEbvError(op2)) {
        return QueryFilters.ebvError();
    }

    if(QueryFilters.isNumeric(op1) && QueryFilters.isNumeric(op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) > QueryFilters.effectiveTypeValue(op2));
    } else if(QueryFilters.isSimpleLiteral(op1) && QueryFilters.isSimpleLiteral(op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) > QueryFilters.effectiveTypeValue(op2));       
    } else if(QueryFilters.isXsdType("string", op1) && QueryFilters.isXsdType("string", op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) > QueryFilters.effectiveTypeValue(op2));       
    } else if(QueryFilters.isXsdType("boolean", op1) && QueryFilters.isXsdType("boolean", op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) > QueryFilters.effectiveTypeValue(op2));
    } else if((QueryFilters.isXsdType("dateTime", op1) || QueryFilters.isXsdType("date", op1)) && 
              (QueryFilters.isXsdType("dateTime", op2) || QueryFilters.isXsdType("date", op2))) {
        if(QueryFilters.isXsdType("dateTime", op1) && QueryFilters.isXsdType("date", op2)) {
            return QueryFilters.ebvFalse();
        }
        if(QueryFilters.isXsdType("date", op1) && QueryFilters.isXsdType("dateTime", op2)) {
            return QueryFilters.ebvFalse();
        }

        var comp = Utils.compareDateComponents(op1.value, op2.value);
        if(comp != null) {
            if(comp == 1) {
                return QueryFilters.ebvTrue();
            } else {
                return QueryFilters.ebvFalse();
            }
        } else {
                return QueryFilters.ebvError();
        }
    } else {
        return QueryFilters.ebvFalse();
    }
};

/**
 * Total gt function used when sorting bindings in the SORT BY clause.
 *
 * @todo
 * Some criteria are not clear
 */
QueryFilters.runTotalGtFunction = function(op1,op2) {
    if(QueryFilters.isEbvError(op1) || QueryFilters.isEbvError(op2)) {
        return QueryFilters.ebvError();
    }

    if((QueryFilters.isNumeric(op1) && QueryFilters.isNumeric(op2)) ||
       (QueryFilters.isSimpleLiteral(op1) && QueryFilters.isSimpleLiteral(op2)) ||
       (QueryFilters.isXsdType("string",op1) && QueryFilters.isSimpleLiteral("string",op2)) ||
       (QueryFilters.isXsdType("boolean",op1) && QueryFilters.isSimpleLiteral("boolean",op2)) ||
       (QueryFilters.isXsdType("dateTime",op1) && QueryFilters.isSimpleLiteral("dateTime",op2))) {
        return QueryFilters.runGtFunction(op1, op2, []);
    } else if(op1.token && op1.token === 'uri' && op2.token && op2.token === 'uri') {
        return QueryFilters.ebvBoolean(op1.value > op2.value);
    } else if(op1.token && op1.token === 'literal' && op2.token && op2.token === 'literal') {
        // one of the literals must have type/lang and the othe may not have them
        return QueryFilters.ebvBoolean(""+op1.value+op1.type+op1.lang > ""+op2.value+op2.type+op2.lang);
    } else if(op1.token && op1.token === 'blank' && op2.token && op2.token === 'blank') {    
        return QueryFilters.ebvBoolean(op1.value > op2.value);
    } else if(op1.value && op2.value) {
        return QueryFilters.ebvBoolean(op1.value > op2.value);
    } else {
        return QueryFilters.ebvTrue();
    }
};


QueryFilters.runLtFunction = function(op1, op2, bindings) {
    if(QueryFilters.isEbvError(op1) || QueryFilters.isEbvError(op2)) {
        return QueryFilters.ebvError();
    }

    if(QueryFilters.isNumeric(op1) && QueryFilters.isNumeric(op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) < QueryFilters.effectiveTypeValue(op2));
    } else if(QueryFilters.isSimpleLiteral(op1) && QueryFilters.isSimpleLiteral(op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) < QueryFilters.effectiveTypeValue(op2));       
    } else if(QueryFilters.isXsdType("string", op1) && QueryFilters.isXsdType("string", op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) < QueryFilters.effectiveTypeValue(op2));       
    } else if(QueryFilters.isXsdType("boolean", op1) && QueryFilters.isXsdType("boolean", op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) < QueryFilters.effectiveTypeValue(op2));
    } else if((QueryFilters.isXsdType("dateTime", op1) || QueryFilters.isXsdType("date", op1)) && 
              (QueryFilters.isXsdType("dateTime", op2) || QueryFilters.isXsdType("date", op2))) {
        if(QueryFilters.isXsdType("dateTime", op1) && QueryFilters.isXsdType("date", op2)) {
            return QueryFilters.ebvFalse();
        }
        if(QueryFilters.isXsdType("date", op1) && QueryFilters.isXsdType("dateTime", op2)) {
            return QueryFilters.ebvFalse();
        }

        var comp = Utils.compareDateComponents(op1.value, op2.value);
        if(comp != null) {
            if(comp == -1) {
                return QueryFilters.ebvTrue();
            } else {
                return QueryFilters.ebvFalse();
            }
        } else {
                return QueryFilters.ebvError();
        }
    } else {
        return QueryFilters.ebvFalse();
    }
};


QueryFilters.runGtEqFunction = function(op1, op2, bindings) {
    if(QueryFilters.isEbvError(op1) || QueryFilters.isEbvError(op2)) {
        return QueryFilters.ebvError();
    }

    if(QueryFilters.isNumeric(op1) && QueryFilters.isNumeric(op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) >= QueryFilters.effectiveTypeValue(op2));
    } else if(QueryFilters.isSimpleLiteral(op1) && QueryFilters.isSimpleLiteral(op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) >= QueryFilters.effectiveTypeValue(op2));       
    } else if(QueryFilters.isXsdType("string", op1) && QueryFilters.isXsdType("string", op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) >= QueryFilters.effectiveTypeValue(op2));       
    } else if(QueryFilters.isXsdType("boolean", op1) && QueryFilters.isXsdType("boolean", op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) >= QueryFilters.effectiveTypeValue(op2));
    } else if((QueryFilters.isXsdType("dateTime", op1) || QueryFilters.isXsdType("date", op1)) && 
              (QueryFilters.isXsdType("dateTime", op2) || QueryFilters.isXsdType("date", op2))) {
        if(QueryFilters.isXsdType("dateTime", op1) && QueryFilters.isXsdType("date", op2)) {
            return QueryFilters.ebvFalse();
        }
        if(QueryFilters.isXsdType("date", op1) && QueryFilters.isXsdType("dateTime", op2)) {
            return QueryFilters.ebvFalse();
        }

        var comp = Utils.compareDateComponents(op1.value, op2.value);
        if(comp != null) {
            if(comp != -1) {
                return QueryFilters.ebvTrue();
            } else {
                return QueryFilters.ebvFalse();
            }
        } else {
                return QueryFilters.ebvError();
        }

    } else {
        return QueryFilters.ebvFalse();
    }
};


QueryFilters.runLtEqFunction = function(op1, op2, bindings) {
    if(QueryFilters.isEbvError(op1) || QueryFilters.isEbvError(op2)) {
        return QueryFilters.ebvError();
    }

    if(QueryFilters.isNumeric(op1) && QueryFilters.isNumeric(op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) <= QueryFilters.effectiveTypeValue(op2));
    } else if(QueryFilters.isSimpleLiteral(op1) && QueryFilters.isSimpleLiteral(op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) <= QueryFilters.effectiveTypeValue(op2));       
    } else if(QueryFilters.isXsdType("string", op1) && QueryFilters.isXsdType("string", op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) <= QueryFilters.effectiveTypeValue(op2));       
    } else if(QueryFilters.isXsdType("boolean", op1) && QueryFilters.isXsdType("boolean", op2)) {
        return QueryFilters.ebvBoolean(QueryFilters.effectiveTypeValue(op1) <= QueryFilters.effectiveTypeValue(op2));
    } else if((QueryFilters.isXsdType("dateTime", op1) || QueryFilters.isXsdType("date", op1)) && 
              (QueryFilters.isXsdType("dateTime", op2) || QueryFilters.isXsdType("date", op2))) {
        if(QueryFilters.isXsdType("dateTime", op1) && QueryFilters.isXsdType("date", op2)) {
            return QueryFilters.ebvFalse();
        }
        if(QueryFilters.isXsdType("date", op1) && QueryFilters.isXsdType("dateTime", op2)) {
            return QueryFilters.ebvFalse();
        }

        var comp = Utils.compareDateComponents(op1.value, op2.value);
        if(comp != null) {
            if(comp != 1) {
                return QueryFilters.ebvTrue();
            } else {
                return QueryFilters.ebvFalse();
            }
        } else {
                return QueryFilters.ebvError();
        }
    } else {
        return QueryFilters.ebvFalse();
    }
};

QueryFilters.runAddition = function(summand, summands, bindings, queryEngine, dataset, env) {
    var summandOp = QueryFilters.runFilter(summand,bindings,queryEngine, dataset, env);
    if(QueryFilters.isEbvError(summandOp)) {
        return QueryFilters.ebvError();
    }

    var acum = summandOp;
    if(QueryFilters.isNumeric(summandOp)) {
        for(var i=0; i<summands.length; i++) {
            var nextSummandOp = QueryFilters.runFilter(summands[i].expression, bindings,queryEngine, dataset, env);
            if(QueryFilters.isNumeric(nextSummandOp)) {
                if(summands[i].operator === '+') {
                    acum = QueryFilters.runSumFunction(acum, nextSummandOp);
                } else if(summands[i].operator === '-') {
                    acum = QueryFilters.runSubFunction(acum, nextSummandOp);
                }
            } else {
                return QueryFilters.ebvFalse();
            }
        }
        return acum;
    } else {
        return QueryFilters.ebvFalse();
    }
};

QueryFilters.runSumFunction = function(suma, sumb) {
    if(QueryFilters.isEbvError(suma) || QueryFilters.isEbvError(sumb)) {
        return QueryFilters.ebvError();
    }
    var val = QueryFilters.effectiveTypeValue(suma) + QueryFilters.effectiveTypeValue(sumb);
    
    if(QueryFilters.isDouble(suma) || QueryFilters.isDouble(sumb)) {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#double", value:val};        
    } else if(QueryFilters.isFloat(suma) || QueryFilters.isFloat(sumb)) {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#float", value:val};        
    } else if(QueryFilters.isDecimal(suma) || QueryFilters.isDecimal(sumb)) {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#decimal", value:val};        
    } else {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#integer", value:val};        
    }
};

QueryFilters.runSubFunction = function(suma, sumb) {
    if(QueryFilters.isEbvError(suma) || QueryFilters.isEbvError(sumb)) {
        return QueryFilters.ebvError();
    }
    var val = QueryFilters.effectiveTypeValue(suma) - QueryFilters.effectiveTypeValue(sumb);

    if(QueryFilters.isDouble(suma) || QueryFilters.isDouble(sumb)) {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#double", value:val};        
    } else if(QueryFilters.isFloat(suma) || QueryFilters.isFloat(sumb)) {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#float", value:val};        
    } else if(QueryFilters.isDecimal(suma) || QueryFilters.isDecimal(sumb)) {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#decimal", value:val};        
    } else {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#integer", value:val};        
    }
};

QueryFilters.runMultiplication = function(factor, factors, bindings, queryEngine, dataset, env) {
    var factorOp = QueryFilters.runFilter(factor,bindings,queryEngine, dataset, env);
    if(QueryFilters.isEbvError(factorOp)) {
        return factorOp;
    }

    var acum = factorOp;
    if(QueryFilters.isNumeric(factorOp)) {
        for(var i=0; i<factors.length; i++) {
            var nextFactorOp = QueryFilters.runFilter(factors[i].expression, bindings,queryEngine, dataset, env);
            if(QueryFilters.isEbvError(nextFactorOp)) {
                return factorOp;
            }
            if(QueryFilters.isNumeric(nextFactorOp)) {
                if(factors[i].operator === '*') {
                    acum = QueryFilters.runMulFunction(acum, nextFactorOp);
                } else if(factors[i].operator === '/') {
                    acum = QueryFilters.runDivFunction(acum, nextFactorOp);
                }
            } else {
                return QueryFilters.ebvFalse();
            }
        }
        return acum;
    } else {
        return QueryFilters.ebvFalse();
    }
};

QueryFilters.runMulFunction = function(faca, facb) {
    if(QueryFilters.isEbvError(faca) || QueryFilters.isEbvError(facb)) {
        return QueryFilters.ebvError();
    }
    var val = QueryFilters.effectiveTypeValue(faca) * QueryFilters.effectiveTypeValue(facb);

    if(QueryFilters.isDouble(faca) || QueryFilters.isDouble(facb)) {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#double", value:val};        
    } else if(QueryFilters.isFloat(faca) || QueryFilters.isFloat(facb)) {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#float", value:val};        
    } else if(QueryFilters.isDecimal(faca) || QueryFilters.isDecimal(facb)) {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#decimal", value:val};        
    } else {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#integer", value:val};        
    }
};

QueryFilters.runDivFunction = function(faca, facb) {
    if(QueryFilters.isEbvError(faca) || QueryFilters.isEbvError(facb)) {
        return QueryFilters.ebvError();
    }
    var val = QueryFilters.effectiveTypeValue(faca) / QueryFilters.effectiveTypeValue(facb);

    if(QueryFilters.isDouble(faca) || QueryFilters.isDouble(facb)) {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#double", value:val};        
    } else if(QueryFilters.isFloat(faca) || QueryFilters.isFloat(facb)) {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#float", value:val};        
    } else if(QueryFilters.isDecimal(faca) || QueryFilters.isDecimal(facb)) {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#decimal", value:val};        
    } else {
        return {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#integer", value:val};        
    }
};

QueryFilters.runBuiltInCall = function(builtincall, args, bindings, queryEngine, dataset, env) {
    if(builtincall === 'notexists' || builtincall === 'exists') {
        // Run the query in the filter applying bindings

        var cloned = JSON.parse(JSON.stringify(args[0])); // @todo CHANGE THIS!!
        var ast = queryEngine.abstractQueryTree.parseSelect({pattern:cloned}, bindings);
        ast = queryEngine.abstractQueryTree.bind(ast.pattern, bindings);

        var result = queryEngine.executeSelectUnit([ {kind:'*'} ], 
                                                   dataset,
                                                   ast,
                                                   env);

        if(builtincall === 'exists') {
            return QueryFilters.ebvBoolean(result.length!==0);            
        } else {
            return QueryFilters.ebvBoolean(result.length===0);            
        }

    }  else {

        var ops = [];
        for(var i=0; i<args.length; i++) {
            if(args[i].token === 'var') {
                ops.push(args[i]);
            } else {
                var op = QueryFilters.runFilter(args[i], bindings, queryEngine, dataset, env);
                if(QueryFilters.isEbvError(op)) {
                    return op;
                }
                ops.push(op);
            }
        }

        if(builtincall === 'str') {
            if(ops[0].token === 'literal') {
                // lexical form literals
                return {token: 'literal', type:null, value:""+ops[0].value}; // type null? or "http://www.w3.org/2001/XMLSchema#string"
            } else if(ops[0].token === 'uri'){
                // codepoint URIs
                return {token: 'literal', type:null, value:ops[0].value}; // idem
            } else {
                return QueryFilters.ebvFalse();
            }
        } else if(builtincall === 'lang') {
            if(ops[0].token === 'literal'){
                if(ops[0].lang != null) {
                    return {token: 'literal', value:""+ops[0].lang};
                } else {
                    return {token: 'literal', value:""};
                }
            } else {
                return QueryFilters.ebvError();
            }
        } else if(builtincall === 'datatype') {
            if(ops[0].token === 'literal'){
                var lit = ops[0];
                if(lit.type != null) {
                    if(typeof(lit.type) === 'string') {
                        return {token: 'uri', value:lit.type, prefix:null, suffix:null};
                    } else {
                        return lit.type;
                    }
                } else if(lit.lang == null) {
                    return {token: 'uri', value:'http://www.w3.org/2001/XMLSchema#string', prefix:null, suffix:null};
                } else {
                    return QueryFilters.ebvError();
                }
            } else {
                return QueryFilters.ebvError();
            }
        } else if(builtincall === 'isliteral') {
            if(ops[0].token === 'literal'){
                return QueryFilters.ebvTrue();
            } else {
                return QueryFilters.ebvFalse();
            }        
        } else if(builtincall === 'isblank') {
            if(ops[0].token === 'blank'){
                return QueryFilters.ebvTrue();
            } else {
                return QueryFilters.ebvFalse();
            }        
        } else if(builtincall === 'isuri' || builtincall === 'isiri') {
            if(ops[0].token === 'uri'){
                return QueryFilters.ebvTrue();
            } else {
                return QueryFilters.ebvFalse();
            }        
        } else if(builtincall === 'sameterm') {
            var op1 = ops[0];
            var op2 = ops[1];
            var res = QueryFilters.RDFTermEquality(op1, op2, queryEngine, env);
            if(QueryFilters.isEbvError(res)) {
                res = false;
            }
            return QueryFilters.ebvBoolean(res);
        } else if(builtincall === 'langmatches') {
            var lang = ops[0];
            var langRange = ops[1];

            if(lang.token === 'literal' && langRange.token === 'literal'){
                if(langRange.value === '*' && lang.value != '') {
                    return QueryFilters.ebvTrue();
                } else {
                    return QueryFilters.ebvBoolean(lang.value.toLowerCase().indexOf(langRange.value.toLowerCase()) === 0)
                }
            } else {
                return QueryFilters.ebvError();
            }        
        } else if(builtincall === 'bound') {
            var boundVar = ops[0].value;
            var acum = [];
            if(boundVar == null) {
                return QueryFilters.ebvError();
            } else  if(bindings[boundVar] != null) {
                return QueryFilters.ebvTrue();
            } else {
                return QueryFilters.ebvFalse();
            }
	} else if(queryEngine.customFns[builtincall] != null) {
	    return queryEngine.customFns[builtincall](QueryFilters, ops);
        } else {
            throw ("Builtin call "+builtincall+" not implemented yet");
        }
    }
};

QueryFilters.runUnaryExpression = function(unaryexpression, expression, bindings, queryEngine, dataset, env) {
    var op = QueryFilters.runFilter(expression, bindings,queryEngine, dataset, env);
    if(QueryFilters.isEbvError(op)) {
        return op;
    }

    if(unaryexpression === '!') {
        var res = QueryFilters.ebv(op);
        //console.log("** Unary ! ");
        //console.log(op)
        if(QueryFilters.isEbvError(res)) {
            //console.log("--- ERROR")
            //console.log(QueryFilters.ebvFalse())
            //console.log("\r\n")

            // ??
            return QueryFilters.ebvFalse();
        } else {
            res = !res;
            //console.log("--- BOOL")
            //console.log(QueryFilters.ebvBoolean(res))
            //console.log("\r\n")

            return QueryFilters.ebvBoolean(res);
        }
    } else if(unaryexpression === '+') {
        if(QueryFilters.isNumeric(op)) {
            return op;
        } else {
            return QueryFilters.ebvError();
        }
    } else if(unaryexpression === '-') {
        if(QueryFilters.isNumeric(op)) {
            var clone = {};
            for(var p in op) {
                clone[p] = op[p];
            }
            clone.value = -clone.value;
            return clone;
        } else {
            return QueryFilters.ebvError();
        }
    }
};

QueryFilters.runRegex = function(text, pattern, flags, bindings, queryEngine, dataset, env) {

    if(text != null) {
        text = QueryFilters.runFilter(text, bindings, queryEngine, dataset, env);
    } else {
        return QueryFilters.ebvError();
    }

    if(pattern != null) {
        pattern = QueryFilters.runFilter(pattern, bindings, queryEngine, dataset, env);
    } else {
        return QueryFilters.ebvError();
    }

    if(flags != null) {
        flags = QueryFilters.runFilter(flags, bindings, queryEngine, dataset, env);
    }


    if(pattern != null && pattern.token === 'literal' && (flags == null || flags.token === 'literal')) {
        pattern = pattern.value;
        flags = (flags == null) ? null : flags.value;
    } else {
        return QueryFilters.ebvError();
    }

    if(text!= null && text.token == 'var') {
        if(bindings[text.value] != null) {
            text = bindings[text.value];
        } else {
            return QueryFilters.ebvError();
        }
    } else if(text!=null && text.token === 'literal') {
        if(text.type == null || QueryFilters.isXsdType("string",text)) {
            text = text.value
        } else {
            return QueryFilters.ebvError();
        }
    } else {
        return QueryFilters.ebvError();
    }

    var regex;
    if(flags == null) {
        regex = new RegExp(pattern);                    
    } else {
        regex = new RegExp(pattern,flags.toLowerCase());
    }
    if(regex.exec(text)) {
        return QueryFilters.ebvTrue();
    } else {
        return QueryFilters.ebvFalse();
    }    
};

QueryFilters.normalizeLiteralDatatype = function(literal, queryEngine, env) {
    if(literal.value.type == null || typeof(literal.value.type) != 'object') {
        return literal;
    } else {
        // type can be parsed as a hash using namespaces
        literal.value.type =  Utils.lexicalFormBaseUri(literal.value.type, env);
        return literal;
    }
};

QueryFilters.runIriRefOrFunction = function(iriref, args, bindings,queryEngine, dataset, env) {
    if(args == null) {
        return iriref;
    } else {
        var ops = [];
        for(var i=0; i<args.length; i++) {
            ops.push(QueryFilters.runFilter(args[i], bindings, queryEngine, dataset, env))
        }

        var fun = Utils.lexicalFormBaseUri(iriref, env);

        if(fun == "http://www.w3.org/2001/XMLSchema#integer" ||
           fun == "http://www.w3.org/2001/XMLSchema#decimal" ||
           fun == "http://www.w3.org/2001/XMLSchema#double" ||
           fun == "http://www.w3.org/2001/XMLSchema#nonPositiveInteger" ||
           fun == "http://www.w3.org/2001/XMLSchema#negativeInteger" ||
           fun == "http://www.w3.org/2001/XMLSchema#long" ||
           fun == "http://www.w3.org/2001/XMLSchema#int" ||
           fun == "http://www.w3.org/2001/XMLSchema#short" ||
           fun == "http://www.w3.org/2001/XMLSchema#byte" ||
           fun == "http://www.w3.org/2001/XMLSchema#nonNegativeInteger" ||
           fun == "http://www.w3.org/2001/XMLSchema#unsignedLong" ||
           fun == "http://www.w3.org/2001/XMLSchema#unsignedInt" ||
           fun == "http://www.w3.org/2001/XMLSchema#unsignedShort" ||
           fun == "http://www.w3.org/2001/XMLSchema#unsignedByte" ||
           fun == "http://www.w3.org/2001/XMLSchema#positiveInteger") {
            var from = ops[0];
            if(from.token === 'literal') {
                from = QueryFilters.normalizeLiteralDatatype(from, queryEngine, env);
                if(from.type == "http://www.w3.org/2001/XMLSchema#integer" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#decimal" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#double" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#nonPositiveInteger" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#negativeInteger" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#long" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#int" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#short" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#byte" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#nonNegativeInteger" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#unsignedLong" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#unsignedInt" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#unsignedShort" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#unsignedByte" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#positiveInteger") {
                    from.type = fun;
                    return from;
                } else if(from.type == 'http://www.w3.org/2001/XMLSchema#boolean') {
                    if(QueryFilters.ebv(from) == true) {
                        from.type = fun;
                        from.value = 1;
                    } else {
                        from.type = fun;
                        from.value = 0;
                    }
                    return from;
                } else if(from.type == 'http://www.w3.org/2001/XMLSchema#float' || 
                          from.type == 'http://www.w3.org/2001/XMLSchema#double') {
                    from.type = fun;
                    from.value = parseInt(from.value);
                    return from;
                } else if(from.type == 'http://www.w3.org/2001/XMLSchema#string' || from.type == null) {
                    if(from.value.split(".").length > 2) {
                        return QueryFilters.ebvError();
                    } else if (from.value.split("-").length > 2) {
                        return QueryFilters.ebvError();                            
                    } else if (from.value.split("/").length > 2) {
                        return QueryFilters.ebvError();                            
                    } else if (from.value.split("+").length > 2) {
                        return QueryFilters.ebvError();                            
                    }

                    // @todo improve this with regular expressions for each lexical representation
                    if(fun == "http://www.w3.org/2001/XMLSchema#decimal") {
                        if(from.value.indexOf("e") != -1 || from.value.indexOf("E") != -1) {
                            return QueryFilters.ebvError();
                        }
                    }

                    // @todo improve this with regular expressions for each lexical representation
                    if(fun == "http://www.w3.org/2001/XMLSchema#int" || fun == "http://www.w3.org/2001/XMLSchema#integer") {
                        if(from.value.indexOf("e") != -1 || from.value.indexOf("E") != -1 || from.value.indexOf(".") != -1) {
                            return QueryFilters.ebvError();
                        }
                    }

                    try {
                        from.value = parseInt(parseFloat(from.value));
                        if(isNaN(from.value)) {
                            return QueryFilters.ebvError();
                        } else {
                            from.type = fun;
                            return from;
                        }
                    } catch(e) {
                        return QueryFilters.ebvError();                        
                    }
                } else {
                    return QueryFilters.ebvError();
                }
            } else {
                return QueryFilters.ebvError();
            }
        } else if(fun == "http://www.w3.org/2001/XMLSchema#boolean") { 
            var from = ops[0];
            if(from.token === "literal" && from.type == null) {
                if(from.value === "true" || from.value === "1") {
                    return QueryFilters.ebvTrue();
                } else if(from.value === "false" || from.value === "0" ) {
                    return QueryFilters.ebvFalse();
                } else {
                    return QueryFilters.ebvError();
                }
            } else if(from.token === "literal") {
              if(QueryFilters.isEbvError(from)) {
                  return from;
              } else {
                  return QueryFilters.ebvBoolean(from);
              }
            } else {
                return QueryFilters.ebvError();
            }
        } else if(fun == "http://www.w3.org/2001/XMLSchema#string") { 
            var from = ops[0];
            if(from.token === 'literal') {
                from = QueryFilters.normalizeLiteralDatatype(from, queryEngine, env);
                if(from.type == "http://www.w3.org/2001/XMLSchema#integer" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#decimal" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#double" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#nonPositiveInteger" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#negativeInteger" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#long" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#int" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#short" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#byte" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#nonNegativeInteger" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#unsignedLong" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#unsignedInt" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#unsignedShort" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#unsignedByte" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#positiveInteger" ||
                   from.type == "http://www.w3.org/2001/XMLSchema#float") {
                    from.type = fun;
                    from.value = ""+from.value;
                    return from;
                } else if(from.type == "http://www.w3.org/2001/XMLSchema#string") {
                    return from;
                } else if(from.type == "http://www.w3.org/2001/XMLSchema#boolean") {
                    if(QueryFilters.ebv(from)) {
                        from.type = fun;
                        from.value = 'true';
                    } else {
                        from.type = fun;
                        from.value = 'false';
                    }
                    return from;
                } else if(from.type == "http://www.w3.org/2001/XMLSchema#dateTime" ||
                          from.type == "http://www.w3.org/2001/XMLSchema#date") {
                    from.type = fun;
                    if(typeof(from.value) != 'string') {
                        from.value = Utils.iso8601(from.value);
                    }
                    return from;
                } else if(from.type == null) {
                    from.value = ""+from.value;
                    from.type = fun;
                    return from;
                } else {
                    return QueryFilters.ebvError();
                }
            } else if(from.token === 'uri') {
                return {token: 'literal',
                        value: Utils.lexicalFormBaseUri(from, env),
                        type: fun,
                        lang: null};
            } else {
                return QueryFilters.ebvError();
            }            
        } else if(fun == "http://www.w3.org/2001/XMLSchema#dateTime" || fun == "http://www.w3.org/2001/XMLSchema#date") { 
            from = ops[0];
            if(from.type == "http://www.w3.org/2001/XMLSchema#dateTime" || from.type == "http://www.w3.org/2001/XMLSchema#date") {
                return from;
            } else if(from.type == "http://www.w3.org/2001/XMLSchema#string" || from.type == null) {
                try {
                    from.value = Utils.iso8601(Utils.parseStrictISO8601(from.value));
                    from.type = fun;
                    return from;
                } catch(e) {
                    return QueryFilters.ebvError();
                }
            } else {
                return QueryFilters.ebvError();
            }
        } else if(fun == "http://www.w3.org/2001/XMLSchema#float") { 
            var from = ops[0];
            if(from.token === 'literal') {
                from = QueryFilters.normalizeLiteralDatatype(from, queryEngine, env);
                if(from.type == 'http://www.w3.org/2001/XMLSchema#decimal' || 
                   from.type == 'http://www.w3.org/2001/XMLSchema#int') {
                    from.type = fun;
                    from.value = parseFloat(from.value);
                    return from;
                } else if(from.type == 'http://www.w3.org/2001/XMLSchema#boolean') {
                    if(QueryFilters.ebv(from) == true) {
                        from.type = fun;
                        from.value = 1.0;
                    } else {
                        from.type = fun;
                        from.value = 0.0;
                    }
                    return from;
                } else if(from.type == 'http://www.w3.org/2001/XMLSchema#float' || 
                          from.type == 'http://www.w3.org/2001/XMLSchema#double') {
                    from.type = fun;
                    from.value = parseFloat(from.value);
                    return from;
                } else if(from.type == 'http://www.w3.org/2001/XMLSchema#string') {
                    try {
                        from.value = parseFloat(from.value);
                        if(isNaN(from.value)) {
                            return QueryFilters.ebvError();
                        } else {
                            from.type = fun;
                            return from;
                        }
                    } catch(e) {
                        return QueryFilters.ebvError();                        
                    }
                } else if(from.type == null) {
                    // checking some exceptions that are parsed as Floats by JS
                    if(from.value.split(".").length > 2) {
                        return QueryFilters.ebvError();
                    } else if (from.value.split("-").length > 2) {
                        return QueryFilters.ebvError();                            
                    } else if (from.value.split("/").length > 2) {
                        return QueryFilters.ebvError();                            
                    } else if (from.value.split("+").length > 2) {
                        return QueryFilters.ebvError();                            
                    }

                    try {
                        from.value = parseFloat(from.value);
                        if(isNaN(from.value)) {
                            return QueryFilters.ebvError();
                        } else {
                            from.type = fun;
                            return from;
                        }
                    } catch(e) {
                        return QueryFilters.ebvError();                        
                    }
                } else {
                    return QueryFilters.ebvError();
                }
            } else {
                return QueryFilters.ebvError();
            }
        } else {
            // unknown function
            return QueryFilters.ebvError();
        }
    }
};

// end of ./src/js-query-engine/src/query_filters.js 
// exports
var QueryPlanDPSize = {};

QueryPlanDPSize.variablesInBGP = function(bgp) {
    // may be cached in the pattern
    var variables = bgp.variables;
    if(variables) {
        return variables;
    }

    var components =  bgp.value || bgp;
    variables  = [];
    for(var comp in components) {
        if(components[comp] && components[comp].token === "var") {
            variables.push(components[comp].value);
        } else if(components[comp] && components[comp].token === "blank") {
            variables.push("blank:"+components[comp].value);
        }
    }
    bgp.variables = variables;

    return variables;
};

QueryPlanDPSize.connected = function(leftPlan, rightPlan) {
    var varsLeft ="/"+leftPlan.vars.join("/")+"/";
    for(var i=0; i<rightPlan.vars.length; i++) {
        if(varsLeft.indexOf("/"+rightPlan.vars[i]+"/") != -1) {
            return true;
        }
    }

    return false;
};

QueryPlanDPSize.variablesIntersectionBGP = function(bgpa, bgpb) {
    var varsa = QueryPlanDPSize.variablesInBGP(bgpa).sort();
    var varsb = QueryPlanDPSize.variablesInBGP(bgpb).sort();
    var ia = 0;
    var ib = 0;

    var intersection = [];

    while(ia<varsa.length && ib<varsb.length) {
        if(varsa[ia] === varsb[ib]) {
            intersection.push(varsa[ia]);
            ia++;
            ib++;
        } else if(varsa[ia] < varsb[ib]) {
            ia++;
        } else {
            ib++;
        }
    }

    return intersection;
};

/**
 * All BGPs sharing variables are grouped together.
 */
QueryPlanDPSize.executeAndBGPsGroups = function(bgps) {
    var groups = {};
    var groupVars = {};
    var groupId = 0;

    for(var i=0; i<bgps.length; i++) {
        var bgp = bgps[i];
	var newGroups = {};
	var newGroupVars = {};

        var vars = [];
        for(var comp in bgp) {
            if(comp != '_cost') {
                if(bgp[comp].token === 'var') {
                    vars.push(bgp[comp].value);
                } else if(bgp[comp].token === 'blank') {
                    vars.push(bgp[comp].value);
                }
            }
        }

	
        var foundGroup = false;
	var currentGroupId = null;
	var toDelete = [];
	var toJoin = {};

        for(var nextGroupId in groupVars) {
            var groupVar = groupVars[nextGroupId];
	    foundGroup = false;
            for(var j=0; j<vars.length; j++) {
                var thisVar = "/"+vars[j]+"/";
                if(groupVar.indexOf(thisVar) != -1) {
		    foundGroup = true;
		    break;
                }
            }

	    if(foundGroup) {
		toJoin[nextGroupId] = true;
	    } else {
		newGroups[nextGroupId] = groups[nextGroupId];
		newGroupVars[nextGroupId] = groupVars[nextGroupId];
	    }
        }

        if(!foundGroup) {
            newGroups[groupId] = [bgp];
            newGroupVars[groupId] = "/"+(vars.join("/"))+"/";
            groupId++;
        } else {
	    var acumGroups = [];
	    var acumId = "";
	    var acumVars = "";
	    for(var gid in toJoin) {
		acumId = acumId+gid;
		acumGroups = acumGroups.concat(groups[gid]);
		acumVars = groupVars[gid];
	    }

	    acumVars = acumVars + vars.join("/") + "/";
	    acumGroups.push(bgp);

	    newGroups[acumId] = acumGroups;
	    newGroupVars[acumId] = acumVars;
	}

	groups = newGroups;
	groupVars = newGroupVars;
    }

    var acum = [];
    for(var groupId in groups) {
        acum.push(groups[groupId]);
    }

    return acum;
};

QueryPlanDPSize.intersectionSize = function(leftPlan, rightPlan) {
    var idsRight = rightPlan.i.split("_");
    for(var i=0; i<idsRight.length; i++) {
        if(idsRight[i]=="")
            continue;
        if(leftPlan.i.indexOf('_'+idsRight[i]+'_') != -1) {
            return 1; // we just need to know if this value is >0
        }
    }
    return 0;
};

QueryPlanDPSize.createJoinTree = function(leftPlan, rightPlan) {
    var varsLeft ="/"+leftPlan.vars.join("/")+"/";
    var acumVars = leftPlan.vars.concat([]);
    var join = [];

    for(var i=0; i<rightPlan.vars.length; i++) {
        if(varsLeft.indexOf("/"+rightPlan.vars[i]+"/") != -1) {
            if(rightPlan.vars[i].indexOf("_:") == 0) {
                join.push("blank:"+rightPlan.vars[i]);
            } else {
                join.push(rightPlan.vars[i]);
            }
        } else {
            acumVars.push(rightPlan.vars[i]);
        }
    }

    var rightIds = rightPlan.i.split("_");
    var leftIds = leftPlan.i.split("_");
    var distinct = {};
    for(var i=0; i<rightIds.length; i++) {
        if(rightIds[i] != "") {
            distinct[rightIds[i]] = true;
        }
    }
    for(var i=0; i<leftIds.length; i++) {
        if(leftIds[i] != "") {
            distinct[leftIds[i]] = true;
        }
    }
    var ids = [];
    for(var id in distinct) {
        ids.push(id);
    }

    // new join tree
    return {
        left: leftPlan,
        right: rightPlan,
        cost: leftPlan.cost+rightPlan.cost,
        i: "_"+(ids.sort().join("_"))+"_",
        vars: acumVars,
        join: join
    };
};

QueryPlanDPSize.executeBushyTree = function(treeNode, dataset, queryEngine, env) {
    if(treeNode.left == null ) {
        return QueryPlanDPSize.executeEmptyJoinBGP(treeNode.right, dataset, queryEngine, env);
    } else if(treeNode.right == null) {
        return QueryPlanDPSize.executeEmptyJoinBGP(treeNode.left, dataset, queryEngine, env);
    } else {
        var resultsLeft = QueryPlanDPSize.executeBushyTree(treeNode.left, dataset, queryEngine, env);

        if(resultsLeft!=null) {
            var resultsRight = QueryPlanDPSize.executeBushyTree(treeNode.right, dataset, queryEngine, env);
            if(resultsRight!=null) {
                return QueryPlanDPSize.joinBindings2(treeNode.join, resultsLeft, resultsRight);
            } else {
                return null;
            }
        }
    }
};


QueryPlanDPSize.executeAndBGPsDPSize = function(allBgps, dataset, queryEngine, env) {
    var groups = QueryPlanDPSize.executeAndBGPsGroups(allBgps);
    var groupResults = [];
    for(var g=0; g<groups.length; g++) {

        // Build bushy tree for this group
        var bgps = groups[g];
        var costFactor = 1;

	var bgpas = queryEngine.computeCosts(bgps,env);

        var bestPlans = {};
        var plans = {};
        var sizes = {};

        var maxSize = 1;
        var maxPlan = null;

        var cache = {};
        
        sizes['1'] = [];

        // Building plans of size 1
        for(var i=0; i<bgps.length; i++) {
            var vars = [];
            for(var comp in bgps[i]) {
                if(comp != '_cost') {
                    if(bgps[i][comp].token === 'var') {
                        vars.push(bgps[i][comp].value);
                    } else if(bgps[i][comp].token === 'blank') {
                        vars.push(bgps[i][comp].value);
                    }
                }
            }

            plans["_"+i+"_"] = {left: bgps[i], right:null, cost:bgps[i]._cost, i:('_'+i+'_'), vars:vars};
            var plan = {left: bgps[i], right:null, cost:bgps[i]._cost, i:('_'+i+'_'), vars:vars};
            bestPlans["_"+i+"_"] = plan;
            delete bgps[i]['_cost'];
            cache["_"+i+"_"] = true;
            sizes['1'].push("_"+i+"_");
            if(maxPlan == null || maxPlan.cost>plan.cost) {
                maxPlan = plan;
            }
        }

        // dynamic programming -> build plans of increasing size
        for(var s=2; s<=bgps.length; s++) { // size
            for(var sl=1; sl<s; sl++) { // size left plan
                var sr = s - sl; // size right plan
                var leftPlans = sizes[''+sl] || [];
                var rightPlans = sizes[''+sr] || [];

                for(var i=0; i<leftPlans.length; i++) {
                    for(var j=0; j<rightPlans.length; j++) {
                        if(leftPlans[i]===rightPlans[j])
                            continue;
                        var leftPlan = plans[leftPlans[i]];
                        var rightPlan = plans[rightPlans[j]];

                        // condition (1)
                        if(QueryPlanDPSize.intersectionSize(leftPlan, rightPlan) == 0) {
                            // condition (2)

                            if(QueryPlanDPSize.connected(leftPlan,rightPlan)) {
                                maxSize = s;
                                var p1 = bestPlans[leftPlan.i];  //QueryPlanDPSize.bestPlan(leftPlan, bestPlans);
                                var p2 = bestPlans[rightPlan.i]; //QueryPlanDPSize.bestPlan(rightPlan, bestPlans);

                                var currPlan = QueryPlanDPSize.createJoinTree(p1,p2);
                                if(!cache[currPlan.i]) {
                                    cache[currPlan.i] = true;

                                    var costUnion = currPlan.cost+1;
                                    if(bestPlans[currPlan.i] != null) {
                                        costUnion = bestPlans[currPlan.i].cost;
                                    }
                                    
                                    var acum = sizes[s] || [];
                                    acum.push(currPlan.i);
                                    plans[currPlan.i] = currPlan;
                                    sizes[s] = acum;
                                    
                                    if(costUnion > currPlan.cost) {
                                        if(maxSize === s) {
                                            maxPlan = currPlan;
                                        }
                                        bestPlans[currPlan.i] = currPlan;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        groupResults.push(maxPlan);
    }


    // now execute the Bushy trees and perform
    // cross products between groups
    var acum = null;

    for(var g=0; g<groupResults.length; g++) {
        var tree = groupResults[g];

        var result = QueryPlanDPSize.executeBushyTree(tree, dataset, queryEngine, env);
        if(acum == null) {
            acum = result;
        } else {
            acum = QueryPlanDPSize.crossProductBindings(acum, result);
        }
    };

    return acum;
};

QueryPlanDPSize.executeEmptyJoinBGP = function(bgp, dataset, queryEngine, queryEnv) {
    return QueryPlanDPSize.executeBGPDatasets(bgp, dataset, queryEngine, queryEnv);
};


QueryPlanDPSize.executeBGPDatasets = function(bgp, dataset, queryEngine, queryEnv) {
    // avoid duplicate queries in the same graph
    // merge of graphs is not guaranted here.
    var duplicates = {};

    if(bgp.graph == null) {
        //union through all default graph(s)
        var acum = [];
        for(var i=0; i<dataset.implicit.length; i++) {
            if(duplicates[dataset.implicit[i].oid] == null) {
                duplicates[dataset.implicit[i].oid] = true;
                bgp.graph = dataset.implicit[i];//.oid
                var results = queryEngine.rangeQuery(bgp, queryEnv);
                results = QueryPlanDPSize.buildBindingsFromRange(results, bgp);
                acum.push(results);
            }
        }
        var acumBindings = QueryPlanDPSize.unionManyBindings(acum);
        return acumBindings;
    } else if(bgp.graph.token === 'var') {
        // union through all named datasets
        var graphVar = bgp.graph.value;        
        var acum = [];

        for(var i=0; i<dataset.named.length; i++) {
            if(duplicates[dataset.named[i].oid] == null) {
                duplicates[dataset.named[i].oid] = true;
                bgp.graph = dataset.named[i];//.oid
                
                var results = queryEngine.rangeQuery(bgp, queryEnv);
                if(results != null) {
                    results = QueryPlanDPSize.buildBindingsFromRange(results, bgp);
                    // add the graph bound variable to the result 
                    for(var j=0; j< results.length; j++) {
                        results[j][graphVar] = dataset.named[i].oid;
                    }
                    acum.push(results);
                } else {
                    return null;
                }
            }
        }
        
        var acumBindings = QueryPlanDPSize.unionManyBindings(acum||[]);
        return acumBindings;

    } else {
        // graph already has an active value, just match.
        // Filtering the results will still be necessary
        var results = queryEngine.rangeQuery(bgp, queryEnv);
        if(results!=null) {
            results = QueryPlanDPSize.buildBindingsFromRange(results, bgp);
            return results;
        } else {
            return null;
        }
    }
};

QueryPlanDPSize.buildBindingsFromRange = function(results, bgp) {
    var variables = QueryPlanDPSize.variablesInBGP(bgp);
    var bindings = {};

    var components =  bgp.value||bgp;
    var bindings = {};
    for(comp in components) {
        if(components[comp] && components[comp].token === "var") {
            bindings[comp] = components[comp].value;
        } else if(components[comp] && components[comp].token === "blank") {
            bindings[comp] = "blank:"+components[comp].value;
        }
    }

    var resultsBindings =[];

    if(results!=null) {
      for(var i=0; i<results.length; i++) {
          var binding = {};
          var result  = results[i];
	  var duplicated = false;
          for(var comp in bindings) {
              var value = result[comp];
	      if(binding[bindings[comp]] == null || binding[bindings[comp]] === value) {
		  binding[bindings[comp]] = value;
	      } else {
		  duplicated = true;
		  break;
	      }
          }
	  if(!duplicated)
              resultsBindings.push(binding);
      }
    }

    return resultsBindings;
};


// @used
QueryPlanDPSize.areCompatibleBindings = function(bindingsa, bindingsb) {
    for(var variable in bindingsa) {
        if(bindingsb[variable]!=null && (bindingsb[variable] != bindingsa[variable])) {
            return false;
        }
    }

    return true;
};

//QueryPlanDPSize.areCompatibleBindingsStrict = function(bindingsa, bindingsb) {
//    var foundSome = false;
//    for(var variable in bindingsa) {
// 	if(bindingsb[variable]!=null && (bindingsb[variable] != bindingsa[variable])) {
// 	    return false;
// 	} else if(bindingsb[variable] == bindingsa[variable]){
// 	    foundSome = true;
// 	}
//    }
//     
//    return foundSome;
//};



QueryPlanDPSize.mergeBindings = function(bindingsa, bindingsb) {
    var merged = {};
    for(var variable in bindingsa) {
        merged[variable] = bindingsa[variable];
    }

    for(var variable in bindingsb) {
        merged[variable] = bindingsb[variable];
    }

    return merged;
};

QueryPlanDPSize.joinBindings2 = function(bindingVars, bindingsa, bindingsb) {
    var acum = {};
    var bindings, variable, variableValue, values, tmp;
    var joined = [];

    for(var i=0; i<bindingsa.length; i++) {
        bindings = bindingsa[i];
        tmp = acum;
        for(var j=0; j<bindingVars.length; j++) {
            variable = bindingVars[j];
            variableValue = bindings[variable];
            if(j == bindingVars.length-1) {
                values = tmp[variableValue] || [];
                values.push(bindings);
                tmp[variableValue] = values;
            } else {
                values = tmp[variableValue] || {};
                tmp[variableValue] = values;
                tmp = values;
            }
        }
    }

    for(var i=0; i<bindingsb.length; i++) {
        bindings = bindingsb[i];
        tmp = acum;
        for(var j=0; j<bindingVars.length; j++) {
            variable = bindingVars[j];
            variableValue = bindings[variable];

            if(tmp[variableValue] != null) {
                if(j == bindingVars.length-1) {
                    for(var k=0; k<tmp[variableValue].length; k++) {
                        joined.push(QueryPlanDPSize.mergeBindings(tmp[variableValue][k],bindings));
                    }
                } else {
                    tmp = tmp[variableValue];
                }
            }
        }
    }

    return joined;
};

QueryPlanDPSize.joinBindings = function(bindingsa, bindingsb) {
    var result = [];

    for(var i=0; i< bindingsa.length; i++) {
        var bindinga = bindingsa[i];
        for(var j=0; j<bindingsb.length; j++) {
            var bindingb = bindingsb[j];
            if(QueryPlanDPSize.areCompatibleBindings(bindinga, bindingb)){
                result.push(QueryPlanDPSize.mergeBindings(bindinga, bindingb));
            }
        }
    }
    return result;
};

QueryPlanDPSize.augmentMissingBindings = function(bindinga, bindingb) {
    for(var pb in bindingb) {
        if(bindinga[pb] == null) {
            bindinga[pb] = null;
        }
    }
    return bindinga;
};

/*
  QueryPlanDPSize.diff = function(bindingsa, biundingsb) {
  var result = [];

  for(var i=0; i< bindingsa.length; i++) {
  var bindinga = bindingsa[i];
  var matched = false;
  for(var j=0; j<bindingsb.length; j++) {
  var bindingb = bindingsb[j];
  if(QueryPlanDPSize.areCompatibleBindings(bindinga, bindingb)){
  matched = true;
  result.push(QueryPlanDPSize.mergeBindings(bindinga, bindingb));
  }
  }
  if(matched === false) {
  // missing bindings must be present for further processing
  // e.g. filtering by not present value (see DAWG tests
  // bev-6)
  QueryPlanDPSize.augmentMissingBindings(bindinga, bindingb);
  result.push(bindinga);
  }
  }

  return result;    
  };
*/

QueryPlanDPSize.leftOuterJoinBindings = function(bindingsa, bindingsb) {
    var result = [];
    // strict was being passes ad an argument
    //var compatibleFunction = QueryPlanDPSize.areCompatibleBindings;
    //if(strict === true)
    // 	compatibleFunction = QueryPlanDPSize.areCompatibleBindingsStrict;

    for(var i=0; i< bindingsa.length; i++) {
        var bindinga = bindingsa[i];
        var matched = false;
        for(var j=0; j<bindingsb.length; j++) {
            var bindingb = bindingsb[j];
            if(QueryPlanDPSize.areCompatibleBindings(bindinga, bindingb)){
                matched = true;
                result.push(QueryPlanDPSize.mergeBindings(bindinga, bindingb));
            }
        }
        if(matched === false) {
            // missing bindings must be present for further processing
            // e.g. filtering by not present value (see DAWG tests
            // bev-6)
            // augmentMissingBindings set their value to null.
            QueryPlanDPSize.augmentMissingBindings(bindinga, bindingb);
            result.push(bindinga);
        }
    }
    return result;
};

QueryPlanDPSize.crossProductBindings = function(bindingsa, bindingsb) {
    var result = [];

    for(var i=0; i< bindingsa.length; i++) {
        var bindinga = bindingsa[i];
        for(var j=0; j<bindingsb.length; j++) {
            var bindingb = bindingsb[j];
            result.push(QueryPlanDPSize.mergeBindings(bindinga, bindingb));
        }
    }

    return result;
};

QueryPlanDPSize.unionBindings = function(bindingsa, bindingsb) {
    return bindingsa.concat(bindingsb);
};

QueryPlanDPSize.unionManyBindings = function(bindingLists) {
    var acum = [];
    for(var i=0; i<bindingLists.length; i++) {
        var bindings = bindingLists[i];
        acum = QueryPlanDPSize.unionBindings(acum, bindings);
    }

    return acum;
};

// end of ./src/js-query-engine/src/query_plan_sync_dpsize.js 
// exports
var QueryEngine = {};

//imports
var QueryPlan = QueryPlanDPSize;
QueryEngine.QueryEngine = function(params) {
    if(arguments.length != 0) {
        this.backend = params.backend;
        this.lexicon = params.lexicon;
        // batch loads should generate events?
        this.eventsOnBatchLoad = (params.eventsOnBatchLoad || false);
        // list of namespaces that will be automatically added to every query
        this.defaultPrefixes = {};
        this.abstractQueryTree = new AbstractQueryTree.AbstractQueryTree();
        this.rdfLoader = new RDFLoader.RDFLoader(params['communication']);
        this.callbacksBackend = new Callbacks.CallbacksBackend(this);
	this.customFns = params.customFns || {};
    }
};

QueryEngine.QueryEngine.prototype.setCustomFunctions = function(customFns) {
    this.customFns = customFns;
};

// Utils
QueryEngine.QueryEngine.prototype.registerNsInEnvironment = function(prologue, env) {
    var prefixes = [];
    if(prologue != null && prologue.prefixes != null) {
	prefixes =prologue.prefixes;
    }
    var toSave = {};

    // adding default prefixes;
    for(var p in this.defaultPrefixes) {
        toSave[p] = this.defaultPrefixes[p];
    }

    for(var i=0; i<prefixes.length; i++) {
        var prefix = prefixes[i];
        if(prefix.token === "prefix") {
            toSave[prefix.prefix] = prefix.local;
        }
    }

    env.namespaces = toSave;
    if(prologue!=null && prologue.base && typeof(prologue.base) === 'object') {
        env.base = prologue.base.value;
    } else {
        env.base = null;
    }
};

QueryEngine.QueryEngine.prototype.applyModifier = function(modifier, projectedBindings) {
    if(modifier == "DISTINCT") {
        var map = {};
        var result = [];
        for(var i=0; i<projectedBindings.length; i++) {
            var bindings = projectedBindings[i];
            var key = "";
         
            // if no projection variables hash is passed, all the bound
            // variable in the current bindings will be used.
            for(var p in (bindings)) {
                // hashing the object
                var obj = bindings[p];
                if(obj == null) {
                    key = key+p+'null';
                } else if(obj.token == 'literal') {
                    if(obj.value != null) {
                        key = key + obj.value;
                    }
                    if(obj.lang != null) {
                        key = key + obj.lang;
                    }
                    if(obj.type != null) {
                        key = key + obj.type;
                    }
                } else if(obj.value) {
                    key  = key + p + obj.value;
                } else {
                    key = key + p + obj;
                }
            }
         
            if(map[key] == null) {
                // this will preserve the order in projectedBindings
                result.push(bindings);
                map[key] = true;
            }
        }
        return result; 
    } else {
        return projectedBindings;
    }
};

QueryEngine.QueryEngine.prototype.applyLimitOffset = function(offset, limit, bindings) {
    if(limit == null && offset == null) {
        return bindings;
    }

    if (offset == null) {
        offset = 0;
    }

    if(limit == null) {
        limit = bindings.length;
    } else {
        limit = offset + limit;
    }

    return bindings.slice(offset, limit);
};


QueryEngine.QueryEngine.prototype.applySingleOrderBy = function(orderFilters, modifiedBindings, dataset, outEnv) {
    var acum = [];
    for(var i=0; i<orderFilters.length; i++) {
        var orderFilter = orderFilters[i];
        var results = QueryFilters.collect(orderFilter.expression, [modifiedBindings], dataset, outEnv, this);
        acum.push(results[0].value);
    }
    return {binding:modifiedBindings, value:acum};
};

QueryEngine.QueryEngine.prototype.applyOrderBy = function(order, modifiedBindings, dataset, outEnv) {
    var that = this;
    var acum = [];
    if(order != null && order.length > 0) {
        for(var i=0; i<modifiedBindings.length; i++) {
            var bindings = modifiedBindings[i];
            var results = that.applySingleOrderBy(order, bindings, dataset, outEnv);
            acum.push(results);
        }

        acum.sort(function(a,b){
            return that.compareFilteredBindings(a, b, order, outEnv);
        });

        var toReturn = [];
        for(var i=0; i<acum.length; i++) {
            toReturn.push(acum[i].binding);
        }

        return toReturn;
    } else {
        return modifiedBindings;
    }
};

QueryEngine.QueryEngine.prototype.compareFilteredBindings = function(a, b, order, env) {
    var found = false;
    var i = 0;
    while(!found) {
        if(i==a.value.length) {
            return 0;
        }
        var direction = order[i].direction;
        var filterResult;

        // unbound first
        if(a.value[i] == null && b.value[i] == null) {
            i++;
            continue;
        }else if(a.value[i] == null) {
            filterResult = {value: false};
        } else if(b.value[i] == null) {
            filterResult = {value: true};
        } else 

        // blanks
        if(a.value[i].token === 'blank' && b.value[i].token === 'blank') {
            i++;
            continue;
        } else if(a.value[i].token === 'blank') { 
            filterResult = {value: false};            
        } else if(b.value[i].token === 'blank') {
            filterResult = {value: true};        
        } else 

        // uris
        if(a.value[i].token === 'uri' && b.value[i].token === 'uri') {
            if(QueryFilters.runEqualityFunction(a.value[i], b.value[i], [], this, env).value == true) {
                i++;
                continue;
            } else {
                filterResult = QueryFilters.runTotalGtFunction(a.value[i], b.value[i], []);
            }
        } else if(a.value[i].token === 'uri') { 
            filterResult = {value: false};            
        } else if(b.value[i].token === 'uri') {
            filterResult = {value: true};        
        } else 

        // simple literals
        if(a.value[i].token === 'literal' && b.value[i].token === 'literal' && a.value[i].type == null && b.value[i].type == null) {
            if(QueryFilters.runEqualityFunction(a.value[i], b.value[i], [], this, env).value == true) {
                i++;
                continue;
            } else {
                filterResult = QueryFilters.runTotalGtFunction(a.value[i], b.value[i], []);
            }
        } else if(a.value[i].token === 'literal' && a.value[i].type == null) { 
            filterResult = {value: false};            
        } else if(b.value[i].token === 'literal' && b.value[i].type == null) {
            filterResult = {value: true};        
        } else 

        // literals
        if(QueryFilters.runEqualityFunction(a.value[i], b.value[i], [], this, env).value == true) {
            i++;
            continue;
        } else {
            filterResult = QueryFilters.runTotalGtFunction(a.value[i], b.value[i], []);
        }     


        // choose value for comparison based on the direction
        if(filterResult.value == true) {
            if(direction === "ASC") {
                return 1;
            } else {
                return -1;
            }
        } else {
            if(direction === "ASC") {
                return -1;
            } else {
                return 1;
            }
        }       
    }
};

QueryEngine.QueryEngine.prototype.removeDefaultGraphBindings = function(bindingsList, dataset) {
    var onlyDefaultDatasets = [];
    var namedDatasetsMap = {};
    for(var i=0; i<dataset.named.length; i++) {
        namedDatasetsMap[dataset.named[i].oid] = true;
    }
    for(i=0; i<dataset.implicit.length; i++) {
        if(namedDatasetsMap[dataset.implicit[i].oid] == null) {
            onlyDefaultDatasets.push(dataset.implicit[i].oid);
        }
    }
    var acum = [];
    for(i=0; i<bindingsList.length; i++) {
        var bindings = bindingsList[i];
        var foundDefaultGraph = false;
        for(var p in bindings) {
            for(var j=0; j<namedDatasetsMap.length; j++) {
                if(bindings[p] === namedDatasetsMap[j]) {
                    foundDefaultGraph = true;
                    break;
                }
            }
            if(foundDefaultGraph) {
                break;
            }
        }
        if(!foundDefaultGraph) {
            acum.push(bindings);
        }
    }

    return acum;
};


QueryEngine.QueryEngine.prototype.aggregateBindings = function(projection, bindingsGroup, dataset, env) {
    var denormBindings = this.copyDenormalizedBindings(bindingsGroup, env.outCache);
    var aggregatedBindings = {};
    for(var i=0; i<projection.length; i++) {
        var aggregatedValue = QueryFilters.runAggregator(projection[i], denormBindings, this, dataset, env);
        if(projection[i].alias) {
            aggregatedBindings[projection[i].alias.value] = aggregatedValue; 
        } else {
            aggregatedBindings[projection[i].value.value] = aggregatedValue; 
        }
    }
    return(aggregatedBindings);
};


QueryEngine.QueryEngine.prototype.projectBindings = function(projection, results, dataset) {
    if(projection[0].kind === '*') {
        return results;
    } else {
        var projectedResults = [];

        for(var i=0; i<results.length; i++) {
            var currentResult = results[i];
            var currentProjected = {};
            var shouldAdd = true;

            for(var j=0; j< projection.length; j++) {
                if(projection[j].token == 'variable' && projection[j].kind != 'aliased') {
                    currentProjected[projection[j].value.value] = currentResult[projection[j].value.value];
                } else if(projection[j].token == 'variable' && projection[j].kind == 'aliased') {
                    var ebv = QueryFilters.runFilter(projection[j].expression, currentResult, this, dataset, {blanks:{}, outCache:{}});
                    if(QueryFilters.isEbvError(ebv)) {
                        shouldAdd = false;
                        break;
                    } else {
                        currentProjected[projection[j].alias.value] = ebv;
                    }
                }
            }

            if(shouldAdd === true) {
                projectedResults.push(currentProjected);
            }
            
        }

        return projectedResults;
    }
};

QueryEngine.QueryEngine.prototype.resolveNsInEnvironment = function(prefix, env) {
    var namespaces = env.namespaces;
    return namespaces[prefix];
};

QueryEngine.QueryEngine.prototype.termCost = function(term, env) {
    if(term.token === 'uri') {
        var uri = Utils.lexicalFormBaseUri(term, env);
        if(uri == null) {
            return(0);
        } else {
            return(this.lexicon.resolveUriCost(uri));
        }

    } else if(term.token === 'literal') {
        var lexicalFormLiteral = Utils.lexicalFormLiteral(term, env);
        return(this.lexicon.resolveLiteralCost(lexicalFormLiteral));
    } else if(term.token === 'blank') {
        var label = term.value;
        return this.lexicon.resolveBlankCost(label);
    } else if(term.token === 'var') {
        return (this.lexicon.oidCounter/3)
    } else {
          return(null);
    }
    
};

QueryEngine.QueryEngine.prototype.normalizeTerm = function(term, env, shouldIndex) {
    if(term.token === 'uri') {
        var uri = Utils.lexicalFormBaseUri(term, env);
        if(uri == null) {
            return(null);
        } else {
            if(shouldIndex) {
                return(this.lexicon.registerUri(uri));
            } else {
                return(this.lexicon.resolveUri(uri));
            }
        }

    } else if(term.token === 'literal') {
        var lexicalFormLiteral = Utils.lexicalFormLiteral(term, env);
        if(shouldIndex) {
           var oid = this.lexicon.registerLiteral(lexicalFormLiteral);
            return(oid);
        } else {
            var oid = this.lexicon.resolveLiteral(lexicalFormLiteral);
            return(oid);
        }
    } else if(term.token === 'blank') {
        var label = term.value;
        var oid = env.blanks[label];
        if( oid != null) {
            return(oid);
        } else {
            if(shouldIndex) {
                var oid = this.lexicon.registerBlank(label);
                env.blanks[label] = oid;
                return(oid);
            } else {
                var oid = this.lexicon.resolveBlank(label);
                env.blanks[label] = oid;
                return(oid);
            }
        }
    } else if(term.token === 'var') {
        return(term.value);
    } else {
          return(null);
    }
};

QueryEngine.QueryEngine.prototype.normalizeDatasets = function(datasets, outerEnv, callback) {
    var that = this;
    for(var i=0; i<datasets.length; i++) {
        var dataset = datasets[i];
        if(dataset.value === that.lexicon.defaultGraphUri) {
            dataset.oid = that.lexicon.defaultGraphOid;
        } else {
            var oid = that.normalizeTerm(dataset, outerEnv, false);      
            if(oid != null) {
                dataset.oid = oid;
            } else {
                return(null);
            }
        }  
    }

    return true
};

QueryEngine.QueryEngine.prototype.normalizeQuad = function(quad, queryEnv, shouldIndex) {
    var subject    = null;
    var predicate  = null;
    var object     = null;
    var graph      = null;
    var oid;

    if(quad.graph == null) {
        graph = 0; // default graph
    } else {
        oid = this.normalizeTerm(quad.graph, queryEnv, shouldIndex);
        if(oid!=null) {
            graph = oid;
            if(shouldIndex === true && quad.graph.token!='var')
                this.lexicon.registerGraph(oid);
        } else {
            return null;
        }
    }

    oid = this.normalizeTerm(quad.subject, queryEnv, shouldIndex);
    if(oid!=null) {
        subject = oid;
    } else {
        return null
    }

    oid = this.normalizeTerm(quad.predicate, queryEnv, shouldIndex);
    if(oid!=null) {
        predicate = oid;
    } else {
        return null
    }

    oid = this.normalizeTerm(quad.object, queryEnv, shouldIndex);
    if(oid!=null) {
        object = oid;
    } else {
        return null
    }

    return({subject:subject, 
            predicate:predicate, 
            object:object, 
            graph:graph});
};

QueryEngine.QueryEngine.prototype.quadCost = function(quad, queryEnv, shouldIndex) {
    var subject    = null;
    var predicate  = null;
    var object     = null;
    var graph      = null;

    if(quad.graph == null) {
        graph = (this.lexicon.oidCounter/4)
    } else {
        graph = this.termCost(quad.graph, queryEnv)
    }

    subject = this.termCost(quad.subject, queryEnv);
    predicate = this.termCost(quad.predicate, queryEnv);
    object = this.termCost(quad.object, queryEnv);

    return(graph+subject+predicate+object);
};

QueryEngine.QueryEngine.prototype.denormalizeBindingsList = function(bindingsList, env) {
    var results = [];

    for(var i=0; i<bindingsList.length; i++) {
        var result = this.denormalizeBindings(bindingsList[i], env);
        results.push(result);
    }
    return(results);
};

/**
 * Receives a bindings map (var -> oid) and an out cache (oid -> value)
 * returns a bindings map (var -> value) storing in cache all the missing values for oids
 *
 * This is required just to save lookups when final results are generated.
 */
QueryEngine.QueryEngine.prototype.copyDenormalizedBindings = function(bindingsList, out, callback) {
    var denormList = [];
    for(var i=0; i<bindingsList.length; i++) {
        var denorm = {};
        var bindings = bindingsList[i];
        var variables = Utils.keys(bindings);
        for(var j=0; j<variables.length; j++) {
            var oid = bindings[variables[j]];
            if(oid == null) {
                // this can be null, e.g. union different variables (check SPARQL recommendation examples UNION)
                denorm[variables[j]] = null;
            } else if(typeof(oid) === 'object') {
                // the binding is already denormalized, this can happen for example because the value of the
                // binding is the result of the aggregation of other bindings in a GROUP clause
                denorm[variables[j]] = oid;
            } else {
                var inOut = out[oid];
                if(inOut!= null) {
                    denorm[variables[j]] = inOut;
                } else {                    
                    var val = this.lexicon.retrieve(oid);
                    out[oid] = val;
                    denorm[variables[j]] = val;
                }
            }
        }
        denormList.push(denorm);
    }
    return denormList;
};

QueryEngine.QueryEngine.prototype.denormalizeBindings = function(bindings, env, callback) {
    var variables = Utils.keys(bindings);
    var envOut = env.outCache;
    for(var i=0; i<variables.length; i++) {
        var oid = bindings[variables[i]];
        if(oid == null) {
            // this can be null, e.g. union different variables (check SPARQL recommendation examples UNION)
            bindings[variables[i]] = null;
        } else {
            if(envOut[oid] != null) {
                bindings[variables[i]] = envOut[oid];
            } else {
                var val = this.lexicon.retrieve(oid);
                bindings[variables[i]] = val;
		if(val.token === 'blank') {
		    env.blanks[val.value] = oid;
		}
            }
        }
    }
    return bindings;
};

// Queries execution

QueryEngine.QueryEngine.prototype.execute = function(queryString, callback, defaultDataset, namedDataset){
    //try{
        queryString = Utils.normalizeUnicodeLiterals(queryString);

        var syntaxTree = this.abstractQueryTree.parseQueryString(queryString);
        if(syntaxTree == null) {
            callback(false,"Error parsing query string");
        } else {
            if(syntaxTree.token === 'query' && syntaxTree.kind == 'update')  {
                this.callbacksBackend.startGraphModification();
                var that = this;
                this.executeUpdate(syntaxTree, function(success, result){
		    if(that.lexicon.updateAfterWrite)
			that.lexicon.updateAfterWrite();

                    if(success) {
                        that.callbacksBackend.endGraphModification(function(){
                            callback(success, result);
                        });
                    } else {
                        that.callbacksBackend.cancelGraphModification();
                        callback(success, result);
                    }
                });
            } else if(syntaxTree.token === 'query' && syntaxTree.kind == 'query') {
                this.executeQuery(syntaxTree, callback, defaultDataset, namedDataset);
            }
        }
    //} catch(e) {
    //    if(e.name && e.name==='SyntaxError') {
    //        callback(false, "Syntax error: \nmessage:"+e.message+"\nline "+e.line+", column:"+e.column);
    //    } else {
    //        callback(false, "Query execution error");
    //    }
    //}
};

// Retrieval queries

QueryEngine.QueryEngine.prototype.executeQuery = function(syntaxTree, callback, defaultDataset, namedDataset) {
    var prologue = syntaxTree.prologue;
    var units = syntaxTree.units;
    var that = this;

    // environment for the operation -> base ns, declared ns, etc.
    var queryEnv = {blanks:{}, outCache:{}};
    this.registerNsInEnvironment(prologue, queryEnv);

    // retrieval queries can only have 1 executable unit
    var aqt = that.abstractQueryTree.parseExecutableUnit(units[0]);

    // can be anything else but a select???
    if(aqt.kind === 'select') {
      this.executeSelect(aqt, queryEnv, defaultDataset, namedDataset, function(success, result){
          if(success) {
              if(typeof(result) === 'object' && result.denorm === true) {
                  callback(true, result['bindings']);
              } else {
                  var result = that.denormalizeBindingsList(result, queryEnv);
                  if(result != null) {                        
                      callback(true, result);
                  } else {
                      callback(false, result);
                  }
              }
          } else {
              callback(false, result);
          }
      });
    } else if(aqt.kind === 'ask') {
        aqt.projection = [{"token": "variable", "kind": "*"}];
        this.executeSelect(aqt, queryEnv, defaultDataset, namedDataset, function(success, result){
            if(success) {
                if(success) {              
                    if(result.length>0) {
                        callback(true, true);
                    } else {
                        callback(true, false);
                    }
                } else {
                    callback(false, result);
                }
            } else {
                callback(false, result);
            }
        });
    } else if(aqt.kind === 'construct') {
        aqt.projection = [{"token": "variable", "kind": "*"}];
        that = this;
        this.executeSelect(aqt, queryEnv, defaultDataset, namedDataset, function(success, result){
            if(success) {
                if(success) {              
                    var result = that.denormalizeBindingsList(result, queryEnv);
                    if(result != null) { 
                        var graph = new RDFJSInterface.Graph();
                            
                        // CONSTRUCT WHERE {} case
                        if(aqt.template == null) {
                            aqt.template = {triplesContext: aqt.pattern};
                        }
                        var blankIdCounter = 1;
			var toClear = [];
                        for(var i=0; i<result.length; i++) {
                            var bindings = result[i];
			    for(var j=0; j<toClear.length; j++)
				delete toClear[j].valuetmp;

                            for(var j=0; j<aqt.template.triplesContext.length; j++) {
                                // fresh IDs for blank nodes in the construct template
                                var components = ['subject', 'predicate', 'object'];
                                var tripleTemplate = aqt.template.triplesContext[j];                                    
                                for(var p=0; p<components.length; p++) {
                                    var component = components[p];
                                    if(tripleTemplate[component].token === 'blank') {
					if(tripleTemplate[component].valuetmp && tripleTemplate[component].valuetmp != null) {
					} else {
					    var blankId = "_:b"+blankIdCounter;
					    blankIdCounter++;
					    tripleTemplate[component].valuetmp = blankId;
					    toClear.push(tripleTemplate[component]);
					}
				    }
                                }
                                var s = RDFJSInterface.buildRDFResource(tripleTemplate.subject,bindings,that,queryEnv);
                                var p = RDFJSInterface.buildRDFResource(tripleTemplate.predicate,bindings,that,queryEnv);
                                var o = RDFJSInterface.buildRDFResource(tripleTemplate.object,bindings,that,queryEnv);
                                if(s!=null && p!=null && o!=null) {
                                    var triple = new RDFJSInterface.Triple(s,p,o);
                                    graph.add(triple);
                                    //} else {
                                    //    return callback(false, "Error creating output graph")
                                }
                            }
                        }
                        callback(true,graph);
                    } else {
                        callback(false, result);
                    }
                } else {
                    callback(false, result);
                }
            } else {
                callback(false, result);
            }
        });
    }
};


// Select queries

QueryEngine.QueryEngine.prototype.executeSelect = function(unit, env, defaultDataset, namedDataset, callback) {
    if(unit.kind === "select" || unit.kind === "ask" || unit.kind === "construct" || unit.kind === "modify") {
        var projection = unit.projection;
        var dataset    = unit.dataset;
        var modifier   = unit.modifier;
        var limit      = unit.limit;
        var offset     = unit.offset;
        var order      = unit.order;
        var that = this;

        if(defaultDataset != null || namedDataset != null) {
            dataset.implicit = defaultDataset || [];
            dataset.named   = namedDataset || [];
        } 

        if(dataset.implicit != null && dataset.implicit.length === 0 && dataset.named !=null && dataset.named.length === 0) {
            // We add the default graph to the default merged graph
            dataset.implicit.push(this.lexicon.defaultGraphUriTerm);
        }

        if (that.normalizeDatasets(dataset.implicit.concat(dataset.named), env) != null) {
            var result = that.executeSelectUnit(projection, dataset, unit.pattern, env);
            if(result != null) {
                // detect single group
                if(unit.group!=null && unit.group === "") {
                    var foundUniqueGroup = false;
                    for(var i=0; i<unit.projection.length; i++) {
                        if(unit.projection[i].expression!=null && unit.projection[i].expression.expressionType === 'aggregate') {
                            foundUniqueGroup = true;
                            break;
                        }
                    }
                    if(foundUniqueGroup === true) {
                        unit.group = 'singleGroup';
                    }
                }
                if(unit.group && unit.group != "") {
                    if(that.checkGroupSemantics(unit.group,projection)) {
                        var groupedBindings = that.groupSolution(result, unit.group, dataset, env);
                             
                        var aggregatedBindings = [];
                        var foundError = false;
                            
                        for(var i=0; i<groupedBindings.length; i++) {
                            var resultingBindings = that.aggregateBindings(projection, groupedBindings[i], dataset, env);
                            aggregatedBindings.push(resultingBindings);
                        }
                        callback(true, {'bindings': aggregatedBindings, 'denorm':true});
                    } else {
                        callback(false, "Incompatible Group and Projection variables");
                    }
                } else {
                    var orderedBindings = that.applyOrderBy(order, result, dataset, env);
                    var projectedBindings = that.projectBindings(projection, orderedBindings, dataset);
                    var modifiedBindings = that.applyModifier(modifier, projectedBindings);
                    var limitedBindings  = that.applyLimitOffset(offset, limit, modifiedBindings);
                    var filteredBindings = that.removeDefaultGraphBindings(limitedBindings, dataset);
                    
                    callback(true, filteredBindings);
                }
                
            } else { // fail selectUnit
                callback(false, result);
            }
        } else { // fail  normalizaing datasets
            callback(false,"Error normalizing datasets");
        }
    } else {
        callback(false,"Cannot execute " + unit.kind + " query as a select query");
    }
};


QueryEngine.QueryEngine.prototype.groupSolution = function(bindings, group, dataset, queryEnv){
    var order = [];
    var filteredBindings = [];
    var initialized = false;
    var that = this;
    if(group === 'singleGroup') {
        return [bindings];
    } else {
        for(var i=0; i<bindings.length; i++) {
            var outFloop = arguments.callee;
            var currentBindings = bindings[i];
            var mustAddBindings = true;

            /**
             * In this loop, we iterate through all the group clauses and tranform the current bindings
             * according to the group by clauses.
             * If it is the first iteration we also save in a different array the order for the 
             * grouped variables that will be used later to build the final groups
             */
            for(var j=0; j<group.length; j++) {
                var floop = arguments.callee;
                var currentOrderClause = group[j];
                var orderVariable = null;

                if(currentOrderClause.token === 'var') {
                    orderVariable = currentOrderClause.value;

                    if(initialized == false) {
                        order.push(orderVariable);
                    }

                } else if(currentOrderClause.token === 'aliased_expression') {
                    orderVariable = currentOrderClause.alias.value;
                    if(initialized == false) {
                        order.push(orderVariable);
                    }

                    if(currentOrderClause.expression.primaryexpression === 'var') {
                        currentBindings[currentOrderClause.alias.value] = currentBindings[currentOrderClause.expression.value.value];
                    } else {
                        var denormBindings = this.copyDenormalizedBindings([currentBindings], queryEnv.outCache);
                        var filterResultEbv = QueryFilters.runFilter(currentOrderClause.expression, denormBindings[0], that, dataset, queryEnv);
                        if(!QueryFilters.isEbvError(filterResultEbv)) {
                            if(filterResultEbv.value != null) {
                                filterResultEbv.value = ""+filterResultEbv.value;
                            }
                            currentBindings[currentOrderClause.alias.value]= filterResultEbv;
                        } else {
                            mustAddBindings = false;
                        }
                    }
                } else {
                    // In this case, we create an additional variable in the binding to hold the group variable value
                    var denormBindings = that.copyDenormalizedBindings([currentBindings], queryEnv.outCache);
                    var filterResultEbv = QueryFilters.runFilter(currentOrderClause, denormBindings[0], that, queryEnv);
                    if(!QueryFilters.isEbvError(filterResultEbv)) {
                        currentBindings["groupCondition"+env._i] = filterResultEbv;
                        orderVariable = "groupCondition"+env._i;
                        if(initialized == false) {
                            order.push(orderVariable);
                        }
                        
                    } else {
                        mustAddBindings = false;
                    }
                         
                }
                
            }
            if(initialized == false) {
                initialized = true;
            } 
            if(mustAddBindings === true) {
                filteredBindings.push(currentBindings);
            }
        }
        /**
         * After processing all the bindings, we build the group using the
         * information stored about the order of the group variables.
         */
        var dups = {};
        var groupMap = {};
        var groupCounter = 0;
        for(var i=0; i<filteredBindings.length; i++) {
            var currentTransformedBinding = filteredBindings[i];
            var key = "";
            for(var j=0; j<order.length; j++) {
                var maybeObject = currentTransformedBinding[order[j]];
                if(typeof(maybeObject) === 'object') {
                    key = key + maybeObject.value;
                } else {
                    key = key + maybeObject;
                }
            }

            if(dups[key] == null) {
                //currentTransformedBinding["__group__"] = groupCounter; 
                groupMap[key] = groupCounter;
                dups[key] = [currentTransformedBinding];
                //groupCounter++
            } else {
                //currentTransformedBinding["__group__"] = dups[key][0]["__group__"]; 
                dups[key].push(currentTransformedBinding);
            }
        }

        // The final result is an array of arrays with all the groups
        var groups = [];
            
        for(var k in dups) {
            groups.push(dups[k]);
        }

        return groups;
    };
};


/**
 * Here, all the constructions of the SPARQL algebra are handled
 */
QueryEngine.QueryEngine.prototype.executeSelectUnit = function(projection, dataset, pattern, env) {
    if(pattern.kind === "BGP") {
        return this.executeAndBGP(projection, dataset, pattern, env);
    } else if(pattern.kind === "UNION") {
        return this.executeUNION(projection, dataset, pattern.value, env);            
    } else if(pattern.kind === "JOIN") {
        return this.executeJOIN(projection, dataset, pattern, env);            
    } else if(pattern.kind === "LEFT_JOIN") {
        return this.executeLEFT_JOIN(projection, dataset, pattern, env);            
    } else if(pattern.kind === "FILTER") {
        // Some components may have the filter inside the unit
        var results = this.executeSelectUnit(projection, dataset, pattern.value, env);
        if(results != null) {
            results = QueryFilters.checkFilters(pattern, results, false, dataset, env, this);
            return results;
        } else {
            return [];
        }
    } else if(pattern.kind === "EMPTY_PATTERN") {
        // as an example of this case  check DAWG test case: algebra/filter-nested-2
        return [];
    } else if(pattern.kind === "ZERO_OR_MORE_PATH" || pattern.kind === 'ONE_OR_MORE_PATH') {
	return this.executeZeroOrMorePath(pattern, dataset, env);
    } else {
        console.log("Cannot execute query pattern " + pattern.kind + ". Not implemented yet.");
        return null;
    }
};

QueryEngine.QueryEngine.prototype.executeZeroOrMorePath = function(pattern, dataset, env) {
    //console.log("EXECUTING ZERO OR MORE PATH");
    //console.log("X");
    //console.log(pattern.x);
    //console.log("Y");
    //console.log(pattern.y);
    var projection = [];
    var starProjection = false;
    if(pattern.x.token === 'var') {
	projection.push({token: 'variable',
			 kind: 'var',
			 value: pattern.x.value});
    }
    if(pattern.y.token === 'var') {
	projection.push({token: 'variable',
			 kind: 'var',
			 value: pattern.y.value});
    }

    if(projection.length === 0) {
	projection.push({"token": "variable", "kind": "*"});
	starProjection = true;
    }

    //console.log("COMPUTED PROJECTION");
    //console.log(projection);


    if(pattern.x.token === 'var' && pattern.y.token === 'var') {
	var bindings = this.executeAndBGP(projection, dataset, pattern.path, env);
	//console.log("BINDINGS "+bindings.length);
	//console.log(bindings);
	var acum = {};
	var results = [];
	var vx, intermediate, nextBinding, vxDenorm;
	var origVXName = pattern.x.value;
	var last = pattern.x;
	var nextPath = pattern.path;
	//console.log("VAR - VAR PATTERN");
	//console.log(nextPath.value);
	for(var i=0; i<bindings.length; i++) {
	    vx = bindings[i][origVXName];
	    if(acum[vx] == null) {
		vxDenorm = this.lexicon.retrieve(vx);
		pattern.x = vxDenorm;
		//console.log("REPLACING");
		//console.log(last);
		//console.log("BY");
		//console.log(vxDenorm);
		//console.log(nextPath.value);
		pattern.path = this.abstractQueryTree.replace(nextPath, last, vxDenorm, env);
		nextPath = Utils.clone(pattern.path);
		intermediate = this.executeZeroOrMorePath(pattern, dataset, env);
		for(var j=0; j<intermediate.length; j++) {
		    nextBinding = intermediate[j];
		    nextBinding[origVXName] = vx;
		    results.push(nextBinding)
		}
		last = vxDenorm;
	    }
	}

	//console.log("RETURNING VAR - VAR");
	return results;
    } else if(pattern.x.token !== 'var' && pattern.y.token === 'var') {
	var finished;
	var acum = {};
	var initial = true;
	var pending = [];
	var bindings,nextBinding;
	var collected = [];
	var origVx = pattern.x;
	var last;

	while(initial == true || pending.length !== 0) {
	    //console.log("-- Iteration");
	    //console.log(pattern.path.value[0]);
	    if(initial === true) {
		bindings = this.executeAndBGP(projection, dataset, pattern.path, env);
		//console.log("SAVING LAST");
		//console.log(pattern.x);
		last = pattern.x;
		initial = false;
	    } else {
		var nextOid = pending.pop();
		//console.log("POPPING:"+nextOid);
		var value = this.lexicon.retrieve(nextOid);
		var path = pattern.path; //Utils.clone(pattern.path);
		//console.log(path.value[0]);
		//console.log("REPLACING");
		//console.log(last);
		//console.log("BY");
		//console.log(value);
		path = this.abstractQueryTree.replace(path, last, value, env);
		//console.log(path.value[0]);
		bindings = this.executeAndBGP(projection, dataset, path, env);
		last = value;
	    }


	    //console.log("BINDINGS!");
	    //console.log(bindings);

	    for(var i=0; i<bindings.length; i++) {
		//console.log(bindings[i][pattern.y.value])
		var value = bindings[i][pattern.y.value];
		//console.log("VALUE:"+value);
		if(acum[value] !== true) {
		    nextBinding = {};
		    nextBinding[pattern.y.value] = value;
		    collected.push(nextBinding);
		    acum[value] = true;
		    pending.push(value);
		}
	    }
	}
	//console.log("RETURNING TERM - VAR");
	//console.log(collected);
	return collected;
    } else {
	throw "Kind of path not supported!";
    }
};

QueryEngine.QueryEngine.prototype.executeUNION = function(projection, dataset, patterns, env) {
    var setQuery1 = patterns[0];
    var setQuery2 = patterns[1];
    var set1 = null;
    var set2 = null;

    if(patterns.length != 2) {
        throw("SPARQL algebra UNION with more than two components");
    }

    var that = this;
    var sets = [];

    set1 = that.executeSelectUnit(projection, dataset, setQuery1, env);
    if(set1==null) {
        return null;
    }

    set2 = that.executeSelectUnit(projection, dataset, setQuery2, env);
    if(set2==null) {
        return null;
    }

    var result = QueryPlan.unionBindings(set1, set2);
    result = QueryFilters.checkFilters(patterns, result, false, dataset, env, that);
    return result;
};

QueryEngine.QueryEngine.prototype.executeAndBGP = function(projection, dataset, patterns, env) {
    var that = this;
    var result = QueryPlan.executeAndBGPsDPSize(patterns.value, dataset, this, env);
    if(result!=null) {
        return QueryFilters.checkFilters(patterns, result, false, dataset, env, that);
    } else {
        return null;
    }
};

QueryEngine.QueryEngine.prototype.executeLEFT_JOIN = function(projection, dataset, patterns, env) {
    var setQuery1 = patterns.lvalue;
    var setQuery2 = patterns.rvalue;

    var set1 = null;
    var set2 = null;

    var that = this;
    var sets = [];
    var acum, duplicates;

    //console.log("SET QUERY 1");
    //console.log(setQuery1.value);
    set1 = that.executeSelectUnit(projection, dataset, setQuery1, env);
    if(set1==null) {
        return null;
    }
     
    //console.log("SET QUERY 2");
    //console.log(setQuery2);
    set2 = that.executeSelectUnit(projection, dataset, setQuery2, env);
    if(set2==null) {
        return null;
    }


    //console.log("\nLEFT JOIN SETS:")
    //console.log(set1)
    //console.log(set2)
    var result = QueryPlan.leftOuterJoinBindings(set1, set2);
    //console.log("---")
    //console.log(result);

    var bindings = QueryFilters.checkFilters(patterns, result, true, dataset, env, that);
    //console.log("---")
    //console.log(bindings)
    //console.log("\r\n")
    
    if(set1.length>1 && set2.length>1) {
            var vars = [];
            var vars1 = {};
            for(var p in set1[0]) {
                vars1[p] = true;
            }
            for(p in set2[0]) {
                if(vars1[p] != true) {
                    vars.push(p);
                }
            }
            acum = [];
            duplicates = {};
            for(var i=0; i<bindings.length; i++) {
                if(bindings[i]["__nullify__"] === true) {
                    for(var j=0; j<vars.length; j++) {
                        bindings[i]["bindings"][vars[j]] = null;
                    }                            
                    var idx = [];
                    var idxColl = [];
                    for(var p in bindings[i]["bindings"]) {
                        if(bindings[i]["bindings"][p] != null) {
                            idx.push(p+bindings[i]["bindings"][p]);
                            idx.sort();
                            idxColl.push(idx.join(""));
                        }
                    }
                    // reject duplicates -> (set union)
                    if(duplicates[idx.join("")]==null) {
                        for(j=0; j<idxColl.length; j++) {
                            //console.log(" - "+idxColl[j])
                            duplicates[idxColl[j]] = true;
                        }
                        ////duplicates[idx.join("")]= true
                        acum.push(bindings[i]["bindings"]);
                    }
                } else {
                    acum.push(bindings[i]);
                    var idx = [];
                    var idxColl = [];
                    for(var p in bindings[i]) {
                        idx.push(p+bindings[i][p]);
                        idx.sort();
                        //console.log(idx.join("") + " -> ok");
                        duplicates[idx.join("")] = true;
                    }

                }
            }

        return acum;
    } else {
        return bindings;
    }
};

QueryEngine.QueryEngine.prototype.executeJOIN = function(projection, dataset, patterns, env) {
    var setQuery1 = patterns.lvalue;
    var setQuery2 = patterns.rvalue;
    var set1 = null;
    var set2 = null;

    var that = this;
    var sets = [];

    set1 = that.executeSelectUnit(projection, dataset, setQuery1, env);
    if(set1 == null) {
        return null;
    }

    set2 = that.executeSelectUnit(projection, dataset, setQuery2, env);
    if(set2 == null) {
        return null;
    }
    
    
    var result = null;
    if(set1.length ===0 || set2.length===0) {
	result = [];
    } else {
	var commonVarsTmp = {};
	var commonVars = [];

	for(var p in set1[0])
	    commonVarsTmp[p] = false;
	for(var p  in set2[0]) {
	    if(commonVarsTmp[p] === false)
		commonVars.push(p);
	}

	if(commonVars.length == 0) {
	    result = QueryPlan.joinBindings(set1,set2);	    
	} else if(this.abstractQueryTree.treeWithUnion(setQuery1) || 
		  this.abstractQueryTree.treeWithUnion(setQuery2)) {
	    result = QueryPlan.joinBindings(set1,set2);	    	    
	} else {
	    result = QueryPlan.joinBindings2(commonVars, set1, set2);
	}
    }
    result = QueryFilters.checkFilters(patterns, result, false, dataset, env, that);
    return result;
};


QueryEngine.QueryEngine.prototype.rangeQuery = function(quad, queryEnv) {
    var that = this;
    //console.log("BEFORE:");
    //console.log("QUAD:");
    //console.log(quad);
    var key = that.normalizeQuad(quad, queryEnv, false);
    if(key != null) {
        //console.log("RANGE QUERY:")
        //console.log(key);
        //console.log(new QuadIndexCommon.Pattern(key));
        var quads = that.backend.range(new QuadIndexCommon.Pattern(key));
        //console.log("retrieved");
        //console.log(quads)
        if(quads == null || quads.length == 0) {
            return [];
        } else {
            return quads;
        }
    } else {
        console.log("ERROR normalizing quad");
        return null;
    }
};

// Update queries

QueryEngine.QueryEngine.prototype.executeUpdate = function(syntaxTree, callback) {
    var prologue = syntaxTree.prologue;
    var units = syntaxTree.units;
    var that = this;

    // environment for the operation -> base ns, declared ns, etc.
    var queryEnv = {blanks:{}, outCache:{}};
    this.registerNsInEnvironment(prologue, queryEnv);
    for(var i=0; i<units.length; i++) {

        var aqt = that.abstractQueryTree.parseExecutableUnit(units[i]);
        if(aqt.kind === 'insertdata') {
            for(var j=0; j<aqt.quads.length; j++) {
                var quad = aqt.quads[j];
                var result = that._executeQuadInsert(quad, queryEnv);
                if(result !== true) {
                    return callback(false, error);
                }
            }
            callback(true);
        } else if(aqt.kind === 'deletedata') {
            for(var j=0; j<aqt.quads.length; j++) {
                var quad = aqt.quads[j];
                this._executeQuadDelete(quad, queryEnv);
            }
            callback(true);
        } else if(aqt.kind === 'modify') {
            this._executeModifyQuery(aqt, queryEnv, callback);
        } else if(aqt.kind === 'create') {
            callback(true);
        } else if(aqt.kind === 'load') {
            var graph = {'uri': Utils.lexicalFormBaseUri(aqt.sourceGraph, queryEnv)};
            if(aqt.destinyGraph != null) {
                graph = {'uri': Utils.lexicalFormBaseUri(aqt.destinyGraph, queryEnv)};
            }
            var that = this;
            this.rdfLoader.load(aqt.sourceGraph.value, graph,function(success, result){
                if(success == false) {
                    console.log("Error loading graph");
                    console.log(result);
                    callback(false, "error batch loading quads");
                } else {
                    var result = that.batchLoad(result);
                    callback(result!=null, result||"error batch loading quads");
                }
            });
        } else if(aqt.kind === 'drop') {
            this._executeClearGraph(aqt.destinyGraph, queryEnv, callback);
        } else if(aqt.kind === 'clear') {
            this._executeClearGraph(aqt.destinyGraph, queryEnv, callback);
        } else {
            throw new Error("not supported execution unit");
        }
    }
};

QueryEngine.QueryEngine.prototype.batchLoad = function(quads, callback) {
    var subject    = null;
    var predicate  = null;
    var object     = null;
    var graph      = null;
    var oldLimit = Utils.stackCounterLimit;
    var counter = 0;
    var success = true;
    var blanks = {};
    var maybeBlankOid, oid, quad, key, originalQuad;

    if(this.eventsOnBatchLoad)
        this.callbacksBackend.startGraphModification();

    for(var i=0; i<quads.length; i++) {
        quad = quads[i];
	
        // subject
        if(quad.subject['uri'] || quad.subject.token === 'uri') {
            oid = this.lexicon.registerUri(quad.subject.uri || quad.subject.value);
	    if(quad.subject.uri != null) {
		quad.subject = {'token': 'uri', 'value': quad.subject.uri};
		delete quad.subject['uri'];
	    }
            subject = oid;
        } else if(quad.subject['literal'] || quad.subject.token === 'literal') {
            oid = this.lexicon.registerLiteral(quad.subject.literal || quad.subject.value);
	    if(quad.subject.literal != null) {
		quad.subject = this.lexicon.parseLiteral(quad.subject.literal);
		delete quad.subject['literal'];
	    }
            subject = oid;                    
        } else {
            maybeBlankOid = blanks[quad.subject.blank || quad.subject.value];
            if(maybeBlankOid == null) {
                maybeBlankOid = this.lexicon.registerBlank(quad.subject.blank || quad.subject.value);
                blanks[(quad.subject.blank || quad.subject.value)] = maybeBlankOid;
            }
	    if(quad.subject.token == null) {
		quad.subject.token = 'blank';
		quad.subject.value = quad.subject.blank;
		delete quad.subject['blank'];
	    }
            subject = maybeBlankOid;
        }

        // predicate
        if(quad.predicate['uri'] || quad.predicate.token === 'uri') {
            oid = this.lexicon.registerUri(quad.predicate.uri || quad.predicate.value);
	    if(quad.predicate.uri != null) {
		quad.predicate = {'token': 'uri', 'value': quad.predicate.uri};
		delete quad.subject['uri'];
	    }
            predicate = oid;
        } else if(quad.predicate['literal'] || quad.predicate.token === 'literal') {
            oid = this.lexicon.registerLiteral(quad.predicate.literal || quad.predicate.value);
	    if(quad.predicate.literal != null) {
		quad.predicate = this.lexicon.parseLiteral(quad.predicate.literal);
		delete quad.predicate['literal'];
	    }
            predicate = oid;                    
        } else {
            maybeBlankOid = blanks[quad.predicate.blank || quad.predicate.value];
            if(maybeBlankOid == null) {
                maybeBlankOid = this.lexicon.registerBlank(quad.predicate.blank || quad.predicate.value);
                blanks[(quad.predicate.blank || quad.predicate.value)] = maybeBlankOid;
            }
	    if(quad.predicate.token == null) {
		quad.predicate.token = 'blank';
		quad.predicate.value = quad.predicate.blank;
		delete quad.predicate['blank'];
	    }
            predicate = maybeBlankOid;
        }

        // object
        if(quad.object['uri'] || quad.object.token === 'uri') {
            oid = this.lexicon.registerUri(quad.object.uri || quad.object.value);
	    if(quad.object.uri != null) {
		quad.object = {'token': 'uri', 'value': quad.object.uri};
		delete quad.subject['uri'];
	    }
            object = oid;
        } else if(quad.object['literal'] || quad.object.token === 'literal') {
	    if(quad.object.token === 'literal') {
		if(quad.object.type != null) {
		    quad.object.value = '"'+quad.object.value+'"^^<'+quad.object.type+'>';
		} else if(quad.object.lang != null) {
		    quad.object.value = '"'+quad.object.value+'"@'+quad.object.lang;		    
		} else {
		    quad.object.value = '"'+quad.object.value+'"';
		}
	    }
            oid = this.lexicon.registerLiteral(quad.object.literal || quad.object.value);
	    if(quad.object.literal != null) {
		quad.object = this.lexicon.parseLiteral(quad.object.literal);
		delete quad.object['literal'];
	    }
            object = oid;                    
        } else {
            maybeBlankOid = blanks[quad.object.blank || quad.object.value];
            if(maybeBlankOid == null) {
                maybeBlankOid = this.lexicon.registerBlank(quad.object.blank || quad.object.value);
                blanks[(quad.object.blank || quad.object.value)] = maybeBlankOid;
            }
	    if(quad.object.token == null) {
		quad.object.token = 'blank';
		quad.object.value = quad.object.blank;
		delete quad.object['blank'];
	    }

            object = maybeBlankOid;
        }

        // graph
        if(quad.graph['uri'] || quad.graph.token === 'uri') {
            oid = this.lexicon.registerUri(quad.graph.uri || quad.graph.value);
	    if(quad.graph.uri != null) {
		quad.graph = {'token': 'uri', 'value': quad.graph.uri};
		delete quad.subject['uri'];
	    }
            this.lexicon.registerGraph(oid);
            graph = oid;

        } else if(quad.graph['literal'] || quad.graph.token === 'literal') {
            oid = this.lexicon.registerLiteral(quad.graph.literal || quad.graph.value);
	    if(quad.predicate.literal != null) {
		quad.predicate = this.lexicon.parseLiteral(quad.predicate.literal);
		delete quad.predicate['literal'];
	    }
            graph = oid;                    
        } else {
            maybeBlankOid = blanks[quad.graph.blank || quad.graph.value];
            if(maybeBlankOid == null) {
                maybeBlankOid = this.lexicon.registerBlank(quad.graph.blank || quad.graph.value);
                blanks[(quad.graph.blank || quad.graph.value)] = maybeBlankOid;
            }
	    if(quad.graph.token == null) {
		quad.graph.token = 'blank';
		quad.graph.value = quad.graph.blank;
		delete quad.graph['blank'];
	    }
            graph = maybeBlankOid;
        }



        originalQuad = quad;
        quad = {subject: subject, predicate:predicate, object:object, graph: graph};
        key = new QuadIndexCommon.NodeKey(quad);

        var result = this.backend.search(key);
        if(!result) {
            result = this.backend.index(key);
            if(result == true){
                if(this.eventsOnBatchLoad)
                    this.callbacksBackend.nextGraphModification(Callbacks.added, [originalQuad,quad]);
                counter = counter + 1;
            } else {
                success = false;
                break;
            }
        }

    }

    if(this.lexicon.updateAfterWrite != null)
	this.lexicon.updateAfterWrite();

    var exitFn = function(){
        if(success) {
            if(callback)
                callback(true, counter);
        } else {
            if(callback)
                callback(false, null);
        }
    };

    if(this.eventsOnBatchLoad) {
        this.callbacksBackend.endGraphModification(function(){
            exitFn();
        });
    } else {
        exitFn();
    }
        
    if(success) {
        return counter;
    } else {
        return null;
    }
};

// @modified dp
QueryEngine.QueryEngine.prototype.computeCosts = function (quads, env) {
    for (var i = 0; i < quads.length; i++) {
        quads[i]['_cost'] = this.quadCost(quads[i], env);
    }

    return quads;
};

// Low level operations for update queries

QueryEngine.QueryEngine.prototype._executeModifyQuery = function(aqt, queryEnv, callback) {
    var that = this;
    var querySuccess = true;
    var error = null;
    var bindings = null;
    var components = ['subject', 'predicate', 'object', 'graph'];

    aqt.insert = aqt.insert == null ? [] : aqt.insert;
    aqt['delete'] = aqt['delete'] == null ? [] : aqt['delete'];

    Utils.seq(
        function(k) {
            // select query

            var defaultGraph = [];
            var namedGraph = [];

            if(aqt['with'] != null) {
                defaultGraph.push(aqt['with']);
            }

            if(aqt['using'] != null) {
                namedGraph = [];
                for(var i=0; i<aqt['using'].length; i++) {
                    var usingGraph = aqt['using'][i];
                    if(usingGraph.kind === 'named') {
                        namedGraph.push(usingGraph.uri);
                    } else {
                        defaultGraph.push(usingGraph.uri);
                    }
                }
            }

            aqt.dataset = {};
            aqt.projection = [{"token": "variable", "kind": "*"}];

            that.executeSelect(aqt, queryEnv, defaultGraph, namedGraph, function(success, result) {                
                if(success) {                    
                    var result = that.denormalizeBindingsList(result, queryEnv);
                    if(result!=null) {
                        bindings = result;
                    } else {
                        querySuccess = false;
                    }
                    return k();
                } else {
                    querySuccess = false;
                    return k();
                }
            });
        },function(k) {
            // delete query

            var defaultGraph = aqt['with'];
            if(querySuccess) {
                var quads = [];
                for(var i=0; i<aqt['delete'].length; i++) {
                    var src = aqt['delete'][i];

                    for(var j=0; j<bindings.length; j++) {
                        var quad = {};
                        var binding = bindings[j];

                        for(var c=0; c<components.length; c++) {
                            var component = components[c];
                            if(component == 'graph' && src[component] == null) {
                                quad['graph'] = defaultGraph;
                            } else if(src[component].token === 'var') {
                                quad[component] = binding[src[component].value];
                            } else {
                                quad[component] = src[component];
                            }
                        }

                        quads.push(quad);
                    }
                }

                var quad;
                for(var j=0; j<quads.length; j++) {
                    quad = quads[j];
                    that._executeQuadDelete(quad, queryEnv);
                }
                k();
            } else {
                k();
            }
        },function(k) {
            // insert query
            var defaultGraph = aqt['with'];

            if(querySuccess) {
                var quads = [];
                for(var i=0; i<aqt.insert.length; i++) {
                    var src = aqt.insert[i];

                    for(var j=0; j<bindings.length; j++) {
                        var quad = {};
                        var binding = bindings[j];

                        for(var c=0; c<components.length; c++) {
                            var component = components[c];
                            if(component == 'graph' && src[component] == null) {
                                quad['graph'] = defaultGraph;
                            } else if(src[component].token === 'var') {
                                quad[component] = binding[src[component].value];
                            } else {
                                quad[component] = src[component];
                            }
                        }

                        quads.push(quad);
                    }
                }

                for(var i=0; i<quads.length; i++) {
                    var quad = quads[i];
                    that._executeQuadInsert(quad, queryEnv);
                }

                k();
            } else {
                k();
            }
        }
    )(function(){
        callback(querySuccess);
    });
};

QueryEngine.QueryEngine.prototype._executeQuadInsert = function(quad, queryEnv) {
    var that = this;
    var normalized = this.normalizeQuad(quad, queryEnv, true);
    if(normalized != null) {
        var key = new QuadIndexCommon.NodeKey(normalized);
        var result = that.backend.search(key);
        if(result){
            return(result);
        } else {
            var result = that.backend.index(key);
            if(result == true){
                that.callbacksBackend.nextGraphModification(Callbacks.added, [quad, normalized]);
                return true;
            } else {
                console.log("ERROR inserting quad");
                return false;
            }
        }
    } else {
        console.log("ERROR normalizing quad");
        return false;
    }
};

QueryEngine.QueryEngine.prototype._executeQuadDelete = function(quad, queryEnv) {
    var that = this;
    var normalized = this.normalizeQuad(quad, queryEnv, false);
    if(normalized != null) {
        var key = new QuadIndexCommon.NodeKey(normalized);
        that.backend['delete'](key);
        var result = that.lexicon.unregister(quad, key);
        if(result == true){
            that.callbacksBackend.nextGraphModification(Callbacks['deleted'], [quad, normalized]);
            return true;
        } else {
            console.log("ERROR unregistering quad");
            return false;
        }
    } else {
        console.log("ERROR normalizing quad");
        return false;
    }
};

QueryEngine.QueryEngine.prototype._executeClearGraph = function(destinyGraph, queryEnv, callback) {
    if(destinyGraph === 'default') {
        this.execute("DELETE { ?s ?p ?o } WHERE { ?s ?p ?o }", callback);
    } else if(destinyGraph === 'named') {
        var that = this;
        var graphs = this.lexicon.registeredGraphs(true);
        if(graphs!=null) {
            var foundErrorDeleting = false;
            Utils.repeat(0, graphs.length,function(k,env) {
                var graph = graphs[env._i];
                var floop = arguments.callee;
                if(!foundErrorDeleting) {
                    that.execute("DELETE { GRAPH <"+graph+"> { ?s ?p ?o } } WHERE { GRAPH <"+graph+"> { ?s ?p ?o } }", function(success, results){
                        foundErrorDeleting = !success;
                        k(floop, env);
                    });
                } else {
                    k(floop, env);
                }
            }, function(env) {
                callback(!foundErrorDeleting);
            });
        } else {
            callback(false, "Error deleting named graphs");
        }
    } else if(destinyGraph === 'all') {
        var that = this;
        this.execute("CLEAR DEFAULT", function(success, result) {
            if(success) {
                that.execute("CLEAR NAMED", callback);
            } else {
                callback(false,result);
            }
        });
    } else {
        // destinyGraph is an URI
        if(destinyGraph.token == 'uri') {
            var graphUri = Utils.lexicalFormBaseUri(destinyGraph,queryEnv);
            if(graphUri != null) {
                this.execute("DELETE { GRAPH <"+graphUri+"> { ?s ?p ?o } } WHERE { GRAPH <"+graphUri+"> { ?s ?p ?o } }", callback);
            } else {
                callback(false, "wrong graph URI");
            }
        } else {
            callback(false, "wrong graph URI");
        }
    }
};

QueryEngine.QueryEngine.prototype.checkGroupSemantics = function(groupVars, projectionVars) {
    if(groupVars === 'singleGroup') {
        return true;        
    }

    var projection = {};

    for(var i=0; i<groupVars.length; i++) {
        var groupVar = groupVars[i];
        if(groupVar.token === 'var') {
            projection[groupVar.value] = true;
        } else if(groupVar.token === 'aliased_expression') {
            projection[groupVar.alias.value] = true;
        }
    }

    for(i=0; i<projectionVars.length; i++) {
        var projectionVar = projectionVars[i];
        if(projectionVar.kind === 'var') {
            if(projection[projectionVar.value.value] == null) {
                return false;
            }
        } else if(projectionVar.kind === 'aliased' && 
                  projectionVar.expression &&
                  projectionVar.expression.primaryexpression === 'var') {
            if(projection[projectionVar.expression.value.value] == null) {
                return false;
            }
        }
    }

    return true;
};

QueryEngine.QueryEngine.prototype.registerDefaultNamespace = function(ns, prefix) {
    this.defaultPrefixes[ns] = prefix;
};

// end of ./src/js-query-engine/src/query_engine.js 
// exports
var Callbacks = {};

//imports


Callbacks.ANYTHING = {'token': 'var', 
                      'value': '_'};

Callbacks.added = 'added';
Callbacks.deleted = 'deleted';
Callbacks.eventsFlushed = 'eventsFlushed';

Callbacks.CallbacksBackend = function() {
    this.aqt = new AbstractQueryTree.AbstractQueryTree();
    this.engine = arguments[0];
    this.indexMap = {};
    this.observersMap = {};
    this.queriesIndexMap = {};
    this.emptyNotificationsMap = {};
    this.queriesList = [];
    this.pendingQueries = [];
    this.matchedQueries = [];
    this.updateInProgress = null;
    this.indices = ['SPOG', 'GP', 'OGS', 'POG', 'GSP', 'OS'];
    this.componentOrders = {
        SPOG: ['subject', 'predicate', 'object', 'graph'],
        GP: ['graph', 'predicate', 'subject', 'object'],
        OGS: ['object', 'graph', 'subject', 'predicate'],
        POG: ['predicate', 'object', 'graph', 'subject'],
        GSP: ['graph', 'subject', 'predicate', 'object'],
        OS: ['object', 'subject', 'predicate', 'graph']
    };

    this.callbackCounter = 0;
    this.callbacksMap = {};
    this.callbacksInverseMap = {};

    this.queryCounter = 0;
    this.queriesMap = {};
    this.queriesCallbacksMap = {};
    this.queriesInverseMap = {};

    for(var i=0; i<this.indices.length; i++) {
        var indexKey = this.indices[i];
        this.indexMap[indexKey] = {};
        this.queriesIndexMap[indexKey] = {};
    };
};

Callbacks.CallbacksBackend.prototype.startGraphModification = function() {
    this.pendingQueries = [].concat(this.queriesList);
    this.matchedQueries = [];

    var added = Callbacks['added'];
    var deleted = Callbacks['deleted'];
    if(this.updateInProgress == null) {
        this.updateInProgress = {added: [], deleted: []};
    }
};

Callbacks.CallbacksBackend.prototype.nextGraphModification = function(event, quad) {
    this.updateInProgress[event].push(quad);
};

Callbacks.CallbacksBackend.prototype.endGraphModification = function(callback) {
    var that = this;
    if(this.updateInProgress != null) {
        var tmp = that.updateInProgress;
        that.updateInProgress = null;
        this.sendNotification(Callbacks['deleted'], tmp[Callbacks['deleted']],function(){
            that.sendNotification(Callbacks['added'], tmp[Callbacks['added']], function(){
                that.sendEmptyNotification(Callbacks['eventsFlushed'], null, function(){
                    that.dispatchQueries(function(){
                        callback(true);
                    });
                });
            });
        });
    } else {
        callback(true);
    }
};

Callbacks.CallbacksBackend.prototype.cancelGraphModification = function() {
    this.updateInProgress = null;
};

Callbacks.CallbacksBackend.prototype.sendNotification = function(event, quadsPairs, doneCallback) {
    var notificationsMap = {};
    for(var i=0; i<quadsPairs.length; i++) {
        var quadPair = quadsPairs[i];
        for(var indexKey in this.indexMap) {
            var index = this.indexMap[indexKey];
            var order = this.componentOrders[indexKey];
            this._searchCallbacksInIndex(index, order, event, quadPair, notificationsMap);
            if(this.pendingQueries.length != 0) {
                index = this.queriesIndexMap[indexKey];
                this._searchQueriesInIndex(index, order, quadPair);
            }
        }
    }

    this.dispatchNotifications(notificationsMap);

    if(doneCallback != null)
        doneCallback(true);
};

Callbacks.CallbacksBackend.prototype.sendEmptyNotification = function(event, value, doneCallback) {
    var callbacks = this.emptyNotificationsMap[event] || [];
    for(var i=0; i<callbacks.length; i++) {
        callbacks[i](event, value);
    }
    doneCallback();
};

Callbacks.CallbacksBackend.prototype.dispatchNotifications = function(notificationsMap) {
    for(var callbackId in notificationsMap) {
        var callback = this.callbacksMap[callbackId];
        var deleted = notificationsMap[callbackId][Callbacks['deleted']];
        if(deleted!=null) {
            try {
                callback(Callbacks['deleted'],deleted);
            }catch(e){}
        }
        for(var event in notificationsMap[callbackId]) {
            if(event!=Callbacks['deleted']) {
                try{
                    callback(event, notificationsMap[callbackId][event]);
                }catch(e){}

            }
        }
    }
};

Callbacks.CallbacksBackend.prototype._searchCallbacksInIndex = function(index, order, event, quadPair, notificationsMap) {
    var quadPairNomalized = quadPair[1];
    var quadPair = quadPair[0];

    for(var i=0; i<(order.length+1); i++) {
        var matched = index['_'] || [];
        
        var filteredIds = [];
        for(var j=0; j<matched.length; j++) {
            var callbackId = matched[j];
            if(this.callbacksMap[callbackId] != null) {
                notificationsMap[callbackId] = notificationsMap[callbackId] || {};
                notificationsMap[callbackId][event] = notificationsMap[callbackId][event] || [];
                notificationsMap[callbackId][event].push(quadPair);
                filteredIds.push(callbackId);
            }
        }
        index['_'] = filteredIds;
        var component = order[i];
        if(index[''+quadPairNomalized[component]] != null) {
            index = index[''+quadPairNomalized[component]];
        } else {
            break;
        }
    }
};

Callbacks.CallbacksBackend.prototype.subscribeEmpty = function(event, callback) {
    var callbacks = this.emptyNotificationsMap[event] || [];
    callbacks.push(callback);
    this.emptyNotificationsMap[event] = callbacks;
};

Callbacks.CallbacksBackend.prototype.unsubscribeEmpty = function(event, callback) {
    var callbacks = this.emptyNotificationsMap[event];
    if(callbacks != null) {
        callbacks = Utils.remove(callbacks, callback);
    }
    this.emptyNotificationsMap[event] = callbacks;
};

Callbacks.CallbacksBackend.prototype.subscribe = function(s,p,o,g,callback, doneCallback) {
    var quad = this._tokenizeComponents(s,p,o,g);
    var queryEnv = {blanks:{}, outCache:{}};
    this.engine.registerNsInEnvironment(null, queryEnv);
    var that = this;
    var normalized = this.engine.normalizeQuad(quad, queryEnv, true);
    var pattern =  new QuadIndexCommon.Pattern(normalized);        
    var indexKey = that._indexForPattern(pattern);
    var indexOrder = that.componentOrders[indexKey];
    var index = that.indexMap[indexKey];
    for(var i=0; i<indexOrder.length; i++) {
        var component = indexOrder[i];
        var quadValue = normalized[component];
        if(quadValue === '_') {
            if(index['_'] == null) {
                index['_'] = [];
            }
            that.callbackCounter++;
            index['_'].push(that.callbackCounter);
            that.callbacksMap[that.callbackCounter] = callback;
            that.callbacksInverseMap[callback] = that.callbackCounter;
            break;
        } else {
            if(i===indexOrder.length-1) {
                index[quadValue] = index[quadValue] || {'_':[]};
                that.callbackCounter++;
                index[quadValue]['_'].push(that.callbackCounter);
                that.callbacksMap[that.callbackCounter] = callback;
                that.callbacksInverseMap[callback] = that.callbackCounter;
            } else {
                index[quadValue] = index[quadValue] || {};
                index = index[quadValue];
            }
        }
    }
    if(doneCallback != null)
        doneCallback(true);
};

Callbacks.CallbacksBackend.prototype.unsubscribe = function(callback) {
    var id = this.callbacksInverseMap[callback];
    if(id != null) {
        delete this.callbacksInverseMap[callback];
        delete this.callbacksMap[id];
    }
};

Callbacks.CallbacksBackend.prototype._tokenizeComponents = function(s, p, o, g) {
    var pattern = {};

    if(s == null) {
        pattern['subject'] = Callbacks.ANYTHING;
    } else {
        if(s.indexOf("_:") == 0) {
            pattern['subject'] = {'token': 'blank', 'value':s};
        } else {
            pattern['subject'] = {'token': 'uri', 'value':s};
        }
    }

    if(p == null) {
        pattern['predicate'] = Callbacks.ANYTHING;
    } else {
        pattern['predicate'] = {'token': 'uri', 'value':p};
    }

    if(o == null) {
        pattern['object'] = Callbacks.ANYTHING;
    } else {
        pattern['object'] = {'token': 'uri', 'value':o};
    }

    if(g == null) {
        pattern['graph'] = Callbacks.ANYTHING;
    } else {
        pattern['graph'] = {'token': 'uri', 'value':g};
    }

    return pattern;
};

Callbacks.CallbacksBackend.prototype._indexForPattern = function(pattern) {
    var indexKey = pattern.indexKey;
    var matchingIndices = this.indices;

    for(var i=0; i<matchingIndices.length; i++) {
        var index = matchingIndices[i];
        var indexComponents = this.componentOrders[index];
        for(var j=0; j<indexComponents.length; j++) {
            if(Utils.include(indexKey, indexComponents[j])===false) {
                break;
            }
            if(j==indexKey.length-1) {
                return index;
            }
        }
    }
    
    return 'SPOG'; // If no other match, we return the most generic index
};

Callbacks.CallbacksBackend.prototype.observeNode = function() {
    var uri,graphUri,callback,doneCallback;

    if(arguments.length === 4) {
        uri = arguments[0];
        graphUri = arguments[1];
        callback = arguments[2];
        doneCallback = arguments[3];
    } else {
        uri = arguments[0];
        graphUri = this.engine.lexicon.defaultGraphUri;
        callback = arguments[1];
        doneCallback = arguments[2];
    }
    var query = "CONSTRUCT { <" + uri + "> ?p ?o } WHERE { GRAPH <" + graphUri + "> { <" + uri + "> ?p ?o } }";
    var that = this;
    var queryEnv = {blanks:{}, outCache:{}};
    this.engine.registerNsInEnvironment(null, queryEnv);
    var bindings = [];
    this.engine.execute(query,  function(success, graph){
        if(success) {
            var node = graph;
            var mustFlush = false;
            var observer = function(event, triples){
                if(event === 'eventsFlushed' && mustFlush ) {
                    mustFlush = false;
                    try {
                        callback(node);
                    }catch(e){}
                } else if(event !== 'eventsFlushed') {
                    mustFlush = true;
                    for(var i = 0; i<triples.length; i++) {
                        var triple = triples[i];
                        var s = RDFJSInterface.buildRDFResource(triple.subject,bindings,that.engine,queryEnv);
                        var p = RDFJSInterface.buildRDFResource(triple.predicate,bindings,that.engine,queryEnv);
                        var o = RDFJSInterface.buildRDFResource(triple.object,bindings,that.engine,queryEnv);
                        if(s!=null && p!=null && o!=null) {
                            triple = new RDFJSInterface.Triple(s,p,o);
                            if(event === Callbacks['added']) {
                                node.add(triple);
                            } else if(event === Callbacks['deleted']) {
                                node.remove(triple);
                            }
                        }
                    }
                }
            };
            that.observersMap[callback] = observer;
            that.subscribeEmpty(Callbacks['eventsFlushed'], observer);
            that.subscribe(uri,null,null,null,observer,function(){
                try {
                    callback(node);
                }catch(e){}

                if(doneCallback)
                    doneCallback(true)
            });
        } else {
            if(doneCallback)
                doneCallback(false);
        }
    });
};

Callbacks.CallbacksBackend.prototype.stopObservingNode = function(callback) {
    var observer = this.observersMap[callback];
    if(observer) {
        this.unsubscribe(observer);
        this.unsubscribeEmpty(Callbacks['eventsFlushed'],observer);
        return true;
    } else {
        return false;
    }
};

// Queries

Callbacks.CallbacksBackend.prototype.observeQuery = function(query, callback, endCallback) {
    var queryParsed = this.aqt.parseQueryString(query);
    var parsedTree = this.aqt.parseSelect(queryParsed.units[0]);
    var patterns = this.aqt.collectBasicTriples(parsedTree);
    var that = this;
    var queryEnv = {blanks:{}, outCache:{}};
    this.engine.registerNsInEnvironment(null, queryEnv);
    var floop, pattern, quad, indexKey, indexOrder, index;

    var counter = this.queryCounter;
    this.queryCounter++;
    this.queriesMap[counter] = query;
    this.queriesInverseMap[query] = counter;
    this.queriesList.push(counter);
    this.queriesCallbacksMap[counter] = callback;

    for(var i=0; i<patterns.length; i++) {
        quad = patterns[i];
        if(quad.graph == null) {
            quad.graph = that.engine.lexicon.defaultGraphUriTerm;
        }

        var normalized = that.engine.normalizeQuad(quad, queryEnv, true);
        pattern =  new QuadIndexCommon.Pattern(normalized);        
        indexKey = that._indexForPattern(pattern);
        indexOrder = that.componentOrders[indexKey];
        index = that.queriesIndexMap[indexKey];

        for(var j=0; j<indexOrder.length; j++) {
            var component = indexOrder[j];
            var quadValue = normalized[component];
            if(typeof(quadValue) === 'string') {
                if(index['_'] == null) {
                    index['_'] = [];
                }
                index['_'].push(counter);
                break;
            } else {
                if(j===indexOrder.length-1) {
                    index[quadValue] = index[quadValue] || {'_':[]};
                    index[quadValue]['_'].push(counter);
                } else {
                    index[quadValue] = index[quadValue] || {};
                    index = index[quadValue];
                }
            }
        }

    }

    this.engine.execute(query, function(success, results){
        if(success){
            callback(results);
        } else {
            console.log("ERROR in query callback "+results);
        }                                             
    });

    if(endCallback != null)
        endCallback();
};

Callbacks.CallbacksBackend.prototype.stopObservingQuery = function(query) {
    var id = this.queriesInverseMap[query];
    if(id != null) {
        delete this.queriesInverseMap[query];
        delete this.queriesMap[id];
        this.queriesList = Utils.remove(this.queriesList, id);
    }
};

Callbacks.CallbacksBackend.prototype._searchQueriesInIndex = function(index, order, quadPair) {
    var quadPairNomalized = quadPair[1];
    var quadPair = quadPair[0];

    for(var i=0; i<(order.length+1); i++) {
        var matched = index['_'] || [];
        
        var filteredIds = [];
        for(var j=0; j<matched.length; j++) {
            var queryId = matched[j];
            if(Utils.include(this.pendingQueries,queryId)) {
                Utils.remove(this.pendingQueries,queryId);
                this.matchedQueries.push(queryId);
            }
            // removing IDs for queries no longer being observed
            if(this.queriesMap[queryId] != null) {
                filteredIds.push(queryId);
            }
        }
        index['_'] = filteredIds;

        var component = order[i];
        if(index[''+quadPairNomalized[component]] != null) {
            index = index[''+quadPairNomalized[component]];
        } else {
            break;
        }
    }
};

Callbacks.CallbacksBackend.prototype.dispatchQueries = function(callback) {
    var that = this;
    var floop, query, queryId, queryCallback;
    var toDispatchMap = {};

    Utils.repeat(0, this.matchedQueries.length,
        function(k, env){
            floop = arguments.callee;
            queryId = that.matchedQueries[env._i];
            // avoid duplicate notifications
            if(toDispatchMap[queryId] == null) {
                toDispatchMap[queryId] = true;
                query = that.queriesMap[queryId];
                queryCallback = that.queriesCallbacksMap[queryId];
                Utils.recur(function(){
                    that.engine.execute(query,
                        function(success, results){
                            if(success) {
                                try{
                                    queryCallback(results);
                                }catch(e){}
                            }
                            k(floop,env);
                        });
                });
            } else {
                k(floop,env);
            }
        },
        function(env) {
            callback();
        });
};

// end of ./src/js-query-engine/src/callbacks.js 
//imports

// exports
var RDFStoreClient = {};


try {
    if(typeof(Worker)=='undefined') {
        Worker = null;
    };
} catch(e) {
    Worker = null;
}

// Checks if this is a webworker
if(!!Worker) {

    RDFStoreClient.RDFStoreClient = function(path_to_store_script, args, cb) {
        console.log("trying to load "+path_to_store_script);
        if(Worker.Worker) {
            this.connection = new Worker.Worker(path_to_store_script);
        } else {
            this.connection = new Worker(path_to_store_script);
        }
        this.callbacksCounter = 1;
        var that = this;
        var creationCallback = function(success, result) {
            if(success === true) {
                cb(true, that);
            } else {
                cb(false, result);
            }
        };

        this.rdf = RDFJSInterface.rdf;

        console.log("The worker");
        console.log(this.connection);
        var that = this;
        this.connection.onmessage = function(event){
            that.receive(event);
        };
        this.observingCallbacks = {};
        this.callbacks = {'0': {'cb':creationCallback, 'fn':'create'}};
        this.connection.postMessage({'fn':'create', 'args':args, 'callback':'0'});
    };

    RDFStoreClient.RDFStoreClient.prototype.receive = function(packet) {
        var event = packet.data || packet;
        //console.log("RECEIVED SOMETHING");
        if(event.fn === 'workerRequest:NetworkTransport:load') {
            var that = this;
            var workerCallback = event['callback'];
            var args = event['arguments'].concat(function(success, results){
                that.connection.postMessage({'fn':'workerRequestResponse', 'results':[success, results], 'callback':workerCallback});
            });
            NetworkTransport.load.apply(NetworkTransport,args);
        } else {
            var callbackData = this.callbacks[event.callback];
            //console.log(packet);
            //console.log(callbackData);
            if(callbackData) {
                if(callbackData.fn === 'create' || callbackData.fn === 'execute' || callbackData.fn === 'insert' || callbackData.fn == 'graph' ||
                   callbackData.fn === 'node' || callbackData.fn === 'insert' || callbackData.fn === 'delete' || callbackData.fn === 'clear' ||
                   callbackData.fn === 'load' || callbackData.fn === 'startObservingQueryEndCb' || callbackData.fn === 'registeredGraphs') {
                    delete this.callbacks[event.callback];
                    callbackData.cb(event.success, event.result);
                } else if(callbackData.fn === 'startObservingQuery') {
                    callbackData.cb(event.result);                
                } else if(callbackData.fn === 'startObservingNode') {
                    callbackData.cb(event.result);
                } else if(callbackData.fn === 'subscribe') {
                    callbackData.cb(event.event, event.result);
                }
            }
        }
    };

    RDFStoreClient.RDFStoreClient.prototype.registerCallback = function(fn, callback) {
        var id = ''+this.callbacksCounter;
        this.callbacks[id] = {'fn':fn, 'cb':callback};
        this.callbacksCounter++;

        return id;
    };

    RDFStoreClient.RDFStoreClient.prototype.execute = function() {
        if(arguments.length === 3) {
            this.executeWithEnvironment(arguments[0],
                                        arguments[1],
                                        arguments[2]);
        } else if(arguments.length === 4) {
            this.executeWithEnvironment(arguments[0],
                                        arguments[1],
                                        arguments[2],
                                        arguments[3]);
        } else {

            var queryString,callback;

            if(arguments.length === 1) {
                queryString = arguments[0];
                callback = function(){};

            } else if(arguments.length === 2) {
                queryString = arguments[0];
                callback = arguments [1];
            }

            var id = this.registerCallback('execute',callback);

            this.connection.postMessage({'fn':'execute', 'args':[queryString], 'callback':id});
        }

    };

    RDFStoreClient.RDFStoreClient.prototype.insert = function() {
        var graph;
        var triples;
        var callback;
        if(arguments.length === 1) {
            triples = arguments[0];
            this.connection.postMessage({'fn':'insert', 'args':[triples]})
        } else if(arguments.length === 2) {
            triples = arguments[0];
            callback= arguments[1] || function(){};
            var id = this.registerCallback('insert', callback);
            this.connection.postMessage({'fn':'insert', 'args':[triples], 'callback':id})
        } else if(arguments.length === 3) {
            triples = arguments[0];
            graph = arguments[1];
            callback= arguments[2] || function(){};
            var id = this.registerCallback('insert', callback);
            this.connection.postMessage({'fn':'insert', 'args':[triples,graph], 'callback':id})
        } else {
            throw("The triples to insert, an optional graph and callback must be provided");
        }
    };

    RDFStoreClient.RDFStoreClient.prototype.graph = function() {
        var graphUri = null;
        var callback = null;
        if(arguments.length === 1) {
            callback = arguments[0] || function(){};
        } else if(arguments.length === 2) {
            callback = arguments[1] || function(){};
            graphUri = arguments[0];
        } else {
            throw("An optional graph URI and a callback function must be provided");
        }

        var that = this;
        var wrapperCallback = function(success, toWrap) {
            //console.log("CALLBACK!\n\n");
            if(success) {
                var triple;
                for(var i=0; i<toWrap.triples.length; i++) {
                    triple = toWrap.triples[i];
                    toWrap.triples[i] = new RDFJSInterface.Triple(that.adaptJSInterface(triple.subject),
                                                                  that.adaptJSInterface(triple.predicate),
                                                                  that.adaptJSInterface(triple.object));
                }                
                callback(success, that.rdf.createGraph(toWrap.triples));
            } else {
                callback(success,toWrap);
            }
        };
        var id = this.registerCallback('insert', wrapperCallback);
        if(graphUri == null) {
            this.connection.postMessage({'fn':'graph', 'args':[], 'callback':id})
        } else {
            this.connection.postMessage({'fn':'graph', 'args':[graphUri], 'callback':id})
        }
    };

    RDFStoreClient.RDFStoreClient.prototype.node = function() {
        var graphUri = null;
        var callback = null;
        var nodeUri  = null;
        if(arguments.length === 2) {
            nodeUri = arguments[0];
            callback = arguments[1] || function(){};
        } else if(arguments.length === 3) {
            nodeUri = arguments[0];
            graphUri = arguments[1];
            callback = arguments[2] || function(){};
        } else {
            throw("An optional graph URI and a callback function must be provided");
        }

        var that = this;
        var wrapperCallback = function(success, toWrap) {
            //console.log("CALLBACK!\n\n");
            if(success) {
                var triple;
                for(var i=0; i<toWrap.triples.length; i++) {
                    triple = toWrap.triples[i];
                    toWrap.triples[i] = new RDFJSInterface.Triple(that.adaptJSInterface(triple.subject),
                                                                  that.adaptJSInterface(triple.predicate),
                                                                  that.adaptJSInterface(triple.object));
                }                
                callback(success, that.rdf.createGraph(toWrap.triples));
            } else {
                callback(success,toWrap);
            }
        };
        var id = this.registerCallback('insert', wrapperCallback);
        if(graphUri == null) {
            this.connection.postMessage({'fn':'node', 'args':[nodeUri], 'callback':id})
        } else {
            this.connection.postMessage({'fn':'node', 'args':[nodeUri, graphUri], 'callback':id})
        }

    };

    RDFStoreClient.RDFStoreClient.prototype.setPrefix = function(prefix, uri) {
        this.rdf.setPrefix(prefix, uri);
        this.connection.postMessage({'fn':'rdf/setPrefix', 'args':[prefix, uri], 'callback':null})
    };

    RDFStoreClient.RDFStoreClient.prototype.setDefaultPrefix = function(uri) {
        this.rdf.setDefaultPrefix(uri);
        this.connection.postMessage({'fn':'rdf/setDefaultPrefix', 'args':[uri], 'callback':null})
    };


    RDFStoreClient.RDFStoreClient.prototype['delete'] = function() {
        var graph;
        var triples;
        var callback;
        if(arguments.length === 1) {
            triples = arguments[0];
            this.connection.postMessage({'fn':'delete', 'args':[triples]})
        } else if(arguments.length === 2) {
            triples = arguments[0];
            callback= arguments[1] || function(){};
            var id = this.registerCallback('delete', callback);
            this.connection.postMessage({'fn':'delete', 'args':[triples], 'callback':id})
        } else if(arguments.length === 3) {
            triples = arguments[0];
            graph = arguments[1];
            callback= arguments[2] || function(){};
            var id = this.registerCallback('delete', callback);
            this.connection.postMessage({'fn':'delete', 'args':[triples,graph], 'callback':id})
        } else {
            throw("The triples to delete, an optional graph and callback must be provided");
        }
    };


    RDFStoreClient.RDFStoreClient.prototype.clear = function() {
        var graph;
        var callback;
     
        if(arguments.length === 1) {
            callback= arguments[0] || function(){};
            var id = this.registerCallback('clear', callback);
            this.connection.postMessage({'fn':'clear', 'args':[], 'callback':id})
        } else if(arguments.length === 2) {
            graph = arguments[0];
            callback= arguments[1] || function(){};
            var id = this.registerCallback('clear', callback);
            this.connection.postMessage({'fn':'clear', 'args':[graph], 'callback':id})
        } else {
            throw("The optional graph and a callback must be provided");
        }
    };


    /**
     * Boolean value determining if loading RDF must produce
     * triple add events and fire callbacks.
     * Default is false.
     */
    RDFStoreClient.RDFStoreClient.prototype.setBatchLoadEvents = function(mustFireEvents){
        this.connection.postMessage({'fn':'setBatchLoadEvents', 'args':[mustFireEvents]});
    };

    /**
     * Registers a namespace prefix that will be automatically declared
     * in all the queries
     */
    RDFStoreClient.RDFStoreClient.prototype.registerDefaultNamespace = function(ns, prefix) {
        this.connection.postMessage({'fn':'registerDefaultNamespace', 'args':[ns,prefix]});
    };
     
    /**
     * Registers the default namespaces declared in the RDF JS Interfaces
     * specification in the default Profile.
     */
    RDFStoreClient.RDFStoreClient.prototype.registerDefaultProfileNamespaces = function() {
        this.connection.postMessage({'fn':'registerDefaultProfileNamespaces', 'args':[]});
    };

    RDFStoreClient.RDFStoreClient.prototype.load = function(){
        var mediaType;
        var data;
        var graph;
        var callback;
     
        if(arguments.length === 3) {
            mediaType = arguments[0];
            data = arguments[1];
            callback= arguments[2] || function(){};
            var id = this.registerCallback('load', callback);
            this.connection.postMessage({'fn':'load', 'args':[mediaType, data], 'callback':id})
        } else if(arguments.length === 4) {
            mediaType = arguments[0];
            data = arguments[1];
            graph = arguments[2];
            callback= arguments[3] || function(){};
            var id = this.registerCallback('load', callback);
            this.connection.postMessage({'fn':'load', 'args':[mediaType, data, graph], 'callback':id})
        } else if(arguments.length === 2) {
            throw("The mediaType of the parser, the data a callback and an optional graph must be provided");
        }
     
    };

    RDFStoreClient.RDFStoreClient.prototype.startObservingQuery = function() {
        var query = arguments[0];
        var callback = arguments[1];
        var endCallback = arguments[2];
        if(endCallback!=null) {
            var id1 = this.registerCallback('startObservingQuery', callback);
            this.observingCallbacks[query] = id1;
            var id2 = this.registerCallback('startObservingQueryEndCb', endCallback);
            this.connection.postMessage({'fn':'startObservingQuery', 'args':[query], 'callback':[id1,id2]})
        } else {
            var id1 = this.registerCallback('startObservingQuery', callback);
            this.observingCallbacks[query] = id1;
            this.connection.postMessage({'fn':'startObservingQuery', 'args':[query], 'callback':[id1]})
        }
    };
     
    RDFStoreClient.RDFStoreClient.prototype.stopObservingQuery = function(query) {
        var id = this.observingCallbacks[query];
        delete this.observingCallbacks[query];
        delete this.callbacks[id];
        this.connection.postMessage({'fn':'stopObservingQuery', 'args':[query], 'callback':[]})
    };

    RDFStoreClient.RDFStoreClient.prototype.startObservingNode = function() {
        var uri, graphUri, callback;

        if(arguments.length === 2) {
            uri = arguments[0];
            callback = arguments[1];

            var that = this;
            var wrapperCallback = function(toWrap) {
                //console.log("CALLBACK!\n\n");
                var triple;
                for(var i=0; i<toWrap.triples.length; i++) {
                    triple = toWrap.triples[i];
                    toWrap.triples[i] = new RDFJSInterface.Triple(that.adaptJSInterface(triple.subject),
                                                                  that.adaptJSInterface(triple.predicate),
                                                                  that.adaptJSInterface(triple.object));
                }                
                callback(that.rdf.createGraph(toWrap.triples));
            };

            var id = this.registerCallback('startObservingNode', wrapperCallback);
            this.observingCallbacks[callback] = id;

            this.connection.postMessage({'fn':'startObservingNode', 'args':[uri], 'callback':id})
        } else if(arguments.length === 3) {
            uri = arguments[0];
            graphUri = arguments[1];
            callback = arguments[2];

            var that = this;
            var wrapperCallback = function(toWrap) {
                //console.log("CALLBACK!\n\n");
                var triple;
                for(var i=0; i<toWrap.triples.length; i++) {
                    triple = toWrap.triples[i];
                    toWrap.triples[i] = new RDFJSInterface.Triple(that.adaptJSInterface(triple.subject),
                                                                  that.adaptJSInterface(triple.predicate),
                                                                  that.adaptJSInterface(triple.object));
                }                
                callback(that.rdf.createGraph(toWrap.triples));
            };

            var id = this.registerCallback('startObservingNode', wrapperCallback);
            this.observingCallbacks[callback] = id;

            this.connection.postMessage({'fn':'startObservingNode', 'args':[uri,graphUri], 'callback':id})
        }
    };
     
    RDFStoreClient.RDFStoreClient.prototype.stopObservingNode = function(callback) {
        var id = this.observingCallbacks[callback];
        delete this.observingCallbacks[callback];
        delete this.callbacks[id];
        //console.log("STOP OBSERVING "+id);
        this.connection.postMessage({'fn':'stopObservingNode', 'args':[id], 'callback':[]})
    };

    RDFStoreClient.RDFStoreClient.prototype.subscribe = function(s, p, o, g, callback) {
        var that = this;
        var wrapperCallback = function(event,triples) {
            //console.log("CALLBACK!\n\n");
            var triple;
            for(var i=0; i<triples.length; i++) {
                triple = triples[i];
                triples[i] = new RDFJSInterface.Triple(that.adaptJSInterface(triple.subject),
                                                       that.adaptJSInterface(triple.predicate),
                                                       that.adaptJSInterface(triple.object));
            }                
            callback(event,triples);
        };
        var id = this.registerCallback('subscribe', wrapperCallback);
        this.observingCallbacks[callback] = id;

        this.connection.postMessage({'fn':'subscribe', 'args':[s,p,o,g], 'callback':id});
    };
     
    RDFStoreClient.RDFStoreClient.prototype.unsubscribe = function(callback) {
        var id = this.observingCallbacks[callback];
        delete this.observingCallbacks[callback];
        delete this.callbacks[id];
        //console.log("STOP OBSERVING "+id);
        this.connection.postMessage({'fn':'unsubscribe', 'args':[id], 'callback':[]})
    };
         
    RDFStoreClient.RDFStoreClient.prototype.registeredGraphs = function(callback) {
        var that = this;
        var wrapperCallback = function(success, graphs) {
            //console.log("CALLBACK!\n\n");
            if(success) {
                var triple;
                for(var i=0; i<graphs.length; i++) {
                    var graph = graphs[i];
                    graphs[i] = that.adaptJSInterface(graph);
                }                
                callback(success, graphs);
            } else {
                callback(success,graphs);
            }
        };

        var id = this.registerCallback('registeredGraphs', wrapperCallback);
        this.connection.postMessage({'fn':'registeredGraphs', 'args':[], 'callback':id})
    };

    // helper functions
    RDFStoreClient.RDFStoreClient.prototype.adaptJSInterface = function(node) {
        if(node.interfaceName === 'BlankNode') {
            return new RDFJSInterface.BlankNode(node.bnodeId);
        } else if(node.interfaceName === 'Literal') {
            return new RDFJSInterface.Literal(node.nominalValue, node.language, node.datatype);
        } else if(node.interfaceName === 'NamedNode') {
            return new RDFJSInterface.NamedNode(node.nominalValue);
        }
    };

    // make possible for clients to test if this i being executed inside a connection
    RDFStoreClient.RDFStoreClient.prototype.isWebWorkerConnection = true;
}

// end of ./src/js-connection/src/rdfstore_client.js 
// exports
var Store = {};

/**
 * @namespace
 * 
 * The Store module defines the public interface to the RDF store.
 */

// imports
var MongodbQueryEngine = { MongodbQueryEngine: function(){ throw 'MongoDB backend not supported in the browser version' } };
var RDFStoreClient = RDFStoreClient;
/**
 * Version of the store
 */
Store.VERSION = "0.8.1";

/**
 * Create a new RDFStore instance that will be
 * executed in a web worker in the browser or a new process
 * in Node.js.
 * <br/>
 * <br/>
 * The first argument to this function is the URL/FS location 
 * of the store script.
 * <br/>
 * <br/>
 * This parameter is mandatory in the browser. It is safe to
 * ignore this parameter in Node.js.
 * <br/>
 * <br/>
 * If support for web workers is not present, a regular
 * store object will be initialized and returned.
 * <br/>
 * <br/>
 *
 * @param {String} [scriptPath] URL of the RDFStore script
 * @param {Object[]} [args] Arguments to be passed to the store that will be created
 * @param {Function} callback Callback function that will be invoked with an error flag and the connection/store object.
 */
Store.connect = function() {
    var path, args, callback;
    if(arguments.length == 1) {
        path = __dirname;
        args = {};
        callback = arguments[0];
    } else if(arguments.length == 2) {
        if(typeof(arguments[0]) === 'string') {
            path = arguments[0];
            args = {};
        } else {
            path = __dirname+"/index.js";
            args = arguments[0];
        }
        callback = arguments[1];
    } else {
        path = arguments[0];
        args = arguments[1];
        callback = arguments[2];
    }
    try {
        if(!!Worker) {
            new RDFStoreClient.RDFStoreClient(path, args, function(success,connection) {
                callback(success, connection);
            });
        } else {
            Store.create(args,function(connection){
                callback(false, connection);
            });
        }
    } catch(e) {
        Store.create(args,function(connection){
            callback(false, connection);
        });        
    }
};

/**
 * Creates a new instance of the store.
 *
 * The function accepts two optional arguments.
 * <br/>
 * If only one argument is passed it must be a
 * callback function that will be invoked when the
 * store had been created.<br/>
 * <br/>
 * If two arguments are passed the first one must
 * be a map of configuration parameters for the
 * store, and the second one the callback function.<br/>
 * <br/>
 * Take a look at the Store constructor function for
 * a detailed list of possible configuration parameters.<br/>
 *
 * @param {Object[]} [args] Arguments to be passed to the store that will be created
 * @param {Function} [callback] Callback function that will be invoked with an error flag and the connection/store object.
 */
Store.create = function(){
    if(arguments.length == 1) {
        return new Store.Store(arguments[0]);
    } else if(arguments.length == 2) {
        return new Store.Store(arguments[0], arguments[1]);
    } else {
        return new Store.Store();
    };
};

/**
 * Creates a new store.<br/>
 * <br/>
 * It accepts two optional arguments, a map of configuration
 * options for the store and a callback function.<br/>
 *
 * @constructor 
 * @param {Function} [callback] Callback that will be invoked when the store has been created
 * @param {Object} [params]
 * <ul>
 *  <li> persistent:  should the store use persistence? </li>
 *  <li> treeOrder: in versions of the store backed by the native indexing system, the order of the BTree indices</li>
 *  <li> name: when using persistence, the name for this store. In the MongoDB backed version, name of the DB used by the store. By default <code>'rdfstore_js'</code> is used</li>
 *  <li> overwrite: clears the persistent storage </li>
 *  <li> maxCacheSize: if using persistence, maximum size of the index cache </li>
 *  <li> engine: the persistent storage to use, a value <code>mongodb</code> selects the MongoDB engine</li>
 *  <li> mongoDomain: when <code>engine=mongodb</code>, server domain name or IP address where the MongoDB server backing the store is running. By default <code>'127.0.0.1'</code> is used</li>
 *  <li> mongoPort: when <code>engine=mongodb</code>, port where the MongoDB server is running. By default <code>27017</code> is used</li>
 *  <li> mongoOptions: when <code>engine=mongodb</code>, additional options for the MongoDB driver. By default <code>{}</code> is used</li>
 * </ul>
 */
Store.Store = function(arg1, arg2) {
    var callback = null;
    var params   = null;

    if(arguments.length == 0) {
        params ={};
    } else if(arguments.length == 1) {
        params   = {};
        callback = arg1;
    } else if(arguments.length > 1) {
        params   = arg1;
        callback = arg2;
    } else {
        throw("An optional argument map and a callback must be provided");
    }

    if(params['treeOrder'] == null) {
        params['treeOrder'] = 15;
    }

    this.functionMap = {};

    var that = this;
    this.customFns = {};
    if(params['engine']==='mongodb') {
        this.isMongodb = true;
        this.engine = new MongodbQueryEngine.MongodbQueryEngine(params);
        this.engine.readConfiguration(function(){
            if(params['overwrite'] === true) {
                that.engine.clean(function(){
                    callback(that);
                });
            } else {
                callback(that);
            }
        });
    } else {
        new Lexicon.Lexicon(function(lexicon){
            if(params['overwrite'] === true) {
                // delete lexicon values
                lexicon.clear();
            }
            new QuadBackend.QuadBackend(params, function(backend){
                if(params['overwrite'] === true) {
                    // delete index values
                    backend.clear();
                }
                params.backend = backend;
                params.lexicon =lexicon;
                that.engine = new QueryEngine.QueryEngine(params);      
                if(callback) {
                    callback(that);
                }
            });
        },params['name']);
    }
};


/**
 * An instance of RDF JS Interface <code>RDFEnvironment</code>
 * associated to this graph instance.
 */
Store.Store.prototype.rdf = RDFJSInterface.rdf;
Store.Store.prototype.rdf.api = RDFJSInterface;

/**
 * Registers a new function with an associated name that can
 * be invoked as 'custom:fn_name(arg1,arg2,...,argn)' inside
 * a SPARQL query.
 * <br/>
 * The registered function will receive two arguments, an
 * instance of the store's query filters engine and a list
 * with the arguments received by the function in the SPARQL query.
 * <br/>
 * The function must return a single token value that can
 * consist in a literal value or an URI.
 * <br/>
 * The following is an example literal value:
 * {token: 'literal', type:"http://www.w3.org/2001/XMLSchema#integer", value:'3'}
 * This is an example URI value:
 * {token: 'uri', value:'http://test.com/my_uri'}
 * <br/>
 * The query filters engine can be used to perform common operations
 * on the input values.
 * An error can be returne dusing the 'ebvError' function of the engine.
 * True and false values can be built directly using the 'ebvTrue' and
 * 'ebvFalse' functions.
 * 
 * A complete reference of the available functions can be found in the
 * documentation or source code of the QueryFilters module.
 *
 * @arguments:
 * @param {String} [name]: name of the custom function, it will be accesible as custom:name in the query
 * @param {Function} [function]: lambda function with the code for the query custom function.
 */
Store.Store.prototype.registerCustomFunction = function(name, fn) {
    this.customFns[name] = fn;
    this.engine.setCustomFunctions(this.customFns);
};

/**
 * Executes a query in the store.<br/>
 * <br/>
 * There are two possible ways of invoking this function,
 * providing a pair of arrays of namespaces that will be
 * used to compute the union of the default and named
 * dataset, or without them.
 * <br/>
 * <br/>
 * Both invocations receive as an optional last parameter
 * a callback function that will receive the return status
 * of the query and the results.
 * <br/>
 * <br/>
 * Results can have different formats:
 * <ul>
 *  <li> SELECT queries: array of binding maps </li>
 *  <li> CONSTRUCT queries: RDF JS Interface Graph object </li>
 *  <li> ASK queries: JS boolean value </li>
 *  <li> LOAD/INSERT... queries: Number of triples modified/inserted </li>
 * </ul>
 *  
 * @arguments: 
 * @param {String} query
 * @param {String} [defaultURIs] default namespaces
 * @param {String} [namespacesURIs] named namespaces
 * @param {Function} [callback]
 */
Store.Store.prototype.execute = function() {
    if(arguments.length === 3) {
        this.executeWithEnvironment(arguments[0],
                                    arguments[1],
                                    arguments[2]);
    } else if(arguments.length === 4) {
        this.executeWithEnvironment(arguments[0],
                                    arguments[1],
                                    arguments[2],
                                    arguments[3]);
    } else {

        var queryString;
        var callback;
     
        if(arguments.length === 1) {
            queryString = arguments[0];
            var callback = function(){};
        } else if(arguments.length === 2) {
            queryString = arguments[0];
            callback = arguments [1];
        }
        this.engine.execute(queryString, callback);
    }
};

/**
 * A variation of the execute function that expects 
 * arguments containing values for the default and named 
 * graphs that will be used in the query.
 *
 *
 * @arguments:
 * @param {String} query
 * @param {String} URIs default namespaces
 * @param {String} URIs named namespaces
 * @param {Function} [callback]
 */
Store.Store.prototype.executeWithEnvironment = function() {
    var queryString, defaultGraphs, namedGraphs;

    if(arguments.length === 3) {
        queryString   = arguments[0];
        // JSDoc fails if this is pushed outside 
        var callback  = function(){};
        defaultGraphs = arguments[1];
        namedGraphs   = arguments[2];
    } else if(arguments.length === 4) {
        queryString   = arguments[0];
        var callback      = arguments [3];
        defaultGraphs = arguments[1];
        namedGraphs   = arguments[2];
    }
    var defaultGraphsNorm = [];
    var namedGraphsNorm = [];
    for(var i=0; i<defaultGraphs.length; i++) {
        defaultGraphsNorm.push({'token':'uri','value':defaultGraphs[i]})
    }
    for(var i=0; i<namedGraphs.length; i++) {
        namedGraphsNorm.push({'token':'uri','value':namedGraphs[i]})
    }
    this.engine.execute(queryString, callback, defaultGraphsNorm, namedGraphsNorm);
};

/**
 * Retrieves all the quads belonging to a certain graph
 * in the store as a RDF JS Interface Graph object.<br/>
 * <br/>
 * The function accepts as mandatory parameter a callback
 * function that will receive the a success notification and the returned graph.<br/>
 * <br/>
 * Optionally, the URI of the graph can also be passed as
 * the first argument. If no graph is specified, the
 * default graph will be returned.<br/>
 *
 * @arguments
 * @param {String} [graphURI] If this parameter is missing, the default graph will be returned
 * @param {Functon} callback
 */
Store.Store.prototype.graph = function() {
    var graphUri = null;
    var callback = null;
    if(arguments.length === 1) {
        callback = arguments[0] || function(){};
        graphUri = this.engine.lexicon.defaultGraphUri;
    } else if(arguments.length === 2) {
        callback = arguments[1] || function(){};
        graphUri = arguments[0];
    } else {
        throw("An optional graph URI and a callback function must be provided");
    }

    if(this.rdf.resolve(graphUri) != null) {
        graphUri = this.rdf.resolve(graphUri);
    }

    this.engine.execute("CONSTRUCT { ?s ?p ?o } WHERE { GRAPH <" + graphUri + "> { ?s ?p ?o } }", callback);
};

/**
 * Retrieves all the quads belonging to a certain node
 * in the store as a RDF JS Interface Graph object containing
 * the collection of triples whose subject is the provided
 * node URI.<br/>
 * <br/>
 * The function accepts as mandatory parameters the node URI and 
 * a callback unction that will receive a success notification and the returned node.<br/>
 * <br/>
 * Optionally, the URI of the graph where the node is contained 
 * can also be passed as the first argument. <br/>
 * <br/>
 * If no graph is specified, the node will be looked into the 
 * default graph.<br/>
 *
 * @arguments
 * @param {String} nodeURI URI of the node to look for
 * @param {String} [graphURI] If this parameter is missing, the node will be looked into the default graph
 * @param {Functon} callback
 */
Store.Store.prototype.node = function() {
    var graphUri = null;
    var callback = null;
    var nodeUri  = null;
    if(arguments.length === 2) {
        nodeUri = arguments[0];
        callback = arguments[1] || function(){};
        graphUri = this.engine.lexicon.defaultGraphUri;
    } else if(arguments.length === 3) {
        nodeUri = arguments[0];
        graphUri = arguments[1];
        callback = arguments[2] || function(){};
    } else {
        throw("An optional graph URI, node URI and a callback function must be provided");
    }

    if(this.rdf.resolve(graphUri) != null) {
        graphUri = this.rdf.resolve(graphUri);
    }

    if(this.rdf.resolve(nodeUri) != null) {
        nodeUri = this.rdf.resolve(nodeUri);
    }

    this.engine.execute("CONSTRUCT { <" + nodeUri + "> ?p ?o } WHERE { GRAPH <" + graphUri + "> { <" + nodeUri + "> ?p ?o } }", callback);
};

/**
 * Associates an event listener function to a node URI. Every time the collection
 * of triples whose subject is the specified node URI changes, because an
 * insertion or deletion, the provided callback function will be invoked
 * receiving as a parameter a RDF JS Interface Graph object with the new
 * collection of triples.<br/>
 * <br/>
 * The function accepts two mandatory arguments, the URI of the node to observe
 * and the function that will receive the event notifications. An optional
 * third parameter, consisting of a callback function, can be passed and will be invoked
 * once the store had correctly configured the event listener.<br/>
 *<br/>
 * LOAD queries, batch loading data into the store, do not 
 * trigger events by default. If you wish to be notified
 * by changes triggered by this kind of queries, invoke
 * the *setBatchLoadEvents* function with a true argument.<br/>
 *<br/>
 * The event listener function can be removed using the stopObservingNode function.
 *
 * @arguments
 * @param {String} nodeURI URI of the node to observe
 * @param {Function} eventListener Function that will be notified with the events
 * @param {Function} [callback] Function that will be invoked, once the event listener had been correctly set up.
 */
Store.Store.prototype.startObservingNode = function() {
    var uri, graphUri, callback;

    if(arguments.length === 2) {
        uri = arguments[0];
        callback = arguments[1];
        this.engine.callbacksBackend.observeNode(uri, callback, function(){});
    } else if(arguments.length === 3) {
        uri = arguments[0];
        graphUri = arguments[1];
        callback = arguments[2];
        this.engine.callbacksBackend.observeNode(uri, graphUri, callback, function(){});
    }
};

/**
 * Removes a callback function associated to a node.<br/>
 * The event listener function object must be passed as an argument.<br/>
 *
 * @arguments
 * @param {Function} eventListener The event listener function to remove, the same passed as an argument to startObservingNode
 */
Store.Store.prototype.stopObservingNode = function(callback) {
    this.engine.callbacksBackend.stopObservingNode(callback);
};

/**
 * Associates an event listener function to a SPARQL SELECT or
 * CONSTRUCT query.<br/>
 * Every time an update (insert, delete...) query modified the 
 * triples in the store in a way that modifies the output of the
 * query, the event listener will be invoked with an updated 
 * result.<br/>
 *<br/>
 * LOAD queries, batch loading data into the store, do not 
 * trigger events by default. If you wish to be notified
 * by changes triggered by this kind of queries, invoke
 * the <code>setBatchLoadEvents</code> function with a true argument.<br/>
 *<br/>
 * The event listener function can be removed invoking the
 * <code>stopObservingQuery</code> function. 
 *
 * @arguments
 * @param {String} query SELECT or CONSTRUCT SPARQL query
 * @param {Function} eventListener the function that will receive the notifications
 * @param {Function} [callback] optional function that will be invoked when the stored had set up the event listener function.
 */
Store.Store.prototype.startObservingQuery = function() {
    var query = arguments[0];
    var callback = arguments[1];
    var endCallback = arguments[2];
    if(endCallback!=null) {
        this.engine.callbacksBackend.observeQuery(query, callback, endCallback);
    } else {
        this.engine.callbacksBackend.observeQuery(query, callback, function(){});
    }
};

/**
 * Removes a callback function associated to a SPARQL query.<br/>
 * The event listener function object must be passed as an argument.
 *
 * @arguments
 * @param {Function} eventListener The event listener function to remove, the same passed as an argument to startObservingQuery
 */
Store.Store.prototype.stopObservingQuery = function(query) {
    this.engine.callbacksBackend.stopObservingQuery(query);
};

/**
 * Associates an event listener to a pattern expressed as the
 * subject, predicate, object and graph string parameters passed
 * to the function. To match any value in that position, a <code>null</code>
 * value can be passed as an argument. e.g. <code>subscribe(null, null, null, g, cb)</code>,
 * will be notified with any change in the g graph.<br/>
 * The graph component of the pattern does not support a <code>null</code> value.<br/>
 *<br/>
 * Results will be notified as an Array of RDF JS Interface
 * <code>Triple</code> objects.<br/>
 *<br/>
 * LOAD queries, batch loading data into the store, do not 
 * trigger events by default. If you wish to be notified
 * by changes triggered by this kind of queries, invoke
 * the <code>setBatchLoadEvents</code> function with a true argument.
 *
 * @arguments
 * @param {String} s subject or null for any subject
 * @param {String} p predicate or null for any predicate
 * @param {String} o object or null for any object
 * @param {String} g graph or null for any graph
 * @param {Function} event listener function that will be notified when a change occurs
 */
Store.Store.prototype.subscribe = function(s, p, o, g, callback) {
    var that = this;
    var adapterCb = function(event,triples){
        var acum = [];
        var queryEnv = {blanks:{}, outCache:{}};
        var bindings = [];

        for(var i=0; i<triples.length; i++) {
            var triple = triples[i];
            var s = RDFJSInterface.buildRDFResource(triple.subject,bindings,that.engine,queryEnv);
            var p = RDFJSInterface.buildRDFResource(triple.predicate,bindings,that.engine,queryEnv);
            var o = RDFJSInterface.buildRDFResource(triple.object,bindings,that.engine,queryEnv);
            if(s!=null && p!=null && o!=null) {
                triple = new RDFJSInterface.Triple(s,p,o);
                acum.push(triple);
            }
        }

        callback(event,acum);
    };

    this.functionMap[callback] = adapterCb;
    this.engine.callbacksBackend.subscribe(s,p,o,g,adapterCb,function(){});
};

/**
 * Removes an event listener associated to a certain pattern.
 * The function passed as an argument to <code>subscribe</code> must be 
 * passed as an argument.
 *
 * @arguments
 * @param {Function} callback The event listener to be removed
 */
Store.Store.prototype.unsubscribe = function(callback) {
    var adapterCb = this.functionMap[callback];
    this.engine.callbacksBackend.unsubscribe(adapterCb);
    delete this.functionMap[callback];
};

/**
 * Register a combination of prefix and URI fragment in the default instance
 * of the RDF JS Interface API <code>RDFEnvironment</code> object associated
 * to the store and available through the <code>storeInstance.rdf</code> property.
 *
 * @arguments
 * @param {String} prefix The prefix to be associated
 * @param {String} URIFragment URI fragment the provided prefix will be resolved
 */
Store.Store.prototype.setPrefix = function(prefix, uri) {
    this.rdf.setPrefix(prefix, uri);
};

/**
 * Defines the URI that will be used by default by the RDF JS Interface
 * API <code>RDFEnvironment</code> object associated to the store and available
 * through the <code>storeInstance.rdf</code> property.
 *
 * @arguments
 * @param {String} URIFragment The URI fragment will be used by default
 */
Store.Store.prototype.setDefaultPrefix = function(uri) {
    this.rdf.setDefaultPrefix(uri);
};

/**
 * Inserts a RDF JS Interface API <code>Graph</code> object into the store.
 * The function receives a mandatory <code>Graph</code> object whose triples
 * will be inserted. Optionally, a URI string for a graph and a 
 * callback function can be passed as arguments.<br/>
 * <br/>
 * If no graph URI is specified, triples will be inserted into the
 * default graph.<br/>
 * <br/>
 * If the callback function is specified, it will be invoked when all the
 * triples had been inserted into the store.<br/>
 *
 * @arguments
 * @param {RDFJSInterface.Graph} triples a RDF JS Interface <code>Graph</code> object
 * @param {String} [graphURI] URI of the graph where the triples will be inserted. If it is missing, triples will be inserted in the default graph
 * @param {String} [callback] A callback function that will be invoked with a success notification and the number of triples inserted
 */ 
Store.Store.prototype.insert = function() {
    var graph;
    var triples;
    var callback;
    if(arguments.length === 1) {
        triples = arguments[0];
        callback= function(){};
    } else if(arguments.length === 2) {
        triples = arguments[0];
        callback= arguments[1] || function(){};
    } else if(arguments.length === 3) {
        triples = arguments[0];
        graph = this.rdf.createNamedNode(arguments[1]);
        callback= arguments[2] || function(){};
    } else {
        throw("The triples to insert, an optional graph and callback must be provided");
    }

    var query = "";
    var that = this;
    triples.forEach(function(triple) {
        query = query + that._nodeToQuery(triple.subject) + that._nodeToQuery(triple.predicate) + that._nodeToQuery(triple.object) + ".";
    });

    if(graph != null) {
        query = "INSERT DATA { GRAPH " + this._nodeToQuery(graph) +" { "+ query + " } }";
    } else {
        query = "INSERT DATA { "+ query + " }";
    }

    this.engine.execute(query, callback);
};

Store.Store.prototype._nodeToQuery = function(term) {
    if(term.interfaceName === 'NamedNode') {
        var resolvedUri = this.rdf.resolve(term.valueOf());
        if(resolvedUri != null) {
            return "<" + resolvedUri + ">";
        } else {
            return "<" + term.valueOf() + ">";
        }
    } else {
        return term.toString();
    }
};

/**
 * Removes the triples in a RDF JS Interface API <code>Graph</code> object from the store.
 * The function receives a mandatory <code>Graph</code> object whose triples
 * will be removed. Optionally, a URI string for a graph and a 
 * callback function can be passed as arguments.<br/>
 * <br/>
 * If no graph URI is specified, triples will be removed from the
 * default graph.<br/>
 * <br/>
 * If the callback function is specified, it will be invoked when all the
 * triples had been removed from the store.
 *
 * @arguments
 * @param {RDFJSInterface.Graph} triples a RDF JS Interface <code>Graph</code> object
 * @param {String} [graphURI] URI of the graph where the triples will be removed from. If it is missing, triples will be removed from the default graph
 * @param {String} [callback] A callback function that will be invoked with a success notification
 */ 
Store.Store.prototype['delete'] = function() {

    var graph;
    var triples;
    var callback;
    if(arguments.length === 1) {
        triples = arguments[0];
        callback= function(){};
    } else if(arguments.length === 2) {
        triples = arguments[0];
        callback= arguments[1] || function(){};
    } else if(arguments.length === 3) {
        triples = arguments[0];
        graph = this.rdf.createNamedNode(arguments[1]);
        callback= arguments[2] || function(){};
    } else {
        throw("The triples to delete, an optional graph and callback must be provided");
    }

    var query = "";
    var that = this;
    triples.forEach(function(triple) {
        query = query + that._nodeToQuery(triple.subject) + that._nodeToQuery(triple.predicate) + that._nodeToQuery(triple.object) + ".";
    });

    if(graph != null) {
        query = "DELETE DATA { GRAPH " + this._nodeToQuery(graph) +" { "+ query + " } }";
    } else {
        query = "DELETE DATA { "+ query + " }";
    }

    this.engine.execute(query, callback);
};

/** 
 * Removes all the triples stored in a graph.
 * 
 * The URI of the graph and a callback function can be
 * optinally passed as parameters.<br/>
 * <br/>
 * If no graph URI is specified, all triples in the 
 * default graph will be removed.
 *
 * @arguments
 * @param {String} [graph] the URI of the graph the triples must be removed from
 * @param {Function} [callback] a function that will be invoked with a success notification
 */
Store.Store.prototype.clear = function() {
    var graph;
    var callback;

    if(arguments.length === 0) {
        graph = this.rdf.createNamedNode(this.engine.lexicon.defaultGraphUri);
        var callback= function(){};
    } else if(arguments.length === 1) {
        graph = this.rdf.createNamedNode(this.engine.lexicon.defaultGraphUri);
        callback= arguments[0] || function(){};
    } else if(arguments.length === 2) {
        graph = this.rdf.createNamedNode(arguments[0]);
        callback= arguments[1] || function(){};
    } else {
        throw("The optional graph and a callback must be provided");
    }

    var query = "CLEAR GRAPH " + this._nodeToQuery(graph);
    this.engine.execute(query, callback);
};

/**
 * Boolean value determining if loading RDF must produce
 * triple add events and fire callbacks.<br/>
 * Default value is false.
 *
 * @arguments
 * @param {boolean} mustFireEvents true/false value.
 */
Store.Store.prototype.setBatchLoadEvents = function(mustFireEvents){
    this.engine.eventsOnBatchLoad = mustFireEvents;
};

/**
 * Registers a namespace prefix that will be automatically declared
 * in all the queries.<br/>
 * <br/>
 * The prefix will also be inserte in the default <code>RDFEnvironment</code> object
 * associated to the <code>rdf</code> property of the store instance.
 *
 * @arguments
 * @param {String} ns the name space to be regsitered
 * @param {String} prefix the URI fragment associated to the name space
 */
Store.Store.prototype.registerDefaultNamespace = function(ns, prefix) {
    this.rdf.prefixes.set(ns,prefix);
    this.engine.registerDefaultNamespace(ns,prefix);
};

/**
 * Registers the default namespaces declared in the RDF JS Interfaces
 * specification in the default Profile.
 */
Store.Store.prototype.registerDefaultProfileNamespaces = function() {
    var defaultNsMap = this.rdf.prefixes.values();
    for (var p in defaultNsMap) {
        this.registerDefaultNamespace(p,defaultNsMap[p]);
    }
};

/**
 * Load triples into a graph in the store. Data can be passed directly to the method
 * or a remote URI speifying where the data is located can be used.<br/>
 *<br/>
 * If the data is passed directly to the load function, the media type stating the format
 * of the data must also be passed to the function.<br/>
 *<br/>
 * If an URI is passed as a parameter, the store will attempt to perform content negotiation
 * with the remote server and get a representation for the RDF data matching one of the
 * the RDF parsers registered in the store. In this case, the media type parameter must be
 * set to the <code>'remote'</code> value.<br/>
 *<br/>
 * An additional URI for the graph where the parsed data will be loaded and a callback function
 * can be also passed as parameters. If no graph is specified, triples will be loaded in the
 * default graph.<br/>
 *<br/>
 * By default loading data will not trigger notification through the events API. If events needs to
 * be trigger, the functio <code>setBatchLoadEvents</code> must be invoked with a true parameter.
 *
 * @arguments
 * @param {String} mediaType Media type (application/json, text/n3...) of the data to be parsed or the value <code>'remote'</code> if a URI for the data is passed instead
 * @param {String} data RDF data to be parsed and loaded or an URI where the data will be retrieved after performing content negotiation
 * @param {String} [graph] Graph where the parsed triples will be inserted. If it is not specified, triples will be loaded in the default graph
 * @param {Function} callback that will be invoked with a success notification and the number of triples loaded.
 */
Store.Store.prototype.load = function(){
    var mediaType;
    var data;
    var graph;
    var callback;
    var options = {};

    if(arguments.length === 3) {
        graph = this.rdf.createNamedNode(this.engine.lexicon.defaultGraphUri);
        mediaType = arguments[0];
        data = arguments[1];
        callback= arguments[2] || function(){};
    } else if(arguments.length === 4) {
        mediaType = arguments[0];
        data = arguments[1];
        options = arguments[2];
        if(typeof(options) === 'string') {
            graph = this.rdf.createNamedNode(options);
            options = {};
        } else {
            graph = this.rdf.createNamedNode(options.graph || this.engine.lexicon.defaultGraphUri);
            delete options['graph'];
        }
        callback= arguments[3] || function(){};
    } else if(arguments.length === 2) {
        throw("The mediaType of the parser, the data a callback and an optional graph must be provided");
    }

    if(mediaType === 'remote') {
        data = this.rdf.createNamedNode(data);
        var query = "LOAD <"+data.valueOf()+"> INTO GRAPH <"+graph.valueOf()+">";
        this.engine.execute(query, callback);
    } else if(data && typeof(data)==='string' && data.indexOf('file://')=== 0) {
        var parser = this.engine.rdfLoader.parsers[mediaType];

        var that = this;
        this.engine.rdfLoader.loadFromFile(parser, {'token':'uri', 'value':graph.valueOf()}, data, function(success, quads) {
            if(success) {
                that.engine.batchLoad(quads,callback);
            } else {
                callback(success, quads);
            }
        });


    } else {
        var parser = this.engine.rdfLoader.parsers[mediaType];
        var that = this;

        this.engine.rdfLoader.tryToParse(parser, {'token':'uri', 'value':graph.valueOf()}, data, options, function(success, quads) {
            if(success) {
                that.engine.batchLoad(quads,callback);
            } else {
                callback(success, quads);
            }
        });
    }
};

/**
 * Registers a new parser associated to the provided media type. If there is a parser already registered for
 * that media type, the new parser will replace the old one.<br/>
 *<br/>
 * Parsers must implement a function *parse* accepting the data to be parsed as the
 * first parameter and the destination graph URI as the second one.
 * They must return an array of objects with properties: 'subject', 'predicate', 'object'
 * and 'graph' containing lexical representations for these values: 
 *<br/>
 *<ul>
 * <li><code>{literal: '"literal"'}</code></li>
 * <li><code>{literal: ''"literal"^^<datatype>'}</code></li>
 * <li><code>{literal: '"literal"@lang'}</code></li>
 * <li><code>{uri: 'uri'}</code></li>
 * <li><code>{blank: '_:label'}</code></li>
 *</ul>
 *<br/>
 * The provided media type will be used to perform content negotiation when dealing with remote
 * resources, or to select the parser in the <code>load</code> function.
 *
 * @arguments
 * @param {String} mediaType the media type for this parser
 * @param {String} parser an object containing the *parse* function with the parser logic
 */
Store.Store.prototype.registerParser = function(mediaType, parser) {
    this.engine.rdfLoader.registerParser(mediaType,parser);
};

/**
 * Returns the URI of all the graphs currently contained
 * in the store
 *
 * @arguments:
 * @param {Function} callback function that will receive a success notification and the array of graph URIs
 */
Store.Store.prototype.registeredGraphs = function(callback) {
    if(this.isMongodb) {
        this.engine.registeredGraphs(true, function(graphs){
            var acum = [];
            for(var i=0; i<graphs.length; i++) {
                var graph = graphs[i];
                var uri = new RDFJSInterface.NamedNode(graph);
                acum.push(uri);
            }
            
            return callback(true, acum);    
        });
    } else {
        var graphs = this.engine.lexicon.registeredGraphs(true);
        var acum = [];
        for(var i=0; i<graphs.length; i++) {
            var graph = graphs[i];
            var uri = new RDFJSInterface.NamedNode(graph);
            acum.push(uri);
        }
     
        return callback(true, acum);    
    }
};

/**
 * Returns the current network transport being used by the
 * the store.
 * 
 * The default transport uses TCP sockets in the Node.js version
 * and relies on jQuery in the browser version. This can be overriden
 * using the <code>setNetworkTransport</code> function.
 */
Store.Store.prototype.getNetworkTransport = function() {
    return NetworkTransport;
};

/**
 * Sets the network transport used by the store.<br/>
 * <br/>
 * Network transport consist of an object implementing the <code>load</code>
 * function, receiving the URI to load, a string with the value
 * of the HTTP 'Accept' header for the store registered parsers,
 * a callback function where the retrieved data and the success notification
 * must be returned.<br/>
 *<br/>
 * Different examples with implementations of different transports can be found
 * in the source code of the store:
 *<ul>
 * <li>src/js-communication/src/tcp_transport.js</li>
 * <li>src/js-communication/src/ajax_transport.js</li>
 *</ul>
 * @arguments
 * @param networkTransportImpl object implementing the transport *load* function.
 */
Store.Store.prototype.setNetworkTransport = function(networkTransportImpl) {
    NetworkTransport = networkTransportImpl;
};


/**
 * Clean-up function releasing all temporary resources held by the
 * store instance.
 */
Store.Store.prototype.close = function(cb) {
    if(cb == null)
	cb = function(){};
    if(this.engine.close)
	this.engine.close(cb);
    else
	cb();
};

// end of ./src/js-store/src/store.js 
// imports
    RDFStoreWorker = {};

    RDFStoreWorker.observingCallbacks = {};
    
    RDFStoreWorker.workerCallbacksCounter = 0;
    RDFStoreWorker.workerCallbacks = {};
    RDFStoreWorker.registerCallback = function(cb) {
        var nextId = ""+RDFStoreWorker.workerCallbacksCounter;
        RDFStoreWorker.workerCallbacksCounter++;
        RDFStoreWorker.workerCallbacks[nextId] = cb;
        return nextId;
    };

    RDFStoreWorker.handleCreate = function(argsObject, cb) {
        // redefine NetworkTransport

        if(typeof(NetworkTransport) != 'undefined'  && NetworkTransport != null) {
            NetworkTransport = {
                load: function(uri, graph, callback) {
                    var cbId = RDFStoreWorker.registerCallback(function(results){
                        callback.apply(callback,results);
                    });
                    postMessage({'fn':'workerRequest:NetworkTransport:load','callback':cbId, 'arguments':[uri,graph]});
                },

                loadFromFile: function(parser, graph, uri, callback) {

                }
            }
        }

        var args = [argsObject];
        //console.log("in handling create");
        args.push(function(result){
            //console.log("created!!!");
            // Stores the store object in the worker
            RDFStoreWorker.store = result;
            //console.log("posting MESSAGE!");

            postMessage({'callback':cb, 'result':'created', 'success':true});
        });
        //console.log("creating");
        Store.create.apply(Store,args)
    };

    RDFStoreWorker.receive = function(packet) {
        var msg = packet.data || packet;
        //console.log("RECEIVED...");
        if(msg.fn === 'workerRequestResponse') {
            var cbId = msg.callback;
            var callback = RDFStoreWorker.workerCallbacks[cbId];
            if(callback != null) {
                delete RDFStoreWorker.workerCallbacks[cbId];
                callback(msg.results);
            }
        } else if(msg.fn === 'create' && msg.args !=null) {
            //console.log("handling create");
            RDFStoreWorker.handleCreate(msg.args, msg.callback);
        } else if(msg.fn === 'setBatchLoadEvents') {
            RDFStoreWorker.store[msg.fn].apply(RDFStoreWorker.store, msg.args);
        } else if(msg.fn === 'registerDefaultNamespace') {
            RDFStoreWorker.store[msg.fn].apply(RDFStoreWorker.store, msg.args);
        } else if(msg.fn === 'registerDefaultProfileNamespaces') {
            RDFStoreWorker.store[msg.fn].apply(RDFStoreWorker.store, msg.args);
        } else if((msg.fn === 'execute' ||
                   msg.fn === 'executeWithEnvironment' ||
                   msg.fn === 'graph'||
                   msg.fn === 'node' ||
                   msg.fn === 'clear' ||
                   msg.fn === 'load') && msg.args != null) {
            msg.args.push(function(success, result){
                //console.log("CALLBACK!");
                if(msg.callback!=null) {
                    postMessage({'callback':msg.callback, 'result':result, 'success':success});
                }
            });
            try {
                RDFStoreWorker.store[msg.fn].apply(RDFStoreWorker.store,msg.args);
            } catch(e) {
                console.log("Error executing method through connection");
                console.log(e);
            }
        } else if((msg.fn === 'insert'||
                   msg.fn === 'delete') && msg.args != null) {
            try {
                msg.args.push(function(success, result){
                    //console.log("CALLBACK!");
                    if(msg.callback!=null) {
                        postMessage({'callback':msg.callback, 'result':result, 'success':success});
                    }
                });
                var triple;
                var toWrap = msg.args[0];
                for(var i=0; i<toWrap.triples.length; i++) {
                    triple = toWrap.triples[i];
                    toWrap.triples[i] = new RDFJSInterface.Triple(RDFStoreWorker.adaptJSInterface(triple.subject),
                                                                  RDFStoreWorker.adaptJSInterface(triple.predicate),
                                                                  RDFStoreWorker.adaptJSInterface(triple.object));
                }                

                if(msg.args[1].interfaceName != null) {
                    msg.args[1] = RDFStoreWorker.adaptJSInterface(msg.args[1]);
                }
                msg.args[0] = RDFStoreWorker.store.rdf.createGraph(toWrap.triples);
                //console.log("ARGS...");
                
                RDFStoreWorker.store[msg.fn].apply(RDFStoreWorker.store,msg.args);
            } catch(e) {
                console.log("Error executing method through connection");
                console.log(e);
            }
        } else if(msg.fn === 'rdf/setPrefix' && msg.args != null) {
            RDFStoreWorker.store.rdf.setPrefix(msg.args[0], msg.args[1]);
        } else if(msg.fn === 'rdf/setDefaultPrefix' && msg.args != null) {
            RDFStoreWorker.store.rdf.setDefaultPrefix(msg.args[0]);
        } else if(msg.fn === 'startObservingQuery' && msg.args != null) {
            // regular callback
            var cb = function(success, result){
                postMessage({'callback':msg.callback[0], 'result':result, 'success':success});
            };

            RDFStoreWorker.observingCallbacks[msg.args[0]] = cb;
            msg.args.push(cb);


            // end register callback
            msg.args.push(function(success, result) {
                //console.log("CALLBACK END REGISTER OBSERVING QUERY!");
                if(msg.callback && msg.callback[1] !=null) {
                    postMessage({'callback':msg.callback[1], 'result':result, 'success':success});                    
                }
            });

            RDFStoreWorker.store[msg.fn].apply(RDFStoreWorker.store,msg.args);

        } else if(msg.fn === 'stopObservingQuery') {
            var cb = RDFStoreWorker.observingCallbacks[msg.args[0]];
            if(cb) {
                RDFStoreWorker.store[msg.fn].apply(RDFStoreWorker.store,[cb]);
            }

            delete RDFStoreWorker.observingCallbacks[msg.args[0]];
        } else if(msg.fn === 'startObservingNode' && msg.args != null) {
            // regular callback
            var cb = function(result){
                //console.log("CALLBACK OBSERVING NODE!");
                postMessage({'callback':msg.callback, 'result':result});
            };

            RDFStoreWorker.observingCallbacks[msg.callback] = cb;
            msg.args.push(cb);

            RDFStoreWorker.store[msg.fn].apply(RDFStoreWorker.store,msg.args);
        } else if(msg.fn === 'stopObservingNode' && msg.args != null) {
            var cb = RDFStoreWorker.observingCallbacks[msg.args[0]];
            if(cb) {
                //console.log("WORKER STOP OBSERVING");
                //console.log(cb);
                RDFStoreWorker.store[msg.fn].apply(RDFStoreWorker.store,[cb]);
            }

            delete RDFStoreWorker.observingCallbacks[msg.args[0]];
        } else if(msg.fn === 'subscribe' && msg.args != null) {
            // regular callback
            var cb = function(event,result){
                //console.log("CALLBACK OBSERVING NODE!");
                postMessage({'callback':msg.callback, 'event':event, 'result':result});
            };

            RDFStoreWorker.observingCallbacks[msg.callback] = cb;
            msg.args.push(cb);

            RDFStoreWorker.store[msg.fn].apply(RDFStoreWorker.store,msg.args);
        } else if(msg.fn === 'stopObservingNode' && msg.args != null) {
            var cb = RDFStoreWorker.observingCallbacks[msg.args[0]];
            if(cb) {
                //console.log("WORKER UNSUBSCRIBE");
                //console.log(cb);
                RDFStoreWorker.store[msg.fn].apply(RDFStoreWorker.store,[cb]);
            }

            delete RDFStoreWorker.observingCallbacks[msg.args[0]];
        } else if(msg.fn === 'registeredGraphs' && msg.args != null) {
            var cb = function(success, result){
                //console.log("CALLBACK!");
                if(msg.callback!=null) {
                    postMessage({'callback':msg.callback, 'result':result, 'success':success});
                }
            };
            RDFStoreWorker.store[msg.fn].apply(RDFStoreWorker.store,[cb]);
        }
    };

    // helper functions
    RDFStoreWorker.adaptJSInterface = function(node) {
        if(node.interfaceName === 'BlankNode') {
            return new RDFJSInterface.BlankNode(node.bnodeId);
        } else if(node.interfaceName === 'Literal') {
            return new RDFJSInterface.Literal(node.nominalValue, node.language, node.datatype);
        } else if(node.interfaceName === 'NamedNode') {
            return new RDFJSInterface.NamedNode(node.nominalValue);
        }
    };

    // @todo
    // I'm setting a global var if this is not a worker
    // FIXME!

    // set the receiver message
    onmessage = RDFStoreWorker.receive;

// end of ./src/js-connection/src/rdfstore_worker.js 
try {
  window.rdfstore = Store;
} catch(e) { }
})();
