<file_sep>module("vie.js - Apache Stanbol Service");

/* All known endpoints of Stanbol */

/* The ones marked with a "!!!" are implemented by the StanbolConnector */
/* The ones marked with a "???" are implemented but still broken */

// !!!  /enhancer/chain/default
// !!!  /enhancer/chain/<chainId>

// !!!  /entityhub/sites/referenced
// !!!  /entityhub/sites/entity
// !!!  /entityhub/sites/find
//   /entityhub/sites/query
// !!!  /entityhub/sites/ldpath
// !!!  /entityhub/site/<siteId>/entity 
// !!!  /entityhub/site/<siteId>/find
//   /entityhub/site/<siteId>/query
// !!!  /entityhub/site/<siteId>/ldpath
//   /entityhub/entity (GET, PUT, POST, DELETE)
//   /entityhub/mapping
// !!!  /entityhub/find
//   /entityhub/query
// !!!  /entityhub/lookup
// !!!  /entityhub/ldpath
// ???  /sparql
//   /contenthub/contenthub/ldpath
// !!!  /contenthub/contenthub/store
//   /contenthub/contenthub/store/raw/<contentId>
//   /contenthub/contenthub/store/metadata/<contentId>
// !!!  /contenthub/<coreId>/store
//   /contenthub/<coreId>/store/raw/<contentId>
//   /contenthub/<coreId>/store/metadata/<contentId>
// ???  /contenthub/content/<contentId>
// !!!  /factstore/facts
// !!!  /factstore/query
//   /ontonet/ontology
//   /ontonet/ontology/<scopeName>
//   /ontonet/ontology/<scopeName>/<ontologyId>
//   /ontonet/ontology/User
//   /ontonet/session/
//   /ontonet/session/<sessionId>
//   /rules/rule/
//   /rules/rule/<ruleId>
//   /rules/recipe/
//   /rules/recipe/<recipeId>
//   /rules/refactor/
//   /rules/refactor/apply
//   /cmsadapter/map
//   /cmsadapter/session
//   /cmsadapter/contenthubfeed


var stanbolRootUrl = ["http://demo.iks-project.eu/stanbolfull", "http://dev.iks-project.eu/stanbolfull"];
test("VIE.js StanbolService - Registration", function() {
    var z = new VIE();
    ok(z.StanbolService, "Checking if the Stanbol Service exists.'");
    z.use(new z.StanbolService);
    ok(z.service('stanbol'));
});

test("VIE.js StanbolService - API", function() {
    var z = new VIE();
    z.use(new z.StanbolService);

    ok(z.service('stanbol').init);
    equal(typeof z.service('stanbol').init, "function");
    ok(z.service('stanbol').analyze);
    equal(typeof z.service('stanbol').analyze, "function");
    ok(z.service('stanbol').find);
    equal(typeof z.service('stanbol').find, "function");
    ok(z.service('stanbol').load);
    equal(typeof z.service('stanbol').load, "function");
    ok(z.service('stanbol').connector);
    ok(z.service('stanbol').connector instanceof z.StanbolConnector);
    ok(z.service('stanbol').rules);
    equal(typeof z.service('stanbol').rules, "object");
});

test("VIE.js StanbolConnector - API", function() {
  var z = new VIE();
    var stanbol = new z.StanbolService({url : stanbolRootUrl});
    z.use(stanbol);
    
    //API
    ok(stanbol.connector.analyze);
    equal(typeof stanbol.connector.analyze, "function");
    ok(stanbol.connector.load);
    equal(typeof stanbol.connector.load, "function");
    ok(stanbol.connector.find);
    equal(typeof stanbol.connector.find, "function");
    ok(stanbol.connector.lookup);
    equal(typeof stanbol.connector.lookup, "function");
    ok(stanbol.connector.referenced);
    equal(typeof stanbol.connector.referenced, "function");
    ok(stanbol.connector.sparql);
    equal(typeof stanbol.connector.sparql, "function");
    ok(stanbol.connector.ldpath);
    equal(typeof stanbol.connector.ldpath, "function");
    ok(stanbol.connector.uploadContent);
    equal(typeof stanbol.connector.uploadContent, "function");
    ok(stanbol.connector.createFactSchema);
    equal(typeof stanbol.connector.createFactSchema, "function");
    ok(stanbol.connector.createFact);
    equal(typeof stanbol.connector.createFact, "function");
    ok(stanbol.connector.queryFact);
    equal(typeof stanbol.connector.queryFact, "function");
});

test("VIE.js StanbolService - Analyze - Default", function () {
    if (navigator.userAgent === 'Zombie') {
       return;
    }
    expect(8);
    // Sending a an example with double quotation marks.
    var elem = $('<p>This is a small test, where <NAME> sings the song \"We want to live forever!\" song.</p>');
    var z = new VIE();
    ok (z.StanbolService);
    equal(typeof z.StanbolService, "function", "The StanbolService exists.");
    z.use(new z.StanbolService({url : stanbolRootUrl}));
    stop();
    z.analyze({element: elem}).using('stanbol').execute().done(function(entities) {

        ok(entities, "The returned results is not null.");
        ok(entities instanceof Array, "The entities are an array.");
        ok(entities.length > 0, "At least one entity returned");
        if(entities.length > 0){
          var allEntities = true;
          for(var i=0; i<entities.length; i++){
              var entity = entities[i];
              if (! (entity instanceof Backbone.Model)){
                  allEntities = false;
                  ok(false, "VIE.js StanbolService - Analyze: Entity is not a Backbone model!");
                  console.error("VIE.js StanbolService - Analyze: ", entity, "is not a Backbone model!");
              }
          }
          ok(allEntities, "All result elements are VIE entities.");
          var firstTextAnnotation = _(entities).filter(function(e){
              return e.isof("enhancer:TextAnnotation") && e.get("enhancer:selected-text");
          })[0];
          ok(firstTextAnnotation);
          if (firstTextAnnotation) {
            var s = firstTextAnnotation.get("enhancer:selected-text").toString();
            ok(s.substring(s.length-4, s.length-2) != "\"@", "Selected text should be converted into a normal string.");
          }
        }
        start();
    })
    .fail(function(f){
        ok(false, f.statusText);
        start();
    });
});

test("VIE.js StanbolService - Analyze with wrong URL of Stanbol", function () {
    if (navigator.userAgent === 'Zombie') {
       return;
    }
    expect(6);
    // Sending a an example with double quotation marks.
    var elem = $('<p>This is a small test, where <NAME> sings the song \"We want to live forever!\" song.</p>');
    var z = new VIE();
    ok (z.StanbolService);
    equal(typeof z.StanbolService, "function");
    var wrongUrls = ["http://www.this-is-wrong.url/", "http://dev.iks-project.eu/stanbolfull", "http://demo.iks-project.eu/stanbolfull"];
    z.use(new z.StanbolService({url : wrongUrls}));
    stop();
    z.analyze({element: elem}).using('stanbol').execute().done(function(entities) {

        ok(entities);
        ok(entities.length > 0, "At least one entity returned");
        ok(entities instanceof Array);
        var allEntities = true;
        for(var i=0; i<entities.length; i++){
            var entity = entities[i];
            if (! (entity instanceof Backbone.Model)){
                allEntities = false;
                ok(false, "VIE.js StanbolService - Analyze: Entity is not a Backbone model!");
                console.error("VIE.js StanbolService - Analyze: ", entity, "is not a Backbone model!");
            }
        }
        ok(allEntities);
        start();
    })
    .fail(function(f){
        ok(false, f.statusText);
        start();
    });
});

test("VIE.js StanbolService - Analyze with Enhancement Chain", function () {
    if (navigator.userAgent === 'Zombie') {
       return;
    }
    expect(4);
    // Sending a an example with double quotation marks.
    var elem = $('<p>This is a small test, where <NAME> sings the song \"We want to live forever!\" song.</p>');
    var v = new VIE();
    v.use(new v.StanbolService({url : stanbolRootUrl, enhancerUrlPostfix: "/enhancer/chain/dbpedia-keyword"}));
    stop();
    v.analyze({element: elem}).using('stanbol').execute().done(function(entities) {
        ok(entities, "Entities is not null");
        ok(entities instanceof Array, "Result is an array");
        ok(entities.length > 0, "At least one entity returned");
        if(entities.length > 0) {
            var allEntities = true;
            for(var i=0; i<entities.length; i++){
                var entity = entities[i];
                if (! (entity instanceof Backbone.Model)){
                    allEntities = false;
                    console.error("VIE.js StanbolService - Analyze: ", entity, "is not a Backbone model!");
                }
            }
            ok(allEntities, "All results are VIE Entities");
        }
        start();
    })
    .fail(function(f){
        ok(false, f.statusText);
        start();
    });
});

test("VIE.js StanbolConnector - Get all referenced sites", function () {
    if (navigator.userAgent === 'Zombie') {
       return;
    } 
    // Sending a an example with double quotation marks.
    var z = new VIE();
    ok (z.StanbolService);
    equal(typeof z.StanbolService, "function");
    var stanbol = new z.StanbolService({url : stanbolRootUrl});
    z.use(stanbol);
    stop();
    stanbol.connector.referenced(function (sites) {
      ok(_.isArray(sites));
      ok(sites.length > 0);
      start();
    }, function (err) {
      ok(false, "No referenced site has been returned!");
      start();
    });
});

test("VIE.js StanbolConnector - Perform SPARQL Query", function () {
    if (navigator.userAgent === 'Zombie') {
       return;
    } 
    
    var query = "PREFIX fise: <http://fise.iks-project.eu/ontology/> " + 
      "PREFIX dc:   <http://purl.org/dc/terms/> " + 
        "SELECT distinct ?enhancement ?content ?engine ?extraction_time " + 
        "WHERE { " + 
          "?enhancement a fise:Enhancement . " + 
          "?enhancement fise:extracted-from ?content . " + 
          "?enhancement dc:creator ?engine . " + 
          "?enhancement dc:created ?extraction_time . " + 
        "} " +
        "ORDER BY DESC(?extraction_time) LIMIT 5";
    
    // Sending a an example with double quotation marks.
    var z = new VIE();
    ok (z.StanbolService);
    equal(typeof z.StanbolService, "function");
    var stanbol = new z.StanbolService({url : stanbolRootUrl});
    z.use(stanbol);
    stop();
    stanbol.connector.sparql(query, function (response) {
      ok(response instanceof Document);
      var xmlString = (new XMLSerializer()).serializeToString(response);
      var myJsonObject = xml2json.parser(xmlString);

      ok(myJsonObject.sparql);
      ok(myJsonObject.sparql.results);
      ok(myJsonObject.sparql.results.result);
      ok(myJsonObject.sparql.results.result.length);
      ok(myJsonObject.sparql.results.result.length > 0);
      
      start();
    }, function (err) {
      ok(false, "SPARQL endpoint returned no response!");
      start();
    });
});


