diff examples/browser/web/js/jOWL.js @ 640:901803e1305f

First instance of audioDB browser code.
author mas01mj
date Thu, 08 Oct 2009 11:19:11 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/browser/web/js/jOWL.js	Thu Oct 08 11:19:11 2009 +0000
@@ -0,0 +1,2242 @@
+/**
+* jOWL - a jQuery plugin for traversing and visualizing OWL-DL documents.
+* Creator - David Decraene
+* Version 1.0
+* Website: 
+*	http://Ontologyonline.org
+* Licensed under the MIT license 
+*	http://www.opensource.org/licenses/mit-license.php
+* Verified with JSLint 
+*	http://www.jslint.com/
+*/
+
+jOWL = window.jOWL = function( resource, options ){ return jOWL.getResource( resource, options );  };
+jOWL.version = "1.0";
+
+/** for debugging compatibility */
+	try { console.log('...'); } catch(e) { console = window.console = { log: function() {} } }
+	if ($.browser.opera && opera.postError) { console = window.console = { log : function(){opera.postError(arguments); } }; }
+
+
+
+(function($){
+
+/** 
+* if no param: @return string of main namespaces
+* if 1 param: assume a documentElement, parse namespaces
+* if prefix & URI: Bind prefix to namespace URI 
+*/
+jOWL.NS = function(prefix, URI){
+	if(!arguments.length)
+	{ return "xmlns:"+jOWL.NS.owl.prefix+"='"+jOWL.NS.owl()+"' xmlns:"+jOWL.NS.rdf.prefix+"='"+jOWL.NS.rdf()+"' xmlns:"+jOWL.NS.rdfs.prefix+"='"+jOWL.NS.rdfs()+"' xmlns:"+jOWL.NS.xsd.prefix+" ='"+jOWL.NS.xsd()+"'";}
+
+	if(arguments.length == 1){
+		var attr = prefix.get(0).attributes;
+		for(var i=0;i<attr.length;i++){
+			var nn = attr[i].nodeName.split(':');
+			if(nn.length == 2){
+				if(attr[i].nodeValue == jOWL.NS.owl.URI){ jOWL.NS.owl.prefix = nn[1];}
+				else if(attr[i].nodeValue == jOWL.NS.rdf.URI){ jOWL.NS.rdf.prefix = nn[1];}
+				else if(attr[i].nodeValue == jOWL.NS.rdfs.URI){ jOWL.NS.rdfs.prefix = nn[1];}
+				else if(attr[i].nodeValue == jOWL.NS.xsd.URI){ jOWL.NS.xsd.prefix = nn[1];}
+				else { jOWL.NS(nn[1], attr[i].nodeValue);}
+			}
+		}
+		jOWL.namespace =  prefix.xmlAttr('xml:base') || prefix.xmlAttr('xmlns');
+		return;
+	}
+	jOWL.NS[prefix] = function(element){
+		if(element){
+			return (arguments.callee.prefix == 'base') ? element : arguments.callee.prefix + ":" + element;
+			}
+		return arguments.callee.URI;
+		};
+	jOWL.NS[prefix].prefix = prefix;
+	jOWL.NS[prefix].URI = URI;	
+};
+
+var __ = jOWL.NS;
+
+/** set Main namespaces */
+__("owl", "http://www.w3.org/2002/07/owl#");
+__("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
+__("rdfs", "http://www.w3.org/2000/01/rdf-schema#");
+__("xsd", "http://www.w3.org/2001/XMLSchema#");
+
+/** jQuery function additions for easy parsing of identities */
+$.fn.extend({
+	/** Used for Opera compatibility when parsing xml attributes, nodeName must be checked, in contrast to native jquery call attr() */
+	xmlAttr : function(nodeName){
+		var t = this[0].attributes; if(!t){ return;}
+		for(var i =0;i<t.length;i++){
+			if(t[i].nodeName == nodeName){ return t[i].nodeValue;}
+		}
+	},
+	RDF_ID : function(match){
+		var res = this.xmlAttr(__.rdf('ID'));
+		if(!res){ return false;}
+		res = jOWL.resolveURI(res);
+		if(match){
+			return res.toLowerCase() == (jOWL.resolveURI(match.toString())).toLowerCase();}
+		return res;
+		},
+	RDF_Resource : function(match){
+		function getClassName(dom){
+			var cl = jOWL.Xpath(__.owl("Class"), dom);
+			if(cl.length == 1){ return new jOWL.Ontology.Class(cl).URI;}
+			return false;
+		}
+		if(!this.length){ return false;}
+		var rsrc = this.xmlAttr(__.rdf('resource'));
+		if(!rsrc){
+			var dom = this.get(0);
+			switch(dom.nodeName){
+				case __.rdfs("subClassOf"): rsrc = getClassName(dom); break;
+				case __.owl("disjointWith"): rsrc = getClassName(dom); break;
+				case __.owl("allValuesFrom"): rsrc = getClassName(dom); break;
+				case __.owl("someValuesFrom"): rsrc = getClassName(dom); break;
+				case __.owl("onProperty"):
+					var t = jOWL.Xpath(__.owl("ObjectProperty"), dom);
+					if(t.length === 0){ t = jOWL.Xpath(__.owl("DatatypeProperty"), dom);}
+					if(t.length === 0){ t = jOWL.Xpath(__.owl("FunctionalProperty"), dom);}
+					rsrc = t.xmlAttr(__.rdf('about')); break;
+				default: return false;
+			}
+		}
+		if(!rsrc){ return false;}
+		rsrc = jOWL.resolveURI(rsrc);
+		if(match){ return rsrc.toLowerCase() == (jOWL.resolveURI(match.toString())).toLowerCase();}
+		return rsrc;
+		},
+	RDF_About : function(match){
+		var res = this.xmlAttr(__.rdf('about'));
+		if(!res){ return false;}
+		res = jOWL.resolveURI(res);
+		if(match){
+			return res.toLowerCase() == (jOWL.resolveURI(match.toString())).toLowerCase();}
+		return res;
+		}
+});
+
+/** Check XPath implementation */
+if( document.implementation.hasFeature("XPath", "3.0") ){
+	XMLDocument.prototype.selectNodes = function(cXPathString, xNode){
+		if( !xNode ){ xNode = this;}
+		var oNSResolver = this.createNSResolver(this.documentElement);
+		var aItems = this.evaluate(cXPathString, xNode, oNSResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); var aResult = []; for( var i = 0; i < aItems.snapshotLength; i++){ aResult[i] = aItems.snapshotItem(i);}  
+		return aResult; 
+		};
+	Element.prototype.selectNodes = function(cXPathString){  
+		if(this.ownerDocument.selectNodes)  {  return this.ownerDocument.selectNodes(cXPathString, this);}
+		else{throw "For XML Elements Only";} 
+		}; 
+	XMLDocument.prototype.selectSingleNode = function(cXPathString, xNode){ if( !xNode ){ xNode = this;}
+		var xItems = this.selectNodes(cXPathString, xNode); if( xItems.length > 0 ){  return xItems[0];} else {  return null;}
+		};
+	Element.prototype.selectSingleNode = function(cXPathString){
+		if(this.ownerDocument.selectSingleNode)  {  return this.ownerDocument.selectSingleNode(cXPathString, this);}
+		else{throw "For XML Elements Only";} 
+		};  
+}
+
+/** @return A jQuery array of xml elements */
+jOWL.Xpath = function(selector, elem){
+	var node = null;
+	if(elem){ if(elem.each){ node = elem.get(0);} else { node = elem;} }
+	var arr = node ? node.selectNodes(selector) : jOWL.document.selectNodes(selector);
+	if($.browser.msie){ return $($.makeArray(arr));} return $(arr); //this is needed for IE, it returns a length of 1 on empty node array
+};
+
+/** @return a String array of class references */
+jOWL.Xpath.classes = function(jnode){
+	var cl = [];
+	jOWL.Xpath(__.rdfs("subClassOf"), jnode)
+		.each(function(){
+			var res = $(this).RDF_Resource();
+			if(res){ cl.push(res);}
+		});
+
+	jOWL.Xpath(__.owl("intersectionOf")+"/"+__.owl("Class"), jnode)
+		.each(function(){
+			var p = $(this).RDF_About(); if(p){ cl.push(p);}
+		});
+	return cl;
+};
+
+/** Functions stored in jOWL.priv are intended for local access only, to avoid a closure function */
+jOWL.priv = {
+	/** Arrray functions */
+	Array : {
+		isArray : function(array){
+			return Object.prototype.toString.call(array) === '[object Array]';
+		},
+		pushUnique : function(array, item){
+			if(jOWL.priv.Array.getIndex(array, item) === -1){	array.push(item); return true;}
+			return false;
+		},
+		getIndex : function(array, item){
+			for (var i=0; i<array.length; i++){ if(item == array[i]){ return i;} }
+			return -1;
+		},
+		/** Sorted array as input, returns the same array without duplicates. */
+		unique : function(array){
+			var result = []; var lastValue="";
+			for (var i=0; i<array.length; i++)
+			{
+				var curValue=array[i];
+				if(curValue != lastValue){ result[result.length] = curValue;}
+				lastValue=curValue;
+			}
+			return result;
+		}
+	}
+};
+
+/** Make values work with jOWL.Ontology.Array */
+jOWL.Literal = function(value){
+	this.name = value;
+};
+
+/** Access to the owl:Ontology element, also the main coding namespace for ontology objects */
+jOWL.Ontology = function(){
+	if(!(this instanceof arguments.callee)){ return new jOWL.Ontology();}
+	this.parse(jOWL.Xpath("/"+__.rdf("RDF")+"/"+__.owl("Ontology")));
+	return this;
+};
+
+/** 'superclass' for referencable ontology objects */
+jOWL.Ontology.Thing = function(jnode){
+	this.parse(jnode);
+};
+
+jOWL.Ontology.Thing.prototype = {
+	jOWL : jOWL.version,
+	equals : function(id){
+		var URI = (typeof id == "string") ? jOWL.resolveURI(id) : id.URI;
+		return URI === this.URI;
+	},
+	/** Initialization */
+	parse : function(jnode){
+		if(!jnode.length){ return;}
+		var identifier;
+		if(typeof jnode == 'string'){
+			identifier = jnode;
+			jnode = $();
+			}
+		else {
+			identifier = jnode.RDF_ID() || jnode.RDF_About();
+			if(!identifier){identifier = "anonymousOntologyObject";
+			this.isAnonymous = true;
+			}
+		}
+		identifier = jOWL.resolveURI(identifier);
+		this.isExternal = jOWL.isExternal(identifier);
+		if(this.isExternal){this.baseURI = this.isExternal[0]; this.name = this.isExternal[1]; this.URI = this.baseURI+this.name;}
+		else { this.baseURI = jOWL.namespace; this.name = identifier; this.URI = this.name;}
+		this.jnode = jnode;
+		this.type = jnode.get(0).nodeName;
+	},
+	/** @return A jQuery array of elements matching the annotation (qualified name or annotation Property) */
+	annotations : function(annotation){
+		return jOWL.Xpath(annotation, this.jnode);
+	},
+	/** @return rdfs:comment annotations */
+	description : function(){
+		return $.map(this.annotations(__.rdfs('comment')), function(n){ return $(n).text();});
+	},
+	/**
+	@return Array of Arrays, where secondary array is of form: [0] = term (rdfs:label) , [1] = identifier, [2] = language; [3] = type of object
+	example:
+	[
+		["bleu", "blue", "fr", "owl:Class"]
+	]
+	*/
+	terms : function(){
+		var terms = [], self = this;
+		if(jOWL.options.dictionary.addID && this.name != "anonymousOntologyObject"){ terms.push([this.name.beautify(), this.URI, jOWL.options.defaultlocale, this.type]);}
+		this.annotations(__.rdfs('label')).each(function(){
+			var lbl = $(this);
+			var locale = lbl.xmlAttr("xml:lang") || jOWL.options.defaultlocale;
+			var txt = lbl.text();
+			var match = false;
+			for(var i =0;i<terms.length;i++){
+			if(terms[i][0].toUpperCase() == txt.toUpperCase() && terms[i][2] == locale){ match = true;}
+			}
+			if(!match){ terms.push([lbl.text(), self.URI, locale, self.type]);}
+		});
+		return terms;
+	},
+	/** @return A representation name */
+	label : function(){
+		var label = false;
+		this.annotations(__.rdfs('label')).each(function(){
+			var $label = $(this);
+			if(jOWL.options.locale){
+				var lang = $label.xmlAttr('xml:lang') || jOWL.options.defaultlocale;
+				if(lang == jOWL.options.locale){ label = $label.text(); return false;}
+			} else { label = $label.text(); return false;}
+		});
+		if(label){ return label;}
+		if(this.name == "anonymousOntologyObject"){ return jOWL.Manchester(this) || "anonymous Object";}
+		if(jOWL.options.niceClassLabels && (this.isClass || this.isThing)){
+			return this.name.beautify();
+		}
+		return this.name;
+	},
+	/** Binds the Ontology element to the jQuery element for visual representation 
+	* @return jQuery Element
+	*/
+	bind : function(jqelem){
+		return jqelem.text(this.label()).attr('typeof', this.type).attr('title', this.URI);
+	}
+};
+
+jOWL.Ontology.prototype = jOWL.Ontology.Thing.prototype;
+
+/** used for jOWL.Ontology.Individual.sourceof */
+jOWL.priv.testObjectTarget = function(target, matchtarget){
+	if(target.isArray){
+		for(var i=0;i<target.length;i++){
+			if(jOWL.priv.testObjectTarget(target.get(i), matchtarget)){ return true;}
+		}
+		return false;
+	}
+	//if the target is a class, fetch individuals instead.
+	else if(target.isClass){
+		 var a = target.individuals();
+		 for(var i=0;i<a.length;i++){
+			if(a.get(i).URI == matchtarget){ return true;}
+		}
+	}
+	else if(target.URI == matchtarget){ return true;}
+	return false;
+};
+
+/** access to Individuals of the ontology*/
+jOWL.Ontology.Individual = function(jnode, owlclass){	
+	this.parse(jnode);
+	if(this.type == __.owl("Thing")){
+	var t = jOWL.Xpath(__.rdf('type'), this.jnode);
+		if(!t.length){ throw "unable to find a Class for the Individual "+this.name;}
+		this.Class = $(t[0]).RDF_Resource();
+	}
+	else {
+		this.Class = jOWL.resolveURI(jnode.get(0));
+	}
+	this.type = __.owl("Thing");
+	if(owlclass){ this.owlClass(owlclass);}
+};
+
+jOWL.Ontology.Individual.prototype = $.extend({}, jOWL.Ontology.Thing.prototype, {
+	isThing : true,
+	/** @return The owl:Class */
+	owlClass : function(owlclass){
+		if(owlclass){ jOWL.data(this.name, "class", owlclass);}
+		else {
+			var cl = jOWL.data(this.name, "class");
+			if(!cl){ cl = jOWL(this.Class); if(cl){ this.owlClass(cl);} }
+			return cl;
+		}
+	},
+	/** Access to restrictions */
+	sourceof : function(property, target, options){
+		options = $.extend({
+			inherited : true, // add restrictions specified on parents as well
+			transitive : true,
+			ignoreGenerics : false, //if a parent has an identical property, with another target 'Thing', skip that restriction
+			ignoreClasses : true,
+			valuesOnly : true
+		}, options);
+
+		var results = new jOWL.Ontology.Array();
+
+		this.jnode.children().filter(function(){return (this.prefix != __.rdfs.prefix && this.prefix != __.rdf.prefix && this.prefix != __.owl.prefix);})
+			.each(function(){
+			var restriction = new jOWL.Ontology.Restriction($(this));
+			var propertyMatch = property ? false : true;
+			var targetMatch = target ? false : true;
+
+			if(!propertyMatch){
+				if( property.isArray){ propertyMatch = property.contains(restriction.property);}
+				else { propertyMatch = (property.URI == restriction.property.URI);}
+				if(!propertyMatch){ return;}
+			}
+
+			if(!target){
+				if(options.transitive && restriction.property.isTransitive && !options.ignoreGenerics){
+					var rTarget = restriction.getTarget();
+					var transitives = rTarget.sourceof(restriction.property, null, options);
+					results.concat(transitives);
+				}
+			}
+			else {
+				if(restriction.property.isObjectProperty){
+					targetMatch = jOWL.priv.testObjectTarget(target, restriction.target);
+					if(!targetMatch && options.transitive && restriction.property.isTransitive){
+						var rTransitives = restriction.getTarget().sourceof(restriction.property, target, options);
+						if(rTransitives.length > 0){ targetMatch = true;}
+					}
+				}
+				else if(restriction.property.isDatatypeProperty){
+					targetMatch = restriction.property.assert(restriction.target, target);
+				}
+				else { targetMatch = (target == restriction.target);}
+			}
+			if(propertyMatch && targetMatch){ results.pushUnique(restriction);}
+
+		});
+		if(options.inherited){ 
+			var clRestrictions = this.owlClass().sourceof(property, target, options)
+				.each(function(){
+				//target can be a class, null, a duplicate individual...
+				var clRestr = this;
+				if(options.valuesOnly && clRestr.target === null){return;}
+				var clTarget = this.getTarget();
+				if(clTarget.isClass && options.ignoreClasses){ return;}
+
+				var containsProperty = false;
+				for(var i = 0;i<results.length;i++){
+					var restr = results.get(i);
+					if(restr.property.URI == clRestr.property.URI){
+						containsProperty = true;
+						if(!options.ignoreGenerics){
+							if(clRestr.target != restr.target){ results.pushUnique(clRestr);}
+						}
+					}
+				}
+				if(!containsProperty){ results.pushUnique(clRestr);}
+			});
+		}
+		return results;
+
+	},
+	localRestrictions : function(property, target){
+		return this.sourceof(property, target, {inherited : false, transitive : false });
+	},
+	/** Include generic will add transitivity reasoning */
+	valueRestrictions : function(includeGeneric){
+		return this.sourceof(null, null, {ignoreGenerics : !includeGeneric, valuesOnly : true });
+	}
+});
+
+/** jNode is of type owl:Restriction */
+jOWL.Ontology.Restriction = function(jnode){
+
+	var jprop, prop, op, restrtype;
+
+	this.cachedTarget = null;
+
+	if(jnode.get(0).nodeName != __.owl("Restriction")){
+		this.property = jOWL(jOWL.resolveURI(jnode.get(0)), {type: "property"});
+		this.target = jnode.RDF_Resource() || jnode.text();
+		restrtype = "Individual";
+	}
+	else
+	{
+		jprop = jOWL.Xpath(__.owl("onProperty"), jnode);
+		prop = jprop.RDF_Resource(); if(!prop){ throw "no property found for the given owl:restriction";}
+		op = jprop.siblings(); 
+		restrtype = op.get(0).nodeName;
+		this.property = jOWL(prop, {type: "property"});
+		this.target = null; //string only
+	}
+
+	this.restriction = { minCard: false, maxCard : false, some: [], all : [], value : false };
+	this.type = jnode.get(0).nodeName;
+	this.isAnonymous = true;
+	this.isValueRestriction = (restrtype == __.owl('someValuesFrom') || restrtype == __.owl('allValuesFrom') || restrtype == __.owl('hasValue'));
+	this.isCardinalityRestriction = (restrtype == __.owl('cardinality') || restrtype == __.owl('maxCardinality') || restrtype == __.owl('minCardinality'));
+
+	if(!this.property || !restrtype){ throw "badly formed owl:restriction";}
+	switch(restrtype){
+		case __.owl('cardinality'): this.restriction.minCard = this.restriction.maxCard = parseInt(op.text(), 10); break;
+		case __.owl('maxCardinality'): this.restriction.maxCard = parseInt(op.text(), 10); break;
+		case __.owl('minCardinality'): this.restriction.minCard = parseInt(op.text(), 10); break;
+		case __.owl('hasValue'): var res = op.RDF_Resource(); if(res){ this.target = res;} break;
+	}
+	if(this.property.isObjectProperty){
+		if(this.isCardinalityRestriction && this.property.range){ this.target = this.property.range;}
+		else if(this.isValueRestriction){
+			var t = op.RDF_Resource(); 
+			if(t == "anonymousOntologyObject"){//nested groupings, anonymous classes
+				this.cachedTarget = new jOWL.Ontology.Class(jOWL.Xpath(__.owl("Class"), op));
+			}
+			this.target = t;
+		}
+	}
+
+	var suffix = this.target || this.restrtype;
+	this.name = this.property.name+'#'+suffix;
+	return this;
+};
+
+jOWL.Ontology.Restriction.prototype = {
+	jOWL : jOWL.version,
+	isRestriction : true,
+	bind : function(){return null;},
+	merge : function(crit){
+		if(this.isCardinalityRestriction && crit.isValueRestriction ){ this.target = crit.target; return true;}
+		else if(this.isValueRestriction && crit.isCardinalityRestriction){
+			switch(crit.restrtype){
+			case __.owl('cardinality'): this.restriction.minCard = this.restriction.maxCard = crit.restriction.minCard; return true;
+			case __.owl('minCardinality'): this.restriction.minCard = crit.restriction.minCard; return true;
+			case __.owl('maxCardinality'): this.restriction.maxCard = crit.restriction.maxCard; return true;
+			}
+		}
+		return false;
+	},
+	getTarget : function(){
+		if(!this.target){ return jOWL('Thing');}
+		if(this.cachedTarget){ return this.cachedTarget;}
+		this.cachedTarget = (this.property.isObjectProperty) ? jOWL(this.target) : new jOWL.Literal(this.target);
+		return this.cachedTarget;	
+	},
+	equals : function(restr){
+		if(!restr.isRestriction){ return false;}
+		if(this.property.URI == restr.property.URI){
+			if(this.target == 'anonymousOntologyObject'){return false;}//oneof lists etc unsupported right now
+			if(this.target && this.target === restr.target){ return true;}
+		}
+		return false;
+	}
+};
+
+/** Datatype Logic, local functions */
+jOWL.priv.Dt = function(options){
+	this.settings = $.extend({base: null, pattern : null, assert: function(b){return true;}, match: function(a, b){return true;}}, options);
+	this.base = jOWL.Ontology.Datatype[this.settings.base];
+};
+
+jOWL.priv.Dt.prototype = {
+	sanitize : function(b){
+		if(this.settings.sanitize){ return this.settings.sanitize(b);}
+		if(this.base && this.base.sanitize){ return this.base.sanitize(b);}
+	},
+	assert : function(b){
+		var v = this.sanitize(b); if(v !== undefined){ b = v;}
+		if(this.base && !this.base.assert(b)){ return false;}
+		if(this.settings.pattern && !this.settings.pattern.test(b)){ return false;}
+		return this.settings.assert(b);
+	},
+	match : function(a, b){
+		var v = this.sanitize(b); if(v !== undefined){ b = v;}
+		if(!this.assert(b)){ return false;}
+		if(this.base && !this.base.match(a, b)){ return false;}
+		return this.settings.match(a, b);
+	}
+};
+
+jOWL.Ontology.Datatype = function(URI, options){
+	jOWL.Ontology.Datatype[URI] = new jOWL.priv.Dt(options);
+};
+
+/** Datatype Definitions */
+jOWL.Ontology.Datatype(__.xsd()+"integer", {sanitize : function(x){return  parseInt(x, 10);}, assert : function(x){ return Math.round(x) == x;}, match : function(a, b){
+	var check = parseInt(a, 10);
+	if(!isNaN(check)){ return check == b;}
+	var arr = a.split('&&');
+	for(var i=0;i<arr.length;i++){ arr[i] = b+arr[i];}
+	try {
+		return eval(arr.join(' && '));
+	} catch(e){ return false;}
+} });
+jOWL.Ontology.Datatype(__.xsd()+"positiveInteger", {base: __.xsd()+"integer", assert : function(x){ return x > 0;} });
+jOWL.Ontology.Datatype(__.xsd()+"decimal", {base: __.xsd()+"integer" });
+jOWL.Ontology.Datatype(__.xsd()+"float", {base: __.xsd()+"integer" });
+jOWL.Ontology.Datatype(__.xsd()+"double", {base: __.xsd()+"integer" });
+jOWL.Ontology.Datatype(__.xsd()+"negativeInteger", {base: __.xsd()+"integer", assert : function(x){ return x < 0;} });
+jOWL.Ontology.Datatype(__.xsd()+"nonNegativeInteger", {base: __.xsd()+"integer", assert : function(x){ return x >= 0;} });
+jOWL.Ontology.Datatype(__.xsd()+"nonPositiveInteger", {base: __.xsd()+"integer", assert : function(x){ return x <= 0;} });
+jOWL.Ontology.Datatype(__.xsd()+"string");
+
+var URIPattern = /^([a-z0-9+.\-]+):(?:\/\/(?:((?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*)@)?((?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*)(?::(\d*))?(\/(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?|(\/?(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9A-F]{2})+(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?)(?:\?((?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*))?(?:#((?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*))?$/i;    
+
+jOWL.Ontology.Datatype(__.xsd()+"anyURI", {base: __.xsd()+"string", pattern : URIPattern });
+jOWL.Ontology.Datatype(__.xsd()+"boolean", {sanitize : function(x){
+		if(typeof x == 'boolean'){ return x;}
+		if(x == 'true'){ return true;}
+		if(x == 'false'){ return false;}
+	}, assert : function(x){
+		return typeof x == 'boolean';
+	}, match: function(a, b){
+		if(a === "false"){ a = false;}
+		if(a === "true"){ a = true;}
+		return (a === b);
+}});
+
+/** 'superclass' for Properties */
+jOWL.Ontology.Property = function(jnode){
+	var r = this.parseProperty(jnode);
+	if(r){ return r;}
+};
+
+jOWL.Ontology.Property.prototype = $.extend({}, jOWL.Ontology.Thing.prototype,{
+	isProperty : true,
+	parseProperty : function(jnode){
+		if(!jnode || typeof jnode == 'string'){
+			this.domain = this.range = null;
+			this.parse(jnode);
+			return;
+		}
+		if(jOWL.options.cacheProperties && jOWL.indices.IDs){
+			var res = jnode.RDF_ID() || jnode.RDF_About();
+			var c = jOWL.index('property').get(res);
+			if(c){ return c;}
+		}
+		this.parse(jnode);
+		this.domain= $(this.jnode.get(0).selectSingleNode(__.rdfs('domain'))).RDF_Resource();
+		this.range = $(this.jnode.get(0).selectSingleNode(__.rdfs('range'))).RDF_Resource();	
+	}
+});
+
+/** access to Datatype properties */
+jOWL.Ontology.DatatypeProperty = function(jnode){
+	var r = this.parseProperty(jnode);
+	if(r){ return r;}
+	if(this.type == __.owl("AnnotationProperty")){ this.range = __.xsd()+"string";}
+};
+
+jOWL.Ontology.DatatypeProperty.prototype = $.extend({}, jOWL.Ontology.Thing.prototype, jOWL.Ontology.Property.prototype, {
+	isDatatypeProperty : true,
+	/** check datatype values against this */
+	assert : function(targetValue, value){
+		var self = this;
+		var dt = jOWL.Ontology.Datatype[this.range];
+		if(!dt){
+			console.log(this.range+" datatype reasoning not implemented");
+			return true;
+		}
+		if(value === undefined){ return dt.assert(targetValue);}
+		else {return dt.match(value, targetValue);}
+	}
+});
+
+/** access to Object properties */
+jOWL.Ontology.ObjectProperty = function(jnode){
+	var r = this.parseProperty(jnode);	
+	if(r){ return r;}
+	var self = this;
+	jOWL.Xpath(__.rdf('type'), this.jnode).each(function(){
+		if($(this).RDF_Resource() == __.owl()+"TransitiveProperty"){ self.isTransitive = true;}
+	});
+	if(this.jnode.get(0).nodeName == __.owl("TransitiveProperty")){ self.isTransitive = true;}
+};
+
+jOWL.Ontology.ObjectProperty.prototype = $.extend({}, jOWL.Ontology.Thing.prototype, jOWL.Ontology.Property.prototype, {
+	isObjectProperty : true
+});
+
+/** access to an owl:Class */
+jOWL.Ontology.Class = function(jnode){
+	this.parse(jnode);
+};
+
+/** @return jOWL Array of Restrictions */
+jOWL.Xpath.restrictions = function(jnode){
+	var result = new jOWL.Ontology.Array();
+	jOWL.Xpath(__.rdfs("subClassOf")+"/"+__.owl("Restriction"), jnode)
+		.add(jOWL.Xpath(__.owl("intersectionOf")+"/"+__.owl("Restriction"), jnode))
+		.each(function(){
+			result.push(new jOWL.Ontology.Restriction($(this)));
+		});
+	return result;
+};
+
+/** Internal Use */
+jOWL.Ontology.Intersection = function(jnode){
+	var self = this;
+	this.jnode = jnode;
+	this._arr = [];
+	this.URI = this.jnode.parent().RDF_ID();
+	this.matches = {};
+	jOWL.Xpath(__.owl("Restriction"), jnode).each(function(){
+		var restr = new jOWL.Ontology.Restriction($(this));
+		if(restr.isValueRestriction){self._arr.push(restr);}
+	});
+	jOWL.Xpath(__.owl('Class'), jnode).each(function(){
+		var uri = $(this).RDF_About();
+		if(uri){ self._arr.push(jOWL(uri));}
+	});
+};
+
+jOWL.Ontology.Intersection.prototype = {
+	isIntersection : true,
+	jOWL : jOWL.version,
+	match : function(id, cls, clRestr){
+		if(id == this.URI){ return false;}
+		if(this.matches[id] !== undefined){ return this.matches[id]; }//local cache
+
+		for(var i =0;i<this._arr.length;i++){
+			var entry = this._arr[i];
+			var m = false;
+			if(entry.isRestriction){
+				clRestr.each(function(){
+					if(this.equals(entry)){ m = true; return false;}
+				});
+				if(!m) {
+					this.matches[id] = false;
+					return false;
+				}
+			} else if(entry.isClass){
+				for(var j = 0;j<cls.length;j++){
+					if(entry.equals(cls[j])){m = true; break;}
+					var it = jOWL.index('ID')[cls[j]];
+					if(it){
+						var narr = jOWL.Xpath.classes(jOWL.index('ID')[cls[j]].jnode);
+						for (var z=0;z<narr.length ; z++){
+							if(entry.equals(narr[z])){m = true; break;}
+						}
+					}
+				}
+				if(!m){
+					this.matches[id] = false;
+					return false;
+				}
+			}
+		}
+		this.matches[id] = true;
+		return this.matches[id];
+	},
+	equals : function(isect){
+		if(!isect.isIntersection){ return false;}
+			for(var i =0;i<this._arr.length;i++){
+				var match = false;
+				for(var j = 0;j<isect._arr.length;j++){
+					if(isect._arr[j].equals(this._arr[i])){ match = true;}
+				}
+				if(!match){ return false;}
+			}
+		return true;
+	}
+};
+
+jOWL.Ontology.Class.prototype = $.extend({}, jOWL.Ontology.Thing.prototype, {
+	isClass : true,
+	/** @return A jOWL.Ontology.Array of individuals for this class & its subclasses */
+	individuals : function(){
+		var arr = new jOWL.Ontology.Array();
+		var q = new jOWL.SPARQL_DL("Type(?x, "+this.name+")").execute({async: false, onComplete: function(r){ arr = r.jOWLArray("?x");}  });
+		return arr;
+	},
+	/** @return A jOWL.Ontology.Array of individuals (if oneOf list) */
+	oneOf : function(){
+		var arr = new jOWL.Ontology.Array();
+		var oneOf = this.jnode.children().filter(function(){return this.tagName == __.owl("oneOf");});
+		oneOf.children().each(function(){
+			arr.push(jOWL($(this).RDF_About()));
+		});
+		return arr;
+	},
+	/** @return A jOWL.Ontology.Array of direct children */
+	children : function(){
+		var that = this;
+		var oChildren = jOWL.data(this.name, "children");
+		if(oChildren){ return oChildren;}
+		oChildren = new jOWL.Ontology.Array();
+		if(this.oneOf().length){return oChildren;}
+		var URI = this.URI;
+
+		for(x in jOWL.index('ID')){
+			if(x === this.URI){ continue;}
+			var node = jOWL.index('ID')[x]; 
+			if(!node.isClass){continue;}
+			var cls = jOWL.Xpath.classes(node.jnode); //direct subClasses
+			for(var i=0;i<cls.length;i++){
+				if(this.equals(cls[i])){
+					oChildren.push(node);
+				}
+			}
+			var clRestr = jOWL.Xpath.restrictions(node.jnode);
+			var intersections = jOWL.index("intersection")[URI];
+			if(intersections){
+				intersections.each(function(){//fully defined Subclasses
+					if(this.match(x, cls, clRestr)){oChildren.push(node);}
+				});
+			}
+		}
+		//an ObjectProperty mentions this as domain
+		jOWL.index("property").each(function(){
+		if(this.domain == that.name){
+			var nodes = jOWL.Xpath('//'+__.owl('onProperty')+'[@'+__.rdf('resource')+'="#'+this.name+'"]/parent::'+__.owl('Restriction')+'/..');
+			nodes.filter(function(){ return (this.nodeName == __.owl('intersectionOf') || this.nodeName == __.rdfs('subClassOf'));
+			}).each(function(){
+				var cl = jOWL($(this.selectSingleNode('parent::'+__.owl('Class'))));
+				if(!oChildren.contains(cl) && cl.name != that.name && cl.name !== undefined){ oChildren.push(cl);}
+				});
+			}
+			});
+		//filter out redundancies
+		oChildren.filter(function(){
+			this.hierarchy(false);
+			return (this.parents().contains(URI));
+		});
+		jOWL.data(this.name, "children", oChildren);
+		return oChildren;
+	},
+	setParents : function(parents){
+		jOWL.data(this.name, "parents", parents); return parents;
+	},
+	/** @return A jOWL.Ontology.Array of parents, includes redundancies, to exclude do a hierarchy search first.*/
+	parents : function(){
+		var self = this;
+		var oParents = jOWL.data(this.name, "parents");
+		if(oParents){ return oParents;}
+
+		var temp = [];
+
+		var cls = jOWL.Xpath.classes(this.jnode);
+			for(var i=0;i<cls.length;i++){ jOWL.priv.Array.pushUnique(temp, cls[i]);}
+
+		var restr = jOWL.Xpath.restrictions(this.jnode);
+			restr.each(function(){
+				if(this.property.domain && this.property.domain != self.name){ jOWL.priv.Array.pushUnique(temp, this.property.domain);
+			}
+		});
+
+		var iSectLoop = function(){
+			if(this.match(self.URI, cls, restr)){
+				jOWL.priv.Array.pushUnique(temp, this.URI);
+			}
+		
+		};
+
+		if(jOWL.options.reason){
+			for(resource in jOWL.index('intersection')){
+				jOWL.index('intersection')[resource].each(iSectLoop);
+			}
+		}
+
+		oParents = new jOWL.Ontology.Array( jOWL.getXML(temp), true);
+		if(!oParents.length){ oParents.push(jOWL('Thing'));}
+		else if(oParents.length > 1){ oParents.filter(function(){return this.name != ('Thing');});} //Remove Thing reference if other parents exist
+		jOWL.data(this.name, "parents", oParents);
+		return oParents;
+	},
+/** @return ancestors to the class in a jOWL.Ontology.Array */
+	ancestors : function(){
+		return this.hierarchy(false).flatindex;
+	},
+/**
+Constructs the entire (parent) hierarchy for a class
+@return a jOWL.Ontology.Array containing top nodes (classes directly subsumed by 'owl:Thing')
+@param addInverse add a variable invParents (jOWL.Ontology.Array of child references) to each node with exception of the leaves (original concept)
+*/
+	hierarchy : function(addInverse){
+		var endNodes = new jOWL.Ontology.Array();
+		var self = this;
+		endNodes.flatindex  = new jOWL.Ontology.Array();
+
+		function URIARR(p_arr, obj){
+			var add = true;
+			if(!obj){ obj = {}; add = false;}
+			if(p_arr.each){
+				p_arr.each(function(){
+					if(obj[this.URI]){return;}
+					if(this.URI == __.owl()+'Thing'){ return;}
+					if(add){ obj[this.URI] = true;}
+					if(this.parents){ URIARR(this.parents(), obj);}
+				});
+			}
+			return obj;
+		}
+
+		function traverse(concept){
+			var parents = concept.parents();
+			if(parents.length == 1 && parents.contains(__.owl()+'Thing')){ endNodes.pushUnique(concept); return;}
+			else
+			{
+				var asso = jOWL.options.reason ? URIARR(parents) : {};
+				parents.filter(function(){ return (!asso[this.URI]);}); //throw out redundancies
+				parents.each(function(){
+						var item = endNodes.flatindex.pushUnique(this);
+						if(addInverse){
+							if(!item.invParents){ item.invParents = new jOWL.Ontology.Array();}
+							item.invParents.pushUnique(concept);
+							}
+						traverse(item);
+					});
+				concept.setParents(parents);
+			}
+		}
+
+		traverse(this);
+		return endNodes;
+
+	},
+	/**
+	@param level depth to fetch children, Default 5 
+	@return jOWL array of classes that are descendant
+	*/
+	descendants : function(level){
+		level = (typeof level == 'number') ? level : 5;
+		var oDescendants = jOWL.data(this.name, "descendants");
+		if(oDescendants && oDescendants.level >= level){ return oDescendants;}
+		oDescendants = new jOWL.Ontology.Array();
+		oDescendants.level = level;
+
+		function descend(concept, i){
+			if(i <= level){
+				i++;
+				var ch = concept.children();
+				oDescendants.concat(ch);
+				ch.each(function(item){ descend(item, i);});
+			}
+		}
+
+		descend(this, 1);
+		jOWL.data(this.name, "descendants", oDescendants);
+		return oDescendants;
+	},
+	/** @return jOWL.Array of Restrictions, target is an individual, not a class or undefined (unless includeAll is specified) - deprecated */
+	valueRestrictions : function(includeAll, array){
+		return this.sourceof(null, null, {ignoreClasses : !includeAll});
+	},
+	/**
+	get all restrictions that satisfy the arguments
+	@param property property or array of properties, or null
+	@param target class, individuals of array of them, or null
+	@return jOWL.Array of Restrictions
+	*/
+	sourceof : function(property, target, options){
+		options = $.extend({
+			inherited : true, // add restrictions specified on parents as well
+			transitive : true, //expand on transitive relations too
+			ignoreGenerics : true, //if a parent has an identical property, with another target 'Thing', skip that restriction
+			ignoreClasses : false, //only individuals should return
+			valuesOnly : true //do not return valueless criteria
+		}, options);
+		var self = this;
+		var crit = jOWL.data(this.name, "sourceof");
+		var jnode = this.jnode;
+
+		if(!crit){
+			crit = new jOWL.Ontology.Array();
+			var arr = jOWL.Xpath(__.rdfs("subClassOf")+"/"+__.owl("Restriction"), jnode)
+				.add(jOWL.Xpath(__.owl("intersectionOf")+"/"+__.owl("Restriction"), jnode));
+			arr.each(function(index, entry){
+			var cr = new jOWL.Ontology.Restriction($(entry));
+				var dupe = false;
+				crit.each(function(item, i){
+						if(this.property.name == cr.property.name){ dupe = item;}
+				});
+				if(dupe){ if(!dupe.merge(cr)){ crit.push(cr);} }
+				else { crit.push(cr);}
+			});
+			jOWL.data(self.name, "sourceof", crit);
+		}
+		var results = new jOWL.Ontology.Array();
+
+		crit.each(function(){
+
+			var propertyMatch = property ? false : true;
+			var targetMatch = target ? false : true;
+
+			if(!propertyMatch){
+				if(property.isArray){	propertyMatch = property.contains(this.property);}
+				else { propertyMatch = (property.URI == this.property.URI);}
+			}
+
+			if(!target){
+				if(options.transitive && this.property.isTransitive){ 
+					var rTarget = this.getTarget();
+					var transitives = rTarget.sourceof(this.property, null, options);
+					results.concat(transitives);
+				}
+			}
+
+			if(!targetMatch && !this.target){
+				targetMatch = !options.valuesOnly;
+			} 
+
+			if(!targetMatch){
+				var targ = this.getTarget();
+				if(targ.isClass && options.ignoreClasses){ return;}
+				targetMatch = jOWL.priv.testObjectTarget(target, this.target);
+				if(!targetMatch && options.transitive && propertyMatch && this.property.isTransitive){
+					if(targ.isThing){
+						if(targ.sourceof(property, target).length){ targetMatch = true;}
+					}
+				}
+			}
+
+			if(propertyMatch && targetMatch){ results.pushUnique(this);}
+		});
+
+		if(!options.inherited){ return results;}
+
+		this.parents().each(function(){ 
+			if(this.sourceof){
+				this.sourceof(property, target, options).each(function(parentsource){
+					var ptarget = this.getTarget();
+					var containsProperty = false; 
+					var tempArray = new jOWL.Ontology.Array();
+					results.filter(function(){
+						var restr = this, keep = true;
+						if(restr.property.URI == parentsource.property.URI){
+							containsProperty = true;
+							if(!options.ignoreGenerics){
+								if(parentsource.target != restr.target){ tempArray.push(parentsource);}
+							} else {
+								if(ptarget.isThing){
+									keep = restr.getTarget().isThing && parentsource.target != restr.target;
+									tempArray.push(parentsource);
+								}
+							}
+						}
+						return keep;
+					});
+					if(!containsProperty){ results.push(parentsource);}
+					results.concat(tempArray);
+				});
+			}
+		});
+		return results;
+	}
+});
+
+/** Utility object */
+jOWL.Ontology.Array = function(arr, isXML){
+	var self = this;
+	this.items = [];
+	if(arr){
+		if(isXML){ $.each(arr, function(){
+			var entry = this.jOWL ? this : jOWL($(this));
+			self.items.push(entry);}); 
+			}
+		else { this.items = arr;}
+	}
+	this.length = this.items.length;
+};
+
+jOWL.Ontology.Array.prototype = {
+	jOWL : jOWL.version,
+	isArray : true,
+	bind : function(listitem, fn){
+		return this.map(function(){
+			var syntax = listitem ? listitem.clone(true) : $('<span/>');
+			var html  = this.bind(syntax).append(document.createTextNode(' '));
+			if(fn){ fn.call(html, html, this);}
+			return html.get(0);
+		});
+	},
+	concat : function(arr, ignoreUnique){
+		var self = this;
+		if(arr.each){ arr.each(function(){
+			if(ignoreUnique){ self.push(this); }
+			else { self.pushUnique(this); }
+			});
+			}
+		else { self.items = self.items.concat(arr.items); this.length = self.items.length;}
+		return this;
+	},
+	contains : function(o){
+		return this.get(o) ? true: false;
+	},
+	each : function(fn, reverse){
+		var i, self = this;
+		var stop = false;
+		if(reverse){
+			for(i=this.items.length - 1; i>=0;i--){ 
+				if(stop){ break;}
+				(function(){
+					var item = self.eq(i); 
+					if(fn.call(item, item, i) === false){ stop = true;}
+				})();
+			}
+		}
+		else {
+			for(i=0;i<this.items.length;i++){
+				if(stop){ break;}
+				(function(){
+					var item = self.eq(i); 
+					if(fn.call(item, item, i) === false){ stop = true;}
+				})();} 
+		}
+		return this;
+	},
+	eq : function(index){
+		if(index < 0 || index > this.items.length -1){ return null;}
+		return this.items[index];
+	},
+	filter : function(fn){
+		var self = this;
+		this.each(function(item, i){
+			var q = fn.call(item, item, i);
+			if(!q){ self.items.splice(i, 1);}
+			}, true);
+		this.length = this.items.length;
+		return this;
+	},
+	getIndex : function(o){
+		var found  = -1;
+		if(o.equals){
+			this.each(function(a, i){
+				if(this.equals && this.equals(o)){ found = i; return false;}
+			});
+		}
+		else {
+			if(typeof o == 'number'){ return o;}
+			var name = typeof o == "string" ? o : o.name;
+			var URI = o.URI || name;
+
+			this.each(function(a, i){
+				if(this.URI){ if(this.URI == URI){ found = i;}}
+				else if(this.name == name){ found = i;}
+			});
+		}
+		return found;
+	},
+	get : function(o){
+		return this.eq(this.getIndex(o));
+	},
+	map : function(fn){
+		var arr = [];
+		this.each(function(){ arr.push(fn.call(this, this));});
+		return arr;
+	},
+	push : function(o){
+		this.items.push(o);
+		this.length = this.items.length;
+		return this;
+	},
+	pushUnique : function(o){
+		return this.get(o) || this.push(o).get(o);
+	},
+	toString : function(){
+		return this.map(function(){return this.URI;}).join(', ');
+	},
+	/** Convert this array into an associative array with key = URI */
+	associative : function(){
+		var arr = {};
+		this.each(function(){
+			if(this.URI){ arr[this.URI] = this;}
+		});
+		return arr;
+	}
+};
+
+
+jOWL.options = {reason: true, locale:false, defaultlocale: 'en',
+	dictionary : { create: true, addID : true },
+	onParseError : function(msg){alert("jOWL parseError: "+msg);}, cacheProperties : true, niceClassLabels : true};
+jOWL.document = null;
+jOWL.namespace = null;
+jOWL.indices = { //internal indices
+	P : null, //jOWL array
+	data : {},
+	IDs : null,
+	I : null, //Intersection
+	T : null, //Thing
+	D : null, //dictionary
+	reset : function(){var i = jOWL.indices; i.data = {}; i.P = null; i.T = null; i.IDs = null; i.I = null;i.D = null;}
+};
+
+jOWL.index = function(type, wipe){
+		var i = jOWL.indices;
+		switch (type)
+		{
+		/**jOWL indexes all elements with rdf:ID, and first order ontology elements specified with rdf:about 
+		@return Associative array with key = URI and value = jOWL object.
+		*/
+		case "ID":
+			if(i.IDs === null || wipe){
+				if(wipe){ i.reset();}
+				i.IDs = {};
+				i.T = {};
+				var start = new Date();
+
+				var rID = jOWL.Xpath("//*[@"+__.rdf("ID")+"]").each(function(){
+					var jowl = jOWL.getResource($(this)); 
+					if(jowl){
+						i.IDs[jowl.URI] = jowl;
+						if(jowl.isThing){
+							if(!i.T[jowl.Class]){ i.T[jowl.Class] = new jOWL.Ontology.Array();}
+							i.T[jowl.Class].push(jowl);
+						}
+					}
+				});
+
+				var rAbout = jOWL.Xpath("/"+__.rdf("RDF")+"/*[@"+__.rdf("about")+"]").each(function(){
+					var jnode = $(this);
+					var jowl = jOWL.getResource($(this));
+					if(!jowl){ return;}
+						if(jowl.isClass || jowl.isProperty || jowl.isThing){
+							if(i.IDs[jowl.URI]){ jnode.children().appendTo(i.IDs[jowl.URI].jnode); return;}
+							i.IDs[jowl.URI] = jowl; 
+							if(jowl.isThing){
+								if(!i.T[jowl.Class]){ i.T[jowl.Class] = new jOWL.Ontology.Array();}
+								i.T[jowl.Class].push(jowl);
+							}
+							return; 
+						}
+				});
+				console.log("Loaded in "+(new Date().getTime() - start.getTime())+"ms");
+				}
+			return i.IDs;
+		/** Generated together with ID index.
+		* @return Associative Array, key = class, value = jOWL Array of individuals.
+		*/
+		case "Thing":
+			return i.T;
+		case "intersection":
+			if(i.I === null || wipe){
+				var temp =  new jOWL.Ontology.Array();
+				i.I  = {};
+				jOWL.Xpath("//"+__.owl("intersectionOf")).each(function(){
+					var isect = new jOWL.Ontology.Intersection($(this));
+					if(!isect.URI){return;}
+					var dupe = temp.get(isect);
+					if(dupe){
+						console.log("duplicate intersection found between : (Ignoring) "+isect.URI+"  and "+dupe.URI);
+					} else {
+						if(!i.I[isect.URI]){i.I[isect.URI] = new jOWL.Ontology.Array();}
+						temp.push(isect);
+						i.I[isect.URI].push(isect);
+					}
+				});
+				}
+			return i.I;
+		case "property":
+			if(i.P === null || wipe)
+			{
+			jOWL.options.cacheProperties = false;
+			i.P = new jOWL.Ontology.Array();
+			for(x in i.IDs){
+				var jowl = i.IDs[x];
+				if(jowl.isProperty){ i.P.push(jowl);}
+			}
+			jOWL.options.cacheProperties = true;
+			}
+			return i.P;
+		case "dictionary":
+			/**Dictionary: Array of Arrays, where secondary array is of form: [0] = term, [1] = rdfID, [2] = locale */
+			if(i.D === null || wipe)
+			{
+				i.D = [];
+				for(x in i.IDs){
+					var entry = i.IDs[x];
+					i.D = i.D.concat(entry.terms());
+				}
+			}
+			return i.D;
+		}
+};
+
+/** Internal Function, storing data in associative array (JSON),
+jquery data function cannot be used as expando data does not work in IE for ActiveX XMLhttprequest*/
+jOWL.data = function(rdfID, dtype, data){
+	var d = jOWL.indices.data;
+	if(!d[rdfID]){ d[rdfID] = {};}
+	if(!data){ return d[rdfID][dtype];}
+	d[rdfID][dtype] = data;
+};
+
+/**
+* Initialize jOWL with an OWL-RDFS document.
+* @param path relative path to xml document
+* @param callback callback function to be called when loaded.
+* @options : optional settings:
+*	onParseError : function(msg){} function to ba called when parsing fails
+*	reason : true/false, turns on additional reasoning at the expense of performance
+*	locale: set preferred language (if available), examples en, fr...
+*/
+jOWL.load = function(path, callback, options){
+	var that = this;
+	if($.browser.msie && location.toString().indexOf('file') === 0){ //IE won't load local xml files otherwise
+		var xml = document.createElement("xml");
+		xml.validateOnParse = false; //IE throws DTD errors (for 'rdf:') on perfectly defined OWL files otherwise
+		xml.src = path;
+		xml.onreadystatechange = function(){
+			if(xml.readyState == "interactive"){ var xmldoc = xml.XMLDocument; document.body.removeChild(xml);callback(that.parse(xmldoc, options));}
+			};
+		document.body.appendChild(xml);
+		}
+	else {
+		$.get(path, function(xml){callback(that.parse(xml, options));});
+	}
+};
+
+/**
+* initialize jOWL with some OWL-RDFS syntax
+* @param doc Either an xmlString or an xmlDocument
+* @param options optional, onParseError(msg) : function to execute when parse fails
+* @returns false on failure, or the jOWL object
+*/
+jOWL.parse = function(doc, options){
+	jOWL.document = null;
+	this.options = $.extend(jOWL.options, options);
+	if(typeof doc == 'string'){ doc = jOWL.fromString(doc);}
+	jOWL.document = doc;
+	if($.browser.msie){
+		if(doc.parseError.errorCode !== 0){ jOWL.options.onParseError(doc.parseError.reason); return false;}
+		}
+	else if(doc.documentElement.nodeName == 'parsererror'){jOWL.options.onParseError(doc.documentElement.firstChild.nodeValue); return false;}
+	var root = $(doc.documentElement);
+	jOWL.NS(root);
+	if($.browser.msie){
+		jOWL.document.setProperty("SelectionLanguage", "XPath");
+		jOWL.document.setProperty("SelectionNamespaces", __());
+	}
+	this.index('ID', true);
+	if(jOWL.options.cacheProperties){ this.index('property', true);}
+	if(jOWL.options.dictionary.create){ jOWL.index("dictionary");}
+	jOWL.Thing = new jOWL.Ontology.Thing($(jOWL.create(__.owl, "Class").attr(__.rdf, 'about', __.owl()+'Thing').node)); 
+	jOWL.Thing.type = false;	
+	return this;
+};
+
+/**
+* A String representation of the OWL-RDFS document
+* @param xmlNode optional, node to generate a string from, when unspecified the entire document
+*/
+jOWL.toString = function(xmlNode){
+	if(!xmlNode){ return jOWL.toString(jOWL.document);}
+	if($.browser.msie){ return xmlNode.xml;}
+	return new XMLSerializer().serializeToString(xmlNode);// Gecko-based browsers, Safari, Opera.
+};
+
+/** create a document from string */
+jOWL.fromString = function(doc){
+	var owldoc;
+	if(document.implementation.createDocument){ owldoc = new DOMParser().parseFromString(doc, "text/xml");} // Mozilla and Netscape browsers
+	else if(window.ActiveXObject){ // MSIE
+		var xmldoc = new ActiveXObject("Microsoft.XMLDOM");
+		xmldoc.async="false";
+		xmldoc.validateOnParse = false;
+		xmldoc.loadXML(doc);
+		owldoc = xmldoc;
+		}
+	return owldoc;
+};
+
+/** @return false if belongs to this namespace, or an array with length two, arr[0] == url, arr[1] == id */
+jOWL.isExternal = function(resource){
+	var r = jOWL.resolveURI(resource, true);
+	return r[0] != jOWL.namespace ? r : false;
+};
+
+/** 
+if a URI belongs to the loaded namespace, then strips the prefix url of, else preserves URI 
+also able to parse and reference html (or jquery) elements for their URI.
+*/
+jOWL.resolveURI = function(URI, array){
+	if(typeof URI != "string"){
+		var node = URI.jquery ? URI.get(0) : URI;
+		URI = node.localName || node.baseName;
+		if(node.namespaceURI){ URI = node.namespaceURI + URI;}
+		return jOWL.resolveURI(URI, array);
+	}
+	var rs = URI, ns = jOWL.namespace;
+	if(URI.indexOf('http') === 0){
+		var tr = URI.indexOf('#');
+		if(tr <= 0){ tr = URI.lastIndexOf('/');}
+		if(tr > 0)
+		{
+			ns = URI.substring(0, tr+1);
+			rs = URI.substring(tr+1);
+		}
+	} else if(URI.charAt(0) == '#'){ return URI.substring(1);}
+	if(array){ return [ns, rs];}
+	if(ns == jOWL.namespace){ return rs;}
+	return URI;
+};
+
+/**
+Main method to get an Ontology Object, access via jOWL(>String>, options);
+resource: rdfID/rdfResource<String> or jQuery node.
+*/
+jOWL.getResource = function(resource, options){
+	if(!jOWL.document){ throw "You must successfully load an ontology before you can find anything";}
+	if(!resource){ throw "No resource specified";}
+	var node;
+	var opts = $.extend({}, options);
+	if(typeof resource == 'string'){
+		resource = jOWL.resolveURI(resource);
+		if(resource == 'Thing' || resource == __.owl()+'Thing'){ return jOWL.Thing;}
+		if(opts.type == 'property' && jOWL.options.cacheProperties){
+			var c = jOWL.index('property').get(resource);
+			if(c){ return c;}
+			if(jOWL.isExternal(resource)){ console.log("undeclared resource: "+resource); return new jOWL.Ontology.Property(resource);}
+			}
+		var match = jOWL.index("ID")[resource];
+		if(!match){ //try case insensitive
+			for(caseIns in jOWL.index("ID")){
+				if(caseIns.toLowerCase() == resource.replace(/ /g, "").toLowerCase()){ match = jOWL.index("ID")[caseIns]; break;}
+			}
+		}
+		if(!match){
+			if(jOWL.isExternal(resource)){
+				console.log("undeclared resource: "+resource);
+				return new jOWL.Ontology.Thing(resource);
+			}
+			console.log(resource+" not found"); 
+			return null; 
+		}
+		return match;
+	}
+	node = resource.jquery ? resource : $(resource);
+	var jj = jOWL.type(node); if(!jj){ return null;}
+	return new (jj)(node);
+};
+
+/** 
+* @param node jquery or html element.
+* @return the ontology type of the object.
+*/
+jOWL.type = function(node){
+	var xmlNode = node.jquery ? node.get(0) : node;
+	switch(xmlNode.nodeName){
+		case __.owl("Class") : return jOWL.Ontology.Class;
+		case __.rdfs("Class") : return jOWL.Ontology.Class; //test
+		case __.owl("Ontology") : return jOWL.Ontology;
+		case __.owl("ObjectProperty") : return jOWL.Ontology.ObjectProperty;
+		case __.owl("DatatypeProperty") : return jOWL.Ontology.DatatypeProperty;
+		case __.owl("FunctionalProperty") : return jOWL.Ontology.Property;
+		case __.rdf("Property") : return jOWL.Ontology.Property;
+		case __.owl("InverseFunctionalProperty") : return jOWL.Ontology.ObjectProperty;
+		case __.owl("TransitiveProperty") : return jOWL.Ontology.ObjectProperty;
+		case __.owl("SymmetricProperty") : return jOWL.Ontology.ObjectProperty;
+		//jOWL currently treats annotationproperties as string datatypeproperties.
+		case __.owl("AnnotationProperty") : return jOWL.Ontology.DatatypeProperty;
+		default :
+			switch(xmlNode.namespaceURI){
+				case __.owl(): if(xmlNode.nodeName == __.owl("Thing") ){ return jOWL.Ontology.Individual;} return false;
+				case __.rdf(): return false;
+				case __.rdfs(): return false;
+				default : return jOWL.Ontology.Individual;
+			}
+	}
+};
+
+/**
+@param rdfID <String> or Array<String>
+@return Array of DOM (xml) Nodes
+*/
+jOWL.getXML = function(rdfID){
+	var node = [];
+	function fetchFromIndex(rdfID){ 
+		var el = jOWL.index("ID")[rdfID];
+		return el ? el : null;
+	}
+
+	if(typeof rdfID == 'string'){ var q = fetchFromIndex(rdfID); if(q){ node.push(q);} }
+	else if(jOWL.priv.Array.isArray(rdfID)){ //assume an array of string rdfIDs
+		$.each(rdfID, function(){  
+			var el = fetchFromIndex(this); if(el){ node.push(el);}
+			});
+	}
+	return node;
+};
+
+/** Create new ontology elements */
+jOWL.create = function(namespace, name, document){
+	var doc = document ? document : jOWL.document;
+
+	var el = {
+		attr : function(namespace, name, value){
+			if($.browser.msie){
+				var attribute = doc.createNode(2, namespace(name), namespace());
+				attribute.nodeValue = value;
+				this.node.setAttributeNode(attribute);
+			}
+			else { this.node.setAttributeNS(namespace(), namespace(name), value);}
+			return this;
+		},
+		appendTo : function(node){
+			var n = node.node ? node.node : node;
+			n.appendChild(this.node);
+			return this;
+		},
+		text : function(text, cdata){
+			var txt = cdata ? doc.createCDATASection(text) : doc.createTextNode(text);
+			this.node.appendChild(txt);
+			return this;
+		}
+	};
+
+	if($.browser.msie){ el.node = doc.createNode(1, namespace(name), namespace());}
+	else { el.node = doc.createElementNS(namespace(), namespace(name));}
+	return el;
+};
+
+/** Create a blank ontology document */
+jOWL.create.document = function(href){
+	var owl = [];
+	var base = href || window.location.href+"#";
+	owl.push('<?xml version="1.0"?>');
+	owl.push('<'+__.rdf('RDF')+' xml:base="'+base+'" xmlns="'+base+'" '+__()+'>');
+	owl.push('   <'+__.owl('Ontology')+' '+__.rdf('about')+'=""/>');
+	owl.push('</'+__.rdf('RDF')+'>');
+	return jOWL.fromString(owl.join('\n'));
+};
+
+/** Extracts RDFa syntax from current page and feeds it to jOWL, simple implementation, only classes for the time being */
+jOWL.parseRDFa = function(fn, options){
+	var entries = options.node ? $("[typeof]", options.node) : $("[typeof]");
+	var doc = jOWL.create.document();
+
+	 function property(p, node){
+		var arr = [];
+		$("[property="+p+"]", node).each(function(){ arr.push($(this).attr('content') || $(this).html());});
+		if(node.attr('property') === p){ arr.push(node.attr('content') || node.html());}
+		return arr;
+	}
+
+	function rel(p, node){
+		var arr = [];
+		$("[rel="+p+"]", node).each(function(){ arr.push($(this).attr('resource'));});
+		if(node.attr("rel") === p){ arr.push(node.attr('resource'));}
+		return arr;
+	}
+
+	function makeClass(node, ID){
+		var cl = jOWL.create(__.owl, "Class", doc).attr(__.rdf, 'about', ID).appendTo(doc.documentElement);
+
+		var parents = property(__.rdfs("subClassOf"), node).concat(rel(__.rdfs("subClassOf"), node));
+		for(var i = 0;i<parents.length;i++){
+			var p = jOWL.create(__.rdfs, "subClassOf", doc).attr(__.rdf, "resource", parents[i]).appendTo(cl);
+		}
+		return cl;
+	}
+
+	entries.each(function(){
+		var node = $(this);
+		var type = node.attr("typeof"), el;
+
+		if(type == __.owl("Class")){ el = makeClass(node, jOWL.resolveURI(node.attr("about")));}
+
+		$.each(property(__.rdfs('comment'), node), function(){
+			jOWL.create(__.rdfs, "comment", doc).appendTo(el).text(this, true);
+		});
+
+		$.each(property(__.rdfs('label'), node), function(){
+			jOWL.create(__.rdfs, "label", doc).appendTo(el).text(this);
+		});
+	});
+	jOWL.parse(doc, options);
+	fn();
+};
+
+/**
+Match part or whole of the rdfResource<String>
+Used for term searches, intend to (partially) replace it by a sparql-dl query later on
+options:
+    filter: filter on a specific type, possible values: Class, Thing, ObjectProperty, DatatypeProperty
+    exclude: exclude specific types, not fully implemented
+*/
+jOWL.query = function(match, options){
+	options = $.extend({exclude : false}, options);
+	if(options.filter == 'Class'){ options.filter = __.owl("Class");}
+	var that = this;
+	//filter : [], exclude : false
+	var items = new jOWL.Ontology.Array();
+	var jsonobj = {};
+	var test = jOWL.index("dictionary");
+
+	function store(item){
+			var include = false, i = 0;
+			if(options.filter){
+				if(typeof options.filter == 'string'){ include = (options.filter == item[3]);}
+				else { for(i = 0;i<options.filter.length;i++){ if(options.filter[i] == item[3]){ include = true;} } }
+				}
+			else if(options.exclude){
+				include = true;
+				if(typeof options.exclude == 'string'){ include = (options.exclude !== item[3]);}
+				else { for(i = 0;i<options.exclude.length;i++){ if(options.exclude[i] == item[3]){ include = false;} } }
+			}
+			else { include = true;}
+			if(!include){ return;}
+			if(!jsonobj[item[1]]){ jsonobj[item[1]] = [];}
+			jsonobj[item[1]].push( { term : item[0], locale: item[2], type: item[3] });
+	}
+
+	for(var y = 0;y<test.length;y++){
+		var item = test[y];
+		var bool = options.exclude;
+		var r = item[0].searchMatch(match);
+		if(r > -1){
+			if(options.locale){ if(options.locale == item[2]){ store(item);} }
+			else { store(item);}
+		}
+	}
+	return jsonobj;
+};
+
+/**
+allows asynchronous looping over arrays (prevent bowser freezing).
+arr the array to loop asynchonrously over.
+options.modify(item) things to do with each item of the array
+options.onUpdate array the size of chewsize or smaller, containing processed entries
+options.onComplete(array of results) function triggered when looping has completed
+*/
+jOWL.throttle =function(array, options){
+	options = $.extend({
+		modify : function(result){},
+		//onUpdate : function(arr){},
+		onComplete : function(arr){},
+		async : true,
+		chewsize : 5,
+		startIndex : 0,
+		timing : 5
+		}, options);
+	var temp = array.jOWL ? array.items : (array.jquery) ? $.makeArray(array) : array;
+	var items = options.startIndex ? temp.slice(startIndex) : temp.concat(); //clone the array
+	var results = [];
+
+	(function(){
+		var count = options.chewsize;
+		var a = [];
+		while (count > 0 && items.length > 0)
+		{
+			var item = items.shift(); count--;
+			var result = options.modify.call(item, item);
+			if(result){ results.push(result); a.push(result);}
+		}
+		if(options.onUpdate){ options.onUpdate(a);}
+
+		if(items.length> 0){
+			if(options.async){ setTimeout(arguments.callee, options.timing);}
+			else {arguments.callee();}
+		}
+		else{ options.onComplete(results);}
+	})();
+};
+
+/** Creates a new resultobj for the SPARQL-DL functionality */
+jOWL.SPARQL_DL_Result = function(){
+	this.assert = undefined;
+	this.head = {}; //associative array of query parameters, with value jOWL Array of results
+	this.results = []; //sparql-dl bindings
+	this.isBound = false;
+};
+
+jOWL.SPARQL_DL_Result.prototype = {
+	sort : function(param){
+		if(!param){ throw "parameter must be defined for sort function";}
+		function sortResults(a, b){
+			var o = a[param].name || a[param];
+			var p = b[param].name || b[param];
+			return (o < p) ? -1 : 1;
+		}
+		if(this.results){ this.results.sort(sortResults); }
+	},
+	jOWLArray : function(param){
+		if(!param){ throw "parameter must be defined for jOWLArray function";}
+		var arr = new jOWL.Ontology.Array();
+		for(var i=0;i<this.results.length;i++){
+		if(this.results[i][param]){ arr.pushUnique(this.results[i][param]);}
+		}
+		return arr;
+	},
+	/** Filter head Parameters */
+	filter : function(param, arr){
+		if(this.head[param] === undefined){this.head[param] = arr;}
+		else {
+			var self = this; 
+			this.head[param].filter(function(){ return (arr.contains(this));});
+			arr.filter(function(){ return (self.head[param].contains(this));});
+		}
+	},
+	/** Update result section, results = SPARQL_DL_Array */
+	bind : function(results){
+		if(!this.isBound){//new results
+			this.results = this.results.concat(results.arr);
+			this.isBound = true;
+			return;
+		}
+		var multimapping = -1;
+		for(x in results.mappings){ multimapping++; }
+		var toAdd = [];
+
+		for(x in results.mappings){
+			var otherKeys;
+			if(multimapping){
+				otherKeys = results.keyCentric(x);
+			}
+			for(var i = this.results.length-1;i>=0;i--){
+				var valueX = this.results[i][x];
+				if(valueX){
+					if(!results.mappings[x].contains(valueX)){
+						this.results.splice(i, 1);
+						continue;
+					}
+					if(multimapping){
+						var keyArr= otherKeys[valueX.URI];
+						//ignoring the opposite for now (assuming original key x is unique (limits statements))
+						//TODO: improve these result merging methods/flexibility
+						for(var oK = 0; oK < keyArr.length;oK++){
+							var obj = (oK === 0) ? this.results[i] : {};
+							var valueY = keyArr[oK];
+							obj[x] = valueX;
+							for(yK in valueY){ obj[yK] = valueY[yK]; }
+							toAdd.push(obj);
+						}
+						this.results.splice(i, 1);
+					}
+				}
+			}
+		}
+		this.results = this.results.concat(toAdd);
+	}
+};
+/** Creates a new query for the SPARQL-DL functionality */
+jOWL.SPARQL_DL_Query = function(syntax, parameters){
+		this.parse(syntax);
+		this.fill(parameters);
+		this.entries = this.entries.sort(this.sort);
+};
+
+jOWL.SPARQL_DL_Query.prototype = {
+	parse : function(syntax){
+		 var r2 = /(\w+)[(]([^)]+)[)]/;
+		 var entries = syntax.match(/(\w+[(][^)]+[)])/g);
+		 if(!entries){ this.error =  "invalid abstract sparql-dl syntax"; return;}
+		 entries = jOWL.priv.Array.unique(entries);
+		 for(var i = 0;i<entries.length;i++){
+			var y = entries[i].match(r2);
+			if(y.length != 3){ this.error = "invalid abstract sparql-dl syntax"; return;}
+			entries[i] = [y[1], y[2].replace(/ /g, "").split(',')];
+		 }
+		 this.entries = entries;
+	},
+	fill : function(parameters){
+		for(var i = 0;i<this.entries.length;i++){
+			for(var j =0; j<this.entries[i][1].length; j++){
+				var p = parameters[this.entries[i][1][j]];
+				if(p !== undefined)  { this.entries[i][1][j] = p;}
+				else {
+					p = this.entries[i][1][j];
+					if(p.charAt(0) != '?')
+					{
+						if(this.entries[i][0] == "PropertyValue" && j == 2)
+						{
+						var m = p.match(/^["'](.+)["']$/);
+						if(m && m.length == 2){ this.entries[i][1][j] = {test: m[1]}; break;}
+						}
+					this.entries[i][1][j] = jOWL(p);
+					if(this.entries[i][1][j] === null){this.entries.error = "a parameter in the query was not found"; return;}
+					}
+				}
+			}
+		}
+	},
+	sort : function(a, b){
+		var i;
+		if(a[1].length == 1){ return (b[0] == 'PropertyValue') ? 1 : -1;}
+		if(b[1].length == 1){ return (a[0] == 'PropertyValue') ? -1 : 1;}
+		var avar = 0; for(i = 0;i<a[1].length;i++){ if(typeof a[1][i] == 'string'){ avar++;} }
+		var bvar = 0; for(i = 0;i<a[1].length;i++){ if(typeof b[1][i] == 'string'){ bvar++;} }
+		if(avar != bvar){ return avar - bvar;}
+		if(a[0] == 'Type' && b[0] != 'Type'){ return -1;}
+		if(a[0] != 'Type' && b[0] == 'Type'){ return 1;}
+		return 0;
+	}
+};
+
+/** Private function */
+function _Binding(bindingarray){
+	this.value = {};
+	this.arr = bindingarray;
+}
+
+_Binding.prototype = {
+	bind : function(key, value){
+		this.value[key] = value;
+		if(!this.arr.mappings[key]){ this.arr.mappings[key] = new jOWL.Ontology.Array();}
+		this.arr.mappings[key].push(value);
+		return this;
+	}
+};
+
+/** Local Function, private access, Temp results */
+function SPARQL_DL_Array(keys){	
+	this.arr = [];
+	this.mappings = {};
+
+	if(keys){
+		for(var i =0;i<keys.length;i++){
+			if(keys[i]){this.mappings[keys[i]] = new jOWL.Ontology.Array();}
+		}
+	}
+}
+
+SPARQL_DL_Array.prototype = {
+	add : function(binding){
+		this.arr.push(binding.value);
+		return binding;
+	},
+	push : function(key, value){
+		var binding = new _Binding(this);
+		binding.bind(key, value);
+		this.arr.push(binding.value);
+		return binding;
+	},
+	keyCentric : function(keyX){
+		var arr = {};
+		for(var i = this.arr.length-1;i>=0;i--){
+			if(this.arr[i][keyX]){
+				if(!arr[this.arr[i][keyX].URI]){ arr[this.arr[i][keyX].URI] = []; }
+				arr[this.arr[i][keyX].URI].push(this.arr[i]);
+			}
+		}
+		return arr;
+	},
+	get : function(key)
+	{
+		return (this.mappings[key]) ? this.mappings[key] : new jOWL.Ontology.Array();
+	},
+	getArray : function(){
+		//check mappings for presence, discard arr entries based on that, return remainder.
+		for(var i = this.arr.length - 1;i>=0;i--){
+			var binding = this.arr[i], splice = false;
+			for(key in binding){
+				if(!splice){
+					splice = (!this.mappings[key] || !this.mappings[key].contains(binding[key]));
+				}
+			}
+			if(splice){
+				this.arr.splice(i, 1);
+			}
+		}
+		return this;
+	}
+};
+
+/**
+Support for abstract SPARQl-DL syntax
+options.onComplete: function triggered when all individuals have been looped over
+options.childDepth: depth to fetch children, default 5, impacts performance
+options.chewsize: arrays will be processed in smaller chunks (asynchronous), with size indicated by chewsize, default 10
+options.async: default true, query asynchronously
+parameters: prefill some sparql-dl parameters with jOWL objects
+execute: start query, results are passed through options.onComplete
+*/
+jOWL.SPARQL_DL = function(syntax, parameters, options){
+	if(!(this instanceof arguments.callee)){ return new jOWL.SPARQL_DL(syntax, parameters, options);}
+	var self = this;
+	this.parameters = $.extend({}, parameters);
+	this.query = new jOWL.SPARQL_DL_Query(syntax, this.parameters).entries;
+	this.result = new jOWL.SPARQL_DL_Result();
+	this.options = $.extend({onComplete: function(results){}}, options);
+};
+
+jOWL.SPARQL_DL.prototype = {
+	error: function(msg){ this.result.error = msg; return this.options.onComplete(this.result);},
+	/**
+	if(options.async == false) then this method returns the result of options.onComplete,
+	no matter what, result is always passed in options.onComplete
+	*/
+	execute : function(options){
+		var self = this;
+		this.options = $.extend(this.options, options);
+		if(this.query.error){ return this.error(this.query.error);}
+		
+		var resultobj = this.result;
+		var i = 0;  
+		var loopoptions = $.extend({}, this.options);
+		loopoptions.onComplete = function(results){ i++; resultobj = results; loop(i);};
+		
+		if(!this.query.length){
+			resultobj.error = "no query found or query did not parse properly";
+			return self.options.onComplete(resultobj);
+			}  
+			
+		function loop(i){
+			if(i < self.query.length){
+				self.process(self.query[i], resultobj, loopoptions );
+				}
+			else {
+				for(var j =0;j<resultobj.results.length;j++){ //Convert Literals into strings
+					var b = resultobj.results[j];
+					for(x in b){
+						if(b[x] instanceof jOWL.Literal){b[x] = b[x].name;}
+					}
+				}
+				return self.options.onComplete(resultobj);
+			}
+		} 
+		loop(i);
+	},
+	/** results are passed in the options.onComplete function */
+	process: function(entry, resultobj, options){
+		var self = this;
+		options = $.extend({chewsize: 10, async : true, onComplete : function(results){}}, options);
+		var q = entry[0];
+		var sizes = {
+			"Type": [__.owl('Thing'), __.owl('Class')],
+			"DirectType": [__.owl('Thing'), __.owl('Class')],
+			"PropertyValue" : [false, false, false],
+			"Class": [false],
+			"Thing": [false],
+			"ObjectProperty": [false],
+			"DatatypeProperty": [false],
+			"SubClassOf" : [__.owl('Class'), __.owl('Class')],
+			"DirectSubClassOf" : [__.owl('Class'), __.owl('Class')]
+			};
+		
+		if(!sizes[q]){ return self.error("'"+q+"' queries are not implemented");}
+		if(sizes[q].length != entry[1].length){ return self.error("invalid SPARQL-DL "+q+" specifications, "+sizes[q].length+" parameters required");}
+		for(var i = 0;i<entry[1].length;i++){
+			var v = sizes[q][i];
+			if(v){
+				var m = entry[1][i];
+				if(typeof m != 'string' && m.type != v){ return self.error("Parameter "+i+" in SPARQL-DL Query for "+q+" must be of the type: "+v);}
+			}
+		}
+		if(q == "DirectType"){ options.childDepth = 0; return self.fn.Type.call(self, entry[1], resultobj, options);}
+		else if(q == "DirectSubClassOf"){ options.childDepth = 1; return self.fn.SubClassOf.call(self, entry[1], resultobj, options);}
+		return self.fn[q].call(self, entry[1], resultobj, options);
+	},
+	fn : {
+			"SubClassOf" : function(syntax, resultobj, options){
+				var atom = new jOWL.SPARQL_DL.DoubleAtom(syntax, resultobj.head);
+				var results = new SPARQL_DL_Array();
+
+				if(atom.source.isURI() && atom.target.isURI()){//assert
+					if(resultobj.assert !== false){
+						var parents = atom.source.value.ancestors();
+						resultobj.assert = parents.contains(atom.target.value);
+					}
+					return options.onComplete(resultobj);
+				}
+				else if(atom.source.isURI()){//get parents
+					atom.source.value.ancestors().each(function(){
+						results.push(atom.target.value, this);
+						});
+					resultobj.filter(atom.target.value, results.get(atom.target.value));
+					resultobj.bind(results.getArray());
+					return options.onComplete(resultobj);
+				}
+				else if(atom.target.isURI()){//get children
+					atom.target.value.descendants(options.childDepth).each(function(){
+						results.push(atom.source.value, this);
+						});
+					resultobj.filter(atom.source.value, results.get(atom.source.value));
+					resultobj.bind(results.getArray());
+					return options.onComplete(resultobj);
+				}
+				else{//both undefined
+					return this.error('Unsupported SubClassOf query');
+				}
+			},
+			"Type" : function(syntax, resultobj, options){
+				var atom = new jOWL.SPARQL_DL.DoubleAtom(syntax, resultobj.head);
+			
+			function addIndividual(cl){
+				if(indivs[this.URI]){ return;}
+				var b = results.push(atom.source.value, this);
+				if(addTarget){  b.bind(atom.target.value, cl);}
+				indivs[this.URI] = true;
+			}
+
+			function traverse(node, match){
+					var a = node.parents();
+					var found = false;
+					if(a.contains(match)){ found = true;}
+					else { 
+						a.each(function(){
+							if(this == jOWL.Thing){ return;}
+							if(!found && traverse(this, match)){ found = true;} });
+						}
+					return found;
+				}
+				
+				if(atom.source.isURI() && atom.target.isURI()){//assert
+					return jOWL.SPARQL_DL.priv.assert(resultobj, function(){
+						var cl = atom.source.value.owlClass();
+						if(cl.URI == atom.target.value.URI){ return true;}
+						return traverse(cl, atom.target.value); 
+					}, options.onComplete);
+				}
+				else if(atom.source.getURIs() && !atom.target.getURIs()){//get class
+					var results = new SPARQL_DL_Array();
+					var addSource = !atom.source.isURI();
+					var addTarget = !atom.target.isURI();
+					 atom.source.getURIs().each(function(){
+						var b;
+						if(addTarget){ b = results.push(atom.target.value, this.owlClass());}
+						if(addSource){ 
+							if(addTarget){ b.bind(atom.source.value, this);}
+							else {results.push(atom.source.value, this);}
+						}
+					 });
+					if(addSource){  resultobj.filter(atom.source.value, results.get(atom.source.value));}
+					if(addTarget){  resultobj.filter(atom.target.value, results.get(atom.target.value));}
+					resultobj.bind(results.getArray());
+					return options.onComplete(resultobj);
+				}
+				else if(atom.target.getURIs()){//get Individuals, slow
+					var addTarget = !atom.target.isURI();
+					var classlist = atom.target.getURIs(),
+						classes = {}, indivs = {};
+
+						var results = new SPARQL_DL_Array();
+
+
+						classlist.each(function(){ //expand list of classes, not very fast!
+							if(classes[this.URI]){ return;}
+							var oneOf = this.oneOf(), cl = this;
+							if(oneOf.length){ oneOf.each(function(){ addIndividual.call(this, cl);});}
+							else{ this.descendants(options.childDepth).each(function(){ //this is the slower call
+								classes[this.URI] = true;
+							}); }
+							classes[this.URI] = true;
+						});
+
+						for(x in classes){
+							var individuals = jOWL.index("Thing")[x];
+							if(individuals){
+								var cl = jOWL.index('ID')[x];
+								if(options.onUpdate){ options.onUpdate(individuals);}
+								individuals.each(function(){
+									addIndividual.call(this, cl);
+								});
+							}
+						}
+						resultobj.filter(atom.source.value, results.get(atom.source.value));
+						resultobj.bind(results.getArray());
+						return options.onComplete(resultobj);
+				}
+				return this.error('Unsupported Type query');
+			},
+			"Thing" : function(syntax, resultobj, options){
+				jOWL.SPARQL_DL.priv.IDQuery(syntax[0], "isThing", resultobj, options);
+			},
+			"Class" : function(syntax, resultobj, options){ console.log('cl');
+				jOWL.SPARQL_DL.priv.IDQuery(syntax[0], "isClass", resultobj, options);
+			},
+			"ObjectProperty" : function(syntax, resultobj, options){
+				jOWL.SPARQL_DL.priv.PropertyQuery(syntax[0], jOWL.index("property").items, "isObjectProperty", resultobj, options);
+			},
+			"DatatypeProperty" : function(syntax, resultobj, options){
+				jOWL.SPARQL_DL.priv.PropertyQuery(syntax[0], jOWL.index("property").items, "isDatatypeProperty", resultobj, options);
+			},
+			"PropertyValue" : function(syntax, resultobj, options){
+				var atom = new jOWL.SPARQL_DL.TripleAtom(syntax, resultobj.head);
+				
+				if(atom.source.isURI() && atom.property.isURI() && atom.target.isURI()){//assert
+					if(resultobj.assert !== false){
+						jOWL.SPARQL_DL.priv.PropertyValuegetSourceInfo(atom.source.value, atom.property.value, atom.target.value, resultobj, { assert : true });
+					}
+					return options.onComplete(resultobj);
+				}
+
+				if(!atom.source.getURIs()){
+					jOWL.SPARQL_DL.priv.IDQuery(atom.source.value, ["isClass", "isThing"], resultobj, options);
+					return;
+				}
+				var filterTarget = atom.target.isVar() ? atom.target.value : false;
+				var filterProperty = atom.property.isVar() ? atom.property.value : false;
+				var filterSource = atom.source.isVar() ? atom.source.value : false;
+				jOWL.SPARQL_DL.priv.PropertyValuegetSourceInfo(atom.source.getURIs(), atom.property.getURIs(), atom.target.getURIs(), resultobj,
+					{
+						filterTarget : filterTarget, filterProperty : filterProperty, filterSource : filterSource
+					});
+				return options.onComplete(resultobj);
+			}
+		}
+};
+
+jOWL.SPARQL_DL.priv = {
+	assert : function(resultobj, fn, onComplete){
+		if(resultobj.assert !== false){
+			resultobj.assert = fn();
+		}
+		onComplete(resultobj);	
+	},
+	//reusable function
+	PropertyValuegetSourceInfo : function(jSource, property, target, resultobj, options){
+		if(!(jSource.isArray)){
+			return jOWL.SPARQL_DL.priv.PropertyValuegetSourceInfo(new jOWL.Ontology.Array([jSource]), property, target, resultobj, options);
+		}
+		
+		options = $.extend({}, options);
+		var results = new SPARQL_DL_Array([options.filterSource, options.filterProperty, options.filterTarget]), 
+			match = false;
+		jSource.each(function(){
+			var source = this;
+			if(target && target.isArray && target.length == 1){
+				var literal = target.get(0).test;
+				if(literal){ target = literal;}//unwrap literal expressions
+			}
+			var restrictions = source.sourceof(property, target);
+			if(options.assert){
+				if(restrictions.length > 0){ match = true;}
+				return;
+			}
+			if(!restrictions.length){ return;}
+			restrictions.each(function(){
+				var binding = new _Binding(results);
+				if(options.filterSource){
+					binding.bind(options.filterSource, source);
+					if(!options.filterProperty && !options.filterTarget){ results.add(binding); return false;}
+				}
+				if(options.filterProperty){
+					binding.bind(options.filterProperty, this.property);
+				}
+				if(options.filterTarget){
+					binding.bind(options.filterTarget, this.getTarget());
+				}
+				results.add(binding);
+			});
+			return true;
+		});
+		if(options.assert){
+			resultobj.assert = match;
+			return resultobj.assert;
+		}
+		if(options.filterSource){ resultobj.filter(options.filterSource, results.get(options.filterSource));}
+		if(options.filterProperty){ resultobj.filter(options.filterProperty, results.get(options.filterProperty));}
+		if(options.filterTarget)  { resultobj.filter(options.filterTarget, results.get(options.filterTarget));}
+		resultobj.bind(results.getArray());
+	},
+	hasClassID: function(match, classID){
+		if(Object.prototype.toString.call(classID) === '[object Array]'){
+			for(var i =0;i<classID.length;i++){
+				if(match[classID]){ return true;}
+			}
+		} else if(match[classID]){  return true;}
+		return false;	
+	},
+	IDQuery : function(parameter, classID, resultobj, options){
+		var atom = new jOWL.SPARQL_DL.Atom(parameter, resultobj.head);
+		if(atom.isURI()){
+			return jOWL.SPARQL_DL.priv.assert(resultobj, function(){
+				return jOWL.SPARQL_DL.priv.hasClassID(atom.getURIs().get(0), classID);
+			}, options.onComplete);
+		}
+		var results = new SPARQL_DL_Array();
+		for(x in jOWL.index("ID")){
+			var match = jOWL.index("ID")[x];
+			if(jOWL.SPARQL_DL.priv.hasClassID(match, classID)){ results.push(parameter, match);}
+		}
+		resultobj.filter(parameter, results.get(parameter));
+		resultobj.bind(results.getArray());
+		options.onComplete(resultobj);
+	},
+	PropertyQuery : function(parameter, index, className, resultobj, options){
+		var atom = new jOWL.SPARQL_DL.Atom(parameter, resultobj.head);
+		if(atom.isURI()){
+			return jOWL.SPARQL_DL.priv.assert(resultobj, function(){
+				return jOWL.SPARQL_DL.priv.hasClassID(atom.getURIs().get(0), className);
+			}, options.onComplete);
+		}
+		var results = new SPARQL_DL_Array();
+		var tr = new jOWL.throttle(index, $.extend({}, options, {
+			modify : function(result){
+				if(!result.jOWL){ result = jOWL(result);}
+				if(jOWL.SPARQL_DL.priv.hasClassID(result, className)){results.push(parameter, result);}
+				return false;
+			},
+			onComplete : function(){
+				resultobj.filter(parameter, results.get(parameter));
+				resultobj.bind(results.getArray());
+				options.onComplete(resultobj);
+			}
+		}));
+	}
+};
+
+jOWL.SPARQL_DL.TripleAtom = function(syntax, store){
+	this.source = new jOWL.SPARQL_DL.Atom(syntax[0], store);
+	this.property = new jOWL.SPARQL_DL.Atom(syntax[1], store);
+	this.target = new jOWL.SPARQL_DL.Atom(syntax[2], store);
+};
+
+jOWL.SPARQL_DL.DoubleAtom = function(syntax, store){
+	this.source = new jOWL.SPARQL_DL.Atom(syntax[0], store);
+	this.target = new jOWL.SPARQL_DL.Atom(syntax[1], store);
+};
+
+
+jOWL.SPARQL_DL.Atom = function(syntax, store){
+	this.value = syntax;
+	this.type = 0;
+	if(typeof syntax == 'string'){
+		if(syntax.indexOf('?') === 0){
+			this.type = this.VAR;
+			if(store && store[syntax]){ this.mappings = store[syntax];}
+		} else {
+			this.type = this.LITERAL;
+		}
+	} else {
+		this.type = this.URI;
+	}
+};
+
+jOWL.SPARQL_DL.Atom.prototype = {
+	URI : 1, LITERAL : 2, VAR : 3,
+	getURIs : function(){
+		if(this.isURI()){return new jOWL.Ontology.Array([this.value]);}
+		return this.mappings;
+	},
+	isVar : function(){return this.type == this.VAR;},
+	isLiteral :  function(){return this.type == this.LITERAL;},
+	isURI : function(){ return this.type == this.URI;}
+};
+
+/**
+* @return Associative array of parameters in the current documents URL 
+*/
+jOWL.getURLParameters = function(){
+	var href = window.location.href.split("?", 2), param = {};
+	if(href.length == 1){ return {};}
+	var qstr = href[1].split('&');
+	for(var i =0;i<qstr.length;i++){
+		var arr = qstr[i].split("=");
+		if(arr.length == 2){ param[arr[0]] = arr[1];}
+	}
+	return param;
+};
+
+/**
+Without arguments this function will parse the current url and see if any parameters are defined, returns a JOWL object
+@return With argument it will return a string that identifies the potential permalink fr the given entry
+*/
+jOWL.permalink = function(entry){
+	if(!entry){
+		var param = jOWL.getURLParameters();
+		if(param.owlClass){ return jOWL(unescape(param.owlClass));}
+	}
+	else {
+		if(!entry.URI){ return false;}
+		var href = window.location.href.split("?", 2);
+		if(window.location.search){ href = href[0];}
+		if(entry.isClass){ return href+'?owlClass='+escape(entry.URI);}
+	}
+	return false;
+};
+
+/** Convert an item into Manchester syntax, currently only for oneOf 
+* @return String
+*/
+jOWL.Manchester = function(owlElement){
+	var syntax = [];
+	if(owlElement.isClass){
+		var oneOf = owlElement.oneOf().map(function(){ return this.label();});
+		if(oneOf.length){ syntax.push("{ "+oneOf.join(", ")+" }");}
+	}
+	return syntax.join(", ");
+};
+
+})(jQuery);
+
+/**
+* @return 1 for exact match, 0 for partial match, -1 for no match.
+*/
+String.prototype.searchMatch = function(matchstring, exact){
+	if(this.search(new RegExp(matchstring, "i")) > -1){ return 1;} //contained within
+	var c = 0; var arr = matchstring.match(new RegExp("\\w+", "ig"));
+	for(var i = 0;i<arr.length;i++){ if(this.search(arr[i]) > -1){ c++;} }
+	if(c == arr.length){ return 0;} //word shift
+	return -1; //nomatch
+};
+/**
+* @return Modified String.
+*/
+String.prototype.beautify = function(){
+	var e1 = new RegExp("([a-z0-9])([A-Z])", "g");
+	var e2 = new RegExp("([A-Z])([A-Z0-9])([a-z])", "g");
+	var e3 = new RegExp("_", "g");
+	return this.replace(e1, "$1 $2").replace(e2, "$1 $2$3").replace(e3, " ");
+};