test("VIE.js StanbolService - Find - Default", function () {
    if (navigator.userAgent === 'Zombie') {
       return;
    } 
    var term = "München";
    var limit = 10;
    var offset = 0;
    var z = new VIE();
    ok (z.StanbolService);
    equal(typeof z.StanbolService, "function");
    z.use(new z.StanbolService({url : stanbolRootUrl}));
    stop();
    
    z.find({term: term, limit: limit, offset: offset})
    .using('stanbol').execute().done(function(entities) {

        ok(entities);
        ok(entities.length > 0);
        ok(entities instanceof Array);
        var allEntities = true;
        for(var i=0; i<entities.length; i++){
            var entity = entities[i];
            if (! (entity instanceof Backbone.Model)){
                allEntities = false;
                ok(false, "VIE.js StanbolService - Find: Entity is not a Backbone model!");
                console.error("VIE.js StanbolService - Find: ", entity, "is not a Backbone model!");
            }
        }
        ok(allEntities);
        start();
    })
    .fail(function(f){
        ok(false, f.statusText);
        start();
    });

});

/*
test("VIE.js StanbolService - Find - Search only in local entities", function () {
    if (navigator.userAgent === 'Zombie') {
        return;
    }
    var term = "European Union";
    var limit = 10;
    var offset = 0;
    var z = new VIE();
    z.use(new z.StanbolService({url : stanbolRootUrl}));
    stop();
    // search only in local entities
    z.find({term: "P*", limit: limit, offset: offset, local : true})
    .using('stanbol').execute().done(function(entities) {
        ok(entities);
        ok(entities.length > 0);
        ok(entities instanceof Array);
        var allEntities = true;
        for(var i=0; i<entities.length; i++){
            var entity = entities[i];
            if (! (entity instanceof Backbone.Model)){
                allEntities = false;
                ok(false, "VIE.js StanbolService - Find: Entity is not a Backbone model!");
                console.error("VIE.js StanbolService - Find: ", entity, "is not a Backbone model!");
            }
        }
        ok(allEntities);
        start();
    })
    .fail(function(f){
        ok(false, f.statusText);
        start();
    });

});
*/

test("VIE.js StanbolService - Find - Only term given, no limit, no offset", function () {
    if (navigator.userAgent === 'Zombie') {
        return;
    }
    var term = "European Union";
    var limit = 10;
    var offset = 0;
    var z = new VIE();
    z.use(new z.StanbolService({url : stanbolRootUrl}));
    stop();
    z.find({term: term}) // only term given, no limit, no offset
    .using('stanbol').execute().done(function(entities) {

        ok(entities);
        ok(entities.length > 0);
        ok(entities instanceof Array);
        var allEntities = true;
        for(var i=0; i<entities.length; i++){
            var entity = entities[i];
            if (! (entity instanceof Backbone.Model)){
                allEntities = false;
                ok(false, "VIE.js StanbolService - Find: Entity is not a Backbone model!");
                console.error("VIE.js StanbolService - Find: ", entity, "is not a Backbone model!");
            }
        }
        ok(allEntities);
        start();
    })
    .fail(function(f){
        ok(false, f.statusText);
        start();
    });

});


test("VIE.js StanbolService - Find - Empty term", function () {
    if (navigator.userAgent === 'Zombie') {
        return;
    }
    var term = "European Union";
    var limit = 10;
    var offset = 0;
    var z = new VIE();
    z.use(new z.StanbolService({url : stanbolRootUrl}));
    stop();
    z.find({term: "", limit: limit, offset: offset})
    .using('stanbol').execute()
    .done(function(entities) {

        ok(false, "this should fail, as there is an empty term given!");
        start();
    })
    .fail(function(f){
        ok(true, f.statusText);
        start();
    });

});


test("VIE.js StanbolService - Find - No term", function () {
    if (navigator.userAgent === 'Zombie') {
        return;
    }
    var term = "European Union";
    var limit = 10;
    var offset = 0;
    var z = new VIE();
    z.use(new z.StanbolService({url : stanbolRootUrl}));
    stop();
    z.find({limit: limit, offset: offset})
    .using('stanbol').execute()
    .done(function(entities) {

        ok(false, "this should fail, as there is no term given!");
        start();
    })
    .fail(function(f){
        ok(true, f.statusText);
        start();
    });
});


test("VIE.js StanbolService - Load", function () {
    if (navigator.userAgent === 'Zombie') {
       return;
    }
    var entity = "<http://dbpedia.org/resource/Barack_Obama>";
    var z = new VIE();
    z.use(new z.StanbolService({url : stanbolRootUrl}));
    stop();
    z.load({entity: entity})
    .using('stanbol').execute().done(function(entities) {
        ok(entities);
        ok(entities.length > 0);
        ok(entities instanceof Array);
        var allEntities = true;
        for(var i=0; i<entities.length; i++){
            var entity = entities[i];
            if (! (entity instanceof Backbone.Model)){
                allEntities = false;
                ok(false, "VIE.js StanbolService - Load: Entity is not a Backbone model!");
                console.error("VIE.js StanbolService - Analyze: ", entity, "is not a Backbone model!");
            }
        }
        ok(allEntities);
        start();
    })
    .fail(function(f){
        ok(false, f.statusText);
        start();
    });
});

test("VIE.js StanbolService - ContentHub: Upload of content / Retrieval of enhancements", function () {
    if (navigator.userAgent === 'Zombie') {
       return;
    }
    var content = 'This is a small test, where <NAME> sings the song "We want to live forever!" song.';

    var z = new VIE();
    ok (z.StanbolService);
    equal(typeof z.StanbolService, "function");
    var stanbol = new z.StanbolService({url : stanbolRootUrl});
    z.use(stanbol);
    
    stop();
    stanbol.connector.uploadContent(content, function(xml,status,xhr){
        var location = xhr.getResponseHeader('Location');
        //TODO: This does not work in jQuery :(
        start();
    }, function (err) {
      ok(false, err);
      start();
    });
});

/*
test("VIE.js StanbolService - ContentHub: Lookup", function () {
    if (navigator.userAgent === 'Zombie') {
       return;
    }
    
    var entity = 'http://dbpedia.org/resource/Paris';

    var z = new VIE();
    z.namespaces.add("cc", "http://creativecommons.org/ns#");
    ok (z.StanbolService);
    equal(typeof z.StanbolService, "function");
    var stanbol = new z.StanbolService({url : stanbolRootUrl});
    z.use(stanbol);
    
    stop();
    stanbol.connector.lookup(entity, function (response) {
      var entities = VIE.Util.rdf2Entities(stanbol, response);
      ok(entities.length > 0, "With 'create'");
      start();
    }, function (err) {
      ok(false, err);
      start();
    }, {
      create : true
    });
    
    stop();
    stanbol.connector.lookup(entity, function (response) {
      var entities = VIE.Util.rdf2Entities(stanbol, response);
      ok(entities.length > 0, "Without 'create'");
      start();
    }, function (err) {
      ok(false, err);
      start();
    });
});
*/
test("VIE.js StanbolConnector - LDPath - on all sites", function () {
    if (navigator.userAgent === 'Zombie') {
       return;
    }
    
    var context = 'http://dbpedia.org/resource/Paris';
    var ldpath = "@prefix dct : <http://purl.org/dc/terms/> ;\n" + 
                 "@prefix geo : <http://www.w3.org/2003/01/geo/wgs84_pos#> ;\n" + 
                 "name = rdfs:label[@en] :: xsd:string;\n" + 
                 "labels = rdfs:label :: xsd:string;\n" + 
                 "comment = rdfs:comment[@en] :: xsd:string;\n" + 
                 "categories = dc:subject :: xsd:anyURI;\n" + 
                 "homepage = foaf:homepage :: xsd:anyURI;\n" + 
                 "location = fn:concat(\"[\",geo:lat,\",\",geo:long,\"]\") :: xsd:string;\n";
    
    var z = new VIE();
    z.namespaces.add("cc", "http://creativecommons.org/ns#");
    ok (z.StanbolService);
    equal(typeof z.StanbolService, "function");
    var stanbol = new z.StanbolService({url : stanbolRootUrl});
    z.use(stanbol);
    
    stop();
    // on all sites
    stanbol.connector.ldpath(ldpath, context, function (response) {
      var entities = VIE.Util.rdf2Entities(stanbol, response);
      ok(entities.length > 0);
      start();
    }, function (err) {
      ok(false, err);
      start();
    });
});
test("VIE.js StanbolService - LDPath - on one specific site", function () {
    if (navigator.userAgent === 'Zombie') {
        return;
    }

    var context = 'http://dbpedia.org/resource/Paris';
    var ldpath = "@prefix dct : <http://purl.org/dc/terms/> ;\n" +
        "@prefix geo : <http://www.w3.org/2003/01/geo/wgs84_pos#> ;\n" +
        "name = rdfs:label[@en] :: xsd:string;\n" +
        "labels = rdfs:label :: xsd:string;\n" +
        "comment = rdfs:comment[@en] :: xsd:string;\n" +
        "categories = dc:subject :: xsd:anyURI;\n" +
        "homepage = foaf:homepage :: xsd:anyURI;\n" +
        "location = fn:concat(\"[\",geo:lat,\",\",geo:long,\"]\") :: xsd:string;\n";

    var z = new VIE();
    z.namespaces.add("cc", "http://creativecommons.org/ns#");
    var stanbol = new z.StanbolService({url : stanbolRootUrl});
    z.use(stanbol);
    stop();

    // on one specific site
    stanbol.connector.ldpath(ldpath, context, function (response) {
      var entities = VIE.Util.rdf2Entities(stanbol, response);
      ok(entities.length > 0);
      start();
    }, function (err) {
      ok(false, err);
      start();
    }, {
      site: "dbpedia"
    });

});
test("VIE.js StanbolService - LDPath - on local entities", function () {
    if (navigator.userAgent === 'Zombie') {
        return;
    }

    var context = 'http://dbpedia.org/resource/Paris';
    var ldpath = "@prefix dct : <http://purl.org/dc/terms/> ;\n" +
        "@prefix geo : <http://www.w3.org/2003/01/geo/wgs84_pos#> ;\n" +
        "name = rdfs:label[@en] :: xsd:string;\n" +
        "labels = rdfs:label :: xsd:string;\n" +
        "comment = rdfs:comment[@en] :: xsd:string;\n" +
        "categories = dc:subject :: xsd:anyURI;\n" +
        "homepage = foaf:homepage :: xsd:anyURI;\n" +
        "location = fn:concat(\"[\",geo:lat,\",\",geo:long,\"]\") :: xsd:string;\n";

    var z = new VIE();
    z.namespaces.add("cc", "http://creativecommons.org/ns#");
    var stanbol = new z.StanbolService({url : stanbolRootUrl});
    z.use(stanbol);

    stop();
    // on local entities
    stanbol.connector.ldpath(ldpath, context, function (response) {
      var entities = VIE.Util.rdf2Entities(stanbol, response);
      ok(entities.length > 0);
      start();
    }, function (err) {
      ok(false, err);
      start();
    }, {
      local : true
    });
});

/* TODO: these tests need to be backed by implementations
test("VIE.js StanbolService - Create a New Fact Schema", function () {
    if (navigator.userAgent === 'Zombie') {
       return;
    }
    
    var employeeOfFact = {
       "@context" : {
       "iks"     : "http://iks-project.eu/ont/",
        "@types"  : {
          "person"       : "iks:person",
          "organization" : "iks:organization"
        }
      }
    };
    
    var employeeOfFactURL = "http://iks-project.eu/ont/employeeOf" + (new Date().getTime());
       
    var z = new VIE();
    z.namespaces.add("cc", "http://creativecommons.org/ns#");
    ok (z.StanbolService);
    equal(typeof z.StanbolService, "function");
    var stanbol = new z.StanbolService({url : stanbolRootUrl});
    z.use(stanbol);
    
    stop();
    // on all sites
    stanbol.connector.createFactSchema(employeeOfFactURL, employeeOfFact, function (response) {
      debugger;
      start();
    }, function (err) {
      ok(false, err);
      start();
    });
});

test("VIE.js StanbolService - Create a New Fact", function () {
    if (navigator.userAgent === 'Zombie') {
       return;
    }
    
    var fact = {
         "@context" : {
             "iks" : "http://iks-project.eu/ont/",
             "upb" : "http://upb.de/persons/"
           },
           "@profile"     : "iks:employeeOf",
           "person"       : { "@iri" : "upb:bnagel" },
           "organization" : { "@iri" : "http://uni-paderborn.de"}
          };
    
    var z = new VIE();
    ok (z.StanbolService);
    equal(typeof z.StanbolService, "function");
    var stanbol = new z.StanbolService({url : stanbolRootUrl});
    z.use(stanbol);
    
    stop();
    stanbol.connector.createFact(fact, function (response) {
      debugger;
      start();
    }, function (err) {
      ok(false, err);
      start();
    });
    
    var moreFactsOfSameType = {
         "@context" : {
             "iks" : "http://iks-project.eu/ont/",
             "upb" : "http://upb.de/persons/"
           },
           "@profile"     : "iks:employeeOf",
           "@subject" : [
             { "person"       : { "@iri" : "upb:bnagel" },
               "organization" : { "@iri" : "http://uni-paderborn.de" }
             },
             { "person"       : { "@iri" : "upb:fchrist" },
               "organization" : { "@iri" : "http://uni-paderborn.de" }
             }
           ]
          };
    
    stop();
    stanbol.connector.createFact(moreFactsOfSameType, function (response) {
      debugger;
      start();
    }, function (err) {
      ok(false, err);
      start();
    });
    
    var moreFactsOfDifferentType = {
         "@context" : {
             "iks" : "http://iks-project.eu/ont/",
             "upb" : "http://upb.de/persons/"
           },
           "@subject" : [
             { "@profile"     : "iks:employeeOf",
               "person"       : { "@iri" : "upb:bnagel" },
               "organization" : { "@iri" : "http://uni-paderborn.de" }
             },
             { "@profile"     : "iks:friendOf",
               "person"       : { "@iri" : "upb:bnagel" },
               "friend"       : { "@iri" : "upb:fchrist" }
             }
           ]
          };
   
   stop();
   stanbol.connector.createFact(moreFactsOfDifferentType, function (response) {
    debugger;
    start();
   }, function (err) {
    ok(false, err);
    start();
   });
});

test("VIE.js StanbolService - Query for Facts of a Certain Type", function () {
    if (navigator.userAgent === 'Zombie') {
       return;
    }
    
    var query = {
         "@context" : {
             "iks" : "http://iks-project.eu/ont/"
           },
           "select" : [ "person" ],
           "from"   : "iks:employeeOf",
           "where"  : [
             {
               "="  : {
                 "organization" : { "@iri" : "http://uni-paderborn.de" }
               }
             }
           ]
          };
    
    var z = new VIE();
    ok (z.StanbolService);
    equal(typeof z.StanbolService, "function");
    var stanbol = new z.StanbolService({url : stanbolRootUrl});
    z.use(stanbol);
    
    stop();
    stanbol.connector.queryFact(query, function (response) {
      debugger;
      start();
    }, function (err) {
      ok(false, err);
      start();
    });
});

test("VIE.js StanbolService - CRUD on local entities", function () {
    if (navigator.userAgent === 'Zombie') {
       return;
    }
    var z = new VIE();
    ok (z.StanbolService);
    equal(typeof z.StanbolService, "function");
    z.use(new z.StanbolService({url : stanbolRootUrl}));
    //TODO
});
*/
<file_sep>//     VIE - Vienna IKS Editables
//     (c) 2011 <NAME>, IKS Consortium
//     (c) 2011 <NAME>, IKS Consortium
//     (c) 2011 <NAME>, IKS Consortium
//     VIE may be freely distributed under the MIT license.
//     For all details and documentation:
//     http://viejs.org/
/*global escape:false */

// ## VIE - StanbolService service
// The StanbolService service allows a VIE developer to directly query
// the <a href="http://incubator.apache.org/stanbol/">Apache Stanbol</a> entityhub for entities and their properties.
// Furthermore, it gives access to the enhance facilities of
// Stanbol to analyze content and semantically enrich it.
(function(){
var defaultStanbolUris = ["http://demo.iks-project.eu/stanbolfull", "http://dev.iks-project.eu/stanbolfull"];

// ## VIE.StanbolService(options)
// This is the constructor to instantiate a new service to collect
// properties of an entity from <a href="http://incubator.apache.org/stanbol/">Apache Stanbol</a>.
// **Parameters**:
// *{object}* **options** Optional set of fields, ```namespaces```, ```rules```, ```url```, or ```name```.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.StanbolService}* : A **new** VIE.StanbolService instance.
// **Example usage**:
//
//     var stnblService = new vie.StanbolService({<some-configuration>});
VIE.prototype.StanbolService = function(options) {
    var defaults = {
        /* the default name of this service */
        name : 'stanbol',
        /* you can pass an array of URLs which are then tried sequentially */
        url: defaultStanbolUris,
        timeout : 20000, /* 20 seconds timeout */
        namespaces : {
            semdeski : "http://www.semanticdesktop.org/ontologies/2007/01/19/nie#",
            semdeskf : "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#",
            skos: "http://www.w3.org/2004/02/skos/core#",
            foaf: "http://xmlns.com/foaf/0.1/",
            opengis: "http://www.opengis.net/gml/",
            dbpedia: "http://dbpedia.org/ontology/",
            dbprop: "http://dbpedia.org/property/",
            owl : "http://www.w3.org/2002/07/owl#",
            geonames : "http://www.geonames.org/ontology#",
            enhancer : "http://fise.iks-project.eu/ontology/",
            entityhub: "http://www.iks-project.eu/ontology/rick/model/",
            entityhub2: "http://www.iks-project.eu/ontology/rick/query/",
            rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
            rdfs: "http://www.w3.org/2000/01/rdf-schema#",
            dcterms  : 'http://purl.org/dc/terms/',
            schema: 'http://schema.org/',
            geo: 'http://www.w3.org/2003/01/geo/wgs84_pos#'
        },
        /* default rules that are shipped with this service */
        rules : [
            /* rule to add backwards-relations to the triples
             * this makes querying for entities a lot easier!
             */
            {
                'left' : [
                    '?subject a <http://fise.iks-project.eu/ontology/EntityAnnotation>',
                    '?subject enhancer:entity-type ?type',
                    '?subject enhancer:confidence ?confidence',
                    '?subject enhancer:entity-reference ?entity',
                    '?subject dcterms:relation ?relation',
                    '?relation a <http://fise.iks-project.eu/ontology/TextAnnotation>',
                    '?relation enhancer:selected-text ?selected-text',
                    '?relation enhancer:selection-context ?selection-context',
                    '?relation enhancer:start ?start',
                    '?relation enhancer:end ?end'
                ],
                'right' : [
                    '?entity a ?type',
                    '?entity enhancer:hasTextAnnotation ?relation',
                    '?entity enhancer:hasEntityAnnotation ?subject'
                ]
            }
        ],
        enhancer : {
            chain : "default"
        },
        entityhub : {
            /* if set to undefined, the Referenced Site Manager @ /entityhub/sites is used. */
            /* if set to, e.g., dbpedia, eferenced Site @ /entityhub/site/dbpedia is used. */
            site : undefined
        }
    };
    /* the options are merged with the default options */
    this.options = jQuery.extend(true, defaults, options ? options : {});

    this.vie = null; /* will be set via VIE.use(); */
    /* overwrite options.name if you want to set another name */
    this.name = this.options.name;

};

VIE.prototype.StanbolService.prototype = {

// ### init()
// This internal method initializes certain properties of the service and is called
// via ```VIE.use()```.
// **Parameters**:
// *nothing*
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.StanbolService}* : The VIE.StanbolService instance itself.
    init: function(){

        for (var key in this.options.namespaces) {
            var val = this.options.namespaces[key];
            this.vie.namespaces.add(key, val);
        }

        this.rules = jQuery.extend([], VIE.Util.transformationRules(this));
        this.rules = jQuery.merge(this.rules, (this.options.rules) ? this.options.rules : []);

        this.connector = new this.vie.StanbolConnector(this.options);

        /* adding these entity types to VIE helps later the querying */
        this.vie.types.addOrOverwrite('enhancer:EntityAnnotation', [
            /*TODO: add attributes */
        ]).inherit("owl:Thing");
        this.vie.types.addOrOverwrite('enhancer:TextAnnotation', [
            /*TODO: add attributes */
        ]).inherit("owl:Thing");
        this.vie.types.addOrOverwrite('enhancer:Enhancement', [
            /*TODO: add attributes */
        ]).inherit("owl:Thing");
    },

// ### analyze(analyzable)
// This method extracts text from the jQuery element and sends it to Apache Stanbol for analysis.
// **Parameters**:
// *{VIE.Analyzable}* **analyzable** The analyzable.
// **Throws**:
// *{Error}* if an invalid VIE.Analyzable is passed.
// **Returns**:
// *{VIE.StanbolService}* : The VIE.StanbolService instance itself.
// **Example usage**:
//
//     vie.analyze({element : jQuery("#foo")})
//     .using(new vie.StanbolService({<some-configuration>}))
//     .execute().success(callback);
    analyze: function(analyzable) {
        var service = this;

        var correct = analyzable instanceof this.vie.Analyzable;
        if (!correct) {throw "Invalid Analyzable passed";}

        var element = analyzable.options.element ? analyzable.options.element : jQuery('body');

        var text = service._extractText(element);

        if (text.length > 0) {
            /* query enhancer with extracted text */
            var success = function (results) {
                _.defer(function(){
                    var entities = VIE.Util.rdf2Entities(service, results);
                    service.vie.entities.addOrUpdate(entities);
                    analyzable.resolve(entities);
                });
            };
            var error = function (e) {
                analyzable.reject(e);
            };

            var options = {
                chain : (analyzable.options.chain)? analyzable.options.chain : service.options.enhancer.chain
            };

            this.connector.analyze(text, success, error, options);

        } else {
            analyzable.resolve([]);
        }

    },

// ### find(findable)
// This method finds entities given the term from the entity hub.
// **Parameters**:
// *{VIE.Findable}* **findable** The findable.
// **Throws**:
// *{Error}* if an invalid VIE.Findable is passed.
// **Returns**:
// *{VIE.StanbolService}* : The VIE.StanbolService instance itself.
// **Example usage**:
//
//     vie.find({
//         term : "Bischofsh",
//         limit : 10,
//         offset: 0,
//         field: "skos:prefLabel", // used for the term lookup, default: "rdfs:label"
//         properties: ["skos:prefLabel", "rdfs:label"] // are going to be loaded with the result entities
//     })
//     .using(new vie.StanbolService({<some-configuration>}))
//     .execute()
//     .success(callback);
    find: function (findable) {
        var correct = findable instanceof this.vie.Findable;
        if (!correct) {throw "Invalid Findable passed";}
        var service = this;
        /* The term to find, * as wildcard allowed */
        if (!findable.options.term) {
            findable.reject([]);
        }
        var term = findable.options.term;
        var limit = (typeof findable.options.limit === "undefined") ? 20 : findable.options.limit;
        var offset = (typeof findable.options.offset === "undefined") ? 0 : findable.options.offset;
        var success = function (results) {
            _.defer(function(){
                var entities = VIE.Util.rdf2Entities(service, results);
                findable.resolve(entities);
            });
        };
        var error = function (e) {
            findable.reject(e);
        };

        findable.options.site = (findable.options.site)? findable.options.site : service.options.entityhub.site;

        var vie = this.vie;
        if(findable.options.properties){
            var properties = findable.options.properties;
            findable.options.ldPath = _(properties)
            .map(function(property){
                if (vie.namespaces.isCurie(property)){
                    return vie.namespaces.uri(property) + ";";
                } else {
                    return property;
                }
            })
            .join("");
        }
        if(findable.options.field && vie.namespaces.isCurie(findable.options.field)){
            var field = findable.options.field;
                findable.options.field = vie.namespaces.uri(field);
        }
        this.connector.find(term, limit, offset, success, error, findable.options);
    },

// ### load(loadable)
// This method loads the entity that is stored within the loadable into VIE.
// **Parameters**:
// *{VIE.Loadable}* **lodable** The loadable.
// **Throws**:
// *{Error}* if an invalid VIE.Loadable is passed.
// **Returns**:
// *{VIE.StanbolService}* : The VIE.StanbolService instance itself.
// **Example usage**:
//     vie.load({
//         entity: "<http://...>"
//     })
//     .using(new vie.StanbolService({<some-configuration>}))
//     .execute()
//     .success(callback);
    load: function(loadable){
        var correct = loadable instanceof this.vie.Loadable;
        if (!correct) {throw "Invalid Loadable passed";}
        var service = this;

        var entity = loadable.options.entity;
        if (!entity){
            loadable.resolve([]);
        }
        var success = function (results) {
            _.defer(function(){
                var entities = VIE.Util.rdf2Entities(service, results);
                _.each(entities, function(vieEntity) {
                    service.vie.entities.addOrUpdate(vieEntity);
                });
                loadable.resolve(entities);
            });
        };
        var error = function (e) {
            loadable.reject(e);
        };

        var options = {
            site : (loadable.options.site)? loadable.options.site : service.options.entityhub.site,
            local : loadable.options.local
        };

        this.connector.load(entity, success, error, options);
    },

 // ### save(savable)
 // This method saves the given entity to the Apache Stanbol installation.
 // **Parameters**:
 // *{VIE.Savable}* **savable** The savable.
 // **Throws**:
 // *{Error}* if an invalid VIE.Savable is passed.
 // **Returns**:
 // *{VIE.StanbolService}* : The VIE.StanbolService instance itself.
 // **Example usage**:
 //
 //      var entity = new vie.Entity({'name' : '<NAME>'});
 //      var stnblService = new vie.StanbolService({<some-configuration>});
 //      stnblService.save(new vie.Savable(entity));
     save: function(savable){
         var correct = savable instanceof this.vie.Savable;
         if (!correct) {throw "Invalid Savable passed";}
         var service = this;

         var entity = savable.options.entity;
         if (!entity){
             savable.reject("StanbolConnector: No entity to save!");
         }
         var success = function (results) {
             _.defer(function() {
                 var entities = VIE.Util.rdf2Entities(service, results);
                 savable.resolve(entities);
             });
         };

         var error = function (e) {
             savable.reject(e);
         };

         var options = {
            site : (savable.options.site)? savable.options.site : service.options.entityhub.site,
            local : savable.options.local
         };

         this.connector.save(entity, success, error, options);
     },

    /* this private method extracts text from a jQuery element */
    _extractText: function (element) {
        if (element.get(0) &&
            element.get(0).tagName &&
            (element.get(0).tagName == 'TEXTAREA' ||
            element.get(0).tagName == 'INPUT' && element.attr('type', 'text'))) {
            return element.get(0).val();
        }
        else {
            var res = element
                .text()    /* get the text of element */
                .replace(/\s+/g, ' ') /* collapse multiple whitespaces */
                .replace(/\0\b\n\r\f\t/g, ''); /* remove non-letter symbols */
            return jQuery.trim(res);
        }
    }
};

// ## VIE.StanbolConnector(options)
// The StanbolConnector is the connection between the VIE Stanbol service
// and the actual ajax calls.
// **Parameters**:
// *{object}* **options** The options.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.StanbolConnector}* : The **new** VIE.StanbolConnector instance.
// **Example usage**:
//
//     var stnblConn = new vie.StanbolConnector({<some-configuration>});
VIE.prototype.StanbolConnector = function (options) {

    var defaults =  {
        /* you can pass an array of URLs which are then tried sequentially */
        url: defaultStanbolUris,
        timeout : 20000, /* 20 seconds timeout */
        enhancer : {
            urlPostfix : "/enhancer",
            chain : "default"
        },
        entityhub : {
            /* if set to undefined, the Referenced Site Manager @ /entityhub/sites is used. */
            /* if set to, e.g., dbpedia, referenced Site @ /entityhub/site/dbpedia is used. */
            site : undefined,
            urlPostfix : "/entityhub",
            local : false
        },
        sparql : {
            urlPostfix : "/sparql"
        },
        contenthub : {
            urlPostfix : "/contenthub",
            index : "contenthub"
        },
        ontonet : {
            urlPostfix : "/ontonet"
        },
        factstore : {
            urlPostfix : "/factstore"
        },
        rules : {
            urlPostfix : "/rules"
        },
        cmsadapter : {
            urlPostfix : "/cmsadapter"
        }
    };

    /* the options are merged with the default options */
    this.options = jQuery.extend(true, defaults, options ? options : {});
    this.options.url = (_.isArray(this.options.url))? this.options.url : [ this.options.url ];

    this._init();

    this.baseUrl = (_.isArray(options.url))? options.url : [ options.url ];
};

VIE.prototype.StanbolConnector.prototype = {

// ### _init()
// Basic setup of the stanbol connector.  This is called internally by the constructor!
// **Parameters**:
// *nothing*
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.StanbolConnector}* : The VIE.StanbolConnector instance itself.
    _init : function () {
        var connector = this;

        /* basic setup for the ajax connection */
        jQuery.ajaxSetup({
            converters: {"text application/rdf+json": function(s){return JSON.parse(s);}},
            timeout: connector.options.timeout
        });

        return this;
    },

    _iterate : function (params) {
        if (!params) { return; }

        if (params.urlIndex >= this.options.url.length) {
            params.error.call(this, "Could not connect to the given Stanbol endpoints! Please check for their setup!");
            return;
        }

        var retryErrorCb = function (c, p) {
            /* in case a Stanbol backend is not responding and
             * multiple URLs have been registered
             */
            return function () {
                p.urlIndex = p.urlIndex+1;
                c._iterate(p);
            };
        }(this, params);

        if (typeof exports !== "undefined" && typeof process !== "undefined") {
            /* We're on Node.js, don't use jQuery.ajax */
            return params.methodNode.call(
                    this,
                    params.url.call(this, params.urlIndex, params.args.options),
                    params.args,
                    params.success,
                    retryErrorCb);
        }

        return params.method.call(
                this,
                params.url.call(this, params.urlIndex, params.args.options),
                params.args,
                params.success,
                retryErrorCb);
    },

// ### analyze(text, success, error, options)
// This method sends the given text to Apache Stanbol returns the result by the success callback.
// **Parameters**:
// *{string}* **text** The text to be analyzed.
// *{function}* **success** The success callback.
// *{function}* **error** The error callback.
// *{object}* **options** Options, like the ```format```, or the ```chain``` to be used.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.StanbolConnector}* : The VIE.StanbolConnector instance itself.
// **Example usage**:
//
//     var stnblConn = new vie.StanbolConnector(opts);
//     stnblConn.analyze("This is some text.",
//                 function (res) { ... },
//                 function (err) { ... });
    analyze: function(text, success, error, options) {
        options = (options)? options :  {};
        var connector = this;

        connector._iterate({
            method : connector._analyze,
            methodNode : connector._analyzeNode,
            url : function (idx, opts) {
                var chain = (opts.chain)? opts.chain : this.options.enhancer.chain;

                var u = this.options.url[idx].replace(/\/$/, '');
                u += this.options.enhancer.urlPostfix + "/chain/" + chain.replace(/\/$/, '');
                return u;
            },
            args : {
                text : text,
                format : options.format || "application/rdf+json",
                options : options
            },
            success : success,
            error : error,
            urlIndex : 0
        });
    },

    _analyze : function (url, args, success, error) {
        jQuery.ajax({
            success: success,
            error: error,
            url: url,
            type: "POST",
            data: args.text,
            dataType: args.format,
            contentType: "text/plain",
            accepts: {"application/rdf+json": "application/rdf+json"}
        });
    },

    _analyzeNode: function(url, args, success, error) {
        var request = require('request');
        var r = request({
            method: "POST",
            uri: url,
            body: args.text,
            headers: {
                Accept: args.format,
                'Content-Type': 'text/plain'
            }
        }, function(err, response, body) {
            try {
                success({results: JSON.parse(body)});
            } catch (e) {
                error(e);
            }
        });
        r.end();
    },

// ### load(uri, success, error, options)
// This method loads all properties from an entity and returns the result by the success callback.
// **Parameters**:
// *{string}* **uri** The URI of the entity to be loaded.
// *{function}* **success** The success callback.
// *{function}* **error** The error callback.
// *{object}* **options** Options, like the ```format```, the ```site```. If ```local``` is set, only the local entities are accessed.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.StanbolConnector}* : The VIE.StanbolConnector instance itself.
// **Example usage**:
//
//     var stnblConn = new vie.StanbolConnector(opts);
//     stnblConn.load("<http://dbpedia.org/resource/Barack_Obama>",
//                 function (res) { ... },
//                 function (err) { ... });

    load: function (uri, success, error, options) {
        var connector = this;
        options = (options)? options :  {};

        options.uri = uri.replace(/^</, '').replace(/>$/, '');

        connector._iterate({
            method : connector._load,
            methodNode : connector._loadNode,
            success : success,
            error : error,
            url : function (idx, opts) {
                var site = (opts.site)? opts.site : this.options.entityhub.site;
                site = (site)? "/" + site : "s";

                var isLocal = opts.local;

                var u = this.options.url[idx].replace(/\/$/, '') + this.options.entityhub.urlPostfix;
                if (isLocal) {
                    u += "/entity?id=" + encodeURIComponent(opts.uri);
                } else {
                    u += "/site" + site + "/entity?id=" + encodeURIComponent(opts.uri);
                }
                return u;
            },
            args : {
                format : options.format || "application/rdf+json",
                options : options
            },
            urlIndex : 0
        });
    },

    _load : function (url, args, success, error) {
        jQuery.ajax({
            success: success,
            error: error,
            url: url,
            type: "GET",
            dataType: args.format,
            contentType: "text/plain",
            accepts: {"application/rdf+json": "application/rdf+json"}
        });
    },

    _loadNode: function(url, args, success, error) {
        var request = require('request');
        var r = request({
            method: "GET",
            uri: url,
            body: args.text,
            headers: {
                Accept: args.format
            }
        }, function(err, response, body) {
            try {
                success({results: JSON.parse(body)});
            } catch (e) {
                error(e);
            }
        });
        r.end();
    },

// ### find(term, limit, offset, success, error, options)
// This method finds entities given the term from the entity hub and returns the result by the success callback.
// **Parameters**:
// *{string}* **term** The term to be searched for.
// *{int}* **limit** The limit of results to be returned.
// *{int}* **offset** The offset to be search for.
// *{function}* **success** The success callback.
// *{function}* **error** The error callback.
// *{object}* **options** Options, like the ```format```. If ```local``` is set, only the local entities are accessed.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.StanbolConnector}* : The VIE.StanbolConnector instance itself.
// **Example usage**:
//
//     var stnblConn = new vie.StanbolConnector(opts);
//     stnblConn.find("Bishofsh", 10, 0,
//                 function (res) { ... },
//                 function (err) { ... });
    find: function(term, limit, offset, success, error, options) {
        options = (options)? options :  {};
        /* curl -X POST -d "name=Bishofsh&limit=10&offset=0" http://localhost:8080/entityhub/sites/find */

        var connector = this;

        if (!term || term === "") {
            error ("No term given!");
            return;
        }

        offset = (offset)? offset : 0;
        limit  = (limit)? limit : 10;

        connector._iterate({
            method : connector._find,
            methodNode : connector._findNode,
            success : success,
            error : error,
            url : function (idx, opts) {
                var site = (opts.site)? opts.site : this.options.entityhub.site;
                site = (site)? "/" + site : "s";

                var isLocal = opts.local;

                var u = this.options.url[idx].replace(/\/$/, '') + this.options.entityhub.urlPostfix;
                if (isLocal) {
                    u += "/sites/find";
                } else {
                    u += "/site" + site + "/find";
                }

                return u;
            },
            args : {
                term : term,
                offset : offset,
                limit : limit,
                format : options.format || "application/rdf+json",
                options : options
            },
            urlIndex : 0
        });
    },

    _find : function (url, args, success, error) {
        var fields={
            "name": args.term,
            "limit": args.limit,
            "offset": args.offset
        };
        jQuery.ajax({
            success: success,
            error: error,
            url: url,
            type: "POST",
            data: jQuery.param(fields),
            dataType: args.format,
            contentType : "application/x-www-form-urlencoded",
            accepts: {"application/rdf+json": "application/rdf+json"}
        });
    },

    _findNode: function(url, args, success, error) {
        var request = require('request');
        var r = request({
            method: "POST",
            uri: url,
            body : "name=" + args.term + "&limit=" + args.limit + "&offset=" + args.offset,
            headers: {
                Accept: args.format
            }
        }, function(err, response, body) {
            try {
                success({results: JSON.parse(body)});
            } catch (e) {
                error(e);
            }
        });
        r.end();
    },

// ### lookup(uri, success, error, options)
// TODO.
// **Parameters**:
// *{string}* **uri** The URI of the entity to be loaded.
// *{function}* **success** The success callback.
// *{function}* **error** The error callback.
// *{object}* **options** Options, ```create```.
//    If the parsed ID is a URI of a Symbol, than the stored information of the Symbol are returned in the requested media type ('accept' header field).
//    If the parsed ID is a URI of an already mapped entity, then the existing mapping is used to get the according Symbol.
//    If "create" is enabled, and the parsed URI is not already mapped to a Symbol, than all the currently active referenced sites are searched for an Entity with the parsed URI.
//    If the configuration of the referenced site allows to create new symbols, than a the entity is imported in the Entityhub, a new Symbol and EntityMapping is created and the newly created Symbol is returned.
//    In case the entity is not found (this also includes if the entity would be available via a referenced site, but create=false) a 404 "Not Found" is returned.
//    In case the entity is found on a referenced site, but the creation of a new Symbol is not allowed a 403 "Forbidden" is returned.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.StanbolConnector}* : The VIE.StanbolConnector instance itself.
    lookup: function(uri, success, error, options) {
        options = (options)? options :  {};
        /*/lookup/?id=http://dbpedia.org/resource/Paris&create=false"*/
        var connector = this;

        uri = uri.replace(/^</, '').replace(/>$/, '');

        options.uri = uri;
        options.create = (options.create)? options.create : false;

        connector._iterate({
            method : connector._lookup,
            methodNode : connector._lookupNode,
            success : success,
            error : error,
            url : function (idx, opts) {

                 var u = this.options.url[idx].replace(/\/$/, '') + this.options.entityhub.urlPostfix;
                 u += "/lookup?id=" + encodeURIComponent(opts.uri) + "&create=" + opts.create;
                 return u;
            },
            args : {
                format : options.format || "application/rdf+json",
                options : options
            },
            urlIndex : 0
         });
     },

     _lookup : function (url, args, success, error) {
        jQuery.ajax({
             success: success,
             error: error,
             url: url,
             type: "GET",
             dataType: args.format,
             contentType: "text/plain",
             accepts: {"application/rdf+json": "application/rdf+json"}
         });
     },

     _lookupNode: function(url, args, success, error) {
         var request = require('request');
         var r = request({
             method: "GET",
             uri: url,
             body: args.text,
             headers: {
                 Accept: args.format
             }
         }, function(err, response, body) {
             try {
                 success({results: JSON.parse(body)});
             } catch (e) {
                 error(e);
             }
         });
         r.end();
     },

 // ### referenced(success, error, options)
 // This method returns a list of all referenced sites that the entityhub comprises.
 // **Parameters**:
 // *{function}* **success** The success callback.
 // *{function}* **error** The error callback.
 // *{object}* **options** Options, unused here.
 // **Throws**:
 // *nothing*
 // **Returns**:
 // *{VIE.StanbolConnector}* : The VIE.StanbolConnector instance itself.
 // **Example usage**:
 //
//      var stnblConn = new vie.StanbolConnector(opts);
//      stnblConn.referenced(
//                  function (res) { ... },
//                  function (err) { ... });
     referenced: function(success, error, options) {
        options = (options)? options :  {};
        var connector = this;

        var successCB = function (sites) {
          if (!_.isArray(sites)) {
            sites = JSON.parse(sites);
          }
          var sitesStripped = [];
          for (var s = 0, l = sites.length; s < l; s++) {
            sitesStripped.push(sites[s].replace(/.+\/(.+?)\/?$/, "$1"));
          }
          return success(sitesStripped);
        };

        connector._iterate({
            method : connector._referenced,
            methodNode : connector._referencedNode,
            success : successCB,
            error : error,
            url : function (idx, opts) {
                 var u = this.options.url[idx].replace(/\/$/, '');
                 u += this.options.entityhub.urlPostfix + "/sites/referenced";

                return u;
            },
            args : {
                options : options
            },
            urlIndex : 0
         });
     },

     _referenced : function (url, args, success, error) {
        jQuery.ajax({
             success: success,
             error: error,
             url: url,
             type: "GET",
             accepts: {"application/rdf+json": "application/rdf+json"}
         });
     },

     _referencedNode: function(url, args, success, error) {
         var request = require('request');
         var r = request({
             method: "GET",
             uri: url,
             headers: {
                 Accept: args.format
             }
         }, function(err, response, body) {
             try {
                 success({results: JSON.parse(body)});
             } catch (e) {
                 error(e);
             }
         });
         r.end();
     },

// ### sparql(query, success, error, options)
// TODO.
// **Parameters**:
// TODO
// *{function}* **success** The success callback.
// *{function}* **error** The error callback.
// *{object}* **options** Options, unused here.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.StanbolConnector}* : The VIE.StanbolConnector instance itself.
     sparql: function(query, success, error, options) {
        options = (options)? options :  {};
         var connector = this;

        connector._iterate({
            method : connector._sparql,
            methodNode : connector._sparqlNode,
            success : success,
            error : error,
            url : function (idx, opts) {
                var u = this.options.url[idx].replace(/\/$/, '');
                u += this.options.sparql.urlPostfix.replace(/\/$/, '');

                return u;
            },
            args : {
                query : query,
                options : options
            },
            urlIndex : 0
          });
      },

      _sparql : function (url, args, success, error) {
        jQuery.ajax({
              success: success,
              error: error,
              url: url,
              type: "POST",
              data : "query=" + args.query,
              contentType : "application/x-www-form-urlencoded"
          });
      },

      _sparqlNode: function(url, args, success, error) {
          var request = require('request');
          var r = request({
              method: "POST",
              uri: url,
              body : JSON.stringify({query : args.query}),
              headers: {
                  Accept: args.format
              }
          }, function(err, response, body) {
              try {
                  success({results: JSON.parse(body)});
              } catch (e) {
                  error(e);
              }
          });
          r.end();
      },

// ### ldpath(query, success, error, options)
// TODO.
// **Parameters**:
// TODO
// *{function}* **success** The success callback.
// *{function}* **error** The error callback.
// *{object}* **options** Options, unused here.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.StanbolConnector}* : The VIE.StanbolConnector instance itself.
    ldpath: function(ldpath, context, success, error, options) {
        options = (options)? options :  {};
        var connector = this;

        context = (_.isArray(context))? context : [ context ];

        var contextStr = "";
        for (var c = 0; c < context.length; c++) {
            contextStr += "&context=" + context[c];
        }

        connector._iterate({
            method : connector._ldpath,
            methodNode : connector._ldpathNode,
            success : success,
            error : error,
            url : function (idx, opts) {
                var site = (opts.site)? opts.site : this.options.entityhub.site;
                site = (site)? "/" + site : "s";

                var isLocal = opts.local;

                var u = this.options.url[idx].replace(/\/$/, '') + this.options.entityhub.urlPostfix;
                if (!isLocal)
                    u += "/site" + site;
                u += "/ldpath";

                return u;
            },
            args : {
                ldpath : ldpath,
                context : contextStr,
                format : options.format || "application/rdf+json",
                options : options
            },
            urlIndex : 0
         });
     },

     _ldpath : function (url, args, success, error) {
        jQuery.ajax({
             success: success,
             error: error,
             url: url,
             type: "POST",
             data : "ldpath=" + args.ldpath + args.context,
             contentType : "application/x-www-form-urlencoded",
             dataType: args.format,
             accepts: {"application/rdf+json": "application/rdf+json"}
         });
     },

     _ldpathNode: function(url, args, success, error) {
         var request = require('request');
         var r = request({
             method: "POST",
             uri: url,
             body : "ldpath=" + args.ldpath + args.context,
             headers: {
                 Accept: args.format
             }
         }, function(err, response, body) {
             try {
                 success({results: JSON.parse(body)});
             } catch (e) {
                 error(e);
             }
         });
         r.end();
     },

// ### uploadContent(content, success, error, options)
// TODO.
// **Parameters**:
// TODO
// *{function}* **success** The success callback.
// *{function}* **error** The error callback.
// *{object}* **options** Options, unused here.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.StanbolConnector}* : The VIE.StanbolConnector instance itself.
      uploadContent: function(content, success, error, options) {
        options = (options)? options :  {};
        var connector = this;

        connector._iterate({
            method : connector._uploadContent,
            methodNode : connector._uploadContentNode,
            success : success,
            error : error,
            url : function (idx, opts) {
                 var u = this.options.url[idx].replace(/\/$/, '');
                 u += this.options.contenthub.urlPostfix.replace(/\/$/, '');

                 var index = (opts.index)? opts.index : this.options.contenthub.index;

                 u += "/" + index.replace(/\/$/, '');
                 u += "/store";

                 return u;
            },
            args : {
                content: content,
                options : options
            },
            urlIndex : 0
           });
       },

       _uploadContent : function (url, args, success, error) {
           jQuery.ajax({
               success: success,
               error: error,
               url: url,
               type: "POST",
               data : args.content,
               contentType : "text/plain"
           });
       },

       _uploadContentNode: function(url, args, success, error) {
           var request = require('request');
           var r = request({
               method: "POST",
               uri: url,
               body : args.content,
               headers: {
                   Accept: "application/rdf+xml",
                   "Content-Type" : "text/plain"
               }
           }, function(err, response, body) {
               try {
                   success({results: JSON.parse(body)});
               } catch (e) {
                   error(e);
               }
           });
           r.end();
       },

//### createFactSchema(url, schema, success, error, options)
//TODO.
//**Parameters**:
//TODO
//*{function}* **success** The success callback.
//*{function}* **error** The error callback.
//*{object}* **options** Options, unused here.
//**Throws**:
//*nothing*
//**Returns**:
//*{VIE.StanbolConnector}* : The VIE.StanbolConnector instance itself.
      createFactSchema: function(url, schema, success, error, options) {
             options = (options)? options :  {};
             var connector = this;

             options.url = url;

             connector._iterate({
                method : connector._createFactSchema,
                methodNode : connector._createFactSchemaNode,
                success : success,
                error : error,
                url : function (idx, opts) {
                  var u = this.options.url[idx].replace(/\/$/, '');
                  u += this.options.factstore.urlPostfix.replace(/\/$/, '');

                  u += "/facts/" + encodeURIComponent(opts.url);

                  return u;
                },
                args : {
                    url : url,
                    schema : schema,
                    options : options
                },
                urlIndex : 0
            });
        },

        _createFactSchema : function (url, args, success, error) {
               jQuery.ajax({
                success: success,
                error: error,
                url: url,
                type: "PUT",
                data : args.schema,
                contentType : "application/json",
                dataType: "application/json"
            });
        },

        _createFactSchemaNode: function(url, args, success, error) {
            var request = require('request');
            var r = request({
                method: "PUT",
                uri: url,
                body : args.schema,
                headers: {
                    Accept: "application/json",
                    "Content-Type" : "application/json"
                }
            }, function(err, response, body) {
                try {
                    success({results: JSON.parse(body)});
                } catch (e) {
                    error(e);
                }
            });
            r.end();
        },

        createFact: function(fact, success, error, options) {
             options = (options)? options :  {};
             var connector = this;

             connector._iterate({
                method : connector._createFact,
                methodNode : connector._createFactNode,
                success : success,
                error : error,
                url : function (idx, opts) {
                     var u = this.options.url[idx].replace(/\/$/, '');
                     u += this.options.factstore.urlPostfix.replace(/\/$/, '');

                     u += "/facts";

                  return u;
                },
                args : {
                    fact : fact,
                    options : options
                },
                urlIndex : 0
               });
       },

       _createFact : function (url, args, success, error) {
           jQuery.ajax({
               success: success,
               error: error,
               url: url,
               type: "POST",
               data : args.fact,
               contentType : "application/json",
               dataType: "application/json"
           });
       },

       _createFactNode: function(url, args, success, error) {
           var request = require('request');
           var r = request({
               method: "POST",
               uri: url,
               body : args.fact,
               headers: {
                   Accept: "application/json",
                   "Content-Type" : "application/json"
               }
           }, function(err, response, body) {
               try {
                   success({results: JSON.parse(body)});
               } catch (e) {
                   error(e);
               }
           });
           r.end();
       },

        queryFact: function(query, success, error, options) {
             options = (options)? options :  {};
             var connector = this;

             connector._iterate({
                method : connector._queryFact,
                methodNode : connector._queryFactNode,
                success : success,
                error : error,
                url : function (idx, opts) {
                     var u = this.options.url[idx].replace(/\/$/, '');
                     u += this.options.factstore.urlPostfix.replace(/\/$/, '');

                     u += "/query";

                  return u;
                },
                args : {
                    query : query,
                    options : options
                },
                urlIndex : 0
               });
       },

       _queryFact : function (url, args, success, error) {
           jQuery.ajax({
               success: success,
               error: error,
               url: url,
               type: "POST",
               data : args.query,
               contentType : "application/json",
               dataType: "application/json"
           });
       },

       _queryFactNode: function(url, args, success, error) {
           var request = require('request');
           var r = request({
               method: "POST",
               uri: url,
               body : args.query,
               headers: {
                   Accept: "application/json",
                   "Content-Type" : "application/json"
               }
           }, function(err, response, body) {
               try {
                   success({results: JSON.parse(body)});
               } catch (e) {
                   error(e);
               }
           });
           r.end();
       }
};
})();

<file_sep>module("Core - Entity");

test('toJSONLD export to JSON', function() {
    var z = new VIE();
    z.namespaces.add('example', 'http://example.net/foo/');
    z.namespaces.add("foaf", "http://xmlns.com/foaf/0.1/");

    var person = z.types.add("foaf:Person").inherit(z.types.get('owl:Thing'));
    var musician = z.types.add("example:Musician").inherit(z.types.get('owl:Thing'));

    z.entities.add({
        '@subject': 'http://example.net/Madonna',
        '@type': ['foaf:Person', 'example:Musician']
    });

    var model = z.entities.get('http://example.net/Madonna');

    var exportedJson = JSON.stringify(model.toJSONLD());
    var parsedJson = JSON.parse(exportedJson);

    equal(parsedJson['@subject'], '<http://example.net/Madonna>');
    deepEqual(parsedJson['@type'], ['<http://xmlns.com/foaf/0.1/Person>', '<http://example.net/foo/Musician>']);
});
<file_sep>module("vie.js - RDFa Service");

test("Test simple RDFa parsing", function() {
    var z = new VIE();
    z.use(new z.RdfaService());

    var html = jQuery('#qunit-fixture .rdfa-simple div');

    stop();
    z.load({element: html}).from('rdfa').execute().done(function(entities) {
        ok(entities);
        equal(entities.length, 2);
        var albert = z.entities.get('<http://dbpedia.org/resource/Albert_Einstein>');
        var germany = z.entities.get('<http://dbpedia.org/resource/Germany>');
        equal(albert.id, '<http://dbpedia.org/resource/Albert_Einstein>');
        equal(albert.get('foaf:name'), '<NAME>');
        equal(germany.get('dbp:conventionalLongName'), 'Federal Republic of Germany');

        start();
    });
});

test("Test updating RDFa views", function() {
    var z = new VIE();
    z.use(new z.RdfaService());

    var html = jQuery('#qunit-fixture .rdfa-updating div');
    
    stop();
    z.load({element: html}).from('rdfa').execute().done(function(entities) {
        ok(entities);
        equal(entities.length, 2);

        var germany = z.entities.get('<http://dbpedia.org/resource/Germany>');

        equal(germany.get('dbp:conventionalLongName'), 'Federal Republic of Germany');

        germany.set({'dbp:conventionalLongName': 'Switzerland'});
        equal(germany.get('dbp:conventionalLongName'), 'Switzerland');

        jQuery('[property="dbp:conventionalLongName"]', html).each(function() {
            equal(jQuery(this).html(), 'Switzerland');
        });

        start();
    });
});

test("Test simple RDFa nested tags", function() {
    var z = new VIE();
    z.use(new z.RdfaService());

    var html = jQuery('#qunit-fixture .rdfa-nested div');

    stop();
    z.load({element: html}).from('rdfa').execute().done(function(entities) {
        equal(entities.length, 1);
        equal(jQuery.trim(entities[0].get('dcterms:title')).toUpperCase(), '<span>News item title</span>'.toUpperCase());
        start();
    });
});

test("Test RDFa property content", function() {
    var z = new VIE();
    z.use(new z.RdfaService());

    var html = jQuery('#qunit-fixture .rdfa-property-content div');

    stop();
    z.load({element: html}).from('rdfa').execute().done(function(entities) {
        equal(entities.length, 1);
        equal(entities[0].get('iks:online'), 0);

        entities[0].set({'iks:online': 1});
        equal(entities[0].get('iks:online'), 1);
        equal(jQuery('[property="iks:online"]', html).attr('content'), 1);
        equal(jQuery('[property="iks:online"]', html).text(), '');

        start();
    });
});

test("Test RDFa example from Wikipedia", function() {
    var z = new VIE();
    z.use(new z.RdfaService());

    var html = jQuery('#qunit-fixture .rdfa-wikipedia p');

    stop();
    z.load({element: html}).from('rdfa').execute().done(function(entities) {
        var objectInstance = z.entities.get('<http://www.example.com/books/wikinomics>');
        equal(objectInstance.get('dc:title'), 'Wikinomics');
        equal(objectInstance.get('dc:creator'), '<NAME>');
        start();
    });
});

test("Test RDFa image entitization", function() {
    var options = {};
    if (navigator.userAgent === 'Zombie') {
        options.attributeExistenceComparator = '';
    }
    var z = new VIE();
    z.use(new z.RdfaService(options));

    var html = jQuery('#qunit-fixture .rdfa-image-entitization div');

    stop();
    
    z.load({element: html}).from('rdfa').execute().done(function(entities) {
      var icons = z.entities.get('<http://example.net/blog/news_item>').get('mgd:icon');
        // Ensure we have the image correctly read
        ok(icons instanceof z.Collection, "Icons should be a collection");
        if (!icons) {
            start();
            return;
        }
        equal(icons.at(0).id, '<http://example.net/image.jpg>');
        
        equal(jQuery('img', html).length, 1);
        
        // Remove it and replace with another image
        icons.remove(icons.at(0));
        equal(jQuery('img', html).length, 0);

        icons.add({'@subject': '<http://example.net/otherimage.jpg>'});
        
        equal(jQuery('img', html).length, 1);
        equal(jQuery('img[src="http://example.net/otherimage.jpg"]', html).length, 1);

        start();
    });
});


test("Test collection reset with RDFa", function() {
    var z = new VIE();
    z.use(new z.RdfaService());

    var html = jQuery('#qunit-fixture .rdfa-collection-reset');

    stop();
    z.load({element: html}).from('rdfa').execute().done(function(entities) {
        var entity = z.entities.get('<http://example.net/collectionreset>');
        ok(entity.isEntity);

        var collection = entity.get('collection');
        ok(collection.isCollection);
        equal(collection.length, 1);
        equal(collection.at(0).get('@type')[1].id, '<http://rdfs.org/sioc/ns#Post>');
        equal(jQuery('li[about]', html).length, 1);

        entity.set({
          collection: ['<http://example.net/collectionreset/item>', '<http://example.net/collectionreset/item2>']
        });

        collection = entity.get('collection');
        ok(collection.isCollection);
        equal(collection.length, 2);
        equal(jQuery('li[about]', html).length, 2);
        equal(jQuery('[about="http://example.net/collectionreset/item"]', html).length, 1);
        equal(jQuery('[about="http://example.net/collectionreset/item2"]', html).length, 1);

        // Add a blank node
        collection.add({});
        equal(jQuery('li[about]', html).length, 3);
        var newItem = collection.at(2);
        ok(newItem.isNew());
        newItem.set('@subject', 'http://example.net/collectionreset/item3');
        equal(jQuery('li[about]', html).length, 3);
        equal(jQuery('[about="http://example.net/collectionreset/item"]', html).length, 1);
        equal(jQuery('[about="http://example.net/collectionreset/item2"]', html).length, 1);
        equal(jQuery('[about="http://example.net/collectionreset/item3"]', html).length, 1);

        // Re-reset
        entity.set({
          collection: ['<http://example.net/collectionreset/item>', '<http://example.net/collectionreset/item2>', '<http://example.net/collectionreset/item3>']
        });
        equal(jQuery('li[about]', html).length, 3);
        equal(jQuery('[about="http://example.net/collectionreset/item"]', html).length, 1);
        equal(jQuery('[about="http://example.net/collectionreset/item2"]', html).length, 1);
        equal(jQuery('[about="http://example.net/collectionreset/item3"]', html).length, 1);
        start();
    });
});

test("Test type-specific collection RDFa templates", function () {
    var z = new VIE();
    z.use(new z.RdfaService());

    var html = jQuery('#qunit-fixture .rdfa-collection-twotemplates');

    stop();
    z.load({element: html}).from('rdfa').execute().done(function (entities) {
        var mainEntity = z.entities.get('<http://example.net/mycollection>');
        ok(mainEntity.isEntity);

        var collection = mainEntity.get('section');
        ok(collection.isCollection);
        equal(collection.length, 2);
        equal(jQuery('div[about]', html).length, 3);
        equal(jQuery('h1', html).length, 1);
        equal(jQuery('h2', html).length, 1);

        collection.add({
          '@type': 'first'
        });
        equal(collection.length, 3);
        equal(jQuery('h1', html).length, 2);
        equal(jQuery('h2', html).length, 1);

        collection.remove(collection.at(2));
        equal(collection.length, 2);
        equal(jQuery('h1', html).length, 1);

        collection.add({
          '@type': 'second'
        });
        equal(collection.length, 3);
        equal(jQuery('h2', html).length, 2);
        equal(jQuery('h1', html).length, 1);

        collection.remove(collection.at(2));
        equal(collection.length, 2);
        equal(jQuery('h2', html).length, 1);

        // Add a model of unspecified type, should add using the second template
        collection.add({});
        equal(collection.length, 3);
        equal(jQuery('h2', html).length, 2);
        equal(jQuery('h1', html).length, 1);

        collection.remove(collection.at(2));
        equal(collection.length, 2);
        equal(jQuery('h2', html).length, 1);

        start();
    });
});

test("Test collection with custom RDFa template", function () {
    var z = new VIE();
    z.use(new z.RdfaService());

    var html = jQuery('#qunit-fixture .rdfa-collection-scripttemplate');

    stop();
    z.load({element: html}).from('rdfa').execute().done(function (entities) {
        var mainEntity = z.entities.get('<http://example.net/mycollection>');
        ok(mainEntity.isEntity);

        var collection = mainEntity.get('section');
        ok(collection.isCollection);
        equal(collection.length, 0);
        equal(jQuery('div[rel="section"]', html).children().length, 0);

        // We should not be able to add to DOM without template
        collection.add({});
        equal(jQuery('div[rel="section"]', html).children().length, 0);
        equal(collection.length, 1);
        collection.remove(collection.at(0));
        equal(collection.length, 0);

        // Register a template with the RDFa service
        z.service('rdfa').setTemplate('second', 'section', jQuery('.template', html).html());

        // Now adding should work
        collection.add({
          '@type': 'second'
        });
        equal(jQuery('div[rel="section"]', html).children().length, 1);
        equal(collection.length, 1);
        equal(jQuery('div[rel="section"] h2', html).length, 1);

        collection.remove(collection.at(0));
        equal(jQuery('div[rel="section"]', html).children().length, 0);

        start();
    });
});

test("Test collection with custom RDFa template function", function () {
    var z = new VIE();
    z.use(new z.RdfaService());

    var html = jQuery('#qunit-fixture .rdfa-collection-scripttemplate2');

    stop();
    z.load({element: html}).from('rdfa').execute().done(function (entities) {
        var mainEntity = z.entities.get('<http://example.net/mycollection>');
        ok(mainEntity.isEntity);

        var collection = mainEntity.get('section');
        ok(collection.isCollection);
        equal(collection.length, 0);
        equal(jQuery('div[rel="section"]', html).children().length, 0);

        // We should not be able to add to DOM without template
        collection.add({});
        equal(jQuery('div[rel="section"]', html).children().length, 0);
        equal(collection.length, 1);
        collection.remove(collection.at(0));
        equal(collection.length, 0);

        // Register a template with the RDFa service
        z.service('rdfa').setTemplate('second', 'section', function (entity, callback, collectionView) {
            ok(collectionView instanceof z.view.Collection);
            window.setTimeout(function () {
                callback(jQuery(jQuery.trim(jQuery('.template', html).html())).clone(false));
            }, 0);
        });

        // Now adding should work
        collection.add({
            '@type': 'second'
        });

        window.setTimeout(function () {
            equal(jQuery('div[rel="section"]', html).children().length, 1);
            equal(collection.length, 1);
            equal(jQuery('div[rel="section"] h2', html).length, 1);

            collection.remove(collection.at(0));
            equal(jQuery('div[rel="section"]', html).children().length, 0);

            start();
        }, 1);
    });
});

test("Test direct RDFa collection", function () {
    var z = new VIE();
    z.use(new z.RdfaService());

    var html = jQuery('#qunit-fixture .rdfa-collection-twotemplates');

    stop();
    z.load({element: html}).from('rdfa').execute().done(function (entities) {
        var mainEntity = z.entities.get('<http://example.net/mycollection>');
        ok(mainEntity.isEntity);

        var collection = mainEntity.get('section');
        ok(collection.isCollection);
        equal(collection.length, 2);

        equal(collection.at(0).get('title'), 'Content');

        equal(jQuery('div[about]', html).length, 3);
        equal(jQuery('h1', html).length, 1);
        equal(jQuery('h2', html).length, 1);

        collection.add({
          '@type': 'first'
        });
        equal(collection.length, 3);
        equal(jQuery('h1', html).length, 2);
        equal(jQuery('h2', html).length, 1);

        collection.remove(collection.at(2));
        equal(collection.length, 2);
        equal(jQuery('h1', html).length, 1);

        collection.add({
          '@type': 'second'
        });
        equal(collection.length, 3);
        equal(jQuery('h2', html).length, 2);
        
        start();
    });
});

test("Test RDFa datatype parsing", function () {
    var z = new VIE();
    z.use(new z.RdfaService());

    var html = jQuery('#qunit-fixture .rdfa-datatypes');

    stop();
    z.load({element: html}).from('rdfa').execute().done(function (entities) {
        var entity = z.entities.get('<http://example.net/datatypes>');

        ok(_.isBoolean(entity.get('boolean')));
        ok(_.isBoolean(entity.get('boolean2')));
        equal(entity.get('boolean'), false);
        equal(entity.get('boolean2'), true);

        ok(_.isDate(entity.get('date')));
        equal(entity.get('date').getFullYear(), 2012);

        ok(_.isNumber(entity.get('number')));
        equal(entity.get('number'), 123);

        // Test writing as well
        equal(jQuery('[property="boolean"]', html).attr('content'), 'false');
        entity.set('boolean', true);
        equal(jQuery('[property="boolean"]', html).attr('content'), 'true');

        entity.set('date', new Date('1999-05-08T21:00:01Z'));
        equal(jQuery('[property="date"]', html).attr('content'), '1999-05-08T21:00:01.000Z');

        entity.set('number', 42);
        equal(jQuery('[property="number"]', html).text(), '42');

        start();
    });
});

test("Test multiple RDFa instances of same entity", function () {
    var z = new VIE();
    z.use(new z.RdfaService());

    var html = jQuery('#qunit-fixture .rdfa-twoinstances');

    stop();
    z.load({element: html}).from('rdfa').execute().done(function (entities) {
        // Freshly parsed, there should be no recorded changes in the entity
        var entity = z.entities.get('<http://example.net/example>');
        equal(entity.changedAttributes(), false);
        equal(entity.hasChanged('<http://purl.org/dc/terms/description>'), false);

        // Change one value, now changes should be recorded
        entity.set('dcterms:description', 'Baz');
        equal(entity.get('<http://purl.org/dc/terms/description>'), 'Baz');
        equal(entity.hasChanged('<http://purl.org/dc/terms/description>'), true);
        start();
    });
});

test("Test anonymous relation", function () {
    var z = new VIE();
    z.use(new z.RdfaService());

    var html = jQuery('#qunit-fixture .rdfa-anonrelation');

    stop();
    z.load({element: html}).from('rdfa').execute().done(function (entities) {
        start();

        var entity = z.entities.get('<http://example.net/example>');
        ok(entity);
        equal(entity.get('dcterms:title'), 'Foo');

        var relations = entity.get('relations');
        equal(relations.length, 1);
        equal(relations.at(0).get('dcterms:title'), 'Bar');
    });
});

test("Test deep relations", function () {
    var z = new VIE();
    z.use(new z.RdfaService());

    var html = jQuery('#qunit-fixture .rdfa-deeprelation');

    stop();
    z.load({element: html}).from('rdfa').execute().done(function (entities) {
        start();

        var entity = z.entities.get('<http://example.net/example>');
        ok(entity);
        equal(entity.get('dcterms:title'), 'Foo');

        equal(jQuery('div[about]', html).length, 3);

        var relations = entity.get('relations');
        equal(relations.length, 1);

        var first = relations.at(0);
        equal(first.get('dcterms:title'), 'Bar');
        equal(jQuery('[rel="relations"] > div[about]', html).length, 1);

        relations.add({
          'dcterms:title': 'BarFoo'
        });
        equal(relations.length, 2);
        equal(relations.at(1).get('dcterms:title'), 'BarFoo');
        equal(jQuery('[rel="relations"] > div[about]', html).length, 2);
        equal(jQuery('div[property]', jQuery('[rel="relations"] > div[about]', html).get(1)).html(), 'BarFoo');

        relations.at(1).set('dcterms:title', 'BarFooBaz');
        equal(jQuery('div[property]', jQuery('[rel="relations"] > div[about]', html).get(1)).html(), 'BarFooBaz');

        relations.remove(relations.at(1));
        equal(relations.length, 1);
        equal(jQuery('[rel="relations"] > div[about]', html).length, 1);
        equal(jQuery('[rel="relations"] > div[about] div[property]', html).html(), 'Bar');

        var subrelations = first.get('subrelations');
        equal(subrelations.length, 1);
        var second = subrelations.at(0);
        equal(second.get('dcterms:title'), 'Baz');

        equal(jQuery('[rel="subrelations"] div[about]', html).length, 1);

        subrelations.add({
          'dcterms:title': 'BazFoo'
        });
        equal(subrelations.length, 2);
        equal(jQuery('[rel="subrelations"] div[about]', html).length, 2);
        equal(jQuery('div[property]', jQuery('[rel="subrelations"] div[about]', html).get(1)).html(), 'BazFoo');

        subrelations.at(1).set('dcterms:title', 'BazFooBar');
        equal(jQuery('div[property]', jQuery('[rel="subrelations"] > div[about]', html).get(1)).html(), 'BazFooBar');

        subrelations.remove(subrelations.at(1));
        equal(subrelations.length, 1);
        equal(jQuery('[rel="subrelations"] div[about]', html).length, 1);
        equal(jQuery('[rel="subrelations"] > div[about] div[property]', html).html(), 'Baz');
    });
});

test("Test local namespace declaration", function () {
    var z = new VIE();
    z.use(new z.RdfaService());

    var html = jQuery('#qunit-fixture .rdfa-localns');

    stop();
    z.load({element: html}).from('rdfa').execute().done(function (entities) {
        start();
        ok(entities.length);
        var entity = z.entities.at(0);
        ok(entity);
        ok(entity.isof('foo:Bar'));
        equal(entity.get('foo:Baz'), 'Foo');
    });
});
<file_sep>(function(){
    
  var entity = undefined;
  /*
  JSLitmus.test('Type: register + unregister new type', function() {
    var newPersonType = new VIE2.Type('PersonWithAge', 'Person', [
        {id       : 'age',
         datatype : 'Integer'
         }], {});
   VIE2.unregisterType('PersonWithAge');
  });

  JSLitmus.test('Model: create without props', function() {
    new VIE2.Entity();
  });
  
  JSLitmus.test('Model: create with props', function() {
    entity = new VIE2.Entity({
       a: 'Person',
       name : '<NAME>',
       description : 'This is a test'
   });
  });
  
  JSLitmus.test('Model: change props', function() {
    entity.set({
      name: '<NAME>',
      description : ['This is a test', 'This is another test']
   });
  });
  */
})();<file_sep>VIE ChangeLog
=============

## 2.2.0 (January 21st 2015)

* Use dependencies from Bower
* Minor fixes regarding updated dependencies

## 2.1.2 (September 10th 2013)

* Namespace registration is now less strict, allowing multiple prefixes pointing to same URI

## 2.1.1 (September 10th 2013)

* `VIE.Entity` was refactored to use regular Backbone Model semantics, allowing it to be [extended as needed](https://groups.google.com/d/topic/viejs/Chg-sO7dw6s/discussion)
* Default [Apache Stanbol](http://stanbol.apache.org/) configuration was swithed to use the IKS-hosted [demo server](http://demo.iks-project.eu/stanbolfull)
* Compatibility with Backbone.js 1.0.0
* Build system was switched from Ant to [Grunt](http://gruntjs.com)
* Dependencies moved to using Bower

## 2.1.0 (December 5th 2012)

See the [release announcement](https://groups.google.com/d/topic/viejs/RYKfp0Fhuag/discussion).

## 2.0.0 (April 25th 2012)

See the [introductory blog post](http://blog.iks-project.eu/vie-towards-v2-0-update/).